coc-tsserver/src/server/languageProvider.ts

366 lines
12 KiB
TypeScript
Raw Normal View History

2018-09-07 20:40:51 +08:00
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Diagnostic, Disposable, CodeActionKind } from 'vscode-languageserver-protocol'
2018-09-07 20:40:51 +08:00
import Uri from 'vscode-uri'
import { workspace, commands, events, languages, DiagnosticKind, ServiceStat, disposeAll } from 'coc.nvim'
import { CachedNavTreeResponse } from './features/baseCodeLensProvider'
import BufferSyncSupport from './features/bufferSyncSupport'
import CompletionItemProvider from './features/completionItemProvider'
import DefinitionProvider from './features/definitionProvider'
import { DiagnosticsManager } from './features/diagnostics'
import DirectiveCommentCompletionProvider from './features/directiveCommentCompletions'
import DocumentHighlight from './features/documentHighlight'
import DocumentSymbolProvider from './features/documentSymbol'
import FileConfigurationManager from './features/fileConfigurationManager'
import Folding from './features/folding'
import FormattingProvider from './features/formatting'
import HoverProvider from './features/hover'
import ImplementationsCodeLensProvider from './features/implementationsCodeLens'
// import TagCompletionProvider from './features/tagCompletion'
import QuickfixProvider from './features/quickfix'
import RefactorProvider from './features/refactor'
import ReferenceProvider from './features/references'
import ReferencesCodeLensProvider from './features/referencesCodeLens'
import RenameProvider from './features/rename'
import SignatureHelpProvider from './features/signatureHelp'
import UpdateImportsOnFileRenameHandler from './features/updatePathOnRename'
import WatchBuild from './features/watchBuild'
import WorkspaceSymbolProvider from './features/workspaceSymbols'
import TypeScriptServiceClient from './typescriptServiceClient'
2019-02-06 17:12:10 +08:00
import InstallModuleProvider from './features/moduleInstall'
2018-09-07 20:40:51 +08:00
import API from './utils/api'
import { LanguageDescription } from './utils/languageDescription'
import TypingsStatus from './utils/typingsStatus'
const validateSetting = 'validate.enable'
const suggestionSetting = 'suggestionActions.enabled'
export default class LanguageProvider {
private readonly diagnosticsManager: DiagnosticsManager
private readonly bufferSyncSupport: BufferSyncSupport
public readonly fileConfigurationManager: FileConfigurationManager // tslint:disable-line
private _validate = true
private _enableSuggestionDiagnostics = true
private readonly disposables: Disposable[] = []
constructor(
public client: TypeScriptServiceClient,
private description: LanguageDescription,
typingsStatus: TypingsStatus
) {
this.fileConfigurationManager = new FileConfigurationManager(client)
this.bufferSyncSupport = new BufferSyncSupport(
client,
description.modeIds,
this._validate
)
this.diagnosticsManager = new DiagnosticsManager()
this.disposables.push(this.diagnosticsManager)
client.onTsServerStarted(async () => {
let document = await workspace.document
if (description.modeIds.indexOf(document.filetype) !== -1) {
this.fileConfigurationManager.ensureConfigurationForDocument(document.textDocument) // tslint:disable-line
}
})
events.on('BufEnter', bufnr => {
let doc = workspace.getDocument(bufnr)
if (!doc) return
if (description.modeIds.indexOf(doc.filetype) == -1) return
if (client.state !== ServiceStat.Running) return
this.fileConfigurationManager.ensureConfigurationForDocument(doc.textDocument) // tslint:disable-line
}, this, this.disposables)
this.configurationChanged()
2018-09-07 20:40:51 +08:00
workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables)
let initialized = false
client.onTsServerStarted(() => { // tslint:disable-line
if (!initialized) {
initialized = true
this.registerProviders(client, typingsStatus)
this.bufferSyncSupport.listen()
} else {
this.reInitialize()
}
})
}
public dispose(): void {
disposeAll(this.disposables)
this.bufferSyncSupport.dispose()
}
private configurationChanged(): void {
const config = workspace.getConfiguration(this.id)
this.updateValidate(config.get(validateSetting, true))
this.updateSuggestionDiagnostics(config.get(suggestionSetting, true))
}
private registerProviders(
client: TypeScriptServiceClient,
typingsStatus: TypingsStatus
): void {
let languageIds = this.description.modeIds
this.disposables.push(
languages.registerCompletionItemProvider(
`tsserver-${this.description.id}`,
'TSC',
languageIds,
new CompletionItemProvider(
client,
typingsStatus,
this.fileConfigurationManager,
this.description.id
),
CompletionItemProvider.triggerCharacters
)
)
if (this.client.apiVersion.gte(API.v230)) {
this.disposables.push(
languages.registerCompletionItemProvider(
`${this.description.id}-directive`,
'TSC',
languageIds,
new DirectiveCommentCompletionProvider(
client,
),
['@']
)
)
}
let definitionProvider = new DefinitionProvider(client)
this.disposables.push(
languages.registerDefinitionProvider(
languageIds,
definitionProvider
)
)
this.disposables.push(
languages.registerTypeDefinitionProvider(
languageIds,
definitionProvider
)
)
this.disposables.push(
languages.registerImplementationProvider(
languageIds,
definitionProvider
)
)
this.disposables.push(
languages.registerReferencesProvider(
languageIds,
new ReferenceProvider(client)
)
)
this.disposables.push(
languages.registerHoverProvider(
languageIds,
new HoverProvider(client))
)
this.disposables.push(
languages.registerDocumentHighlightProvider(languageIds, new DocumentHighlight(this.client))
)
this.disposables.push(
languages.registerSignatureHelpProvider(
languageIds,
new SignatureHelpProvider(client),
['(', ',', '<', ')'])
2018-09-07 20:40:51 +08:00
)
this.disposables.push(
languages.registerDocumentSymbolProvider(
languageIds,
new DocumentSymbolProvider(client))
)
this.disposables.push(
languages.registerWorkspaceSymbolProvider(
languageIds,
new WorkspaceSymbolProvider(client, languageIds))
)
this.disposables.push(
languages.registerRenameProvider(
languageIds,
new RenameProvider(client))
)
let formatProvider = new FormattingProvider(client, this.fileConfigurationManager)
this.disposables.push(
languages.registerDocumentFormatProvider(languageIds, formatProvider)
)
this.disposables.push(
languages.registerDocumentRangeFormatProvider(languageIds, formatProvider)
)
this.disposables.push(
languages.registerOnTypeFormattingEditProvider(languageIds, formatProvider, [';', '}', '\n', String.fromCharCode(27)])
2018-09-07 20:40:51 +08:00
)
// this.disposables.push(
// new ProjectError(client, commandManager)
// )
if (this.client.apiVersion.gte(API.v280)) {
this.disposables.push(
languages.registerFoldingRangeProvider(languageIds, new Folding(this.client))
)
}
let { fileConfigurationManager } = this
let conf = fileConfigurationManager.getLanguageConfiguration(this.id)
if (this.client.apiVersion.gte(API.v290)
&& conf.get<boolean>('updateImportsOnFileMove.enable')) {
this.disposables.push(
new UpdateImportsOnFileRenameHandler(client, this.fileConfigurationManager, this.id)
)
}
if (this.client.apiVersion.gte(API.v240)) {
this.disposables.push(
languages.registerCodeActionProvider(
languageIds,
2018-11-28 04:18:32 +08:00
new RefactorProvider(client, this.fileConfigurationManager),
'tsserver',
[CodeActionKind.Refactor]))
2018-09-07 20:40:51 +08:00
}
2019-02-06 17:12:10 +08:00
this.disposables.push(
languages.registerCodeActionProvider(
languageIds,
new InstallModuleProvider(client),
'tsserver')
)
2018-09-07 20:40:51 +08:00
this.disposables.push(
languages.registerCodeActionProvider(
languageIds,
2018-11-28 04:18:32 +08:00
new QuickfixProvider(client, this.diagnosticsManager, this.bufferSyncSupport),
'tsserver',
[CodeActionKind.QuickFix]))
2018-09-07 20:40:51 +08:00
let cachedResponse = new CachedNavTreeResponse()
if (this.client.apiVersion.gte(API.v206)
&& conf.get<boolean>('referencesCodeLens.enable')) {
this.disposables.push(
languages.registerCodeLensProvider(
languageIds,
new ReferencesCodeLensProvider(client, cachedResponse)))
}
if (this.client.apiVersion.gte(API.v220)
&& conf.get<boolean>('implementationsCodeLens.enable')) {
this.disposables.push(
languages.registerCodeLensProvider(
languageIds,
new ImplementationsCodeLensProvider(client, cachedResponse)))
}
if (this.description.id == 'typescript') {
this.disposables.push(
new WatchBuild(commands)
)
}
// if (this.client.apiVersion.gte(API.v300)) {
// this.disposables.push(
// languages.registerCompletionItemProvider(
// `tsserver-${this.description.id}-tag`,
// 'TSC',
// languageIds,
// new TagCompletionProvider(client),
// ['>']
// )
// )
// }
}
public handles(resource: Uri): boolean {
2018-10-22 20:55:01 +08:00
let { modeIds, configFile } = this.description
if (resource.toString().endsWith(configFile)) {
return true
}
2018-09-07 20:40:51 +08:00
let doc = workspace.getDocument(resource.toString())
if (doc && modeIds.indexOf(doc.filetype) !== -1) {
return true
}
let str = resource.toString()
if (this.id === 'typescript' && /\.ts(x)?$/.test(str)) {
return true
}
if (this.id === 'javascript' && /\.js(x)?$/.test(str)) {
return true
}
return false
}
private get id(): string { // tslint:disable-line
return this.description.id
}
public get diagnosticSource(): string {
return this.description.diagnosticSource
}
private updateValidate(value: boolean): void {
if (this._validate === value) {
return
}
this._validate = value
this.bufferSyncSupport.validate = value
this.diagnosticsManager.validate = value
if (value) {
this.triggerAllDiagnostics()
}
}
private updateSuggestionDiagnostics(value: boolean): void {
if (this._enableSuggestionDiagnostics === value) {
return
}
this._enableSuggestionDiagnostics = value
this.diagnosticsManager.enableSuggestions = value
if (value) {
this.triggerAllDiagnostics()
}
}
public reInitialize(): void {
this.diagnosticsManager.reInitialize()
this.bufferSyncSupport.reInitialize()
}
public triggerAllDiagnostics(): void {
this.bufferSyncSupport.requestAllDiagnostics()
}
public diagnosticsReceived(
diagnosticsKind: DiagnosticKind,
file: Uri,
diagnostics: Diagnostic[]
): void {
this.diagnosticsManager.diagnosticsReceived(
diagnosticsKind,
file.toString(),
diagnostics
)
}
2018-10-22 20:55:01 +08:00
public configFileDiagnosticsReceived(uri: Uri, diagnostics: Diagnostic[]): void {
this.diagnosticsManager.configFileDiagnosticsReceived(uri.toString(), diagnostics)
}
2018-09-07 20:40:51 +08:00
}