mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Fixes #10823: Improve error reporting in tsserver.
This commit is contained in:
parent
a58be75c43
commit
1897d17bce
|
@ -10,7 +10,7 @@ import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionI
|
|||
import { ITypescriptServiceClient } from '../typescriptService';
|
||||
|
||||
import * as PConst from '../protocol.const';
|
||||
import { CompletionEntry, CompletionsRequestArgs, CompletionsResponse, CompletionDetailsRequestArgs, CompletionDetailsResponse, CompletionEntryDetails } from '../protocol';
|
||||
import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails } from '../protocol';
|
||||
import * as Previewer from './previewer';
|
||||
|
||||
class MyCompletionItem extends CompletionItem {
|
||||
|
@ -125,8 +125,8 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
}
|
||||
|
||||
return completionItems;
|
||||
|
||||
}, (err: CompletionsResponse) => {
|
||||
}, (err) => {
|
||||
this.client.error(`'completions' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
@ -168,7 +168,8 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
|
||||
return item;
|
||||
|
||||
}, (err: CompletionDetailsResponse) => {
|
||||
}, (err) => {
|
||||
this.client.error(`'completionEntryDetails' request failed with error.`, err);
|
||||
return item;
|
||||
});
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider
|
|||
return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1));
|
||||
}
|
||||
});
|
||||
}, () => {
|
||||
}, (error) => {
|
||||
this.client.error(`'definition' request failed with error.`, error);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh
|
|||
});
|
||||
}
|
||||
}, (err) => {
|
||||
this.client.error(`'occurrences' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP
|
|||
return result;
|
||||
}
|
||||
}, (err) => {
|
||||
this.client.error(`'navbar' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
|||
return this.client.execute('format', args, token).then((response): TextEdit[] => {
|
||||
return response.body.map(this.codeEdit2SingleEditOperation);
|
||||
}, (err: any) => {
|
||||
this.client.error(`'format' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
});
|
||||
|
@ -149,6 +150,7 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
|||
}
|
||||
return result;
|
||||
}, (err: any) => {
|
||||
this.client.error(`'formatonkey' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@ export default class TypeScriptHoverProvider implements HoverProvider {
|
|||
new Range(data.start.line - 1, data.start.offset - 1, data.end.line - 1, data.end.offset - 1));
|
||||
}
|
||||
}, (err) => {
|
||||
this.client.error(`'quickinfo' request failed with error.`, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider {
|
|||
result.push(location);
|
||||
}
|
||||
return result;
|
||||
}, () => {
|
||||
}, (err) => {
|
||||
this.client.error(`'references' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ export default class TypeScriptRenameProvider implements RenameProvider {
|
|||
});
|
||||
return result;
|
||||
}, (err) => {
|
||||
this.client.error(`'rename' request failed with error.`, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro
|
|||
|
||||
return result;
|
||||
}, (err: any) => {
|
||||
this.client.error(`'signatureHelp' request failed with error.`, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo
|
|||
}
|
||||
|
||||
}, (err) => {
|
||||
this.client.error(`'navto' request failed with error.`, err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -46,6 +46,10 @@ export interface ITypescriptServiceClient {
|
|||
asAbsolutePath(resource: Uri): string;
|
||||
asUrl(filepath: string): Uri;
|
||||
|
||||
info(message: string, data?: any): void;
|
||||
warn(message: string, data?: any): void;
|
||||
error(message: string, data?: any): void;
|
||||
|
||||
logTelemetry(eventName: string, properties?: { [prop: string]: string });
|
||||
|
||||
experimentalAutoBuild: boolean;
|
||||
|
|
|
@ -17,6 +17,7 @@ import * as Proto from './protocol';
|
|||
import { ITypescriptServiceClient, ITypescriptServiceClientHost, APIVersion } from './typescriptService';
|
||||
|
||||
import * as VersionStatus from './utils/versionStatus';
|
||||
import * as is from './utils/is';
|
||||
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
|
||||
|
@ -75,7 +76,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
private tsdk: string;
|
||||
private _experimentalAutoBuild: boolean;
|
||||
private trace: Trace;
|
||||
private output: OutputChannel;
|
||||
private _output: OutputChannel;
|
||||
private servicePromise: Promise<cp.ChildProcess>;
|
||||
private lastError: Error;
|
||||
private reader: Reader<Proto.Response>;
|
||||
|
@ -132,14 +133,18 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
this.startService();
|
||||
}
|
||||
|
||||
private get output(): OutputChannel {
|
||||
if (!this._output) {
|
||||
this._output = window.createOutputChannel(localize('channelName', 'TypeScript'));
|
||||
}
|
||||
return this._output;
|
||||
}
|
||||
|
||||
private readTrace(): Trace {
|
||||
let result: Trace = Trace.fromString(workspace.getConfiguration().get<string>('typescript.tsserver.trace', 'off'));
|
||||
if (result === Trace.Off && !!process.env.TSS_TRACE) {
|
||||
result = Trace.Messages;
|
||||
}
|
||||
if (result !== Trace.Off && !this.output) {
|
||||
this.output = window.createOutputChannel(localize('channelName', 'TypeScript'));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -155,6 +160,52 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
return this._onReady.promise;
|
||||
}
|
||||
|
||||
private data2String(data: any): string {
|
||||
if (data instanceof Error) {
|
||||
if (is.string(data.stack)) {
|
||||
return data.stack;
|
||||
}
|
||||
return (data as Error).message;
|
||||
}
|
||||
if (is.boolean(data.success) && data.success && is.string(data.message)) {
|
||||
return data.message;
|
||||
}
|
||||
if (is.string(data)) {
|
||||
return data;
|
||||
}
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
public info(message: string, data?: any): void {
|
||||
this.output.appendLine(`[Info - ${(new Date().toLocaleTimeString())}] ${message}`);
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data));
|
||||
}
|
||||
}
|
||||
|
||||
public warn(message: string, data?: any): void {
|
||||
this.output.appendLine(`[Warn - ${(new Date().toLocaleTimeString())}] ${message}`);
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data));
|
||||
}
|
||||
}
|
||||
|
||||
public error(message: string, data?: any): void {
|
||||
this.output.appendLine(`[Error - ${(new Date().toLocaleTimeString())}] ${message}`);
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data));
|
||||
}
|
||||
this.output.show();
|
||||
}
|
||||
|
||||
private logTrace(message: string, data?: any): void {
|
||||
this.output.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`);
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data));
|
||||
}
|
||||
this.output.show();
|
||||
}
|
||||
|
||||
private get packageInfo(): IPackageInfo {
|
||||
|
||||
if (this._packageInfo !== undefined) {
|
||||
|
@ -202,7 +253,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
modulePath = path.join(workspace.rootPath, this.tsdk, 'tsserver.js');
|
||||
}
|
||||
}
|
||||
|
||||
this.info(`Using tsserver from location: ${modulePath}`);
|
||||
if (!fs.existsSync(modulePath)) {
|
||||
window.showErrorMessage(localize('noServerFound', 'The path {0} doesn\'t point to a valid tsserver install. TypeScript language features will be disabled.', path.dirname(modulePath)));
|
||||
return;
|
||||
|
@ -229,12 +280,14 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
if (value) {
|
||||
let port = parseInt(value);
|
||||
if (!isNaN(port)) {
|
||||
this.info(`TSServer started in debug mode using port ${port}`);
|
||||
options.execArgv = [`--debug=${port}`];
|
||||
}
|
||||
}
|
||||
electron.fork(modulePath, [], options, (err: any, childProcess: cp.ChildProcess) => {
|
||||
if (err) {
|
||||
this.lastError = err;
|
||||
this.error('Starting TSServer failed with error.', err);
|
||||
window.showErrorMessage(localize('serverCouldNotBeStarted', 'TypeScript language server couldn\'t be started. Error message is: {0}', err.message || err));
|
||||
this.logTelemetry('error', {message: err.message});
|
||||
return;
|
||||
|
@ -242,9 +295,11 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
this.lastStart = Date.now();
|
||||
childProcess.on('error', (err: Error) => {
|
||||
this.lastError = err;
|
||||
this.error('TSServer errored with error.', err);
|
||||
this.serviceExited(false);
|
||||
});
|
||||
childProcess.on('exit', (err: Error) => {
|
||||
childProcess.on('exit', (code: any) => {
|
||||
this.error(`TSServer exited with code: ${code ? code : 'unknown'}`);
|
||||
this.serviceExited(true);
|
||||
});
|
||||
this.reader = new Reader<Proto.Response>(childProcess.stdout, (msg) => {
|
||||
|
@ -408,13 +463,13 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
if (this.requestQueue[i].request.seq === seq) {
|
||||
this.requestQueue.splice(i, 1);
|
||||
if (this.trace !== Trace.Off) {
|
||||
this.output.append(`TypeScript Service: canceled request with sequence number ${seq}\n`);
|
||||
this.logTrace(`TypeScript Service: canceled request with sequence number ${seq}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.trace !== Trace.Off) {
|
||||
this.output.append(`TypeScript Service: tried to cancel request with sequence number ${seq}. But request got already delivered.\n`);
|
||||
this.logTrace(`TypeScript Service: tried to cancel request with sequence number ${seq}. But request got already delivered.`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -461,29 +516,32 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
|||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
this.output.append(`Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${this.requestQueue.length}\n`);
|
||||
let data: string = undefined;
|
||||
if (this.trace === Trace.Verbose && request.arguments) {
|
||||
this.output.append(`Arguments: ${JSON.stringify(request.arguments, null, 4)}\n\n`);
|
||||
data = `Arguments: ${JSON.stringify(request.arguments, null, 4)}`;
|
||||
}
|
||||
this.logTrace(`Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${this.requestQueue.length}`, data);
|
||||
}
|
||||
|
||||
private traceResponse(response: Proto.Response, startTime: number): void {
|
||||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
this.output.append(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}\n`);
|
||||
let data: string = undefined;
|
||||
if (this.trace === Trace.Verbose && response.body) {
|
||||
this.output.append(`Result: ${JSON.stringify(response.body, null, 4)}\n\n`);
|
||||
data = `Result: ${JSON.stringify(response.body, null, 4)}`;
|
||||
}
|
||||
this.logTrace(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data);
|
||||
}
|
||||
|
||||
private traceEvent(event: Proto.Event): void {
|
||||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
this.output.append(`Event received: ${event.event} (${event.seq}).\n`);
|
||||
let data: string = undefined;
|
||||
if (this.trace === Trace.Verbose && event.body) {
|
||||
this.output.append(`Data: ${JSON.stringify(event.body, null, 4)}\n\n`);
|
||||
data = `Data: ${JSON.stringify(event.body, null, 4)}`;
|
||||
}
|
||||
this.logTrace(`Event received: ${event.event} (${event.seq}).`, data);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue