mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 18:19:12 +01:00
Merge remote-tracking branch 'origin/master' into alex/semantic-exploration
This commit is contained in:
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import API from '../utils/api';
|
||||
import { coalesce } from '../utils/arrays';
|
||||
import { Delayer } from '../utils/async';
|
||||
import { nulToken } from '../utils/cancellation';
|
||||
import { Disposable } from '../utils/dispose';
|
||||
@@ -117,7 +118,11 @@ class BufferSynchronizer {
|
||||
}
|
||||
}
|
||||
|
||||
public beforeCommand(command: string) {
|
||||
public reset(): void {
|
||||
this._pending.clear();
|
||||
}
|
||||
|
||||
public beforeCommand(command: string): void {
|
||||
if (command === 'updateOpen') {
|
||||
return;
|
||||
}
|
||||
@@ -149,7 +154,7 @@ class BufferSynchronizer {
|
||||
}
|
||||
|
||||
private get supportsBatching(): boolean {
|
||||
return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get<boolean>('useBatchedBufferSync', true);
|
||||
return this.client.apiVersion.gte(API.v340);
|
||||
}
|
||||
|
||||
private updatePending(resource: vscode.Uri, f: (pending: ResourceMap<CloseOperation | OpenOperation | ChangeOperation>) => void): void {
|
||||
@@ -264,26 +269,23 @@ class GetErrRequest {
|
||||
files: ResourceMap<void>,
|
||||
onDone: () => void
|
||||
) {
|
||||
const token = new vscode.CancellationTokenSource();
|
||||
return new GetErrRequest(client, files, token, onDone);
|
||||
return new GetErrRequest(client, files, onDone);
|
||||
}
|
||||
|
||||
private _done: boolean = false;
|
||||
private readonly _token: vscode.CancellationTokenSource = new vscode.CancellationTokenSource();
|
||||
|
||||
private constructor(
|
||||
client: ITypeScriptServiceClient,
|
||||
public readonly files: ResourceMap<void>,
|
||||
private readonly _token: vscode.CancellationTokenSource,
|
||||
onDone: () => void
|
||||
) {
|
||||
const args: Proto.GeterrRequestArgs = {
|
||||
delay: 0,
|
||||
files: Array.from(files.entries)
|
||||
.map(entry => client.normalizedPath(entry.resource))
|
||||
.filter(x => !!x) as string[]
|
||||
files: coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource)))
|
||||
};
|
||||
|
||||
client.executeAsync('geterr', args, _token.token)
|
||||
client.executeAsync('geterr', args, this._token.token)
|
||||
.finally(() => {
|
||||
if (this._done) {
|
||||
return;
|
||||
@@ -338,6 +340,9 @@ export default class BufferSyncSupport extends Disposable {
|
||||
private readonly _onDelete = this._register(new vscode.EventEmitter<vscode.Uri>());
|
||||
public readonly onDelete = this._onDelete.event;
|
||||
|
||||
private readonly _onWillChange = this._register(new vscode.EventEmitter<vscode.Uri>());
|
||||
public readonly onWillChange = this._onWillChange.event;
|
||||
|
||||
public listen(): void {
|
||||
if (this.listening) {
|
||||
return;
|
||||
@@ -392,7 +397,11 @@ export default class BufferSyncSupport extends Disposable {
|
||||
return vscode.Uri.file(filePath);
|
||||
}
|
||||
|
||||
public reOpenDocuments(): void {
|
||||
public reset(): void {
|
||||
this.pendingGetErr?.cancel();
|
||||
this.pendingDiagnostics.clear();
|
||||
this.synchronizer.reset();
|
||||
|
||||
for (const buffer of this.syncedBuffers.allBuffers) {
|
||||
buffer.open();
|
||||
}
|
||||
@@ -425,6 +434,7 @@ export default class BufferSyncSupport extends Disposable {
|
||||
return;
|
||||
}
|
||||
this.pendingDiagnostics.delete(resource);
|
||||
this.pendingGetErr?.files.delete(resource);
|
||||
this.syncedBuffers.delete(resource);
|
||||
syncedBuffer.close();
|
||||
this._onDelete.fire(resource);
|
||||
@@ -457,6 +467,8 @@ export default class BufferSyncSupport extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
this._onWillChange.fire(syncedBuffer.resource);
|
||||
|
||||
syncedBuffer.onContentChanged(e.contentChanges);
|
||||
const didTrigger = this.requestDiagnostic(syncedBuffer);
|
||||
|
||||
@@ -518,8 +530,10 @@ export default class BufferSyncSupport extends Disposable {
|
||||
if (this.pendingGetErr) {
|
||||
this.pendingGetErr.cancel();
|
||||
|
||||
for (const file of this.pendingGetErr.files.entries) {
|
||||
orderedFileSet.set(file.resource, undefined);
|
||||
for (const { resource } of this.pendingGetErr.files.entries) {
|
||||
if (this.syncedBuffers.get(resource)) {
|
||||
orderedFileSet.set(resource, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,12 +66,13 @@ class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider
|
||||
const children = new Set(item.childItems || []);
|
||||
for (const span of item.spans) {
|
||||
const range = typeConverters.Range.fromTextSpan(span);
|
||||
const selectionRange = item.nameSpan ? typeConverters.Range.fromTextSpan(item.nameSpan) : range;
|
||||
const symbolInfo = new vscode.DocumentSymbol(
|
||||
item.text,
|
||||
'',
|
||||
getSymbolKind(item.kind),
|
||||
range,
|
||||
range);
|
||||
range.contains(selectionRange) ? selectionRange : range);
|
||||
|
||||
for (const child of children) {
|
||||
if (child.spans.some(span => !!range.intersection(typeConverters.Range.fromTextSpan(span)))) {
|
||||
|
||||
@@ -22,8 +22,10 @@ const autoFixableDiagnosticCodes = new Set<number>([
|
||||
|
||||
class TypeScriptAutoFixProvider implements vscode.CodeActionProvider {
|
||||
|
||||
private static readonly kind = vscode.CodeActionKind.SourceFixAll.append('ts');
|
||||
|
||||
public static readonly metadata: vscode.CodeActionProviderMetadata = {
|
||||
providedCodeActionKinds: [vscode.CodeActionKind.SourceFixAll]
|
||||
providedCodeActionKinds: [TypeScriptAutoFixProvider.kind]
|
||||
};
|
||||
|
||||
constructor(
|
||||
@@ -82,7 +84,7 @@ class TypeScriptAutoFixProvider implements vscode.CodeActionProvider {
|
||||
const { edit, fixedDiagnostics } = autoFixResponse;
|
||||
const codeAction = new vscode.CodeAction(
|
||||
localize('autoFix.label', 'Auto fix'),
|
||||
vscode.CodeActionKind.SourceFixAll);
|
||||
TypeScriptAutoFixProvider.kind);
|
||||
codeAction.edit = edit;
|
||||
codeAction.diagnostics = fixedDiagnostics;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import API from '../utils/api';
|
||||
import { coalesce } from '../utils/arrays';
|
||||
import { VersionDependentRegistration } from '../utils/dependentRegistration';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
|
||||
@@ -33,9 +34,7 @@ class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
return response.body
|
||||
.map(span => this.convertOutliningSpan(span, document))
|
||||
.filter(foldingRange => !!foldingRange) as vscode.FoldingRange[];
|
||||
return coalesce(response.body.map(span => this.convertOutliningSpan(span, document)));
|
||||
}
|
||||
|
||||
private convertOutliningSpan(
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
||||
const codeLens = inputCodeLens as ReferencesCodeLens;
|
||||
|
||||
const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start);
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true });
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true, cancelOnResourceChange: codeLens.document });
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
codeLens.command = response.type === 'cancelled'
|
||||
? TypeScriptBaseCodeLensProvider.cancelledCommand
|
||||
|
||||
@@ -123,14 +123,77 @@ class SelectRefactorCommand implements Command {
|
||||
}
|
||||
}
|
||||
|
||||
interface CodeActionKind {
|
||||
readonly kind: vscode.CodeActionKind;
|
||||
matches(refactor: Proto.RefactorActionInfo): boolean;
|
||||
}
|
||||
|
||||
const Extract_Function = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorExtract.append('function'),
|
||||
matches: refactor => refactor.name.startsWith('function_')
|
||||
});
|
||||
|
||||
const Extract_Constant = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorExtract.append('constant'),
|
||||
matches: refactor => refactor.name.startsWith('constant_')
|
||||
});
|
||||
|
||||
const Extract_Type = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorExtract.append('type'),
|
||||
matches: refactor => refactor.name.startsWith('Extract to type alias')
|
||||
});
|
||||
|
||||
const Extract_Interface = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorExtract.append('interface'),
|
||||
matches: refactor => refactor.name.startsWith('Extract to interface')
|
||||
});
|
||||
|
||||
const Move_NewFile = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.Refactor.append('move').append('newFile'),
|
||||
matches: refactor => refactor.name.startsWith('Move to a new file')
|
||||
});
|
||||
|
||||
const Rewrite_Import = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorRewrite.append('import'),
|
||||
matches: refactor => refactor.name.startsWith('Convert namespace import') || refactor.name.startsWith('Convert named imports')
|
||||
});
|
||||
|
||||
const Rewrite_Export = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorRewrite.append('export'),
|
||||
matches: refactor => refactor.name.startsWith('Convert default export') || refactor.name.startsWith('Convert named export')
|
||||
});
|
||||
|
||||
const Rewrite_Arrow_Braces = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorRewrite.append('arrow').append('braces'),
|
||||
matches: refactor => refactor.name.startsWith('Convert default export') || refactor.name.startsWith('Convert named export')
|
||||
});
|
||||
|
||||
const Rewrite_Parameters_ToDestructured = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorRewrite.append('parameters').append('toDestructured'),
|
||||
matches: refactor => refactor.name.startsWith('Convert parameters to destructured object')
|
||||
});
|
||||
|
||||
const Rewrite_Property_GenerateAccessors = Object.freeze<CodeActionKind>({
|
||||
kind: vscode.CodeActionKind.RefactorRewrite.append('property').append('generateAccessors'),
|
||||
matches: refactor => refactor.name.startsWith('Generate \'get\' and \'set\' accessors')
|
||||
});
|
||||
|
||||
const allKnownCodeActionKinds = [
|
||||
Extract_Function,
|
||||
Extract_Constant,
|
||||
Extract_Type,
|
||||
Extract_Interface,
|
||||
Move_NewFile,
|
||||
Rewrite_Import,
|
||||
Rewrite_Export,
|
||||
Rewrite_Arrow_Braces,
|
||||
Rewrite_Parameters_ToDestructured,
|
||||
Rewrite_Property_GenerateAccessors
|
||||
];
|
||||
|
||||
class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
|
||||
public static readonly minVersion = API.v240;
|
||||
|
||||
private static readonly extractFunctionKind = vscode.CodeActionKind.RefactorExtract.append('function');
|
||||
private static readonly extractConstantKind = vscode.CodeActionKind.RefactorExtract.append('constant');
|
||||
private static readonly extractTypeKind = vscode.CodeActionKind.RefactorExtract.append('type');
|
||||
private static readonly moveKind = vscode.CodeActionKind.Refactor.append('move');
|
||||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly formattingOptionsManager: FormattingOptionsManager,
|
||||
@@ -142,7 +205,10 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
|
||||
}
|
||||
|
||||
public static readonly metadata: vscode.CodeActionProviderMetadata = {
|
||||
providedCodeActionKinds: [vscode.CodeActionKind.Refactor],
|
||||
providedCodeActionKinds: [
|
||||
vscode.CodeActionKind.Refactor,
|
||||
...allKnownCodeActionKinds.map(x => x.kind),
|
||||
],
|
||||
};
|
||||
|
||||
public async provideCodeActions(
|
||||
@@ -168,7 +234,7 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
|
||||
const args: Proto.GetApplicableRefactorsRequestArgs = typeConverters.Range.toFileRangeRequestArgs(file, rangeOrSelection);
|
||||
return this.client.execute('getApplicableRefactors', args, token);
|
||||
});
|
||||
if (!response || response.type !== 'response' || !response.body) {
|
||||
if (response?.type !== 'response' || !response.body) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -224,25 +290,17 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
|
||||
}
|
||||
|
||||
private static getKind(refactor: Proto.RefactorActionInfo) {
|
||||
if (refactor.name.startsWith('function_')) {
|
||||
return TypeScriptRefactorProvider.extractFunctionKind;
|
||||
} else if (refactor.name.startsWith('constant_')) {
|
||||
return TypeScriptRefactorProvider.extractConstantKind;
|
||||
} else if (refactor.name.startsWith('Move')) {
|
||||
return TypeScriptRefactorProvider.moveKind;
|
||||
} else if (refactor.name.includes('Extract to type alias')) {
|
||||
return TypeScriptRefactorProvider.extractTypeKind;
|
||||
}
|
||||
return vscode.CodeActionKind.Refactor;
|
||||
const match = allKnownCodeActionKinds.find(kind => kind.matches(refactor));
|
||||
return match ? match.kind : vscode.CodeActionKind.Refactor;
|
||||
}
|
||||
|
||||
private static isPreferred(
|
||||
action: Proto.RefactorActionInfo
|
||||
): boolean {
|
||||
if (action.name.startsWith('constant_')) {
|
||||
if (Extract_Constant.matches(action)) {
|
||||
return action.name.endsWith('scope_0');
|
||||
}
|
||||
if (action.name.includes('Extract to type alias')) {
|
||||
if (Extract_Type.matches(action) || Extract_Interface.matches(action)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -19,7 +19,7 @@ class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvide
|
||||
public async resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise<vscode.CodeLens> {
|
||||
const codeLens = inputCodeLens as ReferencesCodeLens;
|
||||
const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start);
|
||||
const response = await this.client.execute('references', args, token, { lowPriority: true });
|
||||
const response = await this.client.execute('references', args, token, { lowPriority: true, cancelOnResourceChange: codeLens.document });
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
codeLens.command = response.type === 'cancelled'
|
||||
? TypeScriptBaseCodeLensProvider.cancelledCommand
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as jsonc from 'jsonc-parser';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService';
|
||||
import { isTsConfigFileName } from '../utils/languageDescription';
|
||||
import { Lazy } from '../utils/lazy';
|
||||
import { isImplicitProjectConfigFile } from '../utils/tsconfig';
|
||||
@@ -18,14 +17,14 @@ const localize = nls.loadMessageBundle();
|
||||
|
||||
type AutoDetect = 'on' | 'off' | 'build' | 'watch';
|
||||
|
||||
|
||||
const exists = (file: string): Promise<boolean> =>
|
||||
new Promise<boolean>((resolve, _reject) => {
|
||||
fs.exists(file, (value: boolean) => {
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
|
||||
const exists = async (resource: vscode.Uri): Promise<boolean> => {
|
||||
try {
|
||||
const stat = await vscode.workspace.fs.stat(resource);
|
||||
return stat.type === vscode.FileType.File;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
interface TypeScriptTaskDefinition extends vscode.TaskDefinition {
|
||||
tsconfig: string;
|
||||
@@ -36,6 +35,8 @@ interface TypeScriptTaskDefinition extends vscode.TaskDefinition {
|
||||
* Provides tasks for building `tsconfig.json` files in a project.
|
||||
*/
|
||||
export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
|
||||
private readonly projectInfoRequestTimeout = 2000;
|
||||
private autoDetect: AutoDetect = 'on';
|
||||
private readonly tsconfigProvider: TsConfigProvider;
|
||||
private readonly disposables: vscode.Disposable[] = [];
|
||||
@@ -62,8 +63,8 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
const configPaths: Set<string> = new Set();
|
||||
const tasks: vscode.Task[] = [];
|
||||
for (const project of await this.getAllTsConfigs(token)) {
|
||||
if (!configPaths.has(project.path)) {
|
||||
configPaths.add(project.path);
|
||||
if (!configPaths.has(project.fsPath)) {
|
||||
configPaths.add(project.fsPath);
|
||||
tasks.push(...(await this.getTasksForProject(project)));
|
||||
}
|
||||
}
|
||||
@@ -88,7 +89,8 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
const kind: TypeScriptTaskDefinition = (<any>_task.definition);
|
||||
const tsconfigUri: vscode.Uri = _task.scope.uri.with({ path: _task.scope.uri.path + '/' + kind.tsconfig });
|
||||
const tsconfig: TSConfig = {
|
||||
path: tsconfigUri.fsPath,
|
||||
uri: tsconfigUri,
|
||||
fsPath: tsconfigUri.fsPath,
|
||||
posixPath: tsconfigUri.path,
|
||||
workspaceFolder: _task.scope
|
||||
};
|
||||
@@ -104,7 +106,7 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
...await this.getTsConfigsInWorkspace()
|
||||
];
|
||||
for (const config of configs) {
|
||||
if (await exists(config.path)) {
|
||||
if (await exists(config.uri)) {
|
||||
out.add(config);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,8 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
if (isTsConfigFileName(editor.document.fileName)) {
|
||||
const uri = editor.document.uri;
|
||||
return [{
|
||||
path: uri.fsPath,
|
||||
uri,
|
||||
fsPath: uri.fsPath,
|
||||
posixPath: uri.path,
|
||||
workspaceFolder: vscode.workspace.getWorkspaceFolder(uri)
|
||||
}];
|
||||
@@ -129,10 +132,13 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
return [];
|
||||
}
|
||||
|
||||
const response = await this.client.value.execute(
|
||||
'projectInfo',
|
||||
{ file, needFileNameList: false },
|
||||
token);
|
||||
const response = await Promise.race([
|
||||
this.client.value.execute(
|
||||
'projectInfo',
|
||||
{ file, needFileNameList: false },
|
||||
token),
|
||||
new Promise<typeof ServerResponse.NoContent>(resolve => setTimeout(() => resolve(ServerResponse.NoContent), this.projectInfoRequestTimeout))
|
||||
]);
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return [];
|
||||
}
|
||||
@@ -143,7 +149,8 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
const uri = vscode.Uri.file(normalizedConfigPath);
|
||||
const folder = vscode.workspace.getWorkspaceFolder(uri);
|
||||
return [{
|
||||
path: normalizedConfigPath,
|
||||
uri,
|
||||
fsPath: normalizedConfigPath,
|
||||
posixPath: uri.path,
|
||||
workspaceFolder: folder
|
||||
}];
|
||||
@@ -158,7 +165,7 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
|
||||
private static async getCommand(project: TSConfig): Promise<string> {
|
||||
if (project.workspaceFolder) {
|
||||
const localTsc = await TscTaskProvider.getLocalTscAtPath(path.dirname(project.path));
|
||||
const localTsc = await TscTaskProvider.getLocalTscAtPath(path.dirname(project.fsPath));
|
||||
if (localTsc) {
|
||||
return localTsc;
|
||||
}
|
||||
@@ -176,9 +183,9 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
private static async getLocalTscAtPath(folderPath: string): Promise<string | undefined> {
|
||||
const platform = process.platform;
|
||||
const bin = path.join(folderPath, 'node_modules', '.bin');
|
||||
if (platform === 'win32' && await exists(path.join(bin, 'tsc.cmd'))) {
|
||||
if (platform === 'win32' && await exists(vscode.Uri.file(path.join(bin, 'tsc.cmd')))) {
|
||||
return path.join(bin, 'tsc.cmd');
|
||||
} else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(bin, 'tsc'))) {
|
||||
} else if ((platform === 'linux' || platform === 'darwin') && await exists(vscode.Uri.file(path.join(bin, 'tsc')))) {
|
||||
return path.join(bin, 'tsc');
|
||||
}
|
||||
return undefined;
|
||||
@@ -196,7 +203,7 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
}
|
||||
|
||||
private getBuildTask(workspaceFolder: vscode.WorkspaceFolder | undefined, label: string, command: string, args: string[], buildTaskidentifier: TypeScriptTaskDefinition): vscode.Task {
|
||||
const buildTask = new vscode.Task(
|
||||
const buildTask = new vscode.Task2(
|
||||
buildTaskidentifier,
|
||||
workspaceFolder || vscode.TaskScope.Workspace,
|
||||
localize('buildTscLabel', 'build - {0}', label),
|
||||
@@ -233,7 +240,6 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
}
|
||||
|
||||
if (this.autoDetect === 'watch' || this.autoDetect === 'on') {
|
||||
|
||||
tasks.push(this.getWatchTask(project.workspaceFolder, label, command, args, { type: 'typescript', tsconfig: label, option: 'watch' }));
|
||||
}
|
||||
|
||||
@@ -256,25 +262,19 @@ export default class TscTaskProvider implements vscode.TaskProvider {
|
||||
return task;
|
||||
}
|
||||
|
||||
private getBuildShellArgs(project: TSConfig): Promise<Array<string>> {
|
||||
const defaultArgs = ['-p', project.path];
|
||||
return new Promise<Array<string>>((resolve) => {
|
||||
fs.readFile(project.path, (error, result) => {
|
||||
if (error) {
|
||||
return resolve(defaultArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
const tsconfig = jsonc.parse(result.toString());
|
||||
if (tsconfig.references) {
|
||||
return resolve(['-b', project.path]);
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
return resolve(defaultArgs);
|
||||
});
|
||||
});
|
||||
private async getBuildShellArgs(project: TSConfig): Promise<Array<string>> {
|
||||
const defaultArgs = ['-p', project.fsPath];
|
||||
try {
|
||||
const bytes = await vscode.workspace.fs.readFile(project.uri);
|
||||
const text = Buffer.from(bytes).toString('utf-8');
|
||||
const tsconfig = jsonc.parse(text);
|
||||
if (tsconfig?.references) {
|
||||
return ['-b', project.fsPath];
|
||||
}
|
||||
} catch {
|
||||
// noops
|
||||
}
|
||||
return defaultArgs;
|
||||
}
|
||||
|
||||
private getLabelForTasks(project: TSConfig): string {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as jsonc from 'jsonc-parser';
|
||||
import { dirname, join, basename } from 'path';
|
||||
import { basename, dirname, join } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { flatten } from '../utils/arrays';
|
||||
import { coalesce, flatten } from '../utils/arrays';
|
||||
|
||||
function mapChildren<R>(node: jsonc.Node | undefined, f: (x: jsonc.Node) => R): R[] {
|
||||
return node && node.type === 'array' && node.children
|
||||
@@ -25,11 +25,11 @@ class TsconfigLinkProvider implements vscode.DocumentLinkProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
return coalesce([
|
||||
this.getExtendsLink(document, root),
|
||||
...this.getFilesLinks(document, root),
|
||||
...this.getReferencesLinks(document, root)
|
||||
].filter(x => !!x) as vscode.DocumentLink[];
|
||||
]);
|
||||
}
|
||||
|
||||
private getExtendsLink(document: vscode.TextDocument, root: jsonc.Node): vscode.DocumentLink | undefined {
|
||||
@@ -68,7 +68,7 @@ class TsconfigLinkProvider implements vscode.DocumentLinkProvider {
|
||||
}
|
||||
|
||||
return new vscode.DocumentLink(this.getRange(document, pathNode),
|
||||
basename(pathNode.value).match('.json$')
|
||||
basename(pathNode.value).endsWith('.json')
|
||||
? this.getFileTarget(document, pathNode)
|
||||
: this.getFolderTarget(document, pathNode));
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ const testRunner = require('vscode/lib/testrunner');
|
||||
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
|
||||
testRunner.configure({
|
||||
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
|
||||
useColors: process.platform !== 'win32', // colored output from test results (only windows cannot handle)
|
||||
useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'), // colored output from test results (only windows cannot handle)
|
||||
timeout: 60000
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import { PluginManager } from './utils/plugins';
|
||||
import * as typeConverters from './utils/typeConverters';
|
||||
import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus';
|
||||
import VersionStatus from './utils/versionStatus';
|
||||
import { flatten } from './utils/arrays';
|
||||
import { flatten, coalesce } from './utils/arrays';
|
||||
|
||||
// Style check diagnostics that can be reported as warnings
|
||||
const styleCheckDiagnostics = [
|
||||
@@ -182,7 +182,7 @@ export default class TypeScriptServiceClientHost extends Disposable {
|
||||
|
||||
private populateService(): void {
|
||||
this.fileConfigurationManager.reset();
|
||||
this.client.bufferSyncSupport.reOpenDocuments();
|
||||
this.client.bufferSyncSupport.reset();
|
||||
this.client.bufferSyncSupport.requestAllDiagnostics();
|
||||
|
||||
// See https://github.com/Microsoft/TypeScript/issues/5530
|
||||
@@ -245,13 +245,13 @@ export default class TypeScriptServiceClientHost extends Disposable {
|
||||
}
|
||||
const relatedInformation = diagnostic.relatedInformation;
|
||||
if (relatedInformation) {
|
||||
converted.relatedInformation = relatedInformation.map((info: any) => {
|
||||
let span = info.span;
|
||||
converted.relatedInformation = coalesce(relatedInformation.map((info: any) => {
|
||||
const span = info.span;
|
||||
if (!span) {
|
||||
return undefined;
|
||||
}
|
||||
return new vscode.DiagnosticRelatedInformation(typeConverters.Location.fromTextSpan(this.client.toResource(span.file), span), info.message);
|
||||
}).filter((x: any) => !!x) as vscode.DiagnosticRelatedInformation[];
|
||||
}));
|
||||
}
|
||||
if (diagnostic.reportsUnnecessary) {
|
||||
converted.tags = [vscode.DiagnosticTag.Unnecessary];
|
||||
|
||||
@@ -21,7 +21,7 @@ export namespace ServerResponse {
|
||||
) { }
|
||||
}
|
||||
|
||||
export const NoContent = new class { readonly type = 'noContent'; };
|
||||
export const NoContent = { type: 'noContent' } as const;
|
||||
|
||||
export type Response<T extends Proto.Response> = T | Cancelled | typeof NoContent;
|
||||
}
|
||||
@@ -147,6 +147,7 @@ export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRe
|
||||
export type ExecConfig = {
|
||||
readonly lowPriority?: boolean;
|
||||
readonly nonRecoverable?: boolean;
|
||||
readonly cancelOnResourceChange?: vscode.Uri
|
||||
};
|
||||
|
||||
export interface ITypeScriptServiceClient {
|
||||
|
||||
@@ -35,6 +35,11 @@ export interface TsDiagnostics {
|
||||
readonly diagnostics: Proto.Diagnostic[];
|
||||
}
|
||||
|
||||
interface ToCancelOnResourceChanged {
|
||||
readonly resource: vscode.Uri;
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
namespace ServerState {
|
||||
export const enum Type {
|
||||
None,
|
||||
@@ -42,7 +47,7 @@ namespace ServerState {
|
||||
Errored
|
||||
}
|
||||
|
||||
export const None = new class { readonly type = Type.None; };
|
||||
export const None = { type: Type.None } as const;
|
||||
|
||||
export class Running {
|
||||
readonly type = Type.Running;
|
||||
@@ -60,6 +65,8 @@ namespace ServerState {
|
||||
public tsserverVersion: string | undefined,
|
||||
public langaugeServiceEnabled: boolean,
|
||||
) { }
|
||||
|
||||
public readonly toCancelOnResourceChange = new Set<ToCancelOnResourceChanged>();
|
||||
}
|
||||
|
||||
export class Errored {
|
||||
@@ -129,9 +136,14 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
|
||||
this.diagnosticsManager = new DiagnosticsManager('typescript');
|
||||
this.bufferSyncSupport.onDelete(resource => {
|
||||
this.cancelInflightRequestsForResource(resource);
|
||||
this.diagnosticsManager.delete(resource);
|
||||
}, null, this._disposables);
|
||||
|
||||
this.bufferSyncSupport.onWillChange(resource => {
|
||||
this.cancelInflightRequestsForResource(resource);
|
||||
});
|
||||
|
||||
vscode.workspace.onDidChangeConfiguration(() => {
|
||||
const oldConfiguration = this._configuration;
|
||||
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace();
|
||||
@@ -173,6 +185,18 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
}));
|
||||
}
|
||||
|
||||
private cancelInflightRequestsForResource(resource: vscode.Uri): void {
|
||||
if (this.serverState.type !== ServerState.Type.Running) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const request of this.serverState.toCancelOnResourceChange) {
|
||||
if (request.resource.toString() === resource.toString()) {
|
||||
request.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get configuration() {
|
||||
return this._configuration;
|
||||
}
|
||||
@@ -609,12 +633,37 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
}
|
||||
|
||||
public execute(command: keyof TypeScriptRequests, args: any, token: vscode.CancellationToken, config?: ExecConfig): Promise<ServerResponse.Response<Proto.Response>> {
|
||||
const execution = this.executeImpl(command, args, {
|
||||
isAsync: false,
|
||||
token,
|
||||
expectsResult: true,
|
||||
lowPriority: config?.lowPriority
|
||||
});
|
||||
let execution: Promise<ServerResponse.Response<Proto.Response>>;
|
||||
|
||||
if (config?.cancelOnResourceChange) {
|
||||
const runningServerState = this.service();
|
||||
|
||||
const source = new vscode.CancellationTokenSource();
|
||||
token.onCancellationRequested(() => source.cancel());
|
||||
|
||||
const inFlight: ToCancelOnResourceChanged = {
|
||||
resource: config.cancelOnResourceChange,
|
||||
cancel: () => source.cancel(),
|
||||
};
|
||||
runningServerState.toCancelOnResourceChange.add(inFlight);
|
||||
|
||||
execution = this.executeImpl(command, args, {
|
||||
isAsync: false,
|
||||
token: source.token,
|
||||
expectsResult: true,
|
||||
...config,
|
||||
}).finally(() => {
|
||||
runningServerState.toCancelOnResourceChange.delete(inFlight);
|
||||
source.dispose();
|
||||
});
|
||||
} else {
|
||||
execution = this.executeImpl(command, args, {
|
||||
isAsync: false,
|
||||
token,
|
||||
expectsResult: true,
|
||||
...config,
|
||||
});
|
||||
}
|
||||
|
||||
if (config?.nonRecoverable) {
|
||||
execution.catch(() => this.fatalError(command));
|
||||
@@ -654,10 +703,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
||||
private fatalError(command: string): void {
|
||||
/* __GDPR__
|
||||
"fatalError" : {
|
||||
"${include}": [
|
||||
"${TypeScriptCommonProperties}",
|
||||
"command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
]
|
||||
"${include}": [ "${TypeScriptCommonProperties}" ],
|
||||
"command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.logTelemetry('fatalError', { command });
|
||||
|
||||
@@ -19,6 +19,10 @@ export function equals<T>(
|
||||
return a.every((x, i) => itemEquals(x, b[i]));
|
||||
}
|
||||
|
||||
export function flatten<T>(arr: ReadonlyArray<T>[]): T[] {
|
||||
return Array.prototype.concat.apply([], arr);
|
||||
}
|
||||
export function flatten<T>(array: ReadonlyArray<T>[]): T[] {
|
||||
return Array.prototype.concat.apply([], array);
|
||||
}
|
||||
|
||||
export function coalesce<T>(array: ReadonlyArray<T | undefined>): T[] {
|
||||
return <T[]>array.filter(e => !!e);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@ function getTagBodyText(tag: Proto.JSDocTagInfo): string | undefined {
|
||||
|
||||
function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined {
|
||||
switch (tag.name) {
|
||||
case 'augments':
|
||||
case 'extends':
|
||||
case 'param':
|
||||
case 'template':
|
||||
const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/);
|
||||
if (body && body.length === 3) {
|
||||
const param = body[1];
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface TSConfig {
|
||||
readonly path: string;
|
||||
readonly uri: vscode.Uri;
|
||||
readonly fsPath: string;
|
||||
readonly posixPath: string;
|
||||
readonly workspaceFolder?: vscode.WorkspaceFolder;
|
||||
}
|
||||
@@ -20,7 +22,8 @@ export default class TsConfigProvider {
|
||||
const root = vscode.workspace.getWorkspaceFolder(config);
|
||||
if (root) {
|
||||
configs.set(config.fsPath, {
|
||||
path: config.fsPath,
|
||||
uri: config,
|
||||
fsPath: config.fsPath,
|
||||
posixPath: config.path,
|
||||
workspaceFolder: root
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user