Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interactive editor accessibility help polish #183356

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { EditMode } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_ACCESSIBILTY_HELP_VISIBLE, EditMode } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';

export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'chat' | 'editor', currentInput?: string): string {
const keybindingService = accessor.get(IKeybindingService);
Expand All @@ -24,23 +25,23 @@ export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'chat
content.push(descriptionForCommand('chat.action.focus', localize('workbench.action.chat.focus', 'The Focus Chat command ({0}) focuses the chat request/response list, which can be navigated with UpArrow/DownArrow.',), localize('workbench.action.chat.focusNoKb', 'The Focus Chat List command focuses the chat request/response list, which can be navigated with UpArrow/DownArrow and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('workbench.action.chat.focusInput', localize('workbench.action.chat.focusInput', 'The Focus Chat Input command ({0}) focuses the input box for chat requests.'), localize('workbench.action.interactiveSession.focusInputNoKb', 'Focus Chat Input command focuses the input box for chat requests and is currently not triggerable by a keybinding.'), keybindingService));
} else {
content.push(localize('interactiveSession.makeRequest', "Tab once to reach the make request button, which will re-run the request."));
const regex = /^(\/fix|\/explain)/;
const match = currentInput?.match(regex);
const command = match && match.length ? match[0].substring(1) : undefined;
if (command === 'fix') {
content.push(localize('interactiveSession.makeRequest', "Tab once to reach the make request button, which will re-run the request."));
const editMode = configurationService.getValue('interactiveEditor.editMode');
if (editMode === EditMode.Preview) {
const keybinding = keybindingService.lookupKeybinding('editor.action.diffReview.next')?.getAriaLabel();
content.push(keybinding ? localize('interactiveSession.diff', "Tab again to enter the Diff editor with the changes and enter review mode with ({0}). Use Up/DownArrow to navigate lines with the proposed changes.", keybinding) : localize('interactiveSession.diffNoKb', "Tab again to enter the Diff editor with the changes and enter review mode with the Go to Next Difference Command. Use Up/DownArrow to navigate lines with the proposed changes."));
content.push(localize('interactiveSession.acceptReject', "Tab again to reach the action bar, which can be navigated with Left/RightArrow."));
}
} else if (command === 'explain') {
content.push(localize('interactiveSession.makeRequest', "Tab once to reach the make request button, which will re-run the request."));
content.push(localize('interactiveSession.explain', "/explain commands will be run in the chat view."));
content.push(localize('interactiveSession.chatViewFocus', "To focus the chat view, run the GitHub Copilot: Focus on GitHub Copilot View command, which will focus the input box."));
} else {
content.push(localize('interactiveSession.toolbar', "Tab again to reach the action bar, if any, which can be navigated with Left/RightArrow."));
content.push(localize('interactiveSession.toolbarButtons', "Tab again to focus the response."));
content.push(localize('interactiveSession.toolbar', "Use tab to reach conditional parts like commands, status message, message responses and more"));
}
}
return content.join('\n');
Expand All @@ -56,6 +57,8 @@ function descriptionForCommand(commandId: string, msg: string, noKbMsg: string,

export async function runAccessibilityHelpAction(accessor: ServicesAccessor, editor: ICodeEditor, type: 'chat' | 'editor'): Promise<void> {
const widgetService = accessor.get(IChatWidgetService);
const contextKeyService = accessor.get(IContextKeyService);
const contextKey = type === 'editor' ? CTX_INTERACTIVE_EDITOR_ACCESSIBILTY_HELP_VISIBLE.bindTo(contextKeyService) : undefined;
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
const inputEditor: ICodeEditor | undefined = type === 'chat' ? widgetService.lastFocusedWidget?.inputEditor : editor;
const editorUri = editor.getModel()?.uri;

Expand All @@ -69,8 +72,8 @@ export async function runAccessibilityHelpAction(accessor: ServicesAccessor, edi

const cachedInput = inputEditor.getValue();
const cachedPosition = inputEditor.getPosition();
inputEditor.getSupportedActions();
const helpText = getAccessibilityHelpText(accessor, type, type === 'editor' ? cachedInput : undefined);
contextKey?.set(true);
inputEditor.setValue(helpText);
inputEditor.updateOptions({ readOnly: true });
inputEditor.focus();
Expand All @@ -79,6 +82,7 @@ export async function runAccessibilityHelpAction(accessor: ServicesAccessor, edi
return;
}
if (e.keyCode === KeyCode.Escape && inputEditor.getValue() === helpText) {
contextKey?.reset();
inputEditor.updateOptions({ readOnly: false });
inputEditor.setValue(cachedInput);
if (cachedPosition) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InteractiveEditorController, InteractiveEditorRunOptions } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT, CTX_INTERACTIVE_EDITOR_HAS_STASHED_SESSION, MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT, CTX_INTERACTIVE_EDITOR_HAS_STASHED_SESSION, MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, CTX_INTERACTIVE_EDITOR_ACCESSIBILTY_HELP_VISIBLE } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { localize } from 'vs/nls';
import { IAction2Options, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
Expand Down Expand Up @@ -135,7 +135,7 @@ export class MakeRequestAction extends AbstractInteractiveEditorAction {
id: 'interactiveEditor.accept',
title: localize('accept', 'Make Request'),
icon: Codicon.send,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_EMPTY.negate()),
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_ACCESSIBILTY_HELP_VISIBLE.negate(), CTX_INTERACTIVE_EDITOR_EMPTY.negate()),
keybinding: {
when: CTX_INTERACTIVE_EDITOR_FOCUSED,
weight: KeybindingWeight.EditorCore + 7,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ export class InteractiveEditorController implements IEditorContribution {
@IModelService private readonly _modelService: IModelService,
@INotebookEditorService private readonly _notebookEditorService: INotebookEditorService,
@IDialogService private readonly _dialogService: IDialogService,
@IContextKeyService contextKeyService: IContextKeyService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
) {
this._ctxHasActiveRequest = CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST.bindTo(contextKeyService);
this._ctxDidEdit = CTX_INTERACTIVE_EDITOR_DID_EDIT.bindTo(contextKeyService);
this._ctxLastResponseType = CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.bindTo(contextKeyService);
this._ctxLastFeedbackKind = CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK.bindTo(contextKeyService);
this._ctxHasActiveRequest = CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST.bindTo(_contextKeyService);
this._ctxDidEdit = CTX_INTERACTIVE_EDITOR_DID_EDIT.bindTo(_contextKeyService);
this._ctxLastResponseType = CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.bindTo(_contextKeyService);
this._ctxLastFeedbackKind = CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK.bindTo(_contextKeyService);
this._zone = this._store.add(_instaService.createInstance(InteractiveEditorZoneWidget, this._editor));

this._store.add(this._editor.onDidChangeModel(async e => {
Expand Down Expand Up @@ -438,7 +438,9 @@ export class InteractiveEditorController implements IEditorContribution {
});

const typeListener = this._zone.widget.onDidChangeInput(() => {
requestCts.cancel();
if (this._contextKeyService.getContextKeyValue('interactiveEditorAccessibilityHelpVisible') === false) {
requestCts.cancel();
}
});

const sw = StopWatch.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST = new RawContextKey<boolea
export const CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE = new RawContextKey<'cropped' | 'not_cropped' | 'expanded'>('interactiveEditorMarkdownMessageCropState', 'not_cropped', localize('interactiveEditorMarkdownMessageCropState', "Whether the interactive editor message is cropped, not cropped or expanded"));
export const CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION = new RawContextKey<'above' | 'below' | ''>('interactiveEditorOuterCursorPosition', '', localize('interactiveEditorOuterCursorPosition', "Whether the cursor of the outer editor is above or below the interactive editor input"));
export const CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST = new RawContextKey<boolean>('interactiveEditorHasActiveRequest', false, localize('interactiveEditorHasActiveRequest', "Whether interactive editor has an active request"));
export const CTX_INTERACTIVE_EDITOR_ACCESSIBILTY_HELP_VISIBLE = new RawContextKey<boolean>('interactiveEditorAccessibilityHelpVisible', false, localize('interactiveEditorAccessibilityHelpVisible', "Whether the interactive editor accessibility help menu is visible"));
export const CTX_INTERACTIVE_EDITOR_HAS_STASHED_SESSION = new RawContextKey<boolean>('interactiveEditorHasStashedSession', false, localize('interactiveEditorHasStashedSession', "Whether interactive editor has kept a session for quick restore"));
export const CTX_INTERACTIVE_EDITOR_SHOWING_DIFF = new RawContextKey<boolean>('interactiveEditorDiff', false, localize('interactiveEditorDiff', "Whether interactive editor show diffs for changes"));
export const CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE = new RawContextKey<InteractiveEditorResponseType | undefined>('interactiveEditorLastResponseType', undefined, localize('interactiveEditorResponseType', "What type was the last response of the current interactive editor session"));
Expand Down