Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Append stack trace to every language server error #354

Merged
merged 3 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions src/LanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export class LanguageServer {
* Called when the client starts initialization
* @param params
*/
@AddStackToErrorMessage
public onInitialize(params: InitializeParams) {
let clientCapabilities = params.capabilities;

Expand Down Expand Up @@ -223,6 +224,7 @@ export class LanguageServer {
* Called when the client has finished initializing
* @param params
*/
@AddStackToErrorMessage
private async onInitialized() {
let workspaceCreatedDeferred = new Deferred();
this.initialWorkspacesCreated = workspaceCreatedDeferred.promise;
Expand Down Expand Up @@ -515,6 +517,7 @@ export class LanguageServer {
* Provide a list of completion items based on the current cursor position
* @param textDocumentPosition
*/
@AddStackToErrorMessage
private async onCompletion(uri: string, position: Position) {
//ensure programs are initialized
await this.waitAllProgramFirstRuns();
Expand All @@ -539,6 +542,7 @@ export class LanguageServer {
* Provide a full completion item from the selection
* @param item
*/
@AddStackToErrorMessage
private onCompletionResolve(item: CompletionItem): CompletionItem {
if (item.data === 1) {
item.detail = 'TypeScript details';
Expand All @@ -550,6 +554,7 @@ export class LanguageServer {
return item;
}

@AddStackToErrorMessage
private async onCodeAction(params: CodeActionParams) {
//ensure programs are initialized
await this.waitAllProgramFirstRuns();
Expand Down Expand Up @@ -665,6 +670,8 @@ export class LanguageServer {
await workspace.firstRunPromise;
}
}

@AddStackToErrorMessage
private async onDidChangeConfiguration() {
if (this.hasConfigurationCapability) {
await this.reloadWorkspaces();
Expand All @@ -683,6 +690,7 @@ export class LanguageServer {
* file types are watched (.brs,.bs,.xml,manifest, and any json/text/image files)
* @param params
*/
@AddStackToErrorMessage
private async onDidChangeWatchedFiles(params: DidChangeWatchedFilesParams) {
//ensure programs are initialized
await this.waitAllProgramFirstRuns();
Expand Down Expand Up @@ -854,6 +862,7 @@ export class LanguageServer {
}
}

@AddStackToErrorMessage
private async onHover(params: TextDocumentPositionParams) {
//ensure programs are initialized
await this.waitAllProgramFirstRuns();
Expand Down Expand Up @@ -881,6 +890,7 @@ export class LanguageServer {
return hover;
}

@AddStackToErrorMessage
private async onDocumentClose(textDocument: TextDocument): Promise<void> {
let filePath = URI.parse(textDocument.uri).fsPath;
let standaloneFileWorkspace = this.standaloneFileWorkspaces[filePath];
Expand All @@ -893,6 +903,7 @@ export class LanguageServer {
}
}

@AddStackToErrorMessage
private async validateTextDocument(textDocument: TextDocument): Promise<void> {
//ensure programs are initialized
await this.waitAllProgramFirstRuns();
Expand Down Expand Up @@ -923,7 +934,6 @@ export class LanguageServer {
// validate all workspaces
await this.validateAllThrottled();
} catch (e) {
this.connection.tracer.log(e);
this.sendCriticalFailure(`Critical error parsing/ validating ${filePath}: ${e.message}`);
}
}
Expand All @@ -949,6 +959,7 @@ export class LanguageServer {
this.connection.sendNotification('build-status', 'success');
}

@AddStackToErrorMessage
public async onWorkspaceSymbol(params: WorkspaceSymbolParams) {
await this.waitAllProgramFirstRuns();

Expand All @@ -968,6 +979,7 @@ export class LanguageServer {
return allSymbols as SymbolInformation[];
}

@AddStackToErrorMessage
public async onDocumentSymbol(params: DocumentSymbolParams) {
await this.waitAllProgramFirstRuns();

Expand All @@ -982,6 +994,7 @@ export class LanguageServer {
}
}

@AddStackToErrorMessage
private async onDefinition(params: TextDocumentPositionParams) {
await this.waitAllProgramFirstRuns();

Expand All @@ -996,6 +1009,7 @@ export class LanguageServer {
return results;
}

@AddStackToErrorMessage
private async onSignatureHelp(params: SignatureHelpParams) {
await this.waitAllProgramFirstRuns();

Expand All @@ -1020,7 +1034,7 @@ export class LanguageServer {
};
return results;
} catch (e) {
this.connection.console.error(`error in onSignatureHelp: ${e.message}${e.stack ?? ''}`);
this.connection.console.error(`error in onSignatureHelp: ${e.stack ?? e.message ?? e}`);
return {
signatures: [],
activeSignature: 0,
Expand All @@ -1029,6 +1043,7 @@ export class LanguageServer {
}
}

@AddStackToErrorMessage
private async onReferences(params: ReferenceParams) {
await this.waitAllProgramFirstRuns();

Expand Down Expand Up @@ -1069,6 +1084,7 @@ export class LanguageServer {
}
}

@AddStackToErrorMessage
public async onExecuteCommand(params: ExecuteCommandParams) {
await this.waitAllProgramFirstRuns();
if (params.command === CustomCommands.TranspileFile) {
Expand Down Expand Up @@ -1107,3 +1123,34 @@ export interface Workspace {
export enum CustomCommands {
TranspileFile = 'TranspileFile'
}

/**
* Wraps a method. If there's an error (either sync or via a promise),
* this appends the error's stack trace at the end of the error message so that the connection will
*/
function AddStackToErrorMessage(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let originalMethod = descriptor.value;

//wrapping the original method
descriptor.value = function value(...args: any[]) {
try {
let result = originalMethod.apply(this, args);
//if the result looks like a promise, log if there's a rejection
if (result?.then) {
return Promise.resolve(result).catch((e: Error) => {
if (e?.stack) {
e.message = e.stack;
}
return Promise.reject(e);
});
} else {
return result;
}
} catch (e) {
if (e?.stack) {
e.message = e.stack;
}
throw e;
}
};
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"strict": true,
"strictNullChecks": false,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"preserveConstEnums": true,
"downlevelIteration": true,
"noUnusedLocals": true,
Expand Down