Plugin Configuration
Plugins can expose user-configurable settings that appear in the editor's Settings UI under their own "Plugin: <name>" category. The values are saved alongside the rest of the user config and respect the same User/Project/Session layering as built-in settings.
How it works
Each setting is declared from TypeScript by calling one of the strongly-typed editor.defineConfigX(...) methods. The host validates the call synchronously — a typo or wrong shape throws an exception right there, at the call site, instead of failing silently later. The return type is inferred from the call, so plugin code is type-safe without any cast.
const autoEnable = editor.defineConfigBoolean("autoEnable", {
default: false,
description: "Auto-enable the plugin on startup",
});
const maxItems = editor.defineConfigInteger("maxItems", {
default: 5,
minimum: 1,
maximum: 50,
});
const mode = editor.defineConfigEnum("mode", {
values: ["normal", "insert"] as const,
default: "normal",
});
const patterns = editor.defineConfigStringArray("patterns", {
default: ["TODO", "FIXME"],
});
// `mode` is typed as `"normal" | "insert"` thanks to the `as const`.
// `autoEnable: boolean`, `maxItems: number`, `patterns: string[]`.Each call returns the current merged value (user override if any, otherwise the declared default). For values that may change while the plugin is running, re-read on demand:
const cfg = editor.getPluginConfig() as { autoEnable?: boolean };
if (cfg.autoEnable) { /* ... */ }Reacting to changes
The value a defineConfigX(...) call returns is a snapshot from plugin load time. If you keep it in a variable instead of re-reading it at the point of use, subscribe to config_changed — otherwise your setting will appear to do nothing until the editor restarts:
let autoEnable = editor.defineConfigBoolean("autoEnable", { default: false });
editor.on("config_changed", () => {
const cfg = (editor.getPluginConfig() ?? {}) as { autoEnable?: boolean };
autoEnable = cfg.autoEnable === true;
});The hook fires after the user saves from the Settings UI and after a config reload from disk, once the new config is live — so getPluginConfig() and getConfig() already return the new values when your handler runs. It carries no payload: re-read the keys you care about and compare against what you were holding.
It does not fire for your own editor.setSetting(...) writes, so a plugin that re-configures itself from this handler won't wake itself back up.
Plugins that already read the setting at point of use (as in the getPluginConfig() example above) need no subscription — they pick up the change on the next read.
Available methods
| Method | TS return type | Settings UI widget |
|---|---|---|
defineConfigBoolean | boolean | Toggle |
defineConfigInteger | number | Number input |
defineConfigNumber | number | Number input |
defineConfigString | string | Text input |
defineConfigEnum | one of values | Dropdown |
defineConfigStringArray | string[] | List editor |
All methods accept description (string). Numeric methods accept minimum / maximum. Each method's options parameter is strictly typed — unknown keys (defualt → "Did you mean 'default'?"), wrong default types, and out-of-range defaults are all compile-time errors.
The Settings UI renders one Plugin: <name> top-level category per enabled plugin that has registered at least one field, sorted alongside the built-in categories.
What's not supported
By design:
- Colors are not exposed as plugin settings. Plugins should pass theme keys (e.g.
"ui.status_bar_fg","editor.diff_add_bg") toaddOverlay/addVirtualLineinstead, so the colors track the user's active theme. x-enum-frompointing at host config paths like/languages. Plugins that need to react to host config should readeditor.getConfig()directly at use-time.- Per-language settings. Plugin config is flat, namespaced by plugin name.
Layering
Plugin settings follow the same layered-config rules as the rest of the editor:
- Higher layers (Session > Project > User) win for any individual key.
- Object-typed values are deep-merged so a project can add one key without restating the user's defaults.
- Primitive values and arrays are replaced wholesale.
Lifecycle
- Disabled plugins are hidden from the Settings UI. Stored values are preserved in the config file and reappear when re-enabled.
- Uninstalling a plugin leaves its
plugins.<name>.settingsentry in the user's config (cheap; harmless). Reinstalling restores the values. - Reloading a plugin re-runs its
defineConfigX(...)calls, so plugin authors iterating withReload Pluginsee updated schemas immediately. - The Settings UI rebuilds its category list every time it opens, so newly-registered schemas show up without an editor restart.