coc-tsserver/src/utils/plugins.ts
2020-12-07 18:57:53 +08:00

100 lines
3.6 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { extensions, disposeAll } from 'coc.nvim'
import * as arrays from './arrays'
import { Disposable, Emitter } from 'vscode-languageserver-protocol'
export interface TypeScriptServerPlugin {
readonly path: string
readonly name: string
readonly enableForWorkspaceTypeScriptVersions: boolean
readonly languages: ReadonlyArray<string>
readonly configNamespace?: string
}
namespace TypeScriptServerPlugin {
export function equals(a: TypeScriptServerPlugin, b: TypeScriptServerPlugin): boolean {
return a.path === b.path
&& a.name === b.name
&& a.enableForWorkspaceTypeScriptVersions === b.enableForWorkspaceTypeScriptVersions
&& arrays.equals(a.languages, b.languages)
}
}
export class PluginManager implements Disposable {
private readonly _pluginConfigurations = new Map<string, {}>()
private _disposables = []
private _plugins: Map<string, ReadonlyArray<TypeScriptServerPlugin>> | undefined
constructor() {
let loadPlugins = () => {
if (!this._plugins) {
return
}
const newPlugins = this.readPlugins()
if (!arrays.equals(arrays.flatten(Array.from(this._plugins.values())), arrays.flatten(Array.from(newPlugins.values())), TypeScriptServerPlugin.equals)) {
this._plugins = newPlugins
this._onDidUpdatePlugins.fire(this)
}
}
extensions.onDidActiveExtension(loadPlugins, undefined, this._disposables)
extensions.onDidUnloadExtension(loadPlugins, undefined, this._disposables)
}
public dispose(): void {
disposeAll(this._disposables)
}
public get plugins(): ReadonlyArray<TypeScriptServerPlugin> {
if (!this._plugins) {
this._plugins = this.readPlugins()
}
return arrays.flatten(Array.from(this._plugins.values()))
}
public _register<T extends Disposable>(value: T): T {
this._disposables.push(value)
return value
}
private readonly _onDidUpdatePlugins = this._register(new Emitter<this>())
public readonly onDidChangePlugins = this._onDidUpdatePlugins.event
private readonly _onDidUpdateConfig = this._register(new Emitter<{ pluginId: string, config: {} }>())
public readonly onDidUpdateConfig = this._onDidUpdateConfig.event
public setConfiguration(pluginId: string, config: {}): void {
this._pluginConfigurations.set(pluginId, config)
this._onDidUpdateConfig.fire({ pluginId, config })
}
public configurations(): IterableIterator<[string, {}]> {
return this._pluginConfigurations.entries()
}
private readPlugins(): Map<string, ReadonlyArray<TypeScriptServerPlugin>> {
const pluginMap = new Map<string, ReadonlyArray<TypeScriptServerPlugin>>()
for (const extension of extensions.all) {
const pack = extension.packageJSON
if (pack.contributes && Array.isArray(pack.contributes.typescriptServerPlugins)) {
const plugins: TypeScriptServerPlugin[] = []
for (const plugin of pack.contributes.typescriptServerPlugins) {
plugins.push({
name: plugin.name,
enableForWorkspaceTypeScriptVersions: !!plugin.enableForWorkspaceTypeScriptVersions,
path: extension.extensionPath,
languages: Array.isArray(plugin.languages) ? plugin.languages : [],
})
}
if (plugins.length) {
pluginMap.set(extension.id, plugins)
}
}
}
return pluginMap
}
}