From 90a6ac4a63b9ae55f3cf79c7744cd64f35332c29 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 15:25:53 +0200 Subject: [PATCH 01/12] adding a console log --- .../src/languageFeatures/quickFix.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 515402f6e1e..0d87cb86eac 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -216,6 +216,8 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider Date: Tue, 23 May 2023 16:17:41 +0200 Subject: [PATCH 02/12] initial code --- .../src/languageFeatures/quickFix.ts | 42 ++++++++++++++++++- .../src/languageFeatures/util/codeAction.ts | 1 + .../browser/interactiveEditorActions.ts | 2 + 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 0d87cb86eac..b83af8d2526 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -45,12 +45,33 @@ class ApplyCodeActionCommand implements Command { ] } */ + console.log('resource : ', resource); + console.log('action : ', action); + console.log('diagnostic : ', diagnostic); + this.telemetryReporter.logTelemetry('quickFix.execute', { fixName: action.fixName }); this.diagnosticManager.deleteDiagnostic(resource, diagnostic); - return applyCodeActionCommands(this.client, action.commands, nulToken); + // TODO: point of interest + const codeActionResult = await applyCodeActionCommands(this.client, action.commands, nulToken); + + // TODO: how to find the end line number of the class? + // const startLine = diagnostic.range.start.line; + // Find end line using the outline + // vscode.window.activeTextEditor?.document + + const numberLines = vscode.window.activeTextEditor?.document.lineCount; + + // once done, need to call the interactive editor, when working with the implentation interface case + if (action.fixName === 'fixClassIncorrectlyImplementsInterface') { + console.log('case when class incorrectly implements interface'); + await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: 0, endLineNumber: numberLines, startColumn: 0, endColumn: 0 }, message: 'Implement the class from the interface', autoSend: true }); + } + // + + return codeActionResult; } } @@ -230,6 +251,9 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + + console.log('inside of provideCodeActions'); + const file = this.client.toOpenTsFilePath(document); if (!file) { return; @@ -265,6 +289,9 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + + console.log('inside of resolveCodeAction'); + if (!(codeAction instanceof VsCodeFixAllCodeAction) || !codeAction.tsAction.fixId) { return codeAction; } @@ -293,10 +320,14 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + + console.log('inside of getFixesForDiagnostic'); + const args: Proto.CodeFixRequestArgs = { ...typeConverters.Range.toFileRangeRequestArgs(file, diagnostic.range), errorCodes: [+(diagnostic.code!)] }; + // TODO: point of interest const response = await this.client.execute('getCodeFixes', args, token); if (response.type !== 'response' || !response.body) { return results; @@ -315,6 +346,9 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider | undefined, diff --git a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts index 4946a918df2..df5da0c7728 100644 --- a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts +++ b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts @@ -56,6 +56,8 @@ export class StartSessionAction extends EditorAction2 { } override runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) { + console.log('inside of the case when running the interactive editor start command'); + let options: InteractiveEditorRunOptions | undefined; const arg = _args[0]; if (arg && this._isInteractivEditorOptions(arg)) { From e5a37e8d5fc0cba4f47eb2c4437e0cc65669a128 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 17:26:33 +0200 Subject: [PATCH 03/12] setting the right end line number --- .../src/languageFeatures/documentSymbol.ts | 4 +- .../src/languageFeatures/quickFix.ts | 55 +++++++++++++------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts b/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts index ef2d47ef942..349c04c3048 100644 --- a/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts +++ b/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts @@ -33,7 +33,7 @@ const getSymbolKind = (kind: string): vscode.SymbolKind => { return vscode.SymbolKind.Variable; }; -class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider { +export class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider { public constructor( private readonly client: ITypeScriptServiceClient, @@ -60,7 +60,7 @@ class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider return result; } - private static convertNavTree( + public static convertNavTree( resource: vscode.Uri, output: vscode.DocumentSymbol[], item: Proto.NavigationTree, diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index b83af8d2526..f838fb4e4eb 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -35,6 +35,21 @@ class ApplyCodeActionCommand implements Command { private readonly telemetryReporter: TelemetryReporter, ) { } + private findEndLine(startLine: number, navigationTree: Proto.NavigationTree[]): number { + + for (const node of navigationTree) { + const nodeStartLine = node.spans[0].start.line; + const nodeEndLine = node.spans[0].end.line; + + if (nodeStartLine === startLine) { + return nodeEndLine; + } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { + return this.findEndLine(startLine, node.childItems); + } + } + return -1; + } + public async execute({ resource, action, diagnostic }: ApplyCodeActionCommand_args): Promise { /* __GDPR__ "quickFix.execute" : { @@ -45,33 +60,39 @@ class ApplyCodeActionCommand implements Command { ] } */ - console.log('resource : ', resource); - console.log('action : ', action); - console.log('diagnostic : ', diagnostic); this.telemetryReporter.logTelemetry('quickFix.execute', { fixName: action.fixName }); this.diagnosticManager.deleteDiagnostic(resource, diagnostic); - // TODO: point of interest const codeActionResult = await applyCodeActionCommands(this.client, action.commands, nulToken); - // TODO: how to find the end line number of the class? - // const startLine = diagnostic.range.start.line; - // Find end line using the outline - // vscode.window.activeTextEditor?.document - - const numberLines = vscode.window.activeTextEditor?.document.lineCount; - - // once done, need to call the interactive editor, when working with the implentation interface case if (action.fixName === 'fixClassIncorrectlyImplementsInterface') { - console.log('case when class incorrectly implements interface'); - await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: 0, endLineNumber: numberLines, startColumn: 0, endColumn: 0 }, message: 'Implement the class from the interface', autoSend: true }); - } - // - return codeActionResult; + const diagnosticStartLine = diagnostic.range.start.line + 1; + const document = vscode.window.activeTextEditor?.document; + + if (document) { + const filepath = this.client.toOpenTsFilePath(document); + + if (filepath) { + const cancellationTokenSource = new vscode.CancellationTokenSource(); + const response = await this.client.execute('navtree', { file: filepath }, cancellationTokenSource.token); + + if (response.type === 'response' && response.body?.childItems) { + + const endLineFound = this.findEndLine(diagnosticStartLine, response.body.childItems); + const endLine = endLineFound !== -1 ? endLineFound : vscode.window.activeTextEditor?.document.lineCount; + const startLine = endLineFound !== -1 ? diagnosticStartLine : 0; + + await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, endLineNumber: endLine, startColumn: 0, endColumn: 0 }, message: 'Implement the class using the interface', autoSend: true }); + } + } + } + return codeActionResult; + } + return false; } } From b2361a5c83eccaf172fe031dae27ff1a3a574062 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 17:28:46 +0200 Subject: [PATCH 04/12] removing some console logs --- .../src/languageFeatures/quickFix.ts | 24 ------------------- .../src/languageFeatures/util/codeAction.ts | 1 - 2 files changed, 25 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index f838fb4e4eb..02c06c6f49f 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -36,11 +36,9 @@ class ApplyCodeActionCommand implements Command { ) { } private findEndLine(startLine: number, navigationTree: Proto.NavigationTree[]): number { - for (const node of navigationTree) { const nodeStartLine = node.spans[0].start.line; const nodeEndLine = node.spans[0].end.line; - if (nodeStartLine === startLine) { return nodeEndLine; } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { @@ -60,7 +58,6 @@ class ApplyCodeActionCommand implements Command { ] } */ - this.telemetryReporter.logTelemetry('quickFix.execute', { fixName: action.fixName }); @@ -258,8 +255,6 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { - - console.log('inside of provideCodeActions'); - const file = this.client.toOpenTsFilePath(document); if (!file) { return; @@ -310,9 +302,6 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { - - console.log('inside of resolveCodeAction'); - if (!(codeAction instanceof VsCodeFixAllCodeAction) || !codeAction.tsAction.fixId) { return codeAction; } @@ -341,14 +330,10 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { - - console.log('inside of getFixesForDiagnostic'); - const args: Proto.CodeFixRequestArgs = { ...typeConverters.Range.toFileRangeRequestArgs(file, diagnostic.range), errorCodes: [+(diagnostic.code!)] }; - // TODO: point of interest const response = await this.client.execute('getCodeFixes', args, token); if (response.type !== 'response' || !response.body) { return results; @@ -367,9 +352,6 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider | undefined, From 1ef21ddc304cb2d3e077d43627b7e0286125415b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 17:28:51 +0200 Subject: [PATCH 05/12] removing some console logs --- .../interactiveEditor/browser/interactiveEditorActions.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts index df5da0c7728..4946a918df2 100644 --- a/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts +++ b/src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorActions.ts @@ -56,8 +56,6 @@ export class StartSessionAction extends EditorAction2 { } override runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) { - console.log('inside of the case when running the interactive editor start command'); - let options: InteractiveEditorRunOptions | undefined; const arg = _args[0]; if (arg && this._isInteractivEditorOptions(arg)) { From b278ac8a5484165289dcf3a6a350479c92e05f08 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 17:29:40 +0200 Subject: [PATCH 06/12] resetting the privacy modifiers --- .../src/languageFeatures/documentSymbol.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts b/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts index 349c04c3048..ef2d47ef942 100644 --- a/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts +++ b/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts @@ -33,7 +33,7 @@ const getSymbolKind = (kind: string): vscode.SymbolKind => { return vscode.SymbolKind.Variable; }; -export class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider { +class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolProvider { public constructor( private readonly client: ITypeScriptServiceClient, @@ -60,7 +60,7 @@ export class TypeScriptDocumentSymbolProvider implements vscode.DocumentSymbolPr return result; } - public static convertNavTree( + private static convertNavTree( resource: vscode.Uri, output: vscode.DocumentSymbol[], item: Proto.NavigationTree, From 1a50d63321463466998c30a4c7e309de8107d2fc Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 18:18:44 +0200 Subject: [PATCH 07/12] added the arrow function into the private function --- .../src/languageFeatures/quickFix.ts | 99 +++++++++++-------- 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 02c06c6f49f..83f13a291a6 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -23,6 +23,7 @@ type ApplyCodeActionCommand_args = { readonly resource: vscode.Uri; readonly diagnostic: vscode.Diagnostic; readonly action: Proto.CodeFixAction; + readonly followupAction: (resource: vscode.Uri, diagnostic: vscode.Diagnostic, action: Proto.CodeFixAction, client: ITypeScriptServiceClient) => Promise | undefined; }; class ApplyCodeActionCommand implements Command { @@ -35,20 +36,7 @@ class ApplyCodeActionCommand implements Command { private readonly telemetryReporter: TelemetryReporter, ) { } - private findEndLine(startLine: number, navigationTree: Proto.NavigationTree[]): number { - for (const node of navigationTree) { - const nodeStartLine = node.spans[0].start.line; - const nodeEndLine = node.spans[0].end.line; - if (nodeStartLine === startLine) { - return nodeEndLine; - } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { - return this.findEndLine(startLine, node.childItems); - } - } - return -1; - } - - public async execute({ resource, action, diagnostic }: ApplyCodeActionCommand_args): Promise { + public async execute({ resource, action, diagnostic, followupAction }: ApplyCodeActionCommand_args): Promise { /* __GDPR__ "quickFix.execute" : { "owner": "mjbvz", @@ -58,38 +46,21 @@ class ApplyCodeActionCommand implements Command { ] } */ + + console.log('resource : ', resource); + console.log('action : ', action); + console.log('diagnostic : ', diagnostic); + this.telemetryReporter.logTelemetry('quickFix.execute', { fixName: action.fixName }); this.diagnosticManager.deleteDiagnostic(resource, diagnostic); const codeActionResult = await applyCodeActionCommands(this.client, action.commands, nulToken); - - if (action.fixName === 'fixClassIncorrectlyImplementsInterface') { - - const diagnosticStartLine = diagnostic.range.start.line + 1; - const document = vscode.window.activeTextEditor?.document; - - if (document) { - const filepath = this.client.toOpenTsFilePath(document); - - if (filepath) { - const cancellationTokenSource = new vscode.CancellationTokenSource(); - const response = await this.client.execute('navtree', { file: filepath }, cancellationTokenSource.token); - - if (response.type === 'response' && response.body?.childItems) { - - const endLineFound = this.findEndLine(diagnosticStartLine, response.body.childItems); - const endLine = endLineFound !== -1 ? endLineFound : vscode.window.activeTextEditor?.document.lineCount; - const startLine = endLineFound !== -1 ? diagnosticStartLine : 0; - - await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, endLineNumber: endLine, startColumn: 0, endColumn: 0 }, message: 'Implement the class using the interface', autoSend: true }); - } - } - } - return codeActionResult; + if (followupAction) { + await followupAction(resource, diagnostic, action, this.client); } - return false; + return codeActionResult; } } @@ -357,17 +328,65 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + + const findScopeEndLine = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { + for (const node of navigationTree) { + const nodeStartLine = node.spans[0].start.line; + const nodeEndLine = node.spans[0].end.line; + if (nodeStartLine === startLine) { + return nodeEndLine; + } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { + return findScopeEndLine(startLine, node.childItems); + } + } + return -1; + }; + + console.log('inside of classIncorrectlyImplementsInterfaceFollowupAction'); + + if (action.fixName === 'fixClassIncorrectlyImplementsInterface') { + + const diagnosticStartLine = diagnostic.range.start.line + 1; + const document = vscode.window.activeTextEditor?.document; + + if (document) { + const filepath = client.toOpenTsFilePath(document); + + if (filepath) { + const cancellationTokenSource = new vscode.CancellationTokenSource(); + const response = await client.execute('navtree', { file: filepath }, cancellationTokenSource.token); + + if (response.type === 'response' && response.body?.childItems) { + + const endLineFound = findScopeEndLine(diagnosticStartLine, response.body.childItems); + const endLine = endLineFound !== -1 ? endLineFound : vscode.window.activeTextEditor?.document.lineCount; + const startLine = endLineFound !== -1 ? diagnosticStartLine : 0; + + await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, endLineNumber: endLine, startColumn: 0, endColumn: 0 }, message: 'Implement the class using the interface', autoSend: true }); + } + } + } + } + } + private getSingleFixForTsCodeAction( resource: vscode.Uri, diagnostic: vscode.Diagnostic, tsAction: Proto.CodeFixAction ): VsCodeCodeAction { + let followupAction; + const fixName = tsAction.fixName; + switch (fixName) { + case 'fixClassIncorrectlyImplementsInterface': + followupAction = this.classIncorrectlyImplementsInterfaceFollowupAction; + } const codeAction = new VsCodeCodeAction(tsAction, tsAction.description, vscode.CodeActionKind.QuickFix); codeAction.edit = getEditForCodeAction(this.client, tsAction); codeAction.diagnostics = [diagnostic]; codeAction.command = { command: ApplyCodeActionCommand.ID, - arguments: [{ action: tsAction, diagnostic, resource }], + arguments: [{ action: tsAction, diagnostic, resource, followupAction }], title: '' }; return codeAction; From b07e68e5fb97d1f785b321c1b35dc3cda12dce1e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 23 May 2023 18:35:36 +0200 Subject: [PATCH 08/12] cleaning the code --- .../src/languageFeatures/quickFix.ts | 63 +++++++------------ 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 83f13a291a6..076ad1a5da4 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -20,10 +20,10 @@ import { applyCodeActionCommands, getEditForCodeAction } from './util/codeAction import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; type ApplyCodeActionCommand_args = { - readonly resource: vscode.Uri; + readonly document: vscode.TextDocument; readonly diagnostic: vscode.Diagnostic; readonly action: Proto.CodeFixAction; - readonly followupAction: (resource: vscode.Uri, diagnostic: vscode.Diagnostic, action: Proto.CodeFixAction, client: ITypeScriptServiceClient) => Promise | undefined; + readonly followupAction: (document: vscode.TextDocument, diagnostic: vscode.Diagnostic, action: Proto.CodeFixAction, client: ITypeScriptServiceClient) => Promise | undefined; }; class ApplyCodeActionCommand implements Command { @@ -36,7 +36,7 @@ class ApplyCodeActionCommand implements Command { private readonly telemetryReporter: TelemetryReporter, ) { } - public async execute({ resource, action, diagnostic, followupAction }: ApplyCodeActionCommand_args): Promise { + public async execute({ document, action, diagnostic, followupAction }: ApplyCodeActionCommand_args): Promise { /* __GDPR__ "quickFix.execute" : { "owner": "mjbvz", @@ -46,19 +46,14 @@ class ApplyCodeActionCommand implements Command { ] } */ - - console.log('resource : ', resource); - console.log('action : ', action); - console.log('diagnostic : ', diagnostic); - this.telemetryReporter.logTelemetry('quickFix.execute', { fixName: action.fixName }); - this.diagnosticManager.deleteDiagnostic(resource, diagnostic); + this.diagnosticManager.deleteDiagnostic(document.uri, diagnostic); const codeActionResult = await applyCodeActionCommands(this.client, action.commands, nulToken); if (followupAction) { - await followupAction(resource, diagnostic, action, this.client); + await followupAction(document, diagnostic, action, this.client); } return codeActionResult; } @@ -323,12 +318,12 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { + private async classIncorrectlyImplementsInterfaceFollowupAction(document: vscode.TextDocument, diagnostic: vscode.Diagnostic, _action: Proto.CodeFixAction, client: ITypeScriptServiceClient): Promise { const findScopeEndLine = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { for (const node of navigationTree) { @@ -342,42 +337,28 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider{ action: tsAction, diagnostic, resource, followupAction }], + arguments: [{ action: tsAction, diagnostic, document, followupAction }], title: '' }; return codeAction; From 49043016b5a988dc72dd945dd8f40633e3617de6 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 24 May 2023 10:51:07 +0200 Subject: [PATCH 09/12] cleaning the code --- .../src/languageFeatures/quickFix.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 076ad1a5da4..9d5ba9fdef2 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -324,15 +324,14 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { - - const findScopeEndLine = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { + const findScopeEndLineFromNavTree = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { for (const node of navigationTree) { const nodeStartLine = node.spans[0].start.line; const nodeEndLine = node.spans[0].end.line; - if (nodeStartLine === startLine) { + if (startLine === nodeStartLine) { return nodeEndLine; } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { - return findScopeEndLine(startLine, node.childItems); + return findScopeEndLineFromNavTree(startLine, node.childItems); } } return -1; @@ -346,7 +345,7 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider Date: Wed, 24 May 2023 15:02:56 +0200 Subject: [PATCH 10/12] extract logic into `EditorChatFollowUp` class --- .../src/languageFeatures/quickFix.ts | 78 ++++++++++--------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 9d5ba9fdef2..849c2a71356 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -23,9 +23,46 @@ type ApplyCodeActionCommand_args = { readonly document: vscode.TextDocument; readonly diagnostic: vscode.Diagnostic; readonly action: Proto.CodeFixAction; - readonly followupAction: (document: vscode.TextDocument, diagnostic: vscode.Diagnostic, action: Proto.CodeFixAction, client: ITypeScriptServiceClient) => Promise | undefined; + readonly followupAction?: Command; }; +class EditorChatFollowUp implements Command { + + id: string = 'needsBetterName.editorChateFollowUp'; + + constructor(private readonly prompt: string, private readonly document: vscode.TextDocument, private readonly range: vscode.Range, private readonly client: ITypeScriptServiceClient) { + + } + + async execute() { + const findScopeEndLineFromNavTree = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { + for (const node of navigationTree) { + const { start: { line: nodeStartLine }, end: { line: nodeEndLine } } = typeConverters.Range.fromTextSpan(node.spans[0]); + if (startLine === nodeStartLine) { + return nodeEndLine; + } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { + return findScopeEndLineFromNavTree(startLine, node.childItems); + } + } + return -1; + }; + const filepath = this.client.toOpenTsFilePath(this.document); + if (!filepath) { + return; + } + const response = await this.client.execute('navtree', { file: filepath }, (new vscode.CancellationTokenSource()).token); + if (response.type !== 'response' || !response.body?.childItems) { + return; + } + const startLine = this.range.start.line + 1; + const endLine = findScopeEndLineFromNavTree(startLine, response.body.childItems); + if (endLine === -1) { + return; + } + await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, startColumn: 1, endLineNumber: endLine, endColumn: 1 }, message: this.prompt, autoSend: true }); + } +} + class ApplyCodeActionCommand implements Command { public static readonly ID = '_typescript.applyCodeActionCommand'; public readonly id = ApplyCodeActionCommand.ID; @@ -52,9 +89,7 @@ class ApplyCodeActionCommand implements Command { this.diagnosticManager.deleteDiagnostic(document.uri, diagnostic); const codeActionResult = await applyCodeActionCommands(this.client, action.commands, nulToken); - if (followupAction) { - await followupAction(document, diagnostic, action, this.client); - } + await followupAction?.execute(); return codeActionResult; } } @@ -323,43 +358,14 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider { - const findScopeEndLineFromNavTree = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { - for (const node of navigationTree) { - const nodeStartLine = node.spans[0].start.line; - const nodeEndLine = node.spans[0].end.line; - if (startLine === nodeStartLine) { - return nodeEndLine; - } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { - return findScopeEndLineFromNavTree(startLine, node.childItems); - } - } - return -1; - }; - const filepath = client.toOpenTsFilePath(document); - if (!filepath) { - return; - } - const response = await client.execute('navtree', { file: filepath }, (new vscode.CancellationTokenSource()).token); - if (response.type !== 'response' || !response.body?.childItems) { - return; - } - const diagnosticStartLine = diagnostic.range.start.line + 1; - const endLineFound = findScopeEndLineFromNavTree(diagnosticStartLine, response.body.childItems); - const endLine = endLineFound !== -1 ? endLineFound : document.lineCount; - const startLine = endLineFound !== -1 ? diagnosticStartLine : 0; - await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, endLineNumber: endLine, startColumn: 0, endColumn: 0 }, message: 'Implement the class using the interface', autoSend: true }); - } - private getSingleFixForTsCodeAction( document: vscode.TextDocument, diagnostic: vscode.Diagnostic, tsAction: Proto.CodeFixAction ): VsCodeCodeAction { - let followupAction; - switch (tsAction.fixName) { - case 'fixClassIncorrectlyImplementsInterface': - followupAction = this.classIncorrectlyImplementsInterfaceFollowupAction; + let followupAction: Command | undefined; + if (tsAction.fixName === fixNames.classIncorrectlyImplementsInterface) { + followupAction = new EditorChatFollowUp('Implement the class using the interface', document, diagnostic.range, this.client); } const codeAction = new VsCodeCodeAction(tsAction, tsAction.description, vscode.CodeActionKind.QuickFix); codeAction.edit = getEditForCodeAction(this.client, tsAction); From 2b8529fa61d12f27625b5adce1d53f1850c38806 Mon Sep 17 00:00:00 2001 From: Johannes Date: Wed, 24 May 2023 15:21:18 +0200 Subject: [PATCH 11/12] make API command for `interactiveEditor.start` so that initial range can be set properly --- .../src/languageFeatures/quickFix.ts | 20 ++++++------ .../workbench/api/common/extHost.api.impl.ts | 2 +- .../api/common/extHostInteractiveEditor.ts | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 849c2a71356..62cbfb24c8f 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -35,16 +35,16 @@ class EditorChatFollowUp implements Command { } async execute() { - const findScopeEndLineFromNavTree = (startLine: number, navigationTree: Proto.NavigationTree[]): number => { + const findScopeEndLineFromNavTree = (startLine: number, navigationTree: Proto.NavigationTree[]): vscode.Range | undefined => { for (const node of navigationTree) { - const { start: { line: nodeStartLine }, end: { line: nodeEndLine } } = typeConverters.Range.fromTextSpan(node.spans[0]); - if (startLine === nodeStartLine) { - return nodeEndLine; - } else if (startLine > nodeStartLine && startLine <= nodeEndLine && node.childItems) { + const range = typeConverters.Range.fromTextSpan(node.spans[0]); + if (startLine === range.start.line) { + return range; + } else if (startLine > range.start.line && startLine <= range.end.line && node.childItems) { return findScopeEndLineFromNavTree(startLine, node.childItems); } } - return -1; + return undefined; }; const filepath = this.client.toOpenTsFilePath(this.document); if (!filepath) { @@ -54,12 +54,12 @@ class EditorChatFollowUp implements Command { if (response.type !== 'response' || !response.body?.childItems) { return; } - const startLine = this.range.start.line + 1; - const endLine = findScopeEndLineFromNavTree(startLine, response.body.childItems); - if (endLine === -1) { + const startLine = this.range.start.line; + const enclosingRange = findScopeEndLineFromNavTree(startLine, response.body.childItems); + if (!enclosingRange) { return; } - await vscode.commands.executeCommand('interactiveEditor.start', { initialRange: { startLineNumber: startLine, startColumn: 1, endLineNumber: endLine, endColumn: 1 }, message: this.prompt, autoSend: true }); + await vscode.commands.executeCommand('vscode.editorChat.start', { initialRange: enclosingRange, message: this.prompt, autoSend: true }); } } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 3a8b64fa044..7918294f9e2 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -202,7 +202,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol)); const extHostProfileContentHandlers = rpcProtocol.set(ExtHostContext.ExtHostProfileContentHandlers, new ExtHostProfileContentHandlers(rpcProtocol)); rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService)); - const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInteractiveEditor, new ExtHostInteractiveEditor(rpcProtocol, extHostDocuments, extHostLogService)); + const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInteractiveEditor, new ExtHostInteractiveEditor(rpcProtocol, extHostCommands, extHostDocuments, extHostLogService)); const extHostChat = rpcProtocol.set(ExtHostContext.ExtHostChat, new ExtHostChat(rpcProtocol, extHostLogService)); const extHostSemanticSimilarity = rpcProtocol.set(ExtHostContext.ExtHostSemanticSimilarity, new ExtHostSemanticSimilarity(rpcProtocol)); const extHostIssueReporter = rpcProtocol.set(ExtHostContext.ExtHostIssueReporter, new ExtHostIssueReporter(rpcProtocol)); diff --git a/src/vs/workbench/api/common/extHostInteractiveEditor.ts b/src/vs/workbench/api/common/extHostInteractiveEditor.ts index 94ba77eeb02..90164a44aab 100644 --- a/src/vs/workbench/api/common/extHostInteractiveEditor.ts +++ b/src/vs/workbench/api/common/extHostInteractiveEditor.ts @@ -15,6 +15,8 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import type * as vscode from 'vscode'; +import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; +import { IRange } from 'vs/editor/common/core/range'; class ProviderWrapper { @@ -47,10 +49,40 @@ export class ExtHostInteractiveEditor implements ExtHostInteractiveEditorShape { constructor( mainContext: IMainContext, + extHostCommands: ExtHostCommands, private readonly _documents: ExtHostDocuments, private readonly _logService: ILogService, ) { this._proxy = mainContext.getProxy(MainContext.MainThreadInteractiveEditor); + + type EditorChatApiArg = { + initialRange?: vscode.Range; + message?: string; + autoSend?: boolean; + }; + + type InteractiveEditorRunOptions = { + initialRange?: IRange; + message?: string; + autoSend?: boolean; + }; + + extHostCommands.registerApiCommand(new ApiCommand( + 'vscode.editorChat.start', 'interactiveEditor.start', 'Invoke a new editor chat session', + [new ApiCommandArgument('Run arguments', '', _v => true, v => { + + if (!v) { + return undefined; + } + + return { + initialRange: v.initialRange ? typeConvert.Range.from(v.initialRange) : undefined, + message: v.message, + autoSend: v.autoSend + }; + })], + ApiCommandResult.Void + )); } registerProvider(extension: Readonly, provider: vscode.InteractiveEditorSessionProvider): vscode.Disposable { From 203c911ca066ca22c49af5b5924b9922f5287d00 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 24 May 2023 16:18:04 +0200 Subject: [PATCH 12/12] adding a setting in order to control whether the ai assisted setting is enabled or not --- extensions/typescript-language-features/package.json | 6 ++++++ extensions/typescript-language-features/package.nls.json | 1 + .../src/languageFeatures/quickFix.ts | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 0393fbb0ea4..26fd5e64d96 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -143,6 +143,12 @@ "title": "%configuration.typescript%", "order": 20, "properties": { + "typescript.experimental.aiQuickFix": { + "type": "boolean", + "default": false, + "description": "%typescript.experimental.aiQuickFix%", + "scope": "resource" + }, "typescript.tsdk": { "type": "string", "markdownDescription": "%typescript.tsdk.desc%", diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 2d5aa3e7eb7..c46952747fd 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -8,6 +8,7 @@ "configuration.suggest.completeFunctionCalls": "Complete functions with their parameter signature.", "configuration.suggest.includeAutomaticOptionalChainCompletions": "Enable/disable showing completions on potentially undefined values that insert an optional chain call. Requires strict null checks to be enabled.", "configuration.suggest.includeCompletionsForImportStatements": "Enable/disable auto-import-style completions on partially-typed import statements.", + "typescript.experimental.aiQuickFix": "Enable/disable AI-assisted quick fixes.", "typescript.tsdk.desc": "Specifies the folder path to the tsserver and `lib*.d.ts` files under a TypeScript install to use for IntelliSense, for example: `./node_modules/typescript/lib`.\n\n- When specified as a user setting, the TypeScript version from `typescript.tsdk` automatically replaces the built-in TypeScript version.\n- When specified as a workspace setting, `typescript.tsdk` allows you to switch to use that workspace version of TypeScript for IntelliSense with the `TypeScript: Select TypeScript version` command.\n\nSee the [TypeScript documentation](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-newer-typescript-versions) for more detail about managing TypeScript versions.", "typescript.disableAutomaticTypeAcquisition": "Disables [automatic type acquisition](https://code.visualstudio.com/docs/nodejs/working-with-javascript#_typings-and-automatic-type-acquisition). Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.", "typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.", diff --git a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts index 62cbfb24c8f..a6553902cbe 100644 --- a/extensions/typescript-language-features/src/languageFeatures/quickFix.ts +++ b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts @@ -363,8 +363,9 @@ class TypeScriptQuickFixProvider implements vscode.CodeActionProvider