theia - 配置


Theia 有一个preference service(配置服务),它允许模块获取配置值、提供默认配置、监听配置变化。

配置保存在工作区的根目录下的 .theia/settings.json 或 Linux 系统上的 $HOME/.theia/settings.json 下。 对于 Windows 系统,用户设置默认位于 %USERPROFILE%/.theia/settings.json 中(类似于 C:\Users\epatpol\.theia/settings.json)

截至目前,文件必须包含一个有效的 JSON,其中包含首选项的名称和值(请注意,以下首选项名称不是官方名称,仅用作示例)。 如果需要,您还可以向 settings.json 文件添加注释,即

{
    // Enable/Disable the line numbers in the monaco editor
    "monaco.lineNumbers": "off",
    // Tab width in the editor
    "monaco.tabWidth": 4,
    "fs.watcherExcludes": "path/to/file"
}

让我们以文件系统为例,解释如何使用配置服务

使用 inversify 将默认配置作为模块提供
为了提供一些配置的值。 模块必须提供一个有效的 json 模式,用于验证配置。 模块必须将以下 PreferenceContribution 绑定到如下值:

 

export interface PreferenceSchema {
    [name: string]: Object,
    properties: {
        [name: string]: object
    }
}

export interface PreferenceContribution {
    readonly schema: PreferenceSchema;
}

例如,文件系统像这样绑定它:

export const filesystemPreferenceSchema: PreferenceSchema = {
    "type": "object",
    "properties": {
        "files.watcherExclude": {
            "description": "List of paths to exclude from the filesystem watcher",
            "additionalProperties": {
                "type": "boolean"
            }
        }
    }
};

bind(PreferenceContribution).toConstantValue(
{
    schema: filesystemPreferenceSchema
});

以下是一些有助于验证模式的有用链接:

JSON 模式规范(http://json-schema.org/documentation.html)
在线 JSON 验证器(https://jsonlint.com/)
在线 JSON 模式验证器(http://www.jsonschemavalidator.net/)

模式其实就是规定了配置项的规则,如一个配置项的描述说明,数据格式等。比如模式中规定一个参数是boolean类型,如果我们给一个string类型的值,就会报错。

 

通过configuration监听配置变化
要使用配置的值,只需从容器中获取注入的 PreferenceService

const preferences = ctx.container.get(PreferenceService);

以filesystem为例,服务是在绑定前获取的。 您可以使用 onPreferenceChanged 方法注册一个配置更改的回调。

constructor(@inject(PreferenceService) protected readonly prefService: PreferenceService
    prefService.onPreferenceChanged(e => { callback }

收到的事件 e 是这样的:

export interface PreferenceChangedEvent {
    readonly preferenceName: string;
    readonly newValue?: any;
    readonly oldValue?: any;
}

虽然这可以直接在所需的类中使用,但filesystem提供了特定于filesystem配置的代理配置服务(它在后台使用配置服务)。 这允许更快和更有效地搜索配置(因为它在filesystem的配置服务中搜索配置,而不是通过更通用的配置服务搜索所有配置)。 从某种意义上说,它也更有效,只有监视特定配置的模块才会被通知。 为此,filesystem配置有一个代理接口,使用配置代理接口绑定如下:

export type PreferenceProxy<T> = Readonly<T> & Disposable & PreferenceEventEmitter<T>;
export function createPreferenceProxy<T extends Configuration>(preferences: PreferenceService, configuration: T): PreferenceProxy<T> {
    /* Register a client to the preference server
    When a preference is received, it is validated against the schema and then fired if valid, otherwise the default value is provided.

    This proxy is also in charge of calling the configured preference service when the proxy object is called i.e editorPrefs['preferenceName']

    It basically forwards methods to the real object, i.e dispose/ready etc.
}

要使用该代理,只需将其绑定到新类型 X = PreferenceProxy<CONFIGURATION_INTERFACE>,然后使用上述方法 bind(X) 到代理。

export interface FileSystemConfiguration {
    'files.watcherExclude': { [globPattern: string]: boolean }
}

export const FileSystemPreferences = Symbol('FileSystemPreferences');
export type FileSystemPreferences = PreferenceProxy<FileSystemConfiguration>;

export function createFileSystemPreferences(preferences: PreferenceService): FileSystemPreferences {
    return createPreferenceProxy(preferences, defaultFileSystemConfiguration, filesystemPreferenceSchema);
}

export function bindFileSystemPreferences(bind: interfaces.Bind): void {

    bind(FileSystemPreferences).toDynamicValue(ctx => {
        const preferences = ctx.container.get(PreferenceService);
        return createFileSystemPreferences(preferences);
    });

    bind(PreferenceContribution).toConstantValue({ schema: filesystemPreferenceSchema });

}

最后,在你的模块中使用filesystem配置。 只需将其注入您需要的地方。 然后,您可以像这样访问配置(文件系统示例):

const patterns = this.preferences['files.watcherExclude'];

 

您还可以像这样监控配置变更:

this.toDispose.push(preferences.onPreferenceChanged(e => {
    if (e.preferenceName === 'files.watcherExclude') {
        this.toRestartAll.dispose();
    }
}));
constructor(...,
        @inject(FileSystemPreferences) protected readonly preferences: FileSystemPreferences) {
    ...
         this.toDispose.push(preferences.onPreferenceChanged(e => {
            if (e.preferenceName === 'files.watcherExclude') {
                this.toRestartAll.dispose();
            }
        }));
    ...
}

 

修改配置时的配置流
截至目前,当在 ${workspace}/.theia/ 或 os.homedir()/.theia/ 中修改 settings.json 时,这将触发来自 JSON 配置服务器的事件。 目前,有一个 CompoundPreferenceServer 管理不同的服务器(范围),如工作区/用户/默认值(通过上面的贡献提供)。 接下来,PreferenceService 管理该服务器并在其上添加更方便的 api(即 getBoolean、getString 等)。 它还允许客户监控配置修改事件。 然后可以通过模块中的注入或通过更具体的代理(如上面的文件系统配置)直接使用此 PreferenceService。

在修改配置文件的情况下,流程将是:

.theia/settings.json -> JsonPreferenceServer -> CompoundPreferenceServer -> PreferenceService -> PreferenceProxy<FileSystemConfiguration> -> FileSystemWatcher

获取配置的值
对于filesystem,可以使用与上述相同的代理配置来访问首选项。

    if (this.prefService['preferenceName']) {
    ...
    }

    if (this.prefService['preferenceName2']) {
    ...
    }

这是可行的,因为正如我们在上面看到的那样,代理将简单地调用 prefService.get('preferenceName')。

  配置的TODO/FIXME事项
在 CompoundPreferenceServer 中添加具有服务器优先级的字段
从 theia 中修改 settings.json 时添加自动完成/描述

posted @ 2022-07-28 15:40  theiaide  阅读(547)  评论(0)    收藏  举报