add new features:
- Loading status - Batched buffer synchronize - Configuration for showUnused variable - Smart selection support - Support 'auto' as quoteStyle - Support validateDefaultNpmLocation
This commit is contained in:
parent
a3d81e2cb8
commit
f1aa930569
23 changed files with 439 additions and 208 deletions
|
@ -80,6 +80,8 @@ module will be used.
|
|||
- `typescript.preferences.quoteStyle` default: `"single"`
|
||||
- `typescript.suggestionActions.enabled`:Enable/disable suggestion diagnostics for TypeScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace., default: `true`
|
||||
- `typescript.validate.enable`:Enable/disable TypeScript validation., default: `true`
|
||||
- `typescript.useBatchedBufferSync`: use batched buffer synchronize support.
|
||||
- `typescript.showUnused`: show unused variable hint.
|
||||
- `typescript.suggest.enabled` default: `true`
|
||||
- `typescript.suggest.paths`:Enable/disable suggest paths in import statement and require calls, default: `true`
|
||||
- `typescript.suggest.autoImports`:Enable/disable auto import suggests., default: `true`
|
||||
|
@ -99,6 +101,7 @@ module will be used.
|
|||
- `typescript.format.insertSpaceAfterTypeAssertion` default: `false`
|
||||
- `typescript.format.placeOpenBraceOnNewLineForFunctions` default: `false`
|
||||
- `typescript.format.placeOpenBraceOnNewLineForControlBlocks` default: `false`
|
||||
- `javascript.showUnused`: show unused variable hint.
|
||||
- `javascript.updateImportsOnFileMove.enable` default: `true`
|
||||
- `javascript.implementationsCodeLens.enable` default: `true`
|
||||
- `javascript.referencesCodeLens.enable` default: `true`
|
||||
|
|
17
package.json
17
package.json
|
@ -187,6 +187,16 @@
|
|||
"default": false,
|
||||
"description": "Disable download of typings"
|
||||
},
|
||||
"typescript.useBatchedBufferSync": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Use batched buffer sync support."
|
||||
},
|
||||
"typescript.showUnused": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show unused variable hint."
|
||||
},
|
||||
"typescript.updateImportsOnFileMove.enable": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
@ -311,6 +321,11 @@
|
|||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"javascript.showUnused": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show unused variable hint."
|
||||
},
|
||||
"javascript.updateImportsOnFileMove.enable": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
|
@ -467,7 +482,7 @@
|
|||
"semver": "^6.1.1",
|
||||
"tslib": "^1.9.3",
|
||||
"typescript": "3.5.1",
|
||||
"vscode-languageserver-protocol": "^3.15.0-next.1",
|
||||
"vscode-languageserver-protocol": "^3.15.0-next.5",
|
||||
"which": "^1.3.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { disposeAll, workspace } from 'coc.nvim'
|
||||
import { CancellationTokenSource, DidChangeTextDocumentParams, Disposable, TextDocument } from 'vscode-languageserver-protocol'
|
||||
import { Uri, disposeAll, workspace } from 'coc.nvim'
|
||||
import { CancellationTokenSource, Emitter, Event, DidChangeTextDocumentParams, Disposable, TextDocument, TextDocumentContentChangeEvent } from 'vscode-languageserver-protocol'
|
||||
import Proto from '../protocol'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import API from '../utils/api'
|
||||
import { Delayer } from '../utils/async'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import * as languageModeIds from '../utils/languageModeIds'
|
||||
|
||||
function mode2ScriptKind(
|
||||
|
@ -30,10 +31,117 @@ function mode2ScriptKind(
|
|||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages synchronization of buffers with the TS server.
|
||||
*
|
||||
* If supported, batches together file changes. This allows the TS server to more efficiently process changes.
|
||||
*/
|
||||
class BufferSynchronizer {
|
||||
|
||||
private _pending: Proto.UpdateOpenRequestArgs = {}
|
||||
private _pendingFiles = new Set<string>()
|
||||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
) { }
|
||||
|
||||
public open(args: Proto.OpenRequestArgs): void {
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(args.file, pending => {
|
||||
if (!pending.openFiles) {
|
||||
pending.openFiles = []
|
||||
}
|
||||
pending.openFiles.push(args)
|
||||
})
|
||||
} else {
|
||||
this.client.executeWithoutWaitingForResponse('open', args)
|
||||
}
|
||||
}
|
||||
|
||||
public close(filepath: string): void {
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(filepath, pending => {
|
||||
if (!pending.closedFiles) {
|
||||
pending.closedFiles = []
|
||||
}
|
||||
pending.closedFiles.push(filepath)
|
||||
})
|
||||
} else {
|
||||
const args: Proto.FileRequestArgs = { file: filepath }
|
||||
this.client.executeWithoutWaitingForResponse('close', args)
|
||||
}
|
||||
}
|
||||
|
||||
public change(filepath: string, events: TextDocumentContentChangeEvent[]): void {
|
||||
if (!events.length) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(filepath, pending => {
|
||||
if (!pending.changedFiles) {
|
||||
pending.changedFiles = []
|
||||
}
|
||||
pending.changedFiles.push({
|
||||
fileName: filepath,
|
||||
textChanges: events.map((change): Proto.CodeEdit => ({
|
||||
newText: change.text,
|
||||
start: typeConverters.Position.toLocation(change.range.start),
|
||||
end: typeConverters.Position.toLocation(change.range.end),
|
||||
})).reverse(), // Send the edits end-of-document to start-of-document order
|
||||
})
|
||||
})
|
||||
} else {
|
||||
for (const { range, text } of events) {
|
||||
const args: Proto.ChangeRequestArgs = {
|
||||
insertString: text,
|
||||
...typeConverters.Range.toFormattingRequestArgs(filepath, range)
|
||||
}
|
||||
this.client.executeWithoutWaitingForResponse('change', args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public beforeCommand(command: string): void {
|
||||
if (command === 'updateOpen') {
|
||||
return
|
||||
}
|
||||
|
||||
this.flush()
|
||||
}
|
||||
|
||||
private flush(): void {
|
||||
if (!this.supportsBatching) {
|
||||
// We've already eagerly synchronized
|
||||
return
|
||||
}
|
||||
|
||||
if (this._pending.changedFiles || this._pending.closedFiles || this._pending.openFiles) {
|
||||
this.client.executeWithoutWaitingForResponse('updateOpen', this._pending)
|
||||
this._pending = {}
|
||||
this._pendingFiles.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private get supportsBatching(): boolean {
|
||||
return this.client.apiVersion.gte(API.v340) && workspace.getConfiguration('typescript').get<boolean>('useBatchedBufferSync', true)
|
||||
}
|
||||
|
||||
private updatePending(filepath: string, f: (pending: Proto.UpdateOpenRequestArgs) => void): void {
|
||||
if (this.supportsBatching && this._pendingFiles.has(filepath)) {
|
||||
this.flush()
|
||||
this._pendingFiles.clear()
|
||||
f(this._pending)
|
||||
this._pendingFiles.add(filepath)
|
||||
} else {
|
||||
f(this._pending)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default class BufferSyncSupport {
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
|
||||
private _validate: boolean
|
||||
private readonly modeIds: Set<string>
|
||||
private readonly uris: Set<string> = new Set()
|
||||
private readonly disposables: Disposable[] = []
|
||||
|
@ -41,19 +149,28 @@ export default class BufferSyncSupport {
|
|||
private readonly pendingDiagnostics = new Map<string, number>()
|
||||
private readonly diagnosticDelayer: Delayer<any>
|
||||
private pendingGetErr: GetErrRequest | undefined
|
||||
private readonly synchronizer: BufferSynchronizer
|
||||
private _validateJavaScript = true
|
||||
private _validateTypeScript = true
|
||||
|
||||
private listening = false
|
||||
private readonly _onDelete = new Emitter<string>()
|
||||
public readonly onDelete: Event<string> = this._onDelete.event
|
||||
|
||||
constructor(
|
||||
client: ITypeScriptServiceClient,
|
||||
modeIds: string[],
|
||||
validate: boolean
|
||||
) {
|
||||
this.client = client
|
||||
this.modeIds = new Set<string>(modeIds)
|
||||
this._validate = validate || false
|
||||
this.synchronizer = new BufferSynchronizer(client)
|
||||
this.modeIds = new Set<string>(languageModeIds.languageIds)
|
||||
this.diagnosticDelayer = new Delayer<any>(300)
|
||||
}
|
||||
|
||||
public listen(): void {
|
||||
if (this.listening) {
|
||||
return
|
||||
}
|
||||
this.listening = true
|
||||
workspace.onDidOpenTextDocument(
|
||||
this.onDidOpenTextDocument,
|
||||
this,
|
||||
|
@ -70,14 +187,8 @@ export default class BufferSyncSupport {
|
|||
this.disposables
|
||||
)
|
||||
workspace.textDocuments.forEach(this.onDidOpenTextDocument, this)
|
||||
}
|
||||
|
||||
public reInitialize(): void {
|
||||
workspace.textDocuments.forEach(this.onDidOpenTextDocument, this)
|
||||
}
|
||||
|
||||
public set validate(value: boolean) {
|
||||
this._validate = value
|
||||
this.updateConfiguration()
|
||||
workspace.onDidChangeConfiguration(this.updateConfiguration, this, this.disposables)
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
@ -105,8 +216,8 @@ export default class BufferSyncSupport {
|
|||
let root = this.client.getProjectRootPath(document.uri)
|
||||
if (root) args.projectRootPath = root
|
||||
}
|
||||
|
||||
this.client.executeWithoutWaitingForResponse('open', args) // tslint:disable-line
|
||||
this.synchronizer.open(args)
|
||||
// this.client.executeWithoutWaitingForResponse('open', args)
|
||||
this.requestDiagnostic(uri)
|
||||
}
|
||||
|
||||
|
@ -114,10 +225,12 @@ export default class BufferSyncSupport {
|
|||
let { uri } = document
|
||||
if (!this.uris.has(uri)) return
|
||||
let filepath = this.client.toPath(uri)
|
||||
const args: Proto.FileRequestArgs = {
|
||||
file: filepath
|
||||
}
|
||||
this.client.executeWithoutWaitingForResponse('close', args) // tslint:disable-line
|
||||
this.uris.delete(uri)
|
||||
this.pendingDiagnostics.delete(uri)
|
||||
this.synchronizer.close(filepath)
|
||||
this._onDelete.fire(uri)
|
||||
this.requestAllDiagnostics()
|
||||
// this.client.executeWithoutWaitingForResponse('close', args)
|
||||
}
|
||||
|
||||
private onDidChangeTextDocument(e: DidChangeTextDocumentParams): void {
|
||||
|
@ -125,17 +238,7 @@ export default class BufferSyncSupport {
|
|||
let { uri } = textDocument
|
||||
if (!this.uris.has(uri)) return
|
||||
let filepath = this.client.toPath(uri)
|
||||
for (const { range, text } of contentChanges) {
|
||||
const args: Proto.ChangeRequestArgs = {
|
||||
file: filepath,
|
||||
line: range ? range.start.line + 1 : 1,
|
||||
offset: range ? range.start.character + 1 : 1,
|
||||
endLine: range ? range.end.line + 1 : 2 ** 24,
|
||||
endOffset: range ? range.end.character + 1 : 1,
|
||||
insertString: text
|
||||
}
|
||||
this.client.executeWithoutWaitingForResponse('change', args) // tslint:disable-line
|
||||
}
|
||||
this.synchronizer.change(filepath, contentChanges)
|
||||
const didTrigger = this.requestDiagnostic(uri)
|
||||
if (!didTrigger && this.pendingGetErr) {
|
||||
// In this case we always want to re-trigger all diagnostics
|
||||
|
@ -145,6 +248,10 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
}
|
||||
|
||||
public beforeCommand(command: string): void {
|
||||
this.synchronizer.beforeCommand(command)
|
||||
}
|
||||
|
||||
public interuptGetErr<R>(f: () => R): R {
|
||||
if (!this.pendingGetErr) {
|
||||
return f()
|
||||
|
@ -157,6 +264,19 @@ export default class BufferSyncSupport {
|
|||
return result
|
||||
}
|
||||
|
||||
public getErr(resources: Uri[]): any {
|
||||
const handledResources = resources.filter(resource => this.uris.has(resource.toString()))
|
||||
if (!handledResources.length) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const resource of handledResources) {
|
||||
this.pendingDiagnostics.set(resource.toString(), Date.now())
|
||||
}
|
||||
|
||||
this.triggerDiagnostics()
|
||||
}
|
||||
|
||||
private triggerDiagnostics(delay = 200): void {
|
||||
this.diagnosticDelayer.trigger(() => {
|
||||
this.sendPendingDiagnostics()
|
||||
|
@ -164,11 +284,11 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
public requestAllDiagnostics(): void {
|
||||
if (!this._validate) {
|
||||
return
|
||||
}
|
||||
for (const uri of this.uris) {
|
||||
this.pendingDiagnostics.set(uri, Date.now())
|
||||
let doc = workspace.getDocument(uri)
|
||||
if (doc && this.shouldValidate(doc.filetype)) {
|
||||
this.pendingDiagnostics.set(uri, Date.now())
|
||||
}
|
||||
}
|
||||
this.diagnosticDelayer.trigger(() => { // tslint:disable-line
|
||||
this.sendPendingDiagnostics()
|
||||
|
@ -176,11 +296,8 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
public requestDiagnostic(uri: string): boolean {
|
||||
if (!this._validate) {
|
||||
return false
|
||||
}
|
||||
let document = workspace.getDocument(uri)
|
||||
if (!document) return false
|
||||
if (!document || !this.shouldValidate(document.filetype)) return false
|
||||
this.pendingDiagnostics.set(uri, Date.now())
|
||||
const lineCount = document.lineCount
|
||||
const delay = Math.min(Math.max(Math.ceil(lineCount / 20), 300), 800)
|
||||
|
@ -193,9 +310,6 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
private sendPendingDiagnostics(): void {
|
||||
if (!this._validate) {
|
||||
return
|
||||
}
|
||||
const uris = Array.from(this.pendingDiagnostics.entries())
|
||||
.sort((a, b) => a[1] - b[1])
|
||||
.map(entry => entry[0])
|
||||
|
@ -217,6 +331,23 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
this.pendingDiagnostics.clear()
|
||||
}
|
||||
private updateConfiguration(): void {
|
||||
const jsConfig = workspace.getConfiguration('javascript', null)
|
||||
const tsConfig = workspace.getConfiguration('typescript', null)
|
||||
|
||||
this._validateJavaScript = jsConfig.get<boolean>('validate.enable', true)
|
||||
this._validateTypeScript = tsConfig.get<boolean>('validate.enable', true)
|
||||
}
|
||||
|
||||
private shouldValidate(filetype: string): boolean {
|
||||
if (languageModeIds.languageIds.indexOf(filetype) == -1) {
|
||||
return false
|
||||
}
|
||||
if (filetype.startsWith('javascript')) {
|
||||
return this._validateJavaScript
|
||||
}
|
||||
return this._validateTypeScript
|
||||
}
|
||||
}
|
||||
|
||||
class GetErrRequest {
|
||||
|
|
|
@ -16,7 +16,6 @@ import * as typeConverters from '../utils/typeConverters'
|
|||
import TypingsStatus from '../utils/typingsStatus'
|
||||
import FileConfigurationManager, { SuggestOptions } from './fileConfigurationManager'
|
||||
import SnippetString from '../utils/SnippetString'
|
||||
import BufferSyncSupport from './bufferSyncSupport'
|
||||
|
||||
// command center
|
||||
export interface CommandItem {
|
||||
|
@ -59,7 +58,6 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly typingsStatus: TypingsStatus,
|
||||
private readonly fileConfigurationManager: FileConfigurationManager,
|
||||
private readonly bufferSyncSupport: BufferSyncSupport,
|
||||
languageId: string
|
||||
) {
|
||||
|
||||
|
@ -128,7 +126,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
let isNewIdentifierLocation = true
|
||||
if (this.client.apiVersion.gte(API.v300)) {
|
||||
try {
|
||||
const response = await this.bufferSyncSupport.interuptGetErr(() => this.client.execute('completionInfo', args, token))
|
||||
const response = await this.client.interruptGetErr(() => this.client.execute('completionInfo', args, token))
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return null
|
||||
}
|
||||
|
@ -141,7 +139,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
throw e
|
||||
}
|
||||
} else {
|
||||
const response = await this.bufferSyncSupport.interuptGetErr(() => this.client.execute('completions', args, token))
|
||||
const response = await this.client.interruptGetErr(() => this.client.execute('completions', args, token))
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return null
|
||||
}
|
||||
|
@ -218,11 +216,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
|
||||
let response: ServerResponse.Response<Proto.CompletionDetailsResponse>
|
||||
try {
|
||||
response = await this.client.execute(
|
||||
'completionEntryDetails',
|
||||
args,
|
||||
token
|
||||
)
|
||||
response = await this.client.interruptGetErr(() => this.client.execute('completionEntryDetails', args, token))
|
||||
} catch {
|
||||
return item
|
||||
}
|
||||
|
|
|
@ -93,9 +93,7 @@ export class DiagnosticsManager {
|
|||
diagnostics: Diagnostic[]
|
||||
): void {
|
||||
const collection = this._diagnostics.get(kind)
|
||||
if (!collection) {
|
||||
return
|
||||
}
|
||||
if (!collection) return
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
const existing = collection.get(uri)
|
||||
|
|
|
@ -144,10 +144,11 @@ export default class FileConfigurationManager {
|
|||
return {}
|
||||
}
|
||||
const config = workspace.getConfiguration(`${language}`)
|
||||
const defaultQuote = this.client.apiVersion.gte(API.v333) ? 'auto' : undefined
|
||||
return {
|
||||
disableSuggestions: !config.get<boolean>('suggest.enabled', true),
|
||||
importModuleSpecifierPreference: getImportModuleSpecifier(config) as any,
|
||||
quotePreference: config.get<'single' | 'double'>('preferences.quoteStyle', 'single'),
|
||||
quotePreference: config.get<'single' | 'double' | 'auto'>('preferences.quoteStyle', defaultQuote),
|
||||
allowRenameOfImportPath: true,
|
||||
allowTextChangesInNewFiles: true,
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export default class TypeScriptHoverProvider implements HoverProvider {
|
|||
position
|
||||
)
|
||||
try {
|
||||
const response = await this.client.execute('quickinfo', args, token)
|
||||
const response = await this.client.interruptGetErr(() => this.client.execute('quickinfo', args, token))
|
||||
if (response && response.type == 'response' && response.body) {
|
||||
const data = response.body
|
||||
return {
|
||||
|
|
|
@ -142,8 +142,6 @@ export default class TypeScriptQuickFixProvider implements CodeActionProvider {
|
|||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly diagnosticsManager: DiagnosticsManager,
|
||||
private readonly bufferSyncSupport: BufferSyncSupport,
|
||||
) {
|
||||
commands.register(
|
||||
new ApplyCodeActionCommand(client)
|
||||
|
@ -177,7 +175,7 @@ export default class TypeScriptQuickFixProvider implements CodeActionProvider {
|
|||
return []
|
||||
}
|
||||
|
||||
if (this.bufferSyncSupport.hasPendingDiagnostics(document.uri)) {
|
||||
if (this.client.bufferSyncSupport.hasPendingDiagnostics(document.uri)) {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -273,7 +271,7 @@ export default class TypeScriptQuickFixProvider implements CodeActionProvider {
|
|||
}
|
||||
|
||||
// Make sure there are multiple diagnostics of the same type in the file
|
||||
if (!this.diagnosticsManager
|
||||
if (!this.client.diagnosticsManager
|
||||
.getDiagnostics(document.uri)
|
||||
.some(x => x.code === diagnostic.code && x !== diagnostic)) {
|
||||
return
|
||||
|
|
|
@ -127,7 +127,9 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider {
|
|||
)
|
||||
let response
|
||||
try {
|
||||
response = await this.client.execute('getApplicableRefactors', args, token)
|
||||
response = await this.client.interruptGetErr(() => {
|
||||
return this.client.execute('getApplicableRefactors', args, token)
|
||||
})
|
||||
if (!response || !response.body) {
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -81,7 +81,9 @@ export default class TypeScriptRenameProvider implements RenameProvider {
|
|||
findInComments: false
|
||||
}
|
||||
|
||||
return this.client.execute('rename', args, token)
|
||||
return this.client.interruptGetErr(() => {
|
||||
return this.client.execute('rename', args, token)
|
||||
})
|
||||
}
|
||||
|
||||
private toWorkspaceEdit(
|
||||
|
|
|
@ -28,14 +28,11 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro
|
|||
position
|
||||
)
|
||||
|
||||
let info: Proto.SignatureHelpItems | undefined
|
||||
try {
|
||||
const response = await this.client.execute('signatureHelp', args, token)
|
||||
info = (response as any).body
|
||||
if (!info) return undefined
|
||||
} catch {
|
||||
const response = await this.client.interruptGetErr(() => this.client.execute('signatureHelp', args, token))
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return undefined
|
||||
}
|
||||
let info = response.body
|
||||
|
||||
const result: SignatureHelp = {
|
||||
activeSignature: info.selectedItemIndex,
|
||||
|
|
47
src/server/features/smartSelect.ts
Normal file
47
src/server/features/smartSelect.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as Proto from '../protocol'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import { TextDocument, Position, CancellationToken } from 'vscode-languageserver-protocol'
|
||||
import { SelectionRange } from 'vscode-languageserver-protocol/lib/protocol.selectionRange.proposed'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import { SelectionRangeProvider } from 'coc.nvim'
|
||||
|
||||
export default class SmartSelection implements SelectionRangeProvider {
|
||||
public constructor(
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
) { }
|
||||
|
||||
public async provideSelectionRanges(
|
||||
document: TextDocument,
|
||||
positions: Position[],
|
||||
token: CancellationToken,
|
||||
): Promise<SelectionRange[] | undefined> {
|
||||
const file = this.client.toPath(document.uri)
|
||||
if (!file) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const args: Proto.SelectionRangeRequestArgs = {
|
||||
file,
|
||||
locations: positions.map(typeConverters.Position.toLocation)
|
||||
}
|
||||
const response = await this.client.execute('selectionRange', args, token)
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return undefined
|
||||
}
|
||||
return response.body.map(SmartSelection.convertSelectionRange)
|
||||
}
|
||||
|
||||
private static convertSelectionRange(
|
||||
selectionRange: Proto.SelectionRange
|
||||
): SelectionRange {
|
||||
return SelectionRange.create(
|
||||
typeConverters.Range.fromTextSpan(selectionRange.textSpan),
|
||||
selectionRange.parent ? SmartSelection.convertSelectionRange(selectionRange.parent) : undefined,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -74,11 +74,13 @@ export default class UpdateImportsOnFileRenameHandler {
|
|||
|
||||
private async getEditsForFileRename(document: TextDocument, oldFile: string, newFile: string): Promise<WorkspaceEdit> {
|
||||
await this.fileConfigurationManager.ensureConfigurationForDocument(document)
|
||||
const args: Proto.GetEditsForFileRenameRequestArgs = {
|
||||
oldFilePath: oldFile,
|
||||
newFilePath: newFile
|
||||
}
|
||||
const response = await this.client.execute('getEditsForFileRename', args, CancellationToken.None)
|
||||
const response = await this.client.interruptGetErr(() => {
|
||||
const args: Proto.GetEditsForFileRenameRequestArgs = {
|
||||
oldFilePath: oldFile,
|
||||
newFilePath: newFile,
|
||||
}
|
||||
return this.client.execute('getEditsForFileRename', args, CancellationToken.None)
|
||||
})
|
||||
if (!response || response.type != 'response' || !response.body) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
* 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'
|
||||
import { Diagnostic, Disposable, CodeActionKind, DiagnosticSeverity } from 'vscode-languageserver-protocol'
|
||||
import { Uri, 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'
|
||||
|
@ -28,6 +26,7 @@ import SignatureHelpProvider from './features/signatureHelp'
|
|||
import UpdateImportsOnFileRenameHandler from './features/updatePathOnRename'
|
||||
import WatchBuild from './features/watchBuild'
|
||||
import WorkspaceSymbolProvider from './features/workspaceSymbols'
|
||||
import SmartSelection from './features/smartSelect'
|
||||
import TypeScriptServiceClient from './typescriptServiceClient'
|
||||
import InstallModuleProvider from './features/moduleInstall'
|
||||
import API from './utils/api'
|
||||
|
@ -35,15 +34,8 @@ import { LanguageDescription } from './utils/languageDescription'
|
|||
import TypingsStatus from './utils/typingsStatus'
|
||||
import { OrganizeImportsCodeActionProvider } from './organizeImports'
|
||||
|
||||
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(
|
||||
|
@ -52,54 +44,33 @@ export default class LanguageProvider {
|
|||
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 (!doc || client.state !== ServiceStat.Running) 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()
|
||||
workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables)
|
||||
|
||||
let initialized = false
|
||||
|
||||
client.onTsServerStarted(() => { // tslint:disable-line
|
||||
client.onTsServerStarted(async () => { // tslint:disable-line
|
||||
if (!initialized) {
|
||||
for (let doc of workspace.documents) {
|
||||
if (description.modeIds.indexOf(doc.filetype) !== -1) {
|
||||
this.fileConfigurationManager.ensureConfigurationForDocument(doc.textDocument) // tslint:disable-line
|
||||
}
|
||||
}
|
||||
initialized = true
|
||||
this.registerProviders(client, typingsStatus)
|
||||
this.bufferSyncSupport.listen()
|
||||
} else {
|
||||
this.reInitialize()
|
||||
this.client.diagnosticsManager.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(
|
||||
|
@ -117,7 +88,6 @@ export default class LanguageProvider {
|
|||
client,
|
||||
typingsStatus,
|
||||
this.fileConfigurationManager,
|
||||
this.bufferSyncSupport,
|
||||
this.description.id
|
||||
),
|
||||
CompletionItemProvider.triggerCharacters
|
||||
|
@ -256,14 +226,14 @@ export default class LanguageProvider {
|
|||
this.disposables.push(
|
||||
languages.registerCodeActionProvider(
|
||||
languageIds,
|
||||
new QuickfixProvider(client, this.diagnosticsManager, this.bufferSyncSupport),
|
||||
new QuickfixProvider(client),
|
||||
'tsserver',
|
||||
[CodeActionKind.QuickFix]))
|
||||
|
||||
this.disposables.push(
|
||||
languages.registerCodeActionProvider(
|
||||
languageIds,
|
||||
new ImportfixProvider(this.bufferSyncSupport),
|
||||
new ImportfixProvider(this.client.bufferSyncSupport),
|
||||
'tsserver',
|
||||
[CodeActionKind.QuickFix]))
|
||||
let cachedResponse = new CachedNavTreeResponse()
|
||||
|
@ -282,6 +252,11 @@ export default class LanguageProvider {
|
|||
languageIds,
|
||||
new ImplementationsCodeLensProvider(client, cachedResponse)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v350)) {
|
||||
this.disposables.push(
|
||||
languages.registerSelectionRangeProvider(languageIds, new SmartSelection(this.client))
|
||||
)
|
||||
}
|
||||
|
||||
if (this.description.id == 'typescript') {
|
||||
this.disposables.push(
|
||||
|
@ -329,51 +304,31 @@ export default class LanguageProvider {
|
|||
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()
|
||||
this.client.bufferSyncSupport.requestAllDiagnostics()
|
||||
}
|
||||
|
||||
public diagnosticsReceived(
|
||||
diagnosticsKind: DiagnosticKind,
|
||||
file: Uri,
|
||||
diagnostics: Diagnostic[]
|
||||
diagnostics: (Diagnostic & { reportUnnecessary: any })[]
|
||||
): void {
|
||||
this.diagnosticsManager.diagnosticsReceived(
|
||||
this.client.diagnosticsManager.diagnosticsReceived(
|
||||
diagnosticsKind,
|
||||
file.toString(),
|
||||
diagnostics
|
||||
)
|
||||
}
|
||||
|
||||
public configFileDiagnosticsReceived(uri: Uri, diagnostics: Diagnostic[]): void {
|
||||
this.diagnosticsManager.configFileDiagnosticsReceived(uri.toString(), diagnostics)
|
||||
const config = workspace.getConfiguration(this.id, file.toString())
|
||||
const reportUnnecessary = config.get<boolean>('showUnused', true)
|
||||
this.client.diagnosticsManager.diagnosticsReceived(diagnosticsKind, file.toString(), diagnostics.filter(diag => {
|
||||
if (!reportUnnecessary) {
|
||||
diag.tags = undefined
|
||||
if (diag.reportUnnecessary && diag.severity === DiagnosticSeverity.Hint) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export class OrganizeImportsCommand implements Command {
|
|||
}
|
||||
}
|
||||
}
|
||||
const response = await client.execute('organizeImports', args, CancellationToken.None)
|
||||
const response = await this.client.interruptGetErr(() => this.client.execute('organizeImports', args, CancellationToken.None))
|
||||
if (!response || response.type != 'response' || !response.success) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import * as Proto from './protocol'
|
|||
import API from './utils/api'
|
||||
import { TypeScriptServiceConfiguration } from './utils/configuration'
|
||||
import Logger from './utils/logger'
|
||||
import BufferSyncSupport from './features/bufferSyncSupport'
|
||||
import { DiagnosticsManager } from './features/diagnostics'
|
||||
|
||||
export namespace ServerResponse {
|
||||
|
||||
|
@ -74,6 +76,8 @@ export interface ITypeScriptServiceClient {
|
|||
onDidEndInstallTypings: Event<Proto.EndInstallTypesEventBody>
|
||||
onTypesInstallerInitializationFailed: Event<Proto.TypesInstallerInitializationFailedEventBody>
|
||||
readonly logger: Logger
|
||||
readonly bufferSyncSupport: BufferSyncSupport
|
||||
readonly diagnosticsManager: DiagnosticsManager
|
||||
|
||||
getProjectRootPath(uri: string): string | null
|
||||
normalizePath(resource: Uri): string | null
|
||||
|
@ -91,10 +95,15 @@ export interface ITypeScriptServiceClient {
|
|||
executeWithoutWaitingForResponse(command: 'open', args: Proto.OpenRequestArgs): void
|
||||
executeWithoutWaitingForResponse(command: 'close', args: Proto.FileRequestArgs): void
|
||||
executeWithoutWaitingForResponse(command: 'change', args: Proto.ChangeRequestArgs): void
|
||||
// executeWithoutWaitingForResponse(command: 'updateOpen', args: Proto.UpdateOpenRequestArgs): void
|
||||
executeWithoutWaitingForResponse(command: 'updateOpen', args: Proto.UpdateOpenRequestArgs): void
|
||||
executeWithoutWaitingForResponse(command: 'compilerOptionsForInferredProjects', args: Proto.SetCompilerOptionsForInferredProjectsArgs): void
|
||||
executeWithoutWaitingForResponse(command: 'reloadProjects', args: null): void
|
||||
executeWithoutWaitingForResponse(command: 'configurePlugin', args: Proto.ConfigurePluginRequestArguments): void
|
||||
|
||||
executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: CancellationToken): Promise<ServerResponse.Response<Proto.Response>>
|
||||
|
||||
/**
|
||||
* Cancel on going geterr requests and re-queue them after `f` has been evaluated.
|
||||
*/
|
||||
interruptGetErr<R>(f: () => R): R
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import os from 'os'
|
|||
import path from 'path'
|
||||
import { CancellationToken, Disposable, Emitter, Event } from 'vscode-languageserver-protocol'
|
||||
import which from 'which'
|
||||
import { Uri, DiagnosticKind, ServiceStat, workspace, disposeAll } from 'coc.nvim'
|
||||
import { Uri, ServiceStat, workspace, disposeAll } from 'coc.nvim'
|
||||
import FileConfigurationManager from './features/fileConfigurationManager'
|
||||
import * as Proto from './protocol'
|
||||
import { ITypeScriptServiceClient, ServerResponse } from './typescriptService'
|
||||
|
@ -25,6 +25,8 @@ import { PluginManager } from '../utils/plugins'
|
|||
import { ICallback, Reader } from './utils/wireProtocol'
|
||||
import { CallbackMap } from './callbackMap'
|
||||
import { RequestItem, RequestQueue, RequestQueueingType } from './requestQueue'
|
||||
import BufferSyncSupport from './features/bufferSyncSupport'
|
||||
import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'
|
||||
|
||||
class ForkedTsServerProcess {
|
||||
constructor(private childProcess: cp.ChildProcess) { }
|
||||
|
@ -66,6 +68,9 @@ export interface TsDiagnostics {
|
|||
export default class TypeScriptServiceClient implements ITypeScriptServiceClient {
|
||||
public state = ServiceStat.Initial
|
||||
public readonly logger: Logger = new Logger()
|
||||
public readonly bufferSyncSupport: BufferSyncSupport
|
||||
public readonly diagnosticsManager: DiagnosticsManager
|
||||
|
||||
private fileConfigurationManager: FileConfigurationManager
|
||||
private pathSeparator: string
|
||||
private tracer: Tracer
|
||||
|
@ -111,6 +116,16 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
pluginManager.onDidChangePlugins(() => {
|
||||
this.restartTsServer()
|
||||
}, null, this.disposables)
|
||||
|
||||
this.bufferSyncSupport = new BufferSyncSupport(this)
|
||||
this.onTsServerStarted(() => {
|
||||
this.bufferSyncSupport.listen()
|
||||
})
|
||||
|
||||
this.diagnosticsManager = new DiagnosticsManager()
|
||||
this.bufferSyncSupport.onDelete(resource => {
|
||||
this.diagnosticsManager.delete(resource)
|
||||
}, null, this.disposables)
|
||||
}
|
||||
|
||||
private _onDiagnosticsReceived = new Emitter<TsDiagnostics>()
|
||||
|
@ -140,7 +155,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
})
|
||||
.then(undefined, () => void 0)
|
||||
}
|
||||
|
||||
this.bufferSyncSupport.dispose()
|
||||
disposeAll(this.disposables)
|
||||
this.logger.dispose()
|
||||
this._onTsServerStarted.dispose()
|
||||
|
@ -516,6 +531,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
if (this.servicePromise == null) {
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
this.bufferSyncSupport.beforeCommand(command)
|
||||
|
||||
const request = this._requestQueue.createRequest(command, args)
|
||||
const requestInfo: RequestItem = {
|
||||
|
@ -700,7 +716,11 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
)
|
||||
}
|
||||
break
|
||||
|
||||
case 'projectsUpdatedInBackground':
|
||||
const body = (event as Proto.ProjectsUpdatedInBackgroundEvent).body
|
||||
const resources = body.openFiles.map(Uri.file)
|
||||
this.bufferSyncSupport.getErr(resources)
|
||||
break
|
||||
case 'typesInstallerInitializationFailed':
|
||||
if (event.body) {
|
||||
this._onTypesInstallerInitializationFailed.fire(
|
||||
|
@ -708,6 +728,13 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
)
|
||||
}
|
||||
break
|
||||
case 'projectLoadingStart':
|
||||
this.versionStatus.loading = true
|
||||
break
|
||||
|
||||
case 'projectLoadingFinish':
|
||||
this.versionStatus.loading = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,6 +813,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
if (this.apiVersion.gte(API.v291)) {
|
||||
args.push('--noGetErrOnBackgroundUpdate')
|
||||
}
|
||||
|
||||
if (this.apiVersion.gte(API.v345)) {
|
||||
args.push('--validateDefaultNpmLocation')
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
|
@ -816,6 +847,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
public interruptGetErr<R>(f: () => R): R {
|
||||
return this.bufferSyncSupport.interuptGetErr(f)
|
||||
}
|
||||
}
|
||||
|
||||
function getDiagnosticsKind(event: Proto.Event): DiagnosticKind {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Uri, DiagnosticKind, disposeAll, workspace } from 'coc.nvim'
|
||||
import { Range, Diagnostic, DiagnosticSeverity, Disposable, Position, CancellationToken } from 'vscode-languageserver-protocol'
|
||||
import { Range, Diagnostic, DiagnosticSeverity, Disposable, Position, CancellationToken, DiagnosticRelatedInformation } from 'vscode-languageserver-protocol'
|
||||
import LanguageProvider from './languageProvider'
|
||||
import * as Proto from './protocol'
|
||||
import * as PConst from './protocol.const'
|
||||
|
@ -64,13 +64,13 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
let language = this.findLanguage(uri)
|
||||
if (!language) return
|
||||
if (diagnostics.length == 0) {
|
||||
language.configFileDiagnosticsReceived(uri, [])
|
||||
this.client.diagnosticsManager.configFileDiagnosticsReceived(uri.toString(), [])
|
||||
} else {
|
||||
let range = Range.create(Position.create(0, 0), Position.create(0, 1))
|
||||
let { text, code, category } = diagnostics[0]
|
||||
let severity = category == 'error' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning
|
||||
let diagnostic = Diagnostic.create(range, text, severity, code)
|
||||
language.configFileDiagnosticsReceived(uri, [diagnostic])
|
||||
this.client.diagnosticsManager.configFileDiagnosticsReceived(uri.toString(), [diagnostic])
|
||||
}
|
||||
}
|
||||
}, null, this.disposables)
|
||||
|
@ -158,22 +158,34 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
private createMarkerDatas(diagnostics: Proto.Diagnostic[]): Diagnostic[] {
|
||||
private createMarkerDatas(diagnostics: Proto.Diagnostic[]): (Diagnostic & { reportUnnecessary: any })[] {
|
||||
return diagnostics.map(tsDiag => this.tsDiagnosticToLspDiagnostic(tsDiag))
|
||||
}
|
||||
|
||||
private tsDiagnosticToLspDiagnostic(diagnostic: Proto.Diagnostic): Diagnostic {
|
||||
private tsDiagnosticToLspDiagnostic(diagnostic: Proto.Diagnostic): (Diagnostic & { reportUnnecessary: any }) {
|
||||
const { start, end, text } = diagnostic
|
||||
const range = {
|
||||
start: typeConverters.Position.fromLocation(start),
|
||||
end: typeConverters.Position.fromLocation(end)
|
||||
}
|
||||
let relatedInformation: DiagnosticRelatedInformation[]
|
||||
if (diagnostic.relatedInformation) {
|
||||
relatedInformation = diagnostic.relatedInformation.map(o => {
|
||||
let { span, message } = o
|
||||
return {
|
||||
location: typeConverters.Location.fromTextSpan(this.client.toResource(span.file), span),
|
||||
message
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
range,
|
||||
message: text,
|
||||
code: diagnostic.code ? diagnostic.code : null,
|
||||
severity: this.getDiagnosticSeverity(diagnostic),
|
||||
reportUnnecessary: diagnostic.reportsUnnecessary,
|
||||
source: diagnostic.source || 'tsserver',
|
||||
relatedInformation
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,56 +5,61 @@
|
|||
import * as semver from 'semver'
|
||||
|
||||
export default class API {
|
||||
private static fromSimpleString(value: string): API {
|
||||
return new API(value, value)
|
||||
}
|
||||
private static fromSimpleString(value: string): API {
|
||||
return new API(value, value)
|
||||
}
|
||||
|
||||
public static readonly defaultVersion = API.fromSimpleString('1.0.0')
|
||||
public static readonly v203 = API.fromSimpleString('2.0.3')
|
||||
public static readonly v206 = API.fromSimpleString('2.0.6')
|
||||
public static readonly v208 = API.fromSimpleString('2.0.8')
|
||||
public static readonly v213 = API.fromSimpleString('2.1.3')
|
||||
public static readonly v220 = API.fromSimpleString('2.2.0')
|
||||
public static readonly v222 = API.fromSimpleString('2.2.2')
|
||||
public static readonly v230 = API.fromSimpleString('2.3.0')
|
||||
public static readonly v234 = API.fromSimpleString('2.3.4')
|
||||
public static readonly v240 = API.fromSimpleString('2.4.0')
|
||||
public static readonly v250 = API.fromSimpleString('2.5.0')
|
||||
public static readonly v260 = API.fromSimpleString('2.6.0')
|
||||
public static readonly v270 = API.fromSimpleString('2.7.0')
|
||||
public static readonly v280 = API.fromSimpleString('2.8.0')
|
||||
public static readonly v290 = API.fromSimpleString('2.9.0')
|
||||
public static readonly v291 = API.fromSimpleString('2.9.1')
|
||||
public static readonly v292 = API.fromSimpleString('2.9.2')
|
||||
public static readonly v300 = API.fromSimpleString('3.0.0')
|
||||
public static readonly v310 = API.fromSimpleString('3.1.0')
|
||||
public static readonly v314 = API.fromSimpleString('3.1.4')
|
||||
public static readonly v320 = API.fromSimpleString('3.2.0')
|
||||
public static readonly defaultVersion = API.fromSimpleString('1.0.0')
|
||||
public static readonly v203 = API.fromSimpleString('2.0.3')
|
||||
public static readonly v206 = API.fromSimpleString('2.0.6')
|
||||
public static readonly v208 = API.fromSimpleString('2.0.8')
|
||||
public static readonly v213 = API.fromSimpleString('2.1.3')
|
||||
public static readonly v220 = API.fromSimpleString('2.2.0')
|
||||
public static readonly v222 = API.fromSimpleString('2.2.2')
|
||||
public static readonly v230 = API.fromSimpleString('2.3.0')
|
||||
public static readonly v234 = API.fromSimpleString('2.3.4')
|
||||
public static readonly v240 = API.fromSimpleString('2.4.0')
|
||||
public static readonly v250 = API.fromSimpleString('2.5.0')
|
||||
public static readonly v260 = API.fromSimpleString('2.6.0')
|
||||
public static readonly v270 = API.fromSimpleString('2.7.0')
|
||||
public static readonly v280 = API.fromSimpleString('2.8.0')
|
||||
public static readonly v290 = API.fromSimpleString('2.9.0')
|
||||
public static readonly v291 = API.fromSimpleString('2.9.1')
|
||||
public static readonly v292 = API.fromSimpleString('2.9.2')
|
||||
public static readonly v300 = API.fromSimpleString('3.0.0')
|
||||
public static readonly v310 = API.fromSimpleString('3.1.0')
|
||||
public static readonly v314 = API.fromSimpleString('3.1.4')
|
||||
public static readonly v320 = API.fromSimpleString('3.2.0')
|
||||
public static readonly v330 = API.fromSimpleString('3.3.0')
|
||||
public static readonly v333 = API.fromSimpleString('3.3.3')
|
||||
public static readonly v340 = API.fromSimpleString('3.4.0')
|
||||
public static readonly v345 = API.fromSimpleString('3.4.5')
|
||||
public static readonly v350 = API.fromSimpleString('3.5.0')
|
||||
|
||||
public static fromVersionString(versionString: string): API {
|
||||
let version = semver.valid(versionString)
|
||||
if (!version) {
|
||||
return new API('invalid version', '1.0.0')
|
||||
}
|
||||
public static fromVersionString(versionString: string): API {
|
||||
let version = semver.valid(versionString)
|
||||
if (!version) {
|
||||
return new API('invalid version', '1.0.0')
|
||||
}
|
||||
|
||||
// Cut off any prerelease tag since we sometimes consume those on purpose.
|
||||
const index = versionString.indexOf('-')
|
||||
if (index >= 0) {
|
||||
version = version.substr(0, index)
|
||||
}
|
||||
return new API(versionString, version)
|
||||
}
|
||||
// Cut off any prerelease tag since we sometimes consume those on purpose.
|
||||
const index = versionString.indexOf('-')
|
||||
if (index >= 0) {
|
||||
version = version.substr(0, index)
|
||||
}
|
||||
return new API(versionString, version)
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public readonly versionString: string,
|
||||
private readonly version: string
|
||||
) { }
|
||||
private constructor(
|
||||
public readonly versionString: string,
|
||||
private readonly version: string
|
||||
) { }
|
||||
|
||||
public gte(other: API): boolean {
|
||||
return semver.gte(this.version, other.version)
|
||||
}
|
||||
public gte(other: API): boolean {
|
||||
return semver.gte(this.version, other.version)
|
||||
}
|
||||
|
||||
public lt(other: API): boolean {
|
||||
return !this.gte(other)
|
||||
}
|
||||
public lt(other: API): boolean {
|
||||
return !this.gte(other)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,18 @@ import * as languageModeIds from './languageModeIds'
|
|||
export interface LanguageDescription {
|
||||
readonly id: string
|
||||
readonly diagnosticSource: string
|
||||
readonly diagnosticLanguage: DiagnosticLanguage
|
||||
readonly modeIds: string[]
|
||||
readonly configFile?: string
|
||||
readonly isExternal?: boolean
|
||||
readonly diagnosticOwner: string
|
||||
}
|
||||
|
||||
export const enum DiagnosticLanguage {
|
||||
JavaScript,
|
||||
TypeScript
|
||||
}
|
||||
|
||||
export const standardLanguageDescriptions: LanguageDescription[] = [
|
||||
{
|
||||
id: 'typescript',
|
||||
|
@ -20,6 +26,7 @@ export const standardLanguageDescriptions: LanguageDescription[] = [
|
|||
diagnosticOwner: 'typescript',
|
||||
modeIds: [languageModeIds.typescript, languageModeIds.typescriptreact,
|
||||
languageModeIds.typescripttsx, languageModeIds.typescriptjsx],
|
||||
diagnosticLanguage: DiagnosticLanguage.TypeScript,
|
||||
configFile: 'tsconfig.json'
|
||||
},
|
||||
{
|
||||
|
@ -27,6 +34,7 @@ export const standardLanguageDescriptions: LanguageDescription[] = [
|
|||
diagnosticSource: 'ts',
|
||||
diagnosticOwner: 'typescript',
|
||||
modeIds: [languageModeIds.javascript, languageModeIds.javascriptreact],
|
||||
diagnosticLanguage: DiagnosticLanguage.JavaScript,
|
||||
configFile: 'jsconfig.json'
|
||||
}
|
||||
]
|
||||
|
|
|
@ -23,6 +23,14 @@ export namespace Range {
|
|||
}
|
||||
}
|
||||
|
||||
export const toFormattingRequestArgs = (file: string, range: language.Range): Proto.FormatRequestArgs => ({
|
||||
file,
|
||||
line: range.start.line + 1,
|
||||
offset: range.start.character + 1,
|
||||
endLine: range.end.line + 1,
|
||||
endOffset: range.end.character + 1
|
||||
})
|
||||
|
||||
export const toFileRangeRequestArgs = (
|
||||
file: string,
|
||||
range: language.Range
|
||||
|
@ -43,6 +51,11 @@ export namespace Position {
|
|||
}
|
||||
}
|
||||
|
||||
export const toLocation = (position: language.Position): Proto.Location => ({
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1,
|
||||
})
|
||||
|
||||
export const toFileLocationRequestArgs = (
|
||||
file: string,
|
||||
position: language.Position
|
||||
|
|
|
@ -27,6 +27,10 @@ export default class VersionStatus {
|
|||
})
|
||||
}
|
||||
|
||||
public set loading(isLoading: boolean) {
|
||||
this._versionBarEntry.isProgress = isLoading
|
||||
}
|
||||
|
||||
private async showHideStatus(): Promise<void> {
|
||||
let document = await workspace.document
|
||||
if (!document) {
|
||||
|
|
|
@ -553,7 +553,7 @@ vscode-jsonrpc@^4.1.0-next.2:
|
|||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3"
|
||||
integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg==
|
||||
|
||||
vscode-languageserver-protocol@^3.15.0-next.1, vscode-languageserver-protocol@^3.15.0-next.5:
|
||||
vscode-languageserver-protocol@^3.15.0-next.5:
|
||||
version "3.15.0-next.5"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.5.tgz#23afad3d28795f2235eda7a167e2fe0825b7c151"
|
||||
integrity sha512-rR7Zo5WZTGSsE9lq7pPSgO+VMhVV8UVq6emrDoQ3x5dUyhLKB2/gbMkGKucQpsKGLtF/NuccCa+3jMsO788HjQ==
|
||||
|
|
Loading…
Reference in a new issue