diff --git a/history.md b/history.md index a9a19c7..84ea422 100644 --- a/history.md +++ b/history.md @@ -1,3 +1,7 @@ +# 1.11.0 + +- Add command `tsserver.goToSourceDefinition`. + # 1.10.5 - Fix a fold issue #380 diff --git a/package.json b/package.json index 749c97c..c8feb67 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "coc-tsserver", - "version": "1.10.5", + "version": "1.11.7", "description": "tsserver extension for coc.nvim", "main": "lib/index.js", "publisher": "chemzqm", "engines": { - "coc": "^0.0.80" + "coc": "^0.0.82" }, "repository": { "type": "git", @@ -30,11 +30,10 @@ "onLanguage:jsx-tags", "onLanguage:jsonc", "onCommand:_typescript.configurePlugin", - "onCommand:typescript.reloadProjects", - "onCommand:javascript.reloadProjects", - "onCommand:javascript.goToProjectConfig", - "onCommand:typescript.goToProjectConfig", - "onCommand:typescript.openTsServerLog", + "onCommand:tsserver.reloadProjects", + "onCommand:tsserver.goToProjectConfig", + "onCommand:tsserver.openTsServerLog", + "onCommand:tsserver.goToSourceDefinition", "onCommand:tsserver.watchBuild" ], "contributes": { @@ -94,6 +93,11 @@ "category": "TSServer", "command": "tsserver.findAllFileReferences" }, + { + "command": "tsserver.goToSourceDefinition", + "title": "Go to Source Definition", + "category": "TSServer" + }, { "title": "Run `tsc --watch` for current project by use vim's job feature.", "category": "TSServer", diff --git a/src/server/commands.ts b/src/server/commands.ts index 6d99712..3e50184 100644 --- a/src/server/commands.ts +++ b/src/server/commands.ts @@ -218,6 +218,56 @@ export class FileReferencesCommand implements Command { } } +export class SourceDefinitionCommand implements Command { + public static readonly context = 'tsSupportsSourceDefinition' + public static readonly minVersion = API.v470 + + public readonly id = 'tsserver.goToSourceDefinition' + + public constructor(private readonly service: TsserverService) {} + + public async execute() { + const client = await this.service.getClientHost() + if (client.serviceClient.apiVersion.lt(SourceDefinitionCommand.minVersion)) { + window.showErrorMessage('Go to Source Definition failed. Requires TypeScript 4.7+.') + return + } + + const { document, position } = await workspace.getCurrentState() + if (client.serviceClient.modeIds.indexOf(document.languageId) == -1) { + window.showErrorMessage('Go to Source Definition failed. Unsupported file type.') + return + } + const openedFiledPath = client.serviceClient.toOpenedFilePath(document.uri) + if (!openedFiledPath) { + window.showErrorMessage('Go to Source Definition failed. Unknown file type.') + return + } + + await window.withProgress({ title: 'Finding source definitions' }, async (_progress, token) => { + + const args = typeConverters.Position.toFileLocationRequestArgs(openedFiledPath, position) + const response = await client.serviceClient.execute('findSourceDefinition', args, token) + if (response.type === 'response' && response.body) { + const locations: Location[] = (response as Proto.DefinitionResponse).body.map(reference => + typeConverters.Location.fromTextSpan(client.serviceClient.toResource(reference.file), reference)) + + if (locations.length) { + commands.executeCommand('editor.action.showReferences', document.uri, position, locations) + // if (locations.length === 1) { + // commands.executeCommand('vscode.open', locations[0].uri) + // } else { + // commands.executeCommand('editor.action.showReferences', document.uri, position, locations) + // } + return + } + } + + window.showErrorMessage('No source definitions found.') + }) + } +} + export function registCommand(cmd: Command): Disposable { let { id, execute } = cmd return commands.registerCommand(id as string, execute, cmd) diff --git a/src/server/features/bufferSyncSupport.ts b/src/server/features/bufferSyncSupport.ts index a7ae050..1a8fecc 100644 --- a/src/server/features/bufferSyncSupport.ts +++ b/src/server/features/bufferSyncSupport.ts @@ -30,21 +30,21 @@ class CloseOperation { readonly type = BufferOperationType.Close; constructor( public readonly args: string - ) { } + ) {} } class OpenOperation { readonly type = BufferOperationType.Open; constructor( public readonly args: Proto.OpenRequestArgs - ) { } + ) {} } class ChangeOperation { readonly type = BufferOperationType.Change; constructor( public readonly args: Proto.FileCodeEdits - ) { } + ) {} } type BufferOperation = CloseOperation | OpenOperation | ChangeOperation @@ -59,7 +59,7 @@ class SyncedBuffer { public readonly filepath: string, private readonly client: ITypeScriptServiceClient, private readonly synchronizer: BufferSynchronizer, - ) { } + ) {} public open(): void { const args: Proto.OpenRequestArgs = { diff --git a/src/server/features/completionItemProvider.ts b/src/server/features/completionItemProvider.ts index 8280ee2..7d81387 100644 --- a/src/server/features/completionItemProvider.ts +++ b/src/server/features/completionItemProvider.ts @@ -225,8 +225,6 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP let { uri, position, source, name, data } = item.data const filepath = this.client.toPath(uri) if (!filepath) return undefined - let document = workspace.getDocument(uri) - if (!document) return undefined const args: Proto.CompletionDetailsRequestArgs = { ...typeConverters.Position.toFileLocationRequestArgs( filepath, @@ -259,11 +257,10 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP item.additionalTextEdits = additionalTextEdits if (detail && item.insertTextFormat == InsertTextFormat.Snippet) { const shouldCompleteFunction = await this.isValidFunctionCompletionContext(filepath, position, token) - if (shouldCompleteFunction && !item.insertText) { + if (shouldCompleteFunction) { this.createSnippetOfFunctionCall(item, detail) } } - return item } @@ -380,7 +377,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP let { displayParts } = detail const parameterListParts = getParameterListParts(displayParts) const snippet = new SnippetString() - snippet.appendText(`${item.insertText || item.label}(`) + snippet.appendText(`${item.insertText ?? item.label}(`) appendJoinedPlaceholders(snippet, parameterListParts.parts, ', ') if (parameterListParts.hasOptionalParameters) { snippet.appendTabstop() diff --git a/src/server/features/definitionProvider.ts b/src/server/features/definitionProvider.ts index ea57402..178e863 100644 --- a/src/server/features/definitionProvider.ts +++ b/src/server/features/definitionProvider.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TextDocument } from 'coc.nvim' +import { LocationLink, TextDocument } from 'coc.nvim' import { DefinitionProvider, CancellationToken, Definition, Location, Position, DefinitionLink, ImplementationProvider, TypeDefinitionProvider } from 'coc.nvim' import * as Proto from '../protocol' import { ITypeScriptServiceClient } from '../typescriptService' @@ -17,7 +17,7 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider, document: TextDocument, position: Position, token: CancellationToken - ): Promise { + ): Promise { const filepath = this.client.toPath(document.uri) if (!filepath) { return undefined @@ -29,12 +29,21 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider, ) try { const response = await this.client.execute(definitionType, args, token) - const locations: Proto.FileSpan[] = (response.type == 'response' && response.body) || [] - return locations.map(location => - typeConverters.Location.fromTextSpan( - this.client.toResource(location.file), - location - ) + if (response.type !== 'response' || !response.body) { + return undefined + } + const locations: Proto.FileSpanWithContext[] = (response.type == 'response' && response.body) || [] + return locations.map(location => { + const target = typeConverters.Location.fromTextSpan(this.client.toResource(location.file), location) + if (location.contextStart && location.contextEnd) { + return { + targetRange: typeConverters.Range.fromLocations(location.contextStart, location.contextEnd), + targetUri: target.uri, + targetSelectionRange: target.range, + } as any + } + return target + } ) } catch { return [] @@ -84,14 +93,14 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider, public provideTypeDefinition( document: TextDocument, position: Position, - token: CancellationToken): Promise { + token: CancellationToken): Promise { return this.getSymbolLocations('typeDefinition', document, position, token) } public provideImplementation( document: TextDocument, position: Position, - token: CancellationToken): Promise { + token: CancellationToken): Promise { return this.getSymbolLocations('implementation', document, position, token) } } diff --git a/src/server/features/diagnostics.ts b/src/server/features/diagnostics.ts index 87cdd12..9a205df 100644 --- a/src/server/features/diagnostics.ts +++ b/src/server/features/diagnostics.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DiagnosticCollection, languages, workspace } from 'coc.nvim' +import { DiagnosticCollection, Uri, languages, workspace } from 'coc.nvim' import { Diagnostic, DiagnosticTag } from 'vscode-languageserver-protocol' import { ResourceMap } from './resourceMap' diff --git a/src/server/features/documentSymbol.ts b/src/server/features/documentSymbol.ts index 3a78abc..93cb6b5 100644 --- a/src/server/features/documentSymbol.ts +++ b/src/server/features/documentSymbol.ts @@ -86,7 +86,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP output: DocumentSymbol[], item: Proto.NavigationTree, ): boolean { - let shouldInclude = TypeScriptDocumentSymbolProvider.shouldInclueEntry(item) + let shouldInclude = TypeScriptDocumentSymbolProvider.shouldIncludeEntry(item) const children = new Set(item.childItems || []) for (const span of item.spans) { const range = typeConverters.Range.fromTextSpan(span) @@ -129,7 +129,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP return symbolInfo } - private static shouldInclueEntry( + private static shouldIncludeEntry( item: Proto.NavigationTree | Proto.NavigationBarItem ): boolean { if (item.kind === PConst.Kind.alias) { diff --git a/src/server/features/updatePathOnRename.ts b/src/server/features/updatePathOnRename.ts index fb783f3..c7500f3 100644 --- a/src/server/features/updatePathOnRename.ts +++ b/src/server/features/updatePathOnRename.ts @@ -61,11 +61,11 @@ export default class UpdateImportsOnFileRenameHandler { await workspace.nvim.command(`silent ${oldDocument.bufnr}bwipeout!`) } let document = workspace.getDocument(newUri) - if (document) { - await workspace.nvim.command(`silent ${document.bufnr}bwipeout!`) - await wait(30) + if (!document) { + document = await workspace.loadFile(newUri) + } else { + workspace.nvim.command('checktime', true) } - document = await workspace.loadFile(newUri) if (!document) return await wait(50) const edits = await this.getEditsForFileRename( diff --git a/src/server/features/watchBuild.ts b/src/server/features/watchBuild.ts index 7ea12c3..e69de29 100644 --- a/src/server/features/watchBuild.ts +++ b/src/server/features/watchBuild.ts @@ -1,126 +0,0 @@ -import { commands, Disposable, disposeAll, StatusBarItem, TaskOptions, Uri, window, workspace } from 'coc.nvim' -import path from 'path' -import TypeScriptServiceClient from '../typescriptServiceClient' - -const countRegex = /Found\s+(\d+)\s+error/ -const errorRegex = /^(.+)\((\d+),(\d+)\):\s(\w+)\sTS(\d+):\s*(.+)$/ - -export default class WatchProject implements Disposable { - private disposables: Disposable[] = [] - public static readonly id: string = 'tsserver.watchBuild' - public static readonly startTexts: string[] = ['Starting compilation in watch mode', 'Starting incremental compilation'] - private statusItem: StatusBarItem - private task: any - private options: TaskOptions - - public constructor( - private client: TypeScriptServiceClient - ) { - this.statusItem = window.createStatusBarItem(1, { progress: true }) - let task = this.task = workspace.createTask('TSC') - - this.disposables.push(commands.registerCommand(WatchProject.id, async () => { - let opts = this.options = await this.getOptions() - await this.start(opts) - })) - task.onExit(code => { - if (code != 0) { - window.showMessage(`TSC exit with code ${code}`, 'warning') - } - this.onStop() - }) - task.onStdout(lines => { - for (let line of lines) { - this.onLine(line) - } - }) - task.onStderr(lines => { - window.showMessage(`TSC error: ` + lines.join('\n'), 'error') - }) - this.disposables.push(Disposable.create(() => { - task.dispose() - })) - this.check().catch(_e => { - // noop - }) - } - - private async check(): Promise { - let running = await this.task.running - if (running) { - this.options = await this.getOptions() - this.statusItem.isProgress = false - this.statusItem.text = '?' - this.statusItem.show() - } else { - this.onStop() - } - } - - private async start(options: TaskOptions): Promise { - await this.task.start(options) - } - - private onStop(): void { - this.statusItem.hide() - } - - private onStart(): void { - this.statusItem.text = 'compiling' - this.statusItem.isProgress = true - this.statusItem.show() - workspace.nvim.call('setqflist', [[]], true) - } - - private onLine(line: string): void { - if (countRegex.test(line)) { - let ms = line.match(countRegex) - this.statusItem.text = ms[1] == '0' ? '✓' : '✗' - this.statusItem.isProgress = false - } else if (WatchProject.startTexts.findIndex(s => line.indexOf(s) !== -1) != -1) { - this.onStart() - } else { - let ms = line.match(errorRegex) - if (!ms) return - let fullpath = path.join(this.options.cwd, ms[1]) - let uri = Uri.file(fullpath).toString() - let doc = workspace.getDocument(uri) - let bufnr = doc ? doc.bufnr : null - let item = { - filename: fullpath, - lnum: Number(ms[2]), - col: Number(ms[3]), - text: `[tsc ${ms[5]}] ${ms[6]}`, - type: /error/i.test(ms[4]) ? 'E' : 'W' - } as any - if (bufnr) item.bufnr = bufnr - workspace.nvim.call('setqflist', [[item], 'a']) - } - } - - public async getOptions(): Promise { - let { tscPath } = this.client - if (!tscPath) { - window.showMessage(`Local & global tsc not found`, 'error') - return - } - - const tsconfigPath = workspace.getConfiguration('tsserver').get('tsconfigPath', 'tsconfig.json') - let find = await workspace.findUp([tsconfigPath]) - if (!find) { - window.showMessage(`${tsconfigPath} not found!`, 'error') - return - } - - let root = path.dirname(find) - return { - cmd: tscPath, - args: ['-p', tsconfigPath, '--watch', 'true', '--pretty', 'false'], - cwd: root - } - } - - public dispose(): void { - disposeAll(this.disposables) - } -} diff --git a/src/server/index.ts b/src/server/index.ts index 2d42456..1c808a8 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,8 +1,9 @@ import { commands, disposeAll, IServiceProvider, ServiceStat, workspace, WorkspaceConfiguration } from 'coc.nvim' import { Disposable, DocumentSelector, Emitter, Event } from 'vscode-languageserver-protocol' import { PluginManager } from '../utils/plugins' -import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './commands' +import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, SourceDefinitionCommand, TypeScriptGoToProjectConfigCommand } from './commands' import { OrganizeImportsCommand, SourceImportsCommand } from './organizeImports' +import WatchProject from './watchBuild' import TypeScriptServiceClientHost from './typescriptServiceClientHost' import { LanguageDescription, standardLanguageDescriptions } from './utils/languageDescription' @@ -61,6 +62,14 @@ export default class TsserverService implements IServiceProvider { let { id, execute } = cmd subscriptions.push(commands.registerCommand(id as string, execute, cmd)) } + let watchProject = new WatchProject(this) + subscriptions.push(watchProject) + registCommand({ + id: WatchProject.id, + execute: () => { + return watchProject.execute() + } + }) registCommand(new ConfigurePluginCommand(this.pluginManager)) registCommand(new AutoFixCommand(this)) registCommand(new ReloadProjectsCommand(this)) @@ -69,6 +78,7 @@ export default class TsserverService implements IServiceProvider { registCommand(new TypeScriptGoToProjectConfigCommand(this)) registCommand(new OrganizeImportsCommand(this)) registCommand(new SourceImportsCommand(this)) + registCommand(new SourceDefinitionCommand(this)) registCommand({ id: 'tsserver.restart', execute: (): void => { diff --git a/src/server/typescriptServiceClient.ts b/src/server/typescriptServiceClient.ts index 5c6c58c..605fefc 100644 --- a/src/server/typescriptServiceClient.ts +++ b/src/server/typescriptServiceClient.ts @@ -42,6 +42,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient private fileConfigurationManager: FileConfigurationManager private pathSeparator: string + private readonly emptyAuthority = 'ts-nul-authority' private tracer: Tracer private _configuration: TypeScriptServiceConfiguration private versionProvider: TypeScriptVersionProvider @@ -226,7 +227,16 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient if (this.tscPathVim) currentVersion = this.versionProvider.getVersionFromTscPath(this.tscPathVim) if (!currentVersion && !ignoreLocalTsserver) currentVersion = this.versionProvider.getLocalVersion() if (!currentVersion || !fs.existsSync(currentVersion.tsServerPath)) { - this.info('Local tsserver not found, using bundled tsserver with coc-tsserver.') + if (ignoreLocalTsserver) { + this.info(`local tsserver is ignored, try global version`) + } else { + this.info(`local tsserver is not found, try global version`) + } + currentVersion = this.versionProvider.globalVersion + if (currentVersion) this.info('Local and global tsserver not found, using global tsserver from configuration') + } + if (!currentVersion || !fs.existsSync(currentVersion.tsServerPath)) { + this.info('Local and global tsserver not found, using bundled tsserver with coc-tsserver.') currentVersion = this.versionProvider.getDefaultVersion() } if (!currentVersion || !currentVersion.isValid) { @@ -432,7 +442,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient public toResource(filepath: string): string { if (filepath.includes('zipfile:')) { - return filepath.replace(/.*zipfile:/, 'zipfile://'); + return filepath.replace(/.*zipfile:/, 'zipfile://') } if (this._apiVersion.gte(API.v213)) { if (filepath.startsWith(this.inMemoryResourcePrefix + 'untitled:')) { @@ -938,7 +948,7 @@ function getDiagnosticsKind(event: Proto.Event): DiagnosticKind { case 'suggestionDiag': return DiagnosticKind.Suggestion } - throw new Error('Unknown dignostics kind') + throw new Error('Unknown diagnostics kind') } const fenceCommands = new Set(['change', 'close', 'open']) diff --git a/src/server/typescriptServiceClientHost.ts b/src/server/typescriptServiceClientHost.ts index 43e591f..ed3585f 100644 --- a/src/server/typescriptServiceClientHost.ts +++ b/src/server/typescriptServiceClientHost.ts @@ -8,7 +8,6 @@ import { flatten } from '../utils/arrays' import { PluginManager } from '../utils/plugins' import { DiagnosticKind } from './features/diagnostics' import FileConfigurationManager from './features/fileConfigurationManager' -import WatchBuild from './features/watchBuild' import WorkspaceSymbolProvider from './features/workspaceSymbols' import LanguageProvider from './languageProvider' import * as Proto from './protocol' @@ -66,7 +65,6 @@ export default class TypeScriptServiceClientHost implements Disposable { }, null, this.disposables) // features - this.disposables.push(new WatchBuild(this.client)) this.disposables.push(languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this.client, allModeIds))) this.client.onConfigDiagnosticsReceived(diag => { let { body } = diag @@ -217,11 +215,11 @@ export default class TypeScriptServiceClientHost implements Disposable { language.diagnosticsReceived( kind, resource, - this.createMarkerDatas(diagnostics)) + this.createMarkerData(diagnostics)) } } - private createMarkerDatas(diagnostics: Proto.Diagnostic[]): (Diagnostic & { reportUnnecessary: any, reportDeprecated: any })[] { + private createMarkerData(diagnostics: Proto.Diagnostic[]): (Diagnostic & { reportUnnecessary: any, reportDeprecated: any })[] { return diagnostics.map(tsDiag => this.tsDiagnosticToLspDiagnostic(tsDiag)) } diff --git a/src/server/utils/api.ts b/src/server/utils/api.ts index 0dce70a..8331a5a 100644 --- a/src/server/utils/api.ts +++ b/src/server/utils/api.ts @@ -44,6 +44,7 @@ export default class API { public static readonly v420 = API.fromSimpleString('4.2.0') public static readonly v430 = API.fromSimpleString('4.3.0') public static readonly v440 = API.fromSimpleString('4.4.0') + public static readonly v470 = API.fromSimpleString('4.7.0') public static fromVersionString(versionString: string): API { let version = semver.valid(versionString) diff --git a/src/server/utils/versionProvider.ts b/src/server/utils/versionProvider.ts index b488bef..3fbd2db 100644 --- a/src/server/utils/versionProvider.ts +++ b/src/server/utils/versionProvider.ts @@ -102,7 +102,11 @@ export class TypeScriptVersionProvider { public get globalVersion(): TypeScriptVersion | undefined { let { globalTsdk } = this.configuration - if (globalTsdk) return new TypeScriptVersion(workspace.expand(globalTsdk)) + let folder = workspace.expand(globalTsdk) + if (!path.isAbsolute(folder)) { + folder = path.join(workspace.root, folder) + } + if (globalTsdk) return new TypeScriptVersion(folder) return undefined } diff --git a/src/server/watchBuild.ts b/src/server/watchBuild.ts new file mode 100644 index 0000000..fdb4a64 --- /dev/null +++ b/src/server/watchBuild.ts @@ -0,0 +1,129 @@ +import { Disposable, disposeAll, StatusBarItem, TaskOptions, Uri, window, workspace } from 'coc.nvim' +import path from 'path' +import type TsserverService from '../server' + +const countRegex = /Found\s+(\d+)\s+error/ +const errorRegex = /^(.+)\((\d+),(\d+)\):\s(\w+)\sTS(\d+):\s*(.+)$/ + +export default class WatchProject implements Disposable { + private disposables: Disposable[] = [] + public static readonly id: string = 'tsserver.watchBuild' + public static readonly startTexts: string[] = ['Starting compilation in watch mode', 'Starting incremental compilation'] + private statusItem: StatusBarItem + private task: any + private options: TaskOptions + + public constructor( + private readonly service: TsserverService + ) { + this.statusItem = window.createStatusBarItem(1, { progress: true }) + this.disposables.push(this.statusItem) + let task = this.task = workspace.createTask('TSC') + + task.onExit(code => { + if (code != 0) { + window.showMessage(`TSC exit with code ${code}`, 'warning') + } + this.onStop() + }) + task.onStdout(lines => { + for (let line of lines) { + this.onLine(line) + } + }) + task.onStderr(lines => { + window.showMessage(`TSC error: ` + lines.join('\n'), 'error') + }) + this.disposables.push(Disposable.create(() => { + task.dispose() + })) + this.check().catch(_e => { + // noop + }) + } + + public async execute(): Promise { + let opts = this.options = await this.getOptions() + await this.start(opts) + } + + private async check(): Promise { + let running = await this.task.running + if (running) { + this.options = await this.getOptions() + this.statusItem.isProgress = false + this.statusItem.text = '?' + this.statusItem.show() + } else { + this.onStop() + } + } + + private async start(options: TaskOptions): Promise { + await this.task.start(options) + } + + private onStop(): void { + this.statusItem.hide() + } + + private onStart(): void { + this.statusItem.text = 'compiling' + this.statusItem.isProgress = true + this.statusItem.show() + workspace.nvim.call('setqflist', [[]], true) + } + + private onLine(line: string): void { + if (countRegex.test(line)) { + let ms = line.match(countRegex) + this.statusItem.text = ms[1] == '0' ? '✓' : '✗' + this.statusItem.isProgress = false + } else if (WatchProject.startTexts.findIndex(s => line.indexOf(s) !== -1) != -1) { + this.onStart() + } else { + let ms = line.match(errorRegex) + if (!ms) return + let fullpath = path.join(this.options.cwd, ms[1]) + let uri = Uri.file(fullpath).toString() + let doc = workspace.getDocument(uri) + let bufnr = doc ? doc.bufnr : null + let item = { + filename: fullpath, + lnum: Number(ms[2]), + col: Number(ms[3]), + text: `[tsc ${ms[5]}] ${ms[6]}`, + type: /error/i.test(ms[4]) ? 'E' : 'W' + } as any + if (bufnr) item.bufnr = bufnr + workspace.nvim.call('setqflist', [[item], 'a']) + } + } + + public async getOptions(): Promise { + let client = await this.service.getClientHost() + let { tscPath } = client.serviceClient + if (!tscPath) { + window.showMessage(`Local & global tsc not found`, 'error') + return + } + + const tsconfigPath = workspace.getConfiguration('tsserver').get('tsconfigPath', 'tsconfig.json') + let find = await workspace.findUp([tsconfigPath]) + if (!find) { + window.showMessage(`${tsconfigPath} not found!`, 'error') + return + } + + let root = path.dirname(find) + return { + cmd: tscPath, + args: ['-p', tsconfigPath, '--watch', 'true', '--pretty', 'false'], + cwd: root + } + } + + public dispose(): void { + disposeAll(this.disposables) + } +} diff --git a/src/utils/fileSchemes.ts b/src/utils/fileSchemes.ts index ef1510d..e645ff4 100644 --- a/src/utils/fileSchemes.ts +++ b/src/utils/fileSchemes.ts @@ -6,6 +6,7 @@ export const file = 'file' export const untitled = 'untitled' export const git = 'git' +export const fugitive = 'fugitive' /** Live share scheme */ export const vsls = 'vsls' export const walkThroughSnippet = 'walkThroughSnippet' @@ -21,5 +22,6 @@ export const semanticSupportedSchemes = [ */ export const disabledSchemes = new Set([ git, + fugitive, vsls ])