-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add
Rewrite with new syntax
code lens on top level classes and code…
… actions. (#1317) * show `Rewrite with new syntax` code lens on first level classes of java documents. * add code action to inspect java code selection * implement `Inspection.highlight` to highlight the first line of an inspeciton. * delegate to copilot inline chat to fix inspection * chore: Use `sendInfo` to attach properties to telemetry event * rename symbols. * resolve command: renaming/inline/js docs. * extract interface InspectionProblem and rename inspection.problem.symbol as `inspection.problem.indicator` to avoid conflicts
- Loading branch information
1 parent
e22a87d
commit 96eb385
Showing
7 changed files
with
179 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { CodeLens, CodeLensProvider, Event, EventEmitter, ExtensionContext, TextDocument, Uri, languages } from "vscode"; | ||
import { getTopLevelClassesOfDocument, logger } from "../utils"; | ||
import { COMMAND_INSPECT_CLASS } from "./commands"; | ||
|
||
export class InspectActionCodeLensProvider implements CodeLensProvider { | ||
private inspectCodeLenses: Map<Uri, CodeLens[]> = new Map(); | ||
private emitter: EventEmitter<void> = new EventEmitter<void>(); | ||
public readonly onDidChangeCodeLenses: Event<void> = this.emitter.event; | ||
|
||
public install(context: ExtensionContext): InspectActionCodeLensProvider { | ||
logger.debug('[InspectCodeLensProvider] install...'); | ||
context.subscriptions.push( | ||
languages.registerCodeLensProvider({ language: 'java' }, this) | ||
); | ||
return this; | ||
} | ||
|
||
public async rerender(document: TextDocument) { | ||
if (document.languageId !== 'java') return; | ||
logger.debug('[InspectCodeLensProvider] rerender inspect codelenses...'); | ||
const docCodeLenses: CodeLens[] = []; | ||
const classes = await getTopLevelClassesOfDocument(document); | ||
classes.forEach(clazz => docCodeLenses.push(new CodeLens(clazz.range, { | ||
title: "Rewrite with new syntax", | ||
command: COMMAND_INSPECT_CLASS, | ||
arguments: [document, clazz] | ||
}))); | ||
this.inspectCodeLenses.set(document.uri, docCodeLenses); | ||
this.emitter.fire(); | ||
} | ||
|
||
public provideCodeLenses(document: TextDocument): CodeLens[] { | ||
return this.inspectCodeLenses.get(document.uri) ?? []; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,66 @@ | ||
import { TextDocument } from "vscode"; | ||
import { TextDocument, workspace, window, Selection, Range, Position } from "vscode"; | ||
|
||
export interface Inspection { | ||
document?: TextDocument; | ||
problem: { | ||
export interface InspectionProblem { | ||
/** | ||
* short description of the problem | ||
*/ | ||
description: string; | ||
position: { | ||
/** | ||
* short description of the problem | ||
* real line number to the start of the document, will change | ||
*/ | ||
description: string; | ||
position: { | ||
/** | ||
* real line number to the start of the document, will change | ||
*/ | ||
line: number; | ||
/** | ||
* relative line number to the start of the symbol(method/class), won't change | ||
*/ | ||
relativeLine: number; | ||
/** | ||
* code of the first line of the problematic code block | ||
*/ | ||
code: string; | ||
}; | ||
line: number; | ||
/** | ||
* symbol name of the problematic code block, e.g. method name/class name, keywork, etc. | ||
* relative line number to the start of the symbol(method/class), won't change | ||
*/ | ||
symbol: string; | ||
} | ||
relativeLine: number; | ||
/** | ||
* code of the first line of the problematic code block | ||
*/ | ||
code: string; | ||
}; | ||
/** | ||
* indicator of the problematic code block, e.g. method name/class name, keywork, etc. | ||
*/ | ||
indicator: string; | ||
} | ||
|
||
export interface Inspection { | ||
document?: TextDocument; | ||
problem: InspectionProblem; | ||
solution: string; | ||
severity: string; | ||
} | ||
|
||
export namespace Inspection { | ||
export function fix(inspection: Inspection, source: string) { | ||
//TODO: implement me | ||
export function revealFirstLineOfInspection(inspection: Inspection) { | ||
inspection.document && void workspace.openTextDocument(inspection.document.uri).then(document => { | ||
void window.showTextDocument(document).then(editor => { | ||
const range = document.lineAt(inspection.problem.position.line).range; | ||
editor.selection = new Selection(range.start, range.end); | ||
editor.revealRange(range); | ||
}); | ||
}); | ||
} | ||
|
||
export function highlight(inspection: Inspection) { | ||
//TODO: implement me | ||
/** | ||
* get the range of the indicator of the inspection. | ||
* `indicator` will be used as the position of code lens/diagnostics and also used as initial selection for fix commands. | ||
*/ | ||
export function getIndicatorRangeOfInspection(problem: InspectionProblem): Range { | ||
const position = problem.position; | ||
const startLine: number = position.line; | ||
let startColumn: number = position.code.indexOf(problem.indicator), endLine: number = -1, endColumn: number = -1; | ||
if (startColumn > -1) { | ||
// highlight only the symbol | ||
endLine = position.line; | ||
endColumn = startColumn + problem.indicator?.length; | ||
} else { | ||
// highlight entire first line | ||
startColumn = position.code.search(/\S/) ?? 0; // first non-whitespace character | ||
endLine = position.line; | ||
endColumn = position.code.length; // last character | ||
} | ||
return new Range(new Position(startLine, startColumn), new Position(endLine, endColumn)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { DocumentSymbol, TextDocument, Range, Selection, commands } from "vscode"; | ||
import { instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; | ||
import InspectionCopilot from "./InspectionCopilot"; | ||
import { Inspection, InspectionProblem } from "./Inspection"; | ||
import { uncapitalize } from "../utils"; | ||
|
||
export const COMMAND_INSPECT_CLASS = 'java.copilot.inspect.class'; | ||
export const COMMAND_INSPECT_RANGE = 'java.copilot.inspect.range'; | ||
export const COMMAND_FIX = 'java.copilot.fix.inspection'; | ||
|
||
export function registerCommands() { | ||
instrumentOperationAsVsCodeCommand(COMMAND_INSPECT_CLASS, async (document: TextDocument, clazz: DocumentSymbol) => { | ||
const copilot = new InspectionCopilot(); | ||
void copilot.inspectClass(document, clazz); | ||
}); | ||
|
||
instrumentOperationAsVsCodeCommand(COMMAND_INSPECT_RANGE, async (document: TextDocument, range: Range | Selection) => { | ||
const copilot = new InspectionCopilot(); | ||
void copilot.inspectRange(document, range); | ||
}); | ||
|
||
instrumentOperationAsVsCodeCommand(COMMAND_FIX, async (problem: InspectionProblem, solution: string, source: string) => { | ||
// source is where is this command triggered from, e.g. "gutter", "codelens", "diagnostic" | ||
const range = Inspection.getIndicatorRangeOfInspection(problem); | ||
sendInfo(`${COMMAND_FIX}.info`, { problem: problem.description, solution, source }); | ||
void commands.executeCommand('vscode.editorChat.start', { | ||
autoSend: true, | ||
message: `/fix ${problem.description}, maybe ${uncapitalize(solution)}`, | ||
position: range.start, | ||
initialSelection: new Selection(range.start, range.end), | ||
initialRange: range | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, ExtensionContext, TextDocument, languages, window, workspace, Range, Selection } from "vscode"; | ||
import { COMMAND_INSPECT_RANGE, registerCommands } from "./commands"; | ||
import { InspectActionCodeLensProvider } from "./InspectActionCodeLensProvider"; | ||
|
||
export const DEPENDENT_EXTENSIONS = ['github.copilot-chat', 'redhat.java']; | ||
|
||
export async function activateCopilotInspection(context: ExtensionContext): Promise<void> { | ||
|
||
registerCommands(); | ||
|
||
const inspectActionCodeLenses = new InspectActionCodeLensProvider().install(context); | ||
|
||
context.subscriptions.push( | ||
workspace.onDidOpenTextDocument(doc => inspectActionCodeLenses.rerender(doc)), // Rerender class codelens when open a new document | ||
workspace.onDidChangeTextDocument(e => inspectActionCodeLenses.rerender(e.document)), // Rerender class codelens when change a document | ||
languages.registerCodeActionsProvider({ language: 'java' }, { provideCodeActions: rewrite }), // add code action to rewrite code | ||
); | ||
window.visibleTextEditors.forEach(editor => inspectActionCodeLenses.rerender(editor.document)); | ||
} | ||
|
||
async function rewrite(document: TextDocument, range: Range | Selection, _context: CodeActionContext, _token: CancellationToken): Promise<CodeAction[]> { | ||
const action: CodeAction = { | ||
title: "Rewrite with new syntax", | ||
kind: CodeActionKind.RefactorRewrite, | ||
command: { | ||
title: "Rewrite selected code", | ||
command: COMMAND_INSPECT_RANGE, | ||
arguments: [document, range] | ||
} | ||
}; | ||
return [action]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters