diff --git a/clients/tabby-agent/package.json b/clients/tabby-agent/package.json index 7a8ccb73608d..547dbb04354e 100644 --- a/clients/tabby-agent/package.json +++ b/clients/tabby-agent/package.json @@ -26,7 +26,8 @@ "types": "./dist/protocol.d.ts", "scripts": { "build": "tsup --minify", - "watch": "tsup --watch", + "watch": "tsup --watch --onSuccess \"echo '' >> dist/protocol.d.ts\"", + "vscode:dev": "pnpm watch", "openapi-codegen": "openapi-typescript ./openapi/tabby.json -o ./src/types/tabbyApi.d.ts", "test": "mocha", "lint": "eslint --ext .ts ./src && prettier --check .", diff --git a/clients/tabby-agent/src/lsp/ChatEditProvider.ts b/clients/tabby-agent/src/lsp/ChatEditProvider.ts index 3b10cc9ba996..971331588256 100644 --- a/clients/tabby-agent/src/lsp/ChatEditProvider.ts +++ b/clients/tabby-agent/src/lsp/ChatEditProvider.ts @@ -183,25 +183,35 @@ export class ChatEditProvider { } async resolveEdit(params: ChatEditResolveParams): Promise { + if (params.action === "cancel") { + this.mutexAbortController?.abort(); + return false; + } + const document = this.documents.get(params.location.uri); if (!document) { return false; } - const header = document.getText({ - start: { - line: params.location.range.start.line, - character: 0, - }, - end: { - line: params.location.range.start.line + 1, - character: 0, - }, - }); - const match = /^<<<<<<<.+(<.*>)\[(tabby-[0-9|a-z|A-Z]{6})\]/g.exec(header); - const markers = match?.[1]; - if (!match || !markers) { + + let markers; + let line = params.location.range.start.line; + for (; line < document.lineCount; line++) { + const lineText = document.getText({ + start: { line, character: 0 }, + end: { line: line + 1, character: 0 }, + }); + + const match = /^>>>>>>> (tabby-[0-9|a-z|A-Z]{6}) (\[.*\])/g.exec(lineText); + markers = match?.[2]; + if (markers) { + break; + } + } + + if (!markers) { return false; } + const previewRange = { start: { line: params.location.range.start.line, @@ -257,6 +267,32 @@ export class ChatEditProvider { responseCommentTag?: string[], ): Promise { const applyEdit = async (edit: Edit, isFirst: boolean = false, isLast: boolean = false) => { + if (isFirst) { + const workspaceEdit: WorkspaceEdit = { + changes: { + [edit.location.uri]: [ + { + range: edit.editedRange, + newText: `<<<<<<< ${edit.id}\n`, + }, + ], + }, + }; + + await this.applyWorkspaceEdit({ + edit: workspaceEdit, + options: { + undoStopBefore: true, + undoStopAfter: false, + }, + }); + + edit.editedRange = { + start: { line: edit.editedRange.start.line + 1, character: 0 }, + end: { line: edit.editedRange.start.line + 1, character: 0 }, + }; + } + const editedLines = this.generateChangesPreview(edit); const workspaceEdit: WorkspaceEdit = { changes: { @@ -272,7 +308,7 @@ export class ChatEditProvider { await this.applyWorkspaceEdit({ edit: workspaceEdit, options: { - undoStopBefore: isFirst, + undoStopBefore: false, undoStopAfter: isLast, }, }); @@ -321,11 +357,17 @@ export class ChatEditProvider { }; try { + if (!this.currentEdit) { + throw new Error("No current edit"); + } + let inTag: "document" | "comment" | false = false; - let isFirstEdit = true; + + // Insert the first line as early as possible so codelens can be shown + await applyEdit(this.currentEdit, true, false); for await (const delta of stream) { - if (!this.currentEdit || !this.mutexAbortController || this.mutexAbortController.signal.aborted) { + if (!this.mutexAbortController || this.mutexAbortController.signal.aborted) { break; } @@ -341,8 +383,9 @@ export class ChatEditProvider { const closeTag = inTag === "document" ? responseDocumentTag[1] : responseCommentTag?.[1]; if (!closeTag || !openTag) break; inTag = processBuffer(edit, inTag, openTag, closeTag); - await applyEdit(edit, isFirstEdit, false); - isFirstEdit = false; + if (delta.includes("\n")) { + await applyEdit(edit, false, false); + } } } @@ -393,20 +436,14 @@ export class ChatEditProvider { // [+] inserted // [-] deleted // [>] footer + // [x] stopped // footer line // >>>>>>> End of changes private generateChangesPreview(edit: Edit): string[] { const lines: string[] = []; let markers = ""; - // header - let stateDescription = "Editing in progress"; - if (edit.state === "stopped") { - stateDescription = "Editing stopped"; - } else if (edit.state == "completed") { - stateDescription = "Editing completed"; - } - lines.push(`<<<<<<< ${stateDescription} {{markers}}[${edit.id}]`); - markers += "<"; + // lines.push(`<<<<<<< ${stateDescription} {{markers}}[${edit.id}]`); + markers += "["; // comments: split by new line or 80 chars const commentLines = edit.comments .trim() @@ -468,22 +505,30 @@ export class ChatEditProvider { lineIndex++; } if (inProgressChunk && lastDiff) { - pushDiffValue(lastDiff.value, "|"); + if (edit.state === "stopped") { + pushDiffValue(lastDiff.value, "x"); + } else { + pushDiffValue(lastDiff.value, "|"); + } } while (lineIndex < diffs.length - inProgressChunk) { const diff = diffs[lineIndex]; if (!diff) { break; } - pushDiffValue(diff.value, "."); + if (edit.state === "stopped") { + pushDiffValue(diff.value, "x"); + } else { + pushDiffValue(diff.value, "."); + } lineIndex++; } } // footer - lines.push(`>>>>>>> ${stateDescription} {{markers}}[${edit.id}]`); - markers += ">"; + lines.push(`>>>>>>> ${edit.id} {{markers}}`); + markers += "]"; // replace markers - lines[0] = lines[0]!.replace("{{markers}}", markers); + // lines[0] = lines[0]!.replace("{{markers}}", markers); lines[lines.length - 1] = lines[lines.length - 1]!.replace("{{markers}}", markers); return lines; } diff --git a/clients/tabby-agent/src/lsp/CodeLensProvider.ts b/clients/tabby-agent/src/lsp/CodeLensProvider.ts index 9f09bad12341..f55abdbc54a1 100644 --- a/clients/tabby-agent/src/lsp/CodeLensProvider.ts +++ b/clients/tabby-agent/src/lsp/CodeLensProvider.ts @@ -54,7 +54,7 @@ export class CodeLensProvider { const codeLenses: CodeLens[] = []; let lineInPreviewBlock = -1; let previewBlockMarkers = ""; - for (let line = 0; line < textDocument.lineCount; line++) { + for (let line = textDocument.lineCount - 1; line >= 0; line = line - 1) { if (token.isCancellationRequested) { return null; } @@ -64,56 +64,83 @@ export class CodeLensProvider { start: { line: line, character: 0 }, end: { line: line, character: text.length - 1 }, }; + const codeLensLocation: Location = { uri: uri, range: codeLensRange }; const lineCodeLenses: CodeLens[] = []; if (lineInPreviewBlock < 0) { - const match = /^<<<<<<<.+(<.*>)\[(tabby-[0-9|a-z|A-Z]{6})\]/g.exec(text); - const markers = match?.[1]; - const editId = match?.[2]; + const match = /^>>>>>>> (tabby-[0-9|a-z|A-Z]{6}) (\[.*\])/g.exec(text); + const editId = match?.[1]; + const markers = match?.[2]; if (match && markers && editId) { - lineInPreviewBlock = 0; previewBlockMarkers = markers; - - lineCodeLenses.push({ - range: codeLensRange, - command: { - title: "Accept", - command: "tabby/chat/edit/resolve", - arguments: [{ location: codeLensLocation, action: "accept" }], - }, - data: { - type: codeLensType, - line: changesPreviewLineType.header, - }, - }); + lineInPreviewBlock = 0; lineCodeLenses.push({ range: codeLensRange, - command: { - title: "Discard", - command: "tabby/chat/edit/resolve", - arguments: [{ location: codeLensLocation, action: "discard" }], - }, data: { type: codeLensType, - line: changesPreviewLineType.header, + line: changesPreviewLineType.footer, }, }); } } else { - const match = /^>>>>>>>.+(<.*>)\[(tabby-[0-9|a-z|A-Z]{6})\]/g.exec(text); - const editId = match?.[2]; + const match = /^<<<<<<< (tabby-[0-9|a-z|A-Z]{6})/g.exec(text); + const editId = match?.[1]; if (match && editId) { lineInPreviewBlock = -1; - lineCodeLenses.push({ - range: codeLensRange, - data: { - type: codeLensType, - line: changesPreviewLineType.footer, - }, - }); + + if (previewBlockMarkers.includes(".")) { + lineCodeLenses.push({ + range: codeLensRange, + command: { + title: "$(sync~spin) Tabby is working...", + command: " ", + }, + data: { + type: codeLensType, + line: changesPreviewLineType.header, + }, + }); + lineCodeLenses.push({ + range: codeLensRange, + command: { + title: "Cancel", + command: "tabby/chat/edit/resolve", + arguments: [{ location: codeLensLocation, action: "cancel" }], + }, + data: { + type: codeLensType, + line: changesPreviewLineType.header, + }, + }); + } else if (!previewBlockMarkers.includes("x")) { + lineCodeLenses.push({ + range: codeLensRange, + command: { + title: "$(check)Accept", + command: "tabby/chat/edit/resolve", + arguments: [{ location: codeLensLocation, action: "accept" }], + }, + data: { + type: codeLensType, + line: changesPreviewLineType.header, + }, + }); + lineCodeLenses.push({ + range: codeLensRange, + command: { + title: "$(remove-close)Discard", + command: "tabby/chat/edit/resolve", + arguments: [{ location: codeLensLocation, action: "discard" }], + }, + data: { + type: codeLensType, + line: changesPreviewLineType.header, + }, + }); + } } else { lineInPreviewBlock++; - const marker = previewBlockMarkers[lineInPreviewBlock]; + const marker = previewBlockMarkers[previewBlockMarkers.length - lineInPreviewBlock - 1]; let codeLens: CodeLens | undefined = undefined; switch (marker) { case "#": diff --git a/clients/tabby-agent/src/lsp/protocol.ts b/clients/tabby-agent/src/lsp/protocol.ts index f04b7751b12a..50d5679c6e56 100644 --- a/clients/tabby-agent/src/lsp/protocol.ts +++ b/clients/tabby-agent/src/lsp/protocol.ts @@ -469,7 +469,7 @@ export type ChatEditResolveParams = { /** * The action to take for this edit. */ - action: "accept" | "discard"; + action: "accept" | "discard" | "cancel"; }; /** diff --git a/clients/vscode/package.json b/clients/vscode/package.json index dafc150ce0a7..4863dde5a583 100644 --- a/clients/vscode/package.json +++ b/clients/vscode/package.json @@ -423,9 +423,10 @@ } }, "scripts": { - "build": "tsc --noEmit && tsup --minify", + "build": "tsc -p ./tsconfig.build.json --noEmit && tsup --minify", "watch": "tsc-watch --noEmit --onSuccess \"tsup\"", "dev": "code --extensionDevelopmentPath=$PWD --disable-extensions && pnpm watch", + "vscode:dev": "pnpm run dev", "dev:browser": "vscode-test-web --extensionDevelopmentPath=$PWD --browserType=chromium --port=3000 && pnpm watch", "lint": "eslint --ext .ts ./src && prettier --check .", "lint:fix": "eslint --fix --ext .ts ./src && prettier --write .", diff --git a/clients/vscode/src/Commands.ts b/clients/vscode/src/Commands.ts index 5438d2b638e0..219f66ec65e5 100644 --- a/clients/vscode/src/Commands.ts +++ b/clients/vscode/src/Commands.ts @@ -6,19 +6,15 @@ import { ExtensionContext, CancellationTokenSource, Uri, - Position, - Selection, Disposable, InputBoxValidationSeverity, ProgressLocation, ThemeIcon, QuickPickItem, - QuickPickItemKind, } from "vscode"; import os from "os"; import path from "path"; import { strict as assert } from "assert"; -import { ChatEditCommand } from "tabby-agent"; import { Client } from "./lsp/Client"; import { Config, PastServerConfig } from "./Config"; import { ContextVariables } from "./ContextVariables"; @@ -28,6 +24,7 @@ import { GitProvider, Repository } from "./git/GitProvider"; import CommandPalette from "./CommandPalette"; import { showOutputPanel } from "./logger"; import { Issues } from "./Issues"; +import { InlineEditController } from "./inline-edit"; export class Commands { private chatEditCancellationTokenSource: CancellationTokenSource | null = null; @@ -290,7 +287,7 @@ export class Commands { if (!editor) { return; } - const startPosition = new Position(editor.selection.start.line, 0); + const editLocation = { uri: editor.document.uri.toString(), range: { @@ -301,138 +298,15 @@ export class Commands { }, }, }; - //ensure max length - const recentlyCommand = this.config.chatEditRecentlyCommand.slice(0, this.config.maxChatEditHistory); - const suggestedCommand: ChatEditCommand[] = []; - const quickPick = window.createQuickPick(); - const updateQuickPickList = () => { - const input = quickPick.value; - const list: (QuickPickItem & { value: string })[] = []; - list.push( - ...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 = 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, - }); - } - quickPick.items = list; - }; - - const fetchingSuggestedCommandCancellationTokenSource = new CancellationTokenSource(); - this.client.chat.provideEditCommands( - { location: editLocation }, - { commands: suggestedCommand, callback: () => updateQuickPickList() }, - fetchingSuggestedCommandCancellationTokenSource.token, + const inlineEditController = new InlineEditController( + this.client, + this.config, + this.contextVariables, + editor, + editLocation, ); - - quickPick.placeholder = "Enter the command for editing"; - quickPick.matchOnDescription = true; - quickPick.onDidChangeValue(() => updateQuickPickList()); - quickPick.onDidHide(() => { - fetchingSuggestedCommandCancellationTokenSource.cancel(); - }); - quickPick.onDidAccept(() => { - quickPick.hide(); - const command = quickPick.selectedItems[0]?.value; - if (command) { - const updatedRecentlyCommand = [command] - .concat(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) => { - 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: 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; - editor.selection = new Selection(startPosition, startPosition); - }, - ); - } - }); - - quickPick.onDidTriggerItemButton((event) => { - const item = event.item; - const button = event.button; - if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "settings-remove") { - const index = recentlyCommand.indexOf(item.value); - if (index !== -1) { - recentlyCommand.splice(index, 1); - this.config.chatEditRecentlyCommand = recentlyCommand; - updateQuickPickList(); - } - } - - if (button.iconPath instanceof ThemeIcon && button.iconPath.id === "edit") { - quickPick.value = item.value; - } - }); - - quickPick.show(); + inlineEditController.start(); }, "chat.edit.stop": async () => { this.chatEditCancellationTokenSource?.cancel(); diff --git a/clients/vscode/src/extension.ts b/clients/vscode/src/extension.ts index 52a99a6c7de0..9182726cedc3 100644 --- a/clients/vscode/src/extension.ts +++ b/clients/vscode/src/extension.ts @@ -88,9 +88,11 @@ 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-expect-error noUnusedLocals */ + /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ /* eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error */ + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-ignore noUnusedLocals const statusBarItem = new StatusBarItem(context, client, config, issues, inlineCompletionProvider); - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ /* @ts-expect-error noUnusedLocals */ + /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ /* eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error */ + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ // @ts-ignore 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 new file mode 100644 index 000000000000..3a06929622f2 --- /dev/null +++ b/clients/vscode/src/inline-edit/index.ts @@ -0,0 +1,170 @@ +import { ChatEditCommand } from "tabby-agent"; +import { Config } from "../Config"; +import { + CancellationTokenSource, + QuickPickItem, + ThemeIcon, + QuickPickItemKind, + window, + 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; + } + + start() { + this.quickPick.show(); + } + + private async 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; + + this.editor.selection = new Selection(startPosition, startPosition); + this.contextVariables.chatEditInProgress = true; + this.chatEditCancellationTokenSource = new CancellationTokenSource(); + 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 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(); + } + } + + 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; +} + +interface EditLocation { + uri: string; + range: { + start: { line: number; character: number }; + end: { line: number; character: number }; + }; +} diff --git a/clients/vscode/src/lsp/CodeLensMiddleware.ts b/clients/vscode/src/lsp/CodeLensMiddleware.ts index 409cd2db6059..bb5d110b0944 100644 --- a/clients/vscode/src/lsp/CodeLensMiddleware.ts +++ b/clients/vscode/src/lsp/CodeLensMiddleware.ts @@ -16,12 +16,10 @@ import { findTextEditor } from "./vscodeWindowUtils"; type CodeLens = VscodeCodeLens & TabbyCodeLens; const decorationTypeHeader = window.createTextEditorDecorationType({ - backgroundColor: new ThemeColor("merge.incomingHeaderBackground"), isWholeLine: true, rangeBehavior: DecorationRangeBehavior.ClosedClosed, }); const decorationTypeFooter = window.createTextEditorDecorationType({ - backgroundColor: new ThemeColor("merge.incomingHeaderBackground"), isWholeLine: true, rangeBehavior: DecorationRangeBehavior.ClosedClosed, }); @@ -32,49 +30,28 @@ const decorationTypeComments = window.createTextEditorDecorationType({ fontWeight: "normal", isWholeLine: true, rangeBehavior: DecorationRangeBehavior.ClosedOpen, - before: { - contentText: ">", - color: new ThemeColor("editorInlayHint.foreground"), - backgroundColor: new ThemeColor("editorInlayHint.background"), - fontWeight: "bold", - width: "10px", - }, }); -const decorationTypeUnchanged = window.createTextEditorDecorationType({ - before: { - contentText: "", - fontWeight: "bold", - width: "10px", - }, +const decorationTypeUnchanged = window.createTextEditorDecorationType({}); +const decorationTypePending = window.createTextEditorDecorationType({ + isWholeLine: true, + rangeBehavior: DecorationRangeBehavior.ClosedClosed, }); const decorationTypeInserted = window.createTextEditorDecorationType({ backgroundColor: new ThemeColor("diffEditor.insertedTextBackground"), isWholeLine: true, rangeBehavior: DecorationRangeBehavior.ClosedClosed, - before: { - contentText: "+", - backgroundColor: new ThemeColor("diffEditor.insertedTextBackground"), - fontWeight: "bold", - width: "10px", - }, }); const decorationTypeDeleted = window.createTextEditorDecorationType({ backgroundColor: new ThemeColor("diffEditor.removedTextBackground"), isWholeLine: true, rangeBehavior: DecorationRangeBehavior.ClosedClosed, - before: { - contentText: "-", - backgroundColor: new ThemeColor("diffEditor.removedTextBackground"), - fontWeight: "bold", - width: "10px", - }, }); const decorationTypes: Record = { header: decorationTypeHeader, footer: decorationTypeFooter, commentsFirstLine: decorationTypeComments, comments: decorationTypeComments, - waiting: decorationTypeUnchanged, + waiting: decorationTypePending, inProgress: decorationTypeInserted, unchanged: decorationTypeUnchanged, inserted: decorationTypeInserted, diff --git a/clients/vscode/tsconfig.build.json b/clients/vscode/tsconfig.build.json new file mode 100644 index 000000000000..ad64328a35fe --- /dev/null +++ b/clients/vscode/tsconfig.build.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noUnusedLocals": true + } +} diff --git a/clients/vscode/tsconfig.json b/clients/vscode/tsconfig.json index 920eb6ef63ec..1a8f1d42a252 100644 --- a/clients/vscode/tsconfig.json +++ b/clients/vscode/tsconfig.json @@ -9,7 +9,7 @@ "noFallthroughCasesInSwitch": true, "noPropertyAccessFromIndexSignature": true, "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, + "noUnusedLocals": false, "noUnusedParameters": true, "allowSyntheticDefaultImports": true }, diff --git a/package.json b/package.json index 9a8af67ce81e..b63299c27ce4 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "private": true, "scripts": { "build": "turbo build", + "vscode:dev": "turbo vscode:dev", "lint": "turbo lint", "lint:fix": "turbo lint:fix", "test": "turbo test" diff --git a/turbo.json b/turbo.json index 6f99ef0066c0..1173dd8708c9 100644 --- a/turbo.json +++ b/turbo.json @@ -14,6 +14,7 @@ }, "lint": {}, "lint:fix": {}, - "test": {} + "test": {}, + "vscode:dev": {} } } \ No newline at end of file