keyboard shortcuts for accept/reject

This commit is contained in:
Mathew Pareles 2025-05-04 23:46:13 -07:00
parent 9bebbb5615
commit c088ad3c07
4 changed files with 128 additions and 16 deletions

View file

@ -4,3 +4,7 @@
export const VOID_CTRL_L_ACTION_ID = 'void.ctrlLAction'
export const VOID_CTRL_K_ACTION_ID = 'void.ctrlKAction'
export const VOID_ACCEPT_DIFF_ACTION_ID = 'void.acceptDiff'
export const VOID_REJECT_DIFF_ACTION_ID = 'void.rejectDiff'

View file

@ -25,6 +25,8 @@ import { URI } from '../../../../base/common/uri.js';
import { IConsistentEditorItemService, IConsistentItemService } from './helperServices/consistentItemService.js';
import { voidPrefixAndSuffix, ctrlKStream_userMessage, ctrlKStream_systemMessage, defaultQuickEditFimTags, rewriteCode_systemMessage, rewriteCode_userMessage, searchReplaceGivenDescription_systemMessage, searchReplaceGivenDescription_userMessage, tripleTick, } from '../common/prompt/prompts.js';
import { IVoidCommandBarService } from './voidCommandBarService.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
import { VOID_ACCEPT_DIFF_ACTION_ID, VOID_REJECT_DIFF_ACTION_ID } from './actionIDs.js';
import { mountCtrlK } from './react/out/quick-edit-tsx/index.js'
import { QuickEditPropsType } from './quickEditActions.js';
@ -2252,9 +2254,12 @@ registerSingleton(IEditCodeService, EditCodeService, InstantiationType.Eager);
const processRawKeybindingText = (keybindingStr: string) => {
return keybindingStr
.replace(/Enter/g, '↵') // ⏎
.replace(/Backspace/g, '⌫')
}
class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
@ -2282,7 +2287,8 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
startLine: number,
offsetLines: number
},
@IVoidCommandBarService private readonly _voidCommandBarService: IVoidCommandBarService
@IVoidCommandBarService private readonly _voidCommandBarService: IVoidCommandBarService,
@IKeybindingService private readonly _keybindingService: IKeybindingService
) {
super();
@ -2302,6 +2308,27 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
const lineHeight = editor.getOption(EditorOption.lineHeight);
const getAcceptRejectText = () => {
const acceptKeybinding = this._keybindingService.lookupKeybinding(VOID_ACCEPT_DIFF_ACTION_ID);
const rejectKeybinding = this._keybindingService.lookupKeybinding(VOID_REJECT_DIFF_ACTION_ID);
const acceptKeybindLabel = processRawKeybindingText(acceptKeybinding && acceptKeybinding.getLabel() || '');
const rejectKeybindLabel = processRawKeybindingText(rejectKeybinding && rejectKeybinding.getLabel() || '')
const commandBarStateAtUri = this._voidCommandBarService.stateOfURI[uri.fsPath];
const selectedDiffIdx = commandBarStateAtUri?.diffIdx ?? 0; // 0th item is selected by default
const thisDiffIdx = commandBarStateAtUri?.sortedDiffIds.indexOf(diffid) ?? null;
const showLabel = thisDiffIdx === selectedDiffIdx
const acceptText = `Accept${showLabel ? ` ` + acceptKeybindLabel : ''}`;
const rejectText = `Reject${showLabel ? ` ` + rejectKeybindLabel : ''}`;
return { acceptText, rejectText }
}
const { acceptText, rejectText } = getAcceptRejectText()
// Create container div with buttons
const { acceptButton, rejectButton, buttons } = dom.h('div@buttons', [
dom.h('button@acceptButton', []),
@ -2315,11 +2342,14 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
buttons.style.paddingRight = '4px';
buttons.style.zIndex = '1';
buttons.style.transform = `translateY(${offsetLines * lineHeight}px)`;
buttons.style.justifyContent = 'flex-end';
buttons.style.width = '100%';
buttons.style.pointerEvents = 'none';
// Style accept button
acceptButton.onclick = onAccept;
acceptButton.textContent = 'Accept';
acceptButton.textContent = acceptText;
acceptButton.style.backgroundColor = acceptBg;
acceptButton.style.border = acceptBorder;
acceptButton.style.color = buttonTextColor;
@ -2333,10 +2363,12 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
acceptButton.style.cursor = 'pointer';
acceptButton.style.height = '100%';
acceptButton.style.boxShadow = '0 2px 3px rgba(0,0,0,0.2)';
acceptButton.style.pointerEvents = 'auto';
// Style reject button
rejectButton.onclick = onReject;
rejectButton.textContent = 'Reject';
rejectButton.textContent = rejectText;
rejectButton.style.backgroundColor = rejectBg;
rejectButton.style.border = rejectBorder;
rejectButton.style.color = buttonTextColor;
@ -2350,6 +2382,7 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
rejectButton.style.cursor = 'pointer';
rejectButton.style.height = '100%';
rejectButton.style.boxShadow = '0 2px 3px rgba(0,0,0,0.2)';
rejectButton.style.pointerEvents = 'auto';
@ -2384,18 +2417,12 @@ class AcceptRejectInlineWidget extends Widget implements IOverlayWidget {
// Listen for state changes in the command bar service
this._register(this._voidCommandBarService.onDidChangeState(e => {
if (uri && e.uri.fsPath === uri.fsPath) {
const commandBarStateAtUri = this._voidCommandBarService.stateOfURI[uri.fsPath];
const selectedDiffIdx = commandBarStateAtUri?.diffIdx ?? null;
const thisDiffIdx = commandBarStateAtUri?.sortedDiffIds.indexOf(diffid) ?? null;
// Update button text based on styles
if (thisDiffIdx !== null && selectedDiffIdx === thisDiffIdx) {
acceptButton.textContent = 'Accept';
rejectButton.textContent = 'Reject';
} else {
acceptButton.textContent = 'Accept';
rejectButton.textContent = 'Reject';
}
const { acceptText, rejectText } = getAcceptRejectText()
acceptButton.textContent = acceptText;
rejectButton.textContent = rejectText;
}
}));

View file

@ -54,6 +54,8 @@ export interface IEditCodeService {
diffOfId: Record<string, Diff>;
acceptOrRejectAllDiffAreas(opts: { uri: URI, removeCtrlKs: boolean, behavior: 'reject' | 'accept', _addToHistory?: boolean }): void;
acceptDiff({ diffid }: { diffid: number }): void;
rejectDiff({ diffid }: { diffid: number }): void;
// events
onDidAddOrDeleteDiffZones: Event<{ uri: URI }>;

View file

@ -18,6 +18,14 @@ import { IEditCodeService } from './editCodeServiceInterface.js';
import { ITextModel } from '../../../../editor/common/model.js';
import { IModelService } from '../../../../editor/common/services/model.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { VOID_ACCEPT_DIFF_ACTION_ID, VOID_REJECT_DIFF_ACTION_ID } from './actionIDs.js';
import { localize2 } from '../../../../nls.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
import { IMetricsService } from '../common/metricsService.js';
import { KeyMod } from '../../../../editor/common/services/editorBaseApi.js';
import { KeyCode } from '../../../../base/common/keyCodes.js';
@ -456,3 +464,74 @@ class AcceptRejectAllFloatingWidget extends Widget implements IOverlayWidget {
super.dispose();
}
}
registerAction2(class extends Action2 {
constructor() {
super({
id: VOID_ACCEPT_DIFF_ACTION_ID,
f1: true,
title: localize2('voidAcceptDiffAction', 'Void: Accept Diff'),
keybinding: {
primary: KeyMod.Alt | KeyMod.Shift | KeyCode.Enter,
weight: KeybindingWeight.VoidExtension,
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const editCodeService = accessor.get(IEditCodeService);
const commandBarService = accessor.get(IVoidCommandBarService);
const metricsService = accessor.get(IMetricsService);
const activeURI = commandBarService.activeURI;
if (!activeURI) return;
const commandBarState = commandBarService.stateOfURI[activeURI.fsPath];
if (!commandBarState) return;
const diffIdx = commandBarState.diffIdx ?? 0;
const diffid = commandBarState.sortedDiffIds[diffIdx];
if (!diffid) return;
metricsService.capture('Accept Diff', { diffid, keyboard: true });
editCodeService.acceptDiff({ diffid: parseInt(diffid) })
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: VOID_REJECT_DIFF_ACTION_ID,
f1: true,
title: localize2('voidRejectDiffAction', 'Void: Reject Diff'),
keybinding: {
primary: KeyMod.Alt | KeyMod.Shift | KeyCode.Backspace,
weight: KeybindingWeight.VoidExtension,
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const editCodeService = accessor.get(IEditCodeService);
const commandBarService = accessor.get(IVoidCommandBarService);
const metricsService = accessor.get(IMetricsService);
const activeURI = commandBarService.activeURI;
if (!activeURI) return;
const commandBarState = commandBarService.stateOfURI[activeURI.fsPath];
if (!commandBarState) return;
const diffIdx = commandBarState.diffIdx ?? 0;
const diffid = commandBarState.sortedDiffIds[diffIdx];
if (!diffid) return;
metricsService.capture('Reject Diff', { diffid, keyboard: true });
editCodeService.rejectDiff({ diffid: parseInt(diffid) })
}
});