turbo-editors/turbo-jspublic Fork 0
v1.0.2
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-js.git
git clone ssh://git@rickub.com/turbo-editors/turbo-js.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

📦 Turbo JS 91999d1 · on v1.0.2 · k33g · 12h ago
enable-completion.md · 127 lines · 8.5 KBmarkdown
Blame HistoryOpen raw

How to enable JavaScript completion

This guide shows how to get completion, hovers, go-to-definition, references and error marks working. It assumes Turbo JS is already installed.

Completion comes from typescript-language-server, a language server over tsserver — the engine behind every editor's JavaScript support — which serves plain JavaScript as well as TypeScript. Turbo JS does not bundle it: editing and colouring work without it, and only completion, the Code menu and the error marks are lost.

1. Install the server, with TypeScript 6

npm install -g typescript-language-server typescript@6

Two packages, and the @6 is not optional. The server is a thin layer over the typescript package's tsserver.js, and it does not depend on that package, so both have to be installed. TypeScript 7 — the current major — ships no tsserver.js: it is the native port, with a language server of its own inside its compiler, and typescript-language-server installed beside it starts and then refuses with Could not find a valid TypeScript installation. TypeScript 6 is the last version that ships the file.

Turbo JS's own installer will do this for you: scripts/install.sh --with-server. How to install Node.js covers getting npm itself.

2. Make sure Turbo JS can find it

Turbo JS looks on PATH first, then where npm install -g writes on a machine that uses a version manager: $NVM_BIN, $NPM_CONFIG_PREFIX/bin or ~/.npm-global/bin, $PNPM_HOME, $VOLTA_HOME/bin or ~/.volta/bin, then /usr/local/bin and /opt/homebrew/bin. Check:

typescript-language-server --version
6.0.0

If that says "command not found" but Turbo JS still finds it, that is expected and fine: the editor searched the directories above itself.

3. Open a file inside a project

cd /path/to/your/project
turbo-js src/index.js

The server is started in the project root — the nearest directory at or above the file you opened that holds a package.json. That is where node_modules/ is and where import and require resolve from, so it is what decides which modules the server knows. A file with no package.json anywhere above it gets the working directory, and the server infers a project from the files it is shown.

Where you start the editor decides where the JavaScript menu's commands run, which is a different matter: start it from the directory holding package.json too.

4. Ask for a completion

Type a name and a dot, or the first letters of a name and Ctrl-Space:

const text = "hello";
text.

A list drops down under the cursor — charAt, length, toUpperCase, with their signatures. Keep typing to narrow it, ↑ ↓ to walk it, Enter or Tab to accept, Escape to dismiss.

What the list holds

tsserver infers types through a language that declares none, so the list is about what your code is rather than what it says:

Offered Example
Every name in scope — variables, functions, classes, parameters — including ones typed a second ago and not yet saved your own helper
The members of a value, from its inferred type text. → the String methods; process.argv, env, exit
The exports of a module you imported, and the modules under node_modules/ when you type a from " import { readFile } from "node:fs/promises"
Node's globals and the standard library's console, Buffer, setTimeout, structuredClone
Keywords async, await, class

Checking what the server is doing

The right-hand end of the status bar shows the language server's state: LSP: starting…, LSP: ready, or why there is none:

LSP: no typescript-language-server — npm install -g typescript-language-server typescript@6

Run ▸ Language server status shows the same thing in a box, with the path it found the server at and the directory it started it in.

Variants

You do not want a language server at all:

turbo-js -no-lsp main.js

Completion is dead in a window that started without a name. An Untitled window has no file to announce to the server until it is saved — press F2 and give it a name ending in .js, somewhere under the project. From that save on, completion, hover and the error marks work in that window; there is no need to quit and relaunch.

The server starts and then dies. Run it by hand: echo | typescript-language-server --stdio. If it prints Could not find a valid TypeScript installation, the typescript package beside it is version 7 — npm ls -g typescript says — and npm install -g typescript@6 fixes it. A project with its own typescript in node_modules/ is used in preference to the global one, so a project on TypeScript 7 gets the same message: add typescript@6 to its dev dependencies, or point the server elsewhere.

Completion works but nothing is ever underlined. For a plain .js file the server reports syntax errors only. Type errors — calling a method that does not exist, passing a string where a number goes — need // @ts-check as the first line of the file, or a jsconfig.json in the project with "checkJs": true. Both are the server's design, not the editor's.

The list is empty just after the editor starts. tsserver loads the project after it has said it is ready, and answers an empty list until it has. Ask again a second later.

Ctrl-Space does nothing. tmux, screen and IDE terminals frequently claim Ctrl-Space before the editor sees it. Use Run ▸ Completion instead, or type a ..

A request takes too long. Every request gives up after a few seconds, so a stuck server slows the editor but never freezes it. The status bar reports the failure.

You installed the server somewhere unusual. The editor searches PATH and the directories listed above, and nowhere else. Put the directory on PATH, or set the variable your version manager defines — NVM_BIN, PNPM_HOME, VOLTA_HOME — in the shell you start the editor from.

You would rather use TypeScript 7's own server. tsc --lsp --stdio from the typescript package answers every question this editor asks, faster, and publishes no diagnostics: it offers them pull-style, which turbo-core does not request, so the gutter would stay blank. That is why it is not the default. The explanation has the measurement.

What else the server gives you

Completion is the loudest thing it does and the least of what it knows. The same connection answers eight more questions, all of them in the Code menu and all of them about the symbol under the cursor — no selection needed.

Key What it does With typescript-language-server
Ctrl-Space Completion list yes
F1 Describe the symbol under the cursor yes — its signature, and the JSDoc comment written just above a declaration of yours
F12 Jump to where it is declared yes, in this file or another
Shift-F12 List everywhere it is used yes — the declaration and every call, as a list to choose from
Ctrl-T Find a symbol by name anywhere in the project yes

And, without a key: Go to type definition takes const shape = new Circle() to class Circle; Find implementations… on a class lists its subclasses; Symbol in file… lists the file's functions and classes, with each class's methods nested under it; Problems… lists every diagnostic.

All nine questions are answered, and a test in this repository drives each of them against the real server, so this table cannot go stale quietly.

The error marks

Problems the server finds arrive unasked, on open and on every edit. The first error in the file you are editing appears on the right of the status bar, prefixed with ; every line with a problem gets a × in the gutter; and Code ▸ Problems… lists all of them.

For a plain .js file they are syntax errors — a missing bracket, an unexpected token — reported at the exact column. Type errors need // @ts-check or checkJs, as above. A program that parses and then fails when run gets no mark: the server never runs anything.

How to ask what the code means walks through the Code menu.

See also

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# How to enable JavaScript completion

This guide shows how to get completion, hovers, go-to-definition, references and error marks working. It assumes Turbo JS is already installed.

Completion comes from **`typescript-language-server`**, a language server over `tsserver` — the engine behind every editor's JavaScript support — which serves plain JavaScript as well as TypeScript. Turbo JS does not bundle it: editing and colouring work without it, and only completion, the Code menu and the error marks are lost.

## 1. Install the server, with TypeScript 6

```bash
npm install -g typescript-language-server typescript@6
```

Two packages, and the `@6` is not optional. The server is a thin layer over the `typescript` package's `tsserver.js`, and it does not depend on that package, so both have to be installed. **TypeScript 7 — the current major — ships no `tsserver.js`**: it is the native port, with a language server of its own inside its compiler, and `typescript-language-server` installed beside it starts and then refuses with *Could not find a valid TypeScript installation*. TypeScript 6 is the last version that ships the file.

Turbo JS's own installer will do this for you: `scripts/install.sh --with-server`. [How to install Node.js](install-node.md) covers getting `npm` itself.

## 2. Make sure Turbo JS can find it

Turbo JS looks on `PATH` first, then where `npm install -g` writes on a machine that uses a version manager: `$NVM_BIN`, `$NPM_CONFIG_PREFIX/bin` or `~/.npm-global/bin`, `$PNPM_HOME`, `$VOLTA_HOME/bin` or `~/.volta/bin`, then `/usr/local/bin` and `/opt/homebrew/bin`. Check:

```bash
typescript-language-server --version
```

```
6.0.0
```

If that says "command not found" but Turbo JS still finds it, that is expected and fine: the editor searched the directories above itself.

## 3. Open a file inside a project

```bash
cd /path/to/your/project
turbo-js src/index.js
```

The server is started in the **project root** — the nearest directory at or above the file you opened that holds a `package.json`. That is where `node_modules/` is and where `import` and `require` resolve from, so it is what decides which modules the server knows. A file with no `package.json` anywhere above it gets the working directory, and the server infers a project from the files it is shown.

Where you *start* the editor decides where the JavaScript menu's commands run, which is a different matter: start it from the directory holding `package.json` too.

## 4. Ask for a completion

Type a name and a dot, or the first letters of a name and **Ctrl-Space**:

```javascript
const text = "hello";
text.
```

A list drops down under the cursor — `charAt`, `length`, `toUpperCase`, with their signatures. Keep typing to narrow it, **↑ ↓** to walk it, **Enter** or **Tab** to accept, **Escape** to dismiss.

## What the list holds

`tsserver` infers types through a language that declares none, so the list is about what your code *is* rather than what it says:

| Offered | Example |
| --- | --- |
| Every name in scope — variables, functions, classes, parameters — including ones typed a second ago and not yet saved | your own `helper` |
| The members of a value, from its inferred type | `text.` → the String methods; `process.``argv`, `env`, `exit` |
| The exports of a module you imported, and the modules under `node_modules/` when you type a `from "` | `import { readFile } from "node:fs/promises"` |
| Node's globals and the standard library's | `console`, `Buffer`, `setTimeout`, `structuredClone` |
| Keywords | `async`, `await`, `class` |

## Checking what the server is doing

The right-hand end of the status bar shows the language server's state: `LSP: starting…`, `LSP: ready`, or why there is none:

```
LSP: no typescript-language-server — npm install -g typescript-language-server typescript@6
```

`Run ▸ Language server status` shows the same thing in a box, with the path it found the server at and the directory it started it in.

## Variants

**You do not want a language server at all:**

```bash
turbo-js -no-lsp main.js
```

**Completion is dead in a window that started without a name.** An Untitled window has no file to announce to the server until it is saved — press **F2** and give it a name ending in `.js`, somewhere under the project. From that save on, completion, hover and the error marks work in that window; there is no need to quit and relaunch.

**The server starts and then dies.** Run it by hand: `echo | typescript-language-server --stdio`. If it prints *Could not find a valid TypeScript installation*, the `typescript` package beside it is version 7 — `npm ls -g typescript` says — and `npm install -g typescript@6` fixes it. A project with its own `typescript` in `node_modules/` is used in preference to the global one, so a project on TypeScript 7 gets the same message: add `typescript@6` to its dev dependencies, or point the server elsewhere.

**Completion works but nothing is ever underlined.** For a plain `.js` file the server reports **syntax errors** only. Type errors — calling a method that does not exist, passing a string where a number goes — need `// @ts-check` as the first line of the file, or a `jsconfig.json` in the project with `"checkJs": true`. Both are the server's design, not the editor's.

**The list is empty just after the editor starts.** `tsserver` loads the project after it has said it is ready, and answers an empty list until it has. Ask again a second later.

**Ctrl-Space does nothing.** tmux, screen and IDE terminals frequently claim `Ctrl-Space` before the editor sees it. Use `Run ▸ Completion` instead, or type a `.`.

**A request takes too long.** Every request gives up after a few seconds, so a stuck server slows the editor but never freezes it. The status bar reports the failure.

**You installed the server somewhere unusual.** The editor searches `PATH` and the directories listed above, and nowhere else. Put the directory on `PATH`, or set the variable your version manager defines — `NVM_BIN`, `PNPM_HOME`, `VOLTA_HOME` — in the shell you start the editor from.

**You would rather use TypeScript 7's own server.** `tsc --lsp --stdio` from the `typescript` package answers every question this editor asks, faster, and publishes **no diagnostics**: it offers them pull-style, which turbo-core does not request, so the gutter would stay blank. That is why it is not the default. [The explanation](../explanation/colouring-and-completion.md) has the measurement.

## What else the server gives you

Completion is the loudest thing it does and the least of what it knows. The same connection answers eight more questions, all of them in the **Code** menu and all of them about the symbol under the cursor — no selection needed.

| Key | What it does | With `typescript-language-server` |
| --- | --- | --- |
| **Ctrl-Space** | Completion list | yes |
| **F1** | Describe the symbol under the cursor | yes — its signature, and the JSDoc comment written just above a declaration of yours |
| **F12** | Jump to where it is declared | yes, in this file or another |
| **Shift-F12** | List everywhere it is used | yes — the declaration and every call, as a list to choose from |
| **Ctrl-T** | Find a symbol by name anywhere in the project | yes |

And, without a key: *Go to type definition* takes `const shape = new Circle()` to `class Circle`; *Find implementations…* on a class lists its subclasses; *Symbol in file…* lists the file's functions and classes, with each class's methods nested under it; *Problems…* lists every diagnostic.

All nine questions are answered, and a test in this repository drives each of them against the real server, so this table cannot go stale quietly.

## The error marks

Problems the server finds arrive unasked, on open and on every edit. The first error in the file you are editing appears on the right of the status bar, prefixed with `⚠`; every line with a problem gets a `×` in the gutter; and **Code ▸ Problems…** lists all of them.

For a plain `.js` file they are **syntax errors** — a missing bracket, an unexpected token — reported at the exact column. Type errors need `// @ts-check` or `checkJs`, as above. A program that parses and then fails when run gets no mark: the server never runs anything.

[How to ask what the code means](ask-about-code.md) walks through the Code menu.

## See also

- Why the server is optional, and why it is TypeScript's: [Colouring and completion](../explanation/colouring-and-completion.md)
- Getting Node and npm: [How to install Node.js](install-node.md)
- Every key: [keyboard reference](../reference/keyboard.md)