插件在清单里声明用户可以修改的选项。宿主负责显示控件、保存值、区分全局和项目两层,并把生效值传给 Core;Core 合并后展开到启动计划、initializationOptions 或语言服务器的 workspaceConfiguration。插件不写设置页代码,宿主也不需要认识插件。
| 项目 | 内容 |
|---|---|
| 清单字段 | settings、settingActions |
| 能力 | settings,版本 0。workspaceConfiguration 的展开和推送见语言 |
| 协议 | 没有专用协议;settingActions 调用的是插件自己的插件函数 |
| API 编号 | API-19:声明式设置。运行期读取、查看来源、修改设置和变化事件仍在计划中。API-37:设置文字的包内翻译 |
| 权限 | 不需要额外权限。设置不会改变运行的程序,所以不进入安装审查的程序列表 |
| 激活事件 | 不需要。值按设置的 effect 在下一次启动、模型重载、下一次运行或 immediate 推送时生效 |
| 桌面端 | 已声明 settings:按语言和构建系统分页、分组、全部控件类型、项目层、生效方式和页面按钮都已呈现。还没有读取包内翻译 l10n/,始终显示清单原文 |
type |
字段 | 规则 |
|---|---|---|
integer |
minimum、maximum、unit(可选) |
minimum 和 maximum 必填 |
enum |
options,每项 {value, title} |
1–16 个选项;值只含字母、数字、.、_、- |
boolean |
— | 值是 true 或 false |
multiSelect |
options,每项 {value, title} |
1–32 个选项;值是互不相同的选项值数组 |
text |
pattern(必填)、maxLength(可选)、placeholder(可选) |
pattern 必须匹配整个值;maxLength 默认 256,最多 1024 个 Unicode 标量 |
file、directory |
placeholder(可选) |
绝对路径,最多 1024 个 Unicode 标量;空值表示“未设置” |
所有类型的 title、description 都是宿主显示的文字,用英文写;其他界面语言用包内翻译文件提供(见翻译)。text、file 和 directory 的值不以 - 开头,也不含控制字符。default 的 JSON 类型必须符合 type,并且被这个声明接受。
"settings": [
{ "id": "heapMB", "type": "integer", "title": "Maximum memory",
"default": 2048, "minimum": 512, "maximum": 8192, "unit": "MB" },
{ "id": "logLevel", "type": "enum", "title": "Log level", "default": "info",
"options": [{ "value": "info", "title": "Information" }, { "value": "debug", "title": "Debug" }] },
{ "id": "telemetry", "type": "boolean", "title": "Send usage data", "default": false }
]因为每个值都是数字、布尔值或已声明的选项值,设置永远不能注入额外参数,也不能改变运行的包内文件。存储的值如果已经不被声明接受(例如更新后缩小了范围),会被默认值替换,启动不会因此失败。未声明的 ID 的值被忽略。
设置还可以声明它显示在哪里、什么时候生效。宿主只提供通用的注册点:每种语言和构建系统一个页面、分组、每种类型一个控件、项目/全局切换和按钮。页面上出现什么,由清单决定。
"settings": [
{ "id": "dialyzer", "type": "boolean", "title": "Dialyzer", "default": true,
"scope": "project", "effect": "immediate", "page": { "languageID": "elixir" } },
{ "id": "mixEnv", "type": "text", "title": "MIX_ENV", "default": "dev", "pattern": "[a-z]+",
"scope": "project", "page": { "languageID": "elixir" }, "section": "Server" }
],
"settingActions": [
{ "id": "rebuildPlt", "title": "Rebuild PLT", "function": "dialyzer.rebuild",
"page": { "languageID": "elixir" }, "confirm": true }
]| 字段 | 含义 |
|---|---|
scope |
global(默认):所有项目共用一个值。project:打开的项目可以覆盖它 |
effect |
修改何时生效。restart(默认):插件进程下一次启动。immediate:通过 workspaceConfiguration 推送给运行中的语言服务器。reload:下一次构建模型重载,宿主会重载插件的构建模型。nextRun:下一次运行或构建命令 |
page |
{ "languageID": … } 或 { "buildSystemID": … }:设置显示在哪个语言或构建系统的设置页上,与插件自己的页面并列。任何插件都可以往页面上加内容;只要有已启用的插件为它提供内容,宿主就显示该页面 |
section |
设置在页面上所属分组的标题 |
settingActions 最多 16 个,按唯一的 id 排序。每个按钮显示在插件自己的页面和它声明的 page 上;点击后调用本插件的插件函数 function,参数为空,由本插件为当前项目运行的提供者进程执行(见插件函数)。confirm: true 让宿主先询问用户。宿主只负责按钮本身,不知道函数做什么。声明按钮也算使用了 settings。
由 Core 在校验时检查的放置和使用规则:
immediate设置只能出现在语言服务器的workspaceConfiguration里,它从不进入命令行或initializationOptions,所以修改它从不需要新进程。text、file、directory设置只能是一个完整的模板值,或某个name=参数的值,不能是较长参数的一部分。
宿主为每个插件的每个设置保存一个全局值,并把项目值保存在项目的 .lithe/plugin-settings.json 里(格式 {pluginID: {settingID: value}},适合通过版本控制共享)。宿主把两者都作为 settings 和 projectSettings 传给 Core。Core 按这个顺序合并:项目值(只对 scope: "project" 有效)、全局值、默认值;存储的值如果不被声明接受,就跳过。
plugins.declarative.resolveSettings 返回每个生效值及其 source(project、global 或 default)。
插件包里的 l10n/<语言>.json(如 l10n/zh-Hans.json,schema)把设置文字翻译成别的界面语言,按 ID 对应清单里的条目。没有翻译的语言,以及文件里没写到的文字,都显示 plugin.json 的原文。
{
"settings": {
"dialyzer": { "title": "Dialyzer 静态分析" },
"checks": { "title": "检查项", "options": { "format": "格式检查" } }
},
"sections": { "Server": "服务器" },
"settingActions": { "rebuildPlt": { "title": "重建 PLT" } }
}| 成员 | 翻译的内容 |
|---|---|
settings.<id> |
设置的 title、description、placeholder、unit;options.<值> 是 enum、multiSelect 选项的标题 |
sections.<标题> |
分组标题,键与 section 里写的原文完全一致 |
settingActions.<id> |
按钮的 title、description |
- ID、选项值和顺序、保存的值、分组和分组顺序在所有语言下都不变,翻译只换显示的文字。
- 界面语言是
zh-Hans-CN时,依次找l10n/zh-Hans-CN.json、l10n/zh-Hans.json、l10n/zh.json,显示第一个通过检查的文件,所以一份zh-Hans就能覆盖所有地区。 - 一个文件有任何问题都整份不用,并以
plugin.settings.invalidLocalization记进宿主日志,页面改用下一个候选或清单原文,不会因为翻译坏了而看不到设置。问题包括:不是 JSON 对象、超过 1 MiB、键重复、出现null;条目里有格式没定义的字段;写了清单没有的设置、选项值、分组或按钮;翻译了清单没写的字段,或给没有选项的设置写options;标题、占位符、单位、分组为空或超过 120 个字符,说明为空或超过 480 个字符。 - 不需要声明能力或
requires;不读翻译的宿主照常显示清单原文。Core 忽略不认识的顶层成员,以后翻译更多插件文字时沿用同一份文件。 - 翻译文件可以写
"$schema",方便编辑器校验。
| 章节 | 内容 |
|---|---|
| Plugin settings | 设置的字段、类型、模板 ${setting:<id>} 和使用规则 |
| Placement, scope, effect, and page buttons | 放置位置、层级、生效时机、页面按钮和校验规则 |
| Translations | 包内翻译文件的格式、语言候选顺序和拒绝规则 |
| Workspace configuration | workspaceConfiguration 的展开和推送 |
| Executable resolution | setting 类型的可执行文件候选:引用全局 file 设置选择工具路径、候选顺序和严格选择 |
| Launch templates | 设置值在模板里的替换规则 |
| 文件 | 内容 |
|---|---|
settings/settings.plugin.json |
放在 Elixir 语言页和 Mix 构建系统页上的设置、immediate 设置、settingActions 按钮 |
settings/l10n/zh-Hans.json |
上面这份清单的简体中文翻译:设置标题、选项标题、分组标题和按钮 |
settings/localization-cases.json |
13 个翻译用例:按语言挑选文件、坏文件回退,以及每种拒绝和它的字段 |
languages/node-runtime.plugin.json |
带插件设置的语言服务器(node 运行时) |
build-systems/build-tool-path.plugin.json |
用 file 设置选择构建工具的可执行文件候选 |
debug-adapters/debug-adapter.plugin.json |
调试适配器用 file 设置(nextRun)选择要调试的程序 |
设置相关的拒绝用例在 manifest/invalid-manifests.json。
A plugin declares, in its manifest, the options a user may change. The host draws the controls, stores the values, keeps the global and project layers apart, and passes the effective values to Core. Core merges them and expands them into launch plans, initializationOptions, or a language server's workspaceConfiguration. The plugin writes no settings-page code, and the host never needs to know the plugin.
| Item | Value |
|---|---|
| Manifest fields | settings, settingActions |
| Capability | settings, version 0. Expanding and pushing workspaceConfiguration is described in Languages |
| Protocol | None of its own; settingActions call the plugin's own plugin functions |
| API IDs | API-19: declarative settings. Runtime reads, source inspection, writes, and change events are still planned. API-37: packaged translations of settings text |
| Permissions | None. Settings never change which program runs, so they are not in the install review's program list |
| Activation | Not needed. Values take effect according to the setting's effect: at the next start, a model reload, the next run, or an immediate push |
| Desktop | Declares settings: pages per language and build system, sections, every control type, the project layer, effects, and page buttons are presented. It does not read packaged translations l10n/ yet and always shows the manifest text |
type |
Fields | Rule |
|---|---|---|
integer |
minimum, maximum, unit (optional) |
minimum and maximum are required |
enum |
options, each {value, title} |
One to 16 options; values contain only letters, digits, ., _, - |
boolean |
— | The value is true or false |
multiSelect |
options, each {value, title} |
One to 32 options; the value is an array of distinct option values |
text |
pattern (required), maxLength (optional), placeholder (optional) |
pattern matches the whole value; maxLength defaults to 256 and is at most 1024 Unicode scalars |
file, directory |
placeholder (optional) |
An absolute path of at most 1024 Unicode scalars, or empty for "not set" |
title and description are text the host shows; write them in English and translate them for other interface languages in the package (see Translations). Text and paths never start with - and contain no control characters. default must have the JSON type of type and must be accepted by the declaration.
"settings": [
{ "id": "heapMB", "type": "integer", "title": "Maximum memory",
"default": 2048, "minimum": 512, "maximum": 8192, "unit": "MB" },
{ "id": "logLevel", "type": "enum", "title": "Log level", "default": "info",
"options": [{ "value": "info", "title": "Information" }, { "value": "debug", "title": "Debug" }] },
{ "id": "telemetry", "type": "boolean", "title": "Send usage data", "default": false }
]Because every value is a number, a boolean, or one of the declared option values, a setting can never inject extra arguments or change which package file runs. A stored value the declaration no longer accepts (for example after an update narrowed a range) is replaced by the default, and a launch never fails for it. Values for undeclared IDs are ignored.
A setting may also say where it is shown and when a change takes effect. The host offers only generic registration points: a page per language and per build system, sections, one control per setting type, a project/global switch, and buttons. What appears there comes from the manifest.
"settings": [
{ "id": "dialyzer", "type": "boolean", "title": "Dialyzer", "default": true,
"scope": "project", "effect": "immediate", "page": { "languageID": "elixir" } },
{ "id": "mixEnv", "type": "text", "title": "MIX_ENV", "default": "dev", "pattern": "[a-z]+",
"scope": "project", "page": { "languageID": "elixir" }, "section": "Server" }
],
"settingActions": [
{ "id": "rebuildPlt", "title": "Rebuild PLT", "function": "dialyzer.rebuild",
"page": { "languageID": "elixir" }, "confirm": true }
]| Field | Meaning |
|---|---|
scope |
global (default): one value for every project. project: the open project may override it |
effect |
When a change takes effect. restart (default): the next start of the plugin's processes. immediate: pushed to the running language server through workspaceConfiguration. reload: the next build-model reload, which the host performs for the plugin's build models. nextRun: the next run or build command |
page |
{ "languageID": … } or { "buildSystemID": … }: the settings page that shows the setting beside the plugin's own page. Any plugin may add to a page; the host shows the page while an enabled plugin contributes to it |
section |
Heading the setting is grouped under on its page |
settingActions (at most 16, sorted by unique id) are buttons the host draws on the plugin's page and on their page. Each invokes the plugin function function of the same plugin with empty params, served by the plugin's own provider process for the open project (see plugin functions). confirm: true makes the host ask first. The host owns the button and knows nothing about what the function does. Declaring actions counts as using settings.
Placement and use rules that Core checks at validation:
- An
immediatesetting may appear only in a language server'sworkspaceConfiguration. It never reaches a command line orinitializationOptions, so a change never needs a new process. - A
text,file, ordirectorysetting is a whole template value, or the value of onename=argument; it is never part of a longer argument.
The host stores one global value per plugin and setting, and a project value in the project's .lithe/plugin-settings.json ({pluginID: {settingID: value}}, meant to be shared through version control). It sends both as settings and projectSettings. Core merges them in this order: project (only for scope: "project"), then global, then default, skipping a stored value the declaration no longer accepts.
plugins.declarative.resolveSettings returns each effective value with its source (project, global, or default).
l10n/<language>.json files in the package (such as l10n/zh-Hans.json, schema) translate settings text into other interface languages, matched to manifest entries by ID. A language without a translation, and any text a file leaves out, shows the plugin.json text.
{
"settings": {
"dialyzer": { "title": "Dialyzer 静态分析" },
"checks": { "title": "检查项", "options": { "format": "格式检查" } }
},
"sections": { "Server": "服务器" },
"settingActions": { "rebuildPlt": { "title": "重建 PLT" } }
}| Member | Translates |
|---|---|
settings.<id> |
The setting's title, description, placeholder, and unit; options.<value> is the title of an enum or multiSelect option |
sections.<heading> |
A section heading, keyed by the exact text section writes |
settingActions.<id> |
The button's title and description |
- IDs, option values and their order, stored values, and sections and their order are the same in every language; a translation changes only the shown text.
- For the interface language
zh-Hans-CNthe host looks forl10n/zh-Hans-CN.json,l10n/zh-Hans.json, andl10n/zh.json, and shows the first file that passes the checks, so onezh-Hansfile serves every region. - A file with any problem is not used at all and is logged by the host with
plugin.settings.invalidLocalization; the page uses the next candidate or the manifest text, so a broken translation never hides a setting. Problems are: not a JSON object, larger than 1 MiB, a repeated key, ornull; a field the format does not define inside an entry; a setting, option value, heading, or action the manifest does not declare; a translation of a field the manifest leaves out, oroptionsfor a setting without options; an empty title, placeholder, unit, or heading or one longer than 120 characters, or an empty description or one longer than 480. - No capability or
requiresentry is needed; a host that does not read translations shows the manifest text. Core ignores top-level members it does not know, so translations of more plugin text will use the same files. - A translation file may contain
"$schema"for editor validation.
| Section | Content |
|---|---|
| Plugin settings | Setting fields, types, the ${setting:<id>} template, and use rules |
| Placement, scope, effect, and page buttons | Placement, layers, effect timing, page buttons, and validation rules |
| Translations | Packaged translation files: format, language candidate order, and rejection rules |
| Workspace configuration | Expanding and pushing workspaceConfiguration |
| Executable resolution | setting executable candidates: a global file setting selects the tool path, candidate order, and strict selection |
| Launch templates | How setting values are substituted in templates |
| File | Content |
|---|---|
settings/settings.plugin.json |
Settings on the Elixir language page and the Mix build-system page, an immediate setting, and settingActions buttons |
settings/l10n/zh-Hans.json |
Simplified Chinese translation of that manifest: setting, option, and section titles and a button |
settings/localization-cases.json |
13 translation cases: choosing a file by language, falling back past a broken file, and each rejection with its field |
languages/node-runtime.plugin.json |
A language server with plugin settings (node runtime) |
build-systems/build-tool-path.plugin.json |
A file setting selects the build tool's executable candidate |
debug-adapters/debug-adapter.plugin.json |
A debug adapter uses a file setting (nextRun) to pick the program to debug |
Settings rejections are in manifest/invalid-manifests.json.