Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes)
[![LiveCodes: languages](https://img.shields.io/badge/languages-116-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: languages](https://img.shields.io/badge/languages-118-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/)
[![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt)
[![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt)
Expand Down
112 changes: 112 additions & 0 deletions docs/docs/languages/nim-wasm.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Nim (Wasm)

[Nim](https://nim-lang.org/) is a statically typed, compiled systems programming language.

In LiveCodes, Nim runs in the browser using the [Nim compiler](https://nim-lang.org/) compiled to WebAssembly. This target (Nim's `c` backend) compiles the program to C and then to WebAssembly using the [Clang](https://clang.llvm.org/) toolchain, the same one used for [C (Wasm)](./c-wasm.mdx), entirely client-side.

> For Nim's JavaScript backend, which compiles to JavaScript and allows DOM access for the [result page](../features/result.mdx), see [Nim](./nim.mdx).

## Usage

Demo:

import LiveCodes from '../../src/components/LiveCodes.tsx';

export const nimWasmConfig = {
activeEditor: 'script',
script: {
language: 'nim-wasm',
content: `echo "Hello, World!"`,
},
mode: 'simple',
editor: 'auto',
tools: {
status: 'full',
},
};

<LiveCodes config={nimWasmConfig}></LiveCodes>

### Communication with JavaScript

The Nim code is compiled and run in a web worker. The following helpers are available in the browser global `livecodes.nimWasm` object:

- `livecodes.nimWasm.input`: The standard input passed to the program.
- `livecodes.nimWasm.loaded`: A promise that resolves when the compiler is loaded and the program has run once.
- `livecodes.nimWasm.output`: The program's output.
- `livecodes.nimWasm.error`: The compiler diagnostics, if the code failed to compile.
- `livecodes.nimWasm.exitCode`: The program's exit code.
- `livecodes.nimWasm.run`: A function that compiles and runs the code with new input. It takes a string as input and returns a promise that resolves with an object containing `output`, `error` and `exitCode`.

Example:

<LiveCodes template="nim-wasm" params={{ activeEditor: 'markup' }} height="80vh"></LiveCodes>

## Language Info

### Name

`nim-wasm`

### Aliases / Extensions

`nimwasm`, `wasm.nim`

### Editor

`script`

## Compiler

The [Nim compiler](https://nim-lang.org/) (Nim's `c` backend) compiled to WebAssembly. The generated C is compiled and linked by the [Clang](https://clang.llvm.org/) toolchain of [@live-codes/clang-wasm](https://www.npmjs.com/package/@live-codes/clang-wasm).

### Version

Nim `v2.2.4`, Clang `v22.1.8`.

## Custom Settings

The compiler can be configured using [custom settings](../advanced/custom-settings.mdx) added to the property `nim-wasm`:

| Property | Type | Description |
| --- | --- | --- |
| `compileArgs` | `string[]` | Extra Nim flags, e.g. `["--define:release2"]`. |
| `args` | `string[]` | Command-line arguments passed to the program. |

```json title="Custom Settings"
{
"nim-wasm": {
"compileArgs": ["--define:release2"],
"args": ["--name", "LiveCodes"]
}
}
```

## Live Reload

By default, new code changes are sent to the result page without a full page reload, avoiding the need to re-download the compiler. Adding the code comment `# __livecodes_reload__` forces a full page reload.

## Example Usage

```nim
import std/strutils

echo "Hello, World!"

let name = stdin.readLine()
echo "Hello, ", name, "!"
```

This target supports standard input, command-line arguments and real exit codes. A program that reads standard input gets an end-of-input error when it is left blank.

## Starter Template

https://livecodes.io/?template=nim-wasm

## Links

- [Nim official website](https://nim-lang.org/)
- [Nim manual](https://nim-lang.org/docs/manual.html)
- [Nim standard library](https://nim-lang.org/docs/lib.html)
- [@live-codes/nim-wasm](https://www.npmjs.com/package/@live-codes/nim-wasm)
- [C (Wasm)](./c-wasm.mdx) in LiveCodes
88 changes: 88 additions & 0 deletions docs/docs/languages/nim.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Nim

[Nim](https://nim-lang.org/) is a statically typed, compiled systems programming language.

In LiveCodes, Nim runs in the browser using the [Nim compiler](https://nim-lang.org/) compiled to WebAssembly, through Nim's JavaScript backend. The compiled program runs in the result page, so it can drive the DOM directly (e.g. through the `dom` and `jsffi` modules).

> For Nim's WebAssembly backend, which supports standard input, command-line arguments and real exit codes, see [Nim (Wasm)](./nim-wasm.mdx).

## Usage

Demo:

import LiveCodes from '../../src/components/LiveCodes.tsx';

export const nimConfig = {
activeEditor: 'script',
script: {
language: 'nim',
content: `echo "Hello, World!"`,
},
mode: 'simple',
editor: 'auto',
tools: {
status: 'full',
},
};

<LiveCodes config={nimConfig}></LiveCodes>

### Communication with the result page

Nim's JavaScript backend emits one self-sufficient program that runs in the result page. It has a document and a console, so `echo` writes to the console, and the browser modules that ship with the compiler (`dom`, `jsffi`, `jsconsole`, `jscore`, `jsre` and `asyncjs`) are on its search path:

```nim
import dom

document.title = "Nim in LiveCodes"
let element = document.createElement("p")
element.innerText = "Hello from Nim!"
document.body.appendChild(element)
```

Example:

<LiveCodes template="nim" params={{ compiled: 'open' }} height="80vh"></LiveCodes>

## Language Info

### Name

`nim`

### Aliases / Extensions

`nim`, `nims`, `nimble`, `nim-js`, `js.nim`

### Editor

`script`

## Compiler

The [Nim compiler](https://nim-lang.org/) (Nim's `js` backend) compiled to WebAssembly, packaged as [@live-codes/nim-wasm](https://www.npmjs.com/package/@live-codes/nim-wasm). It is compiled with `execute: false`, and the emitted program runs in the result page.

### Version

Nim `v2.2.4`.

## Example Usage

```nim
import std/strutils

echo "Hello, World!"
echo "2 + 2 = ", 2 + 2
```

## Starter Template

https://livecodes.io/?template=nim

## Links

- [Nim official website](https://nim-lang.org/)
- [Nim manual](https://nim-lang.org/docs/manual.html)
- [Nim standard library](https://nim-lang.org/docs/lib.html)
- [@live-codes/nim-wasm](https://www.npmjs.com/package/@live-codes/nim-wasm)
- [Nim (Wasm)](./nim-wasm.mdx) in LiveCodes
2 changes: 2 additions & 0 deletions docs/src/components/LanguageSliders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export default function Sliders() {
{ name: 'rescript', title: 'ReScript' },
{ name: 'reason', title: 'Reason' },
{ name: 'ocaml', title: 'OCaml' },
{ name: 'nim', title: 'Nim' },
{ name: 'nim-wasm', title: 'Nim (Wasm)' },
{ name: 'python', title: 'Python' },
{ name: 'python-wasm', title: 'Python (Wasm)' },
{ name: 'r', title: 'R' },
Expand Down
2 changes: 2 additions & 0 deletions docs/src/components/TemplateList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const templates = [
{ name: 'rescript', title: 'ReScript Starter', thumbnail: 'rescript.png' },
{ name: 'reason', title: 'Reason Starter', thumbnail: 'reason.svg' },
{ name: 'ocaml', title: 'Ocaml Starter', thumbnail: 'ocaml.svg' },
{ name: 'nim', title: 'Nim Starter', thumbnail: 'nim.svg' },
{ name: 'nim-wasm', title: 'Nim (Wasm) Starter', thumbnail: 'nim.svg' },
{ name: 'python', title: 'Python Starter', thumbnail: 'python.svg' },
{ name: 'python-wasm', title: 'Python (Wasm) Starter', thumbnail: 'python.svg' },
{ name: 'r', title: 'R Starter', thumbnail: 'r.svg' },
Expand Down
92 changes: 92 additions & 0 deletions e2e/specs/starter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,56 @@ test.describe('Starter Templates from UI', () => {
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});

test('nim Starter', async ({ page, getTestUrl }) => {
// the compiler is downloaded on the first run
test.slow();

await page.goto(getTestUrl());

const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);

await app.click('[aria-label="Project"]');
await app.click('text=New');
await app.click('text=Nim Starter');

await waitForEditorFocus(app);
await waitForResultUpdate();

// the heading is set by the compiled program, and only then is the click handler wired up
await expect(getResult().locator('h1')).toHaveText('Hello, Nim!', { timeout: 120_000 });

await getResult().click('text=Click me');
await getResult().click('text=Click me');
await getResult().click('text=Click me');

await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});

test('nim-wasm Starter', async ({ page, getTestUrl }) => {
// the compiler, linker and sysroot (~29 MB) are downloaded on the first run
test.slow();

await page.goto(getTestUrl());

const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);

await app.click('[aria-label="Project"]');
await app.click('text=New');
await app.click('text=Nim (Wasm) Starter');

await waitForEditorFocus(app);
await waitForResultUpdate();

// the counter stays disabled until the compiler has loaded and run once
await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 280_000 });

await getResult().click('text=Click me');
await getResult().click('text=Click me');
await getResult().click('text=Click me');

await expect(getResult().locator('h1')).toHaveText('Hello, Nim!');
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});
test('haskell Starter', async ({ page, getTestUrl }) => {
test.slow();

Expand Down Expand Up @@ -1228,6 +1278,48 @@ test.describe('Starter Templates from URL', () => {
expect(counterText).toBe('You clicked 3 times.');
});

test('nim Starter (in URL)', async ({ page, getTestUrl }) => {
// the compiler is downloaded on the first run
test.slow();

await page.goto(getTestUrl({ template: 'nim' }));

const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);

await waitForEditorFocus(app);
await waitForResultUpdate();

// the heading is set by the compiled program, and only then is the click handler wired up
await expect(getResult().locator('h1')).toHaveText('Hello, Nim!', { timeout: 120_000 });

await getResult().click('text=Click me');
await getResult().click('text=Click me');
await getResult().click('text=Click me');

await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});

test('nim-wasm Starter (in URL)', async ({ page, getTestUrl }) => {
// the compiler, linker and sysroot (~29 MB) are downloaded on the first run
test.slow();

await page.goto(getTestUrl({ template: 'nim-wasm' }));

const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);

await waitForEditorFocus(app);
await waitForResultUpdate();

// the counter stays disabled until the compiler has loaded and run once
await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 280_000 });

await getResult().click('text=Click me');
await getResult().click('text=Click me');
await getResult().click('text=Click me');

await expect(getResult().locator('h1')).toHaveText('Hello, Nim!');
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});
test('haskell Starter (in URL)', async ({ page, getTestUrl }) => {
test.slow();

Expand Down
2 changes: 2 additions & 0 deletions functions/vendors/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export const starterTemplates = {
"rescript": "ReScript Starter",
"reason": "Reason Starter",
"ocaml": "Ocaml Starter",
"nim": "Nim Starter",
"nim-wasm": "Nim (Wasm) Starter",
"python": "Python Starter",
"python-wasm": "Python (Wasm) Starter",
"r": "R Starter",
Expand Down
1 change: 1 addition & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ const iifeBuild = () =>
'languages/java/lang-java-script.ts',
'languages/cpp/lang-cpp-script.ts',
'languages/clang-wasm/lang-clang-wasm-script.ts',
'languages/nim/lang-nim-wasm-script.ts',
'languages/fortran-wasm/lang-fortran-wasm-script.ts',
'languages/d-wasm/lang-d-wasm-script.ts',
'languages/cobol-wasm/lang-cobol-wasm-script.ts',
Expand Down
2 changes: 2 additions & 0 deletions server/php/inc/starter-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"rescript": "ReScript Starter",
"reason": "Reason Starter",
"ocaml": "Ocaml Starter",
"nim": "Nim Starter",
"nim-wasm": "Nim (Wasm) Starter",
"python": "Python Starter",
"python-wasm": "Python (Wasm) Starter",
"r": "R Starter",
Expand Down
2 changes: 2 additions & 0 deletions src/livecodes/UI/command-menu-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ export const getCommandMenuActions = ({
'rescript',
'reason',
'ocaml',
'nim',
'nim-wasm',
'python',
'python-wasm',
'r',
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/assets/templates/nim.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading