|
1 | 1 | import { instrumentSimpleOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; |
2 | 2 | import Copilot from "../Copilot"; |
3 | | -import { logger } from "../utils"; |
| 3 | +import { getClassesContainedInRange, getInnermostClassContainsRange, getIntersectionMethodsOfRange, getUnionRange, logger } from "../utils"; |
4 | 4 | import { Inspection } from "./Inspection"; |
| 5 | +import path from "path"; |
| 6 | +import { TextDocument, DocumentSymbol, SymbolKind, ProgressLocation, Position, Range, Selection, window } from "vscode"; |
5 | 7 |
|
6 | 8 | export default class InspectionCopilot extends Copilot { |
7 | 9 |
|
@@ -110,6 +112,61 @@ export default class InspectionCopilot extends Copilot { |
110 | 112 | super(messages); |
111 | 113 | } |
112 | 114 |
|
| 115 | + public async inspectDocument(document: TextDocument): Promise<Inspection[]> { |
| 116 | + logger.info('inspecting document:', document.fileName); |
| 117 | + const range = new Range(document.lineAt(0).range.start, document.lineAt(document.lineCount - 1).range.end); |
| 118 | + return this.inspectRange(document, range); |
| 119 | + } |
| 120 | + |
| 121 | + public async inspectClass(document: TextDocument, clazz: DocumentSymbol): Promise<Inspection[]> { |
| 122 | + logger.info('inspecting class:', clazz.name); |
| 123 | + return this.inspectRange(document, clazz.range); |
| 124 | + } |
| 125 | + |
| 126 | + public async inspectSymbol(document: TextDocument, symbol: DocumentSymbol): Promise<Inspection[]> { |
| 127 | + logger.info(`inspecting symbol ${SymbolKind[symbol.kind]} ${symbol.name}`); |
| 128 | + return this.inspectRange(document, symbol.range); |
| 129 | + } |
| 130 | + |
| 131 | + public async inspectRange(document: TextDocument, range: Range | Selection): Promise<Inspection[]> { |
| 132 | + // ajust the range to the minimal container class or (multiple) method symbols |
| 133 | + const methods: DocumentSymbol[] = await getIntersectionMethodsOfRange(range, document); |
| 134 | + const classes: DocumentSymbol[] = await getClassesContainedInRange(range, document); |
| 135 | + const symbols: DocumentSymbol[] = [...classes, ...methods]; |
| 136 | + if (symbols.length < 1) { |
| 137 | + const containingClass: DocumentSymbol = await getInnermostClassContainsRange(range, document); |
| 138 | + symbols.push(containingClass); |
| 139 | + } |
| 140 | + |
| 141 | + // get the union range of the container symbols, which will be insepcted by copilot |
| 142 | + const expandedRange: Range = getUnionRange(symbols); |
| 143 | + |
| 144 | + // inspect the expanded union range |
| 145 | + const symbolName = symbols[0].name; |
| 146 | + const symbolKind = SymbolKind[symbols[0].kind].toLowerCase(); |
| 147 | + const inspections = await window.withProgress({ |
| 148 | + location: ProgressLocation.Notification, |
| 149 | + title: `Inspecting ${symbolKind} ${symbolName}... of \"${path.basename(document.fileName)}\"`, |
| 150 | + cancellable: false |
| 151 | + }, (_progress) => { |
| 152 | + return this.doInspectRange(document, expandedRange); |
| 153 | + }); |
| 154 | + |
| 155 | + // show message based on the number of inspections |
| 156 | + if (inspections.length < 1) { |
| 157 | + void window.showInformationMessage(`Inspected ${symbolKind} ${symbolName}... of \"${path.basename(document.fileName)}\" and got 0 suggestions.`); |
| 158 | + } else if (inspections.length == 1) { |
| 159 | + // apply the only suggestion automatically |
| 160 | + void Inspection.fix(inspections[0], 'auto'); |
| 161 | + } else { |
| 162 | + // show message to go to the first suggestion |
| 163 | + void window.showInformationMessage(`Inspected ${symbolKind} ${symbolName}... of \"${path.basename(document.fileName)}\" and got ${inspections.length} suggestions.`, "Go to").then(selection => { |
| 164 | + selection === "Go to" && void Inspection.highlight(inspections[0]); |
| 165 | + }); |
| 166 | + } |
| 167 | + return inspections; |
| 168 | + } |
| 169 | + |
113 | 170 | /** |
114 | 171 | * inspect the given code (debouncely if `key` is provided) using copilot and return the inspections |
115 | 172 | * @param code code to inspect |
@@ -139,6 +196,19 @@ export default class InspectionCopilot extends Copilot { |
139 | 196 | }); |
140 | 197 | } |
141 | 198 |
|
| 199 | + private async doInspectRange(document: TextDocument, range: Range | Selection): Promise<Inspection[]> { |
| 200 | + const adjustedRange = new Range(new Position(range.start.line, 0), new Position(range.end.line, document.lineAt(range.end.line).text.length)); |
| 201 | + const content: string = document.getText(adjustedRange); |
| 202 | + const startLine = range.start.line; |
| 203 | + const inspections = await this.inspectCode(content); |
| 204 | + inspections.forEach(s => { |
| 205 | + s.document = document; |
| 206 | + // real line index to the start of the document |
| 207 | + s.problem.position.line = s.problem.position.relativeLine + startLine; |
| 208 | + }); |
| 209 | + return inspections; |
| 210 | + } |
| 211 | + |
142 | 212 | private async doInspectCode(code: string): Promise<Inspection[]> { |
143 | 213 | const originalLines: string[] = code.split(/\r?\n/); |
144 | 214 | // code lines without empty lines and comments |
|
0 commit comments