diff --git a/clients/vscode/src/Commands.ts b/clients/vscode/src/Commands.ts index 60d1007fd0bc..3edd0ecc008c 100644 --- a/clients/vscode/src/Commands.ts +++ b/clients/vscode/src/Commands.ts @@ -299,7 +299,7 @@ export class Commands { }, }; - new InlineEditController(this.client, this.config, this.contextVariables, editor, editLocation ) + new InlineEditController(this.client, this.config, this.contextVariables, editor, editLocation); }, "chat.edit.stop": async () => { this.chatEditCancellationTokenSource?.cancel(); diff --git a/clients/vscode/src/extension.ts b/clients/vscode/src/extension.ts index 6b61996c5196..889e76f9eeec 100644 --- a/clients/vscode/src/extension.ts +++ b/clients/vscode/src/extension.ts @@ -88,9 +88,9 @@ export async function activate(context: ExtensionContext) { const issues = new Issues(client, config); const contextVariables = new ContextVariables(client, config); - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-ignore noUnusedLocals + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-expect-error noUnusedLocals const statusBarItem = new StatusBarItem(context, client, config, issues, inlineCompletionProvider); - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-ignore noUnusedLocals + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-expect-error noUnusedLocals const commands = new Commands( context, client, diff --git a/clients/vscode/src/inline-edit/index.ts b/clients/vscode/src/inline-edit/index.ts index 17c200f808f3..c6c5e644f188 100644 --- a/clients/vscode/src/inline-edit/index.ts +++ b/clients/vscode/src/inline-edit/index.ts @@ -1,171 +1,184 @@ import { ChatEditCommand } from "tabby-agent"; import { Config } from "../Config"; -import { CancellationTokenSource, QuickPickItem, ThemeIcon, QuickPickItemKind, window, ProgressLocation, TextEditor, Selection, Position, QuickPick, QuickPickItemButtonEvent } from "vscode"; +import { + CancellationTokenSource, + QuickPickItem, + ThemeIcon, + QuickPickItemKind, + window, + ProgressLocation, + TextEditor, + Selection, + Position, + QuickPick, + QuickPickItemButtonEvent, +} from "vscode"; import { Client } from "../lsp/Client"; import { ContextVariables } from "../ContextVariables"; export class InlineEditController { - private chatEditCancellationTokenSource: CancellationTokenSource | null = null; - private quickPick: QuickPick; - - private recentlyCommand: string[] = []; - private suggestedCommand: ChatEditCommand[] = []; - - constructor(private client: Client, private config: Config, - private contextVariables: ContextVariables, - private editor: TextEditor, - private editLocation: EditLocation) { - this.recentlyCommand = this.config.chatEditRecentlyCommand.slice(0, this.config.maxChatEditHistory); - - const fetchingSuggestedCommandCancellationTokenSource = new CancellationTokenSource(); - this.client.chat.provideEditCommands( - { location: editLocation }, - { commands: this.suggestedCommand, callback: () => this.updateQuickPickList() }, - fetchingSuggestedCommandCancellationTokenSource.token, - ); - - const quickPick = window.createQuickPick(); - quickPick.placeholder = "Enter the command for editing"; - quickPick.matchOnDescription = true; - quickPick.onDidChangeValue(() => this.updateQuickPickList()); - quickPick.onDidHide(() => { - fetchingSuggestedCommandCancellationTokenSource.cancel(); - }); - quickPick.onDidAccept(this.onDidAccept, this); - quickPick.onDidTriggerItemButton(this.onDidTriggerItemButton, this); - - this.quickPick = quickPick; - quickPick.show(); - } - - private onDidAccept() { - const startPosition = new Position(this.editLocation.range.start.line, this.editLocation.range.start.character); - const quickPick = this.quickPick; - quickPick.hide(); - - - const command = quickPick.selectedItems[0]?.value; - - if (command) { - const updatedRecentlyCommand = [command] - .concat(this.recentlyCommand.filter((item) => item !== command)) - .slice(0, this.config.maxChatEditHistory); - this.config.chatEditRecentlyCommand = updatedRecentlyCommand; - - window.withProgress( - { - location: ProgressLocation.Notification, - title: "Editing in progress...", - cancellable: true, - }, - async (_, token) => { - this.editor.selection = new Selection(startPosition, startPosition); - this.contextVariables.chatEditInProgress = true; - if (token.isCancellationRequested) { - return; - } - this.chatEditCancellationTokenSource = new CancellationTokenSource(); - token.onCancellationRequested(() => { - this.chatEditCancellationTokenSource?.cancel(); - }); - try { - await this.client.chat.provideEdit( - { - location: this.editLocation, - command, - format: "previewChanges", - }, - this.chatEditCancellationTokenSource.token, - ); - } catch (error) { - if (typeof error === "object" && error && "message" in error && typeof error["message"] === "string") { - window.showErrorMessage(error["message"]); - } - } - this.chatEditCancellationTokenSource.dispose(); - this.chatEditCancellationTokenSource = null; - this.contextVariables.chatEditInProgress = false; - this.editor.selection = new Selection(startPosition, startPosition); - }, + private chatEditCancellationTokenSource: CancellationTokenSource | null = null; + private quickPick: QuickPick; + + private recentlyCommand: string[] = []; + private suggestedCommand: ChatEditCommand[] = []; + + constructor( + private client: Client, + private config: Config, + private contextVariables: ContextVariables, + private editor: TextEditor, + private editLocation: EditLocation, + ) { + this.recentlyCommand = this.config.chatEditRecentlyCommand.slice(0, this.config.maxChatEditHistory); + + const fetchingSuggestedCommandCancellationTokenSource = new CancellationTokenSource(); + this.client.chat.provideEditCommands( + { location: editLocation }, + { commands: this.suggestedCommand, callback: () => this.updateQuickPickList() }, + fetchingSuggestedCommandCancellationTokenSource.token, + ); + + const quickPick = window.createQuickPick(); + quickPick.placeholder = "Enter the command for editing"; + quickPick.matchOnDescription = true; + quickPick.onDidChangeValue(() => this.updateQuickPickList()); + quickPick.onDidHide(() => { + fetchingSuggestedCommandCancellationTokenSource.cancel(); + }); + quickPick.onDidAccept(this.onDidAccept, this); + quickPick.onDidTriggerItemButton(this.onDidTriggerItemButton, this); + + this.quickPick = quickPick; + quickPick.show(); + } + + private onDidAccept() { + const startPosition = new Position(this.editLocation.range.start.line, this.editLocation.range.start.character); + const quickPick = this.quickPick; + quickPick.hide(); + + const command = quickPick.selectedItems[0]?.value; + + if (command) { + const updatedRecentlyCommand = [command] + .concat(this.recentlyCommand.filter((item) => item !== command)) + .slice(0, this.config.maxChatEditHistory); + this.config.chatEditRecentlyCommand = updatedRecentlyCommand; + + window.withProgress( + { + location: ProgressLocation.Notification, + title: "Editing in progress...", + cancellable: true, + }, + async (_, token) => { + this.editor.selection = new Selection(startPosition, startPosition); + this.contextVariables.chatEditInProgress = true; + if (token.isCancellationRequested) { + return; + } + this.chatEditCancellationTokenSource = new CancellationTokenSource(); + token.onCancellationRequested(() => { + this.chatEditCancellationTokenSource?.cancel(); + }); + try { + await this.client.chat.provideEdit( + { + location: this.editLocation, + command, + format: "previewChanges", + }, + this.chatEditCancellationTokenSource.token, ); - } - - } - - private onDidTriggerItemButton(event: QuickPickItemButtonEvent) { - const item = event.item; - const button = event.button; - if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "settings-remove") { - const index = this.recentlyCommand.indexOf(item.value); - if (index !== -1) { - this.recentlyCommand.splice(index, 1); - this.config.chatEditRecentlyCommand = this.recentlyCommand; - this.updateQuickPickList(); + } catch (error) { + if (typeof error === "object" && error && "message" in error && typeof error["message"] === "string") { + window.showErrorMessage(error["message"]); } - } - - if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "edit") { - this.quickPick.value = item.value; - } + } + this.chatEditCancellationTokenSource.dispose(); + this.chatEditCancellationTokenSource = null; + this.contextVariables.chatEditInProgress = false; + this.editor.selection = new Selection(startPosition, startPosition); + }, + ); + } + } + + private onDidTriggerItemButton(event: QuickPickItemButtonEvent) { + const item = event.item; + const button = event.button; + if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "settings-remove") { + const index = this.recentlyCommand.indexOf(item.value); + if (index !== -1) { + this.recentlyCommand.splice(index, 1); + this.config.chatEditRecentlyCommand = this.recentlyCommand; + this.updateQuickPickList(); + } } - private updateQuickPickList() { - const input = this.quickPick.value; - const list: (QuickPickItem & { value: string })[] = []; - list.push( - ...this.suggestedCommand.map((item) => ({ - label: item.label, - value: item.command, - iconPath: item.source === "preset" ? new ThemeIcon("run") : new ThemeIcon("spark"), - description: item.source === "preset" ? item.command : "Suggested", - })), - ); - if (list.length > 0) { - list.push({ - label: "", - value: "", - kind: QuickPickItemKind.Separator, - alwaysShow: true, - }); - } - const recentlyCommandToAdd = this.recentlyCommand.filter((item) => !list.find((i) => i.value === item)); - list.push( - ...recentlyCommandToAdd.map((item) => ({ - label: item, - value: item, - iconPath: new ThemeIcon("history"), - description: "History", - buttons: [ - { - iconPath: new ThemeIcon("edit"), - }, - { - iconPath: new ThemeIcon("settings-remove"), - }, - ], - })), - ); - if (input.length > 0 && !list.find((i) => i.value === input)) { - list.unshift({ - label: input, - value: input, - iconPath: new ThemeIcon("run"), - description: "", - alwaysShow: true, - }); - } - this.quickPick.items = list; - }; + if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "edit") { + this.quickPick.value = item.value; + } + } + + private updateQuickPickList() { + const input = this.quickPick.value; + const list: (QuickPickItem & { value: string })[] = []; + list.push( + ...this.suggestedCommand.map((item) => ({ + label: item.label, + value: item.command, + iconPath: item.source === "preset" ? new ThemeIcon("run") : new ThemeIcon("spark"), + description: item.source === "preset" ? item.command : "Suggested", + })), + ); + if (list.length > 0) { + list.push({ + label: "", + value: "", + kind: QuickPickItemKind.Separator, + alwaysShow: true, + }); + } + const recentlyCommandToAdd = this.recentlyCommand.filter((item) => !list.find((i) => i.value === item)); + list.push( + ...recentlyCommandToAdd.map((item) => ({ + label: item, + value: item, + iconPath: new ThemeIcon("history"), + description: "History", + buttons: [ + { + iconPath: new ThemeIcon("edit"), + }, + { + iconPath: new ThemeIcon("settings-remove"), + }, + ], + })), + ); + if (input.length > 0 && !list.find((i) => i.value === input)) { + list.unshift({ + label: input, + value: input, + iconPath: new ThemeIcon("run"), + description: "", + alwaysShow: true, + }); + } + this.quickPick.items = list; + } } interface EditCommand extends QuickPickItem { - value: string + value: string; } interface EditLocation { - uri: string; - range: { - start: { line: number; character: number }; - end: { line: number; character: number }; - }; -} \ No newline at end of file + uri: string; + range: { + start: { line: number; character: number }; + end: { line: number; character: number }; + }; +}