
# Settings editor

`settingsEditor` puts a **Settings** row under the gear at the foot of the activity bar, and
**Preferences: Open Settings (JSON)** in the command palette. Either opens a tab listing every
setting key any mounted extension declared, at its current value — edit the value and it's
written back as you type.

```ts
import { settingsEditor } from "codelet/extensions/settings";
import { Workbench, FileSystem } from "codelet/workbench";

const workbench = new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/README.md": "# Hello" }),
  extensions: [settingsEditor],
});
```

It takes no options and fetches nothing.

## Not a file in the tree

The tab is served under its own `settings:` scheme, not a file in your workspace. Settings
belong to the page, not the project — a `settings.json` sitting in the tree would be mirrored to
disk by [remote](/extensions/remote), packed by [tar](/extensions/tar), and shared by
[live](/extensions/live), none of which is what a reader's own preferences are. Nothing in the
explorer changes when the tab is open.

Where the values actually live is the workbench's `settings` option — `localStorage` by default,
or a store of your own. See [Settings](/guide/settings).

## What the document holds

Every declared key, sorted, at what it reads as right now:

```json
{
  "markdown.preview.theme": "dark",
  "typescript.suggest.autoImports": true
}
```

So the document is the list of what _can_ be set, as much as what has been. The rules it
round-trips by:

| What you type                      | What happens                                                                       |
| ---------------------------------- | ---------------------------------------------------------------------------------- |
| A value different from the default | Written to the store.                                                              |
| A value equal to the default       | Removed from the store — the default is the manifest's to keep saying.             |
| A key deleted from the document    | The same: that setting reverts to its manifest default.                            |
| A key nobody declares              | Kept as written, and flagged — it's a setting for an extension you're not running. |
| A value of the wrong type          | Reported, not written — the manifest said what the key takes.                      |
| Half-typed JSON                    | Nothing written, until it parses again.                                            |

## Schema, completion and hover

The manifests double as the schema. Typing a key offers every key not already in the document,
with its default and which extension declared it; hovering a key shows the same.
**Preferences: Open Settings Schema** opens the generated JSON Schema itself, read-only.

None of this needs a JSON language server — the keys come straight from the manifests the
workbench already holds. Mounting `json()` from `codelet/extensions/lsp/json` alongside changes
nothing here; see [Language servers](/extensions/lsp).

## Reading settings from your own extension

The tab only edits what any extension can already read:

```ts
const theme = vscode.workspace.getConfiguration("markdown").get("preview.theme", "auto");
vscode.workspace.onDidChangeConfiguration((event) => {
  if (event.affectsConfiguration("markdown.preview")) redraw();
});
```

Declare the keys you read, or they have no default and never show up in the tab:

```ts
contributes: {
  configuration: {
    title: "Markdown",
    properties: {
      "markdown.preview.theme": {
        type: "string",
        default: "auto",
        description: "Which theme the preview paints in.",
      },
    },
  },
},
```

:read-more{to="/api/extension"}
