mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Disable ctrl+A in notebook renderer and support Ctrl+A for inputs (#208635)
* Disable ctrl+A in notebook renderer * Select All in input elements in outputs
This commit is contained in:
parent
11f4586955
commit
a8a38595ac
|
@ -597,7 +597,7 @@ registerAction2(class extends NotebookCellAction {
|
|||
title: localize('notebook.cell.output.selectAll', "Select All"),
|
||||
keybinding: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KeyA,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey), NOTEBOOK_OUTPUT_FOCUSED),
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_OUTPUT_FOCUSED),
|
||||
weight: NOTEBOOK_OUTPUT_WEBVIEW_ACTION_WEIGHT
|
||||
}
|
||||
});
|
||||
|
@ -615,7 +615,11 @@ registerAction2(class extends NotebookCellAction {
|
|||
if (!cell || !cell.outputIsFocused || !editor.hasWebviewFocus()) {
|
||||
return true;
|
||||
}
|
||||
editor.selectOutputContent(cell);
|
||||
if (cell.inputInOutputIsFocused) {
|
||||
editor.selectInputContents(cell);
|
||||
} else {
|
||||
editor.selectOutputContent(cell);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
|
@ -62,6 +62,15 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe
|
|||
this._onDidChangeState.fire({ outputIsFocusedChanged: true });
|
||||
}
|
||||
|
||||
private _focusInputInOutput: boolean = false;
|
||||
public get inputInOutputIsFocused(): boolean {
|
||||
return this._focusInputInOutput;
|
||||
}
|
||||
|
||||
public set inputInOutputIsFocused(v: boolean) {
|
||||
this._focusInputInOutput = v;
|
||||
}
|
||||
|
||||
private _outputViewModels: ICellOutputViewModel[];
|
||||
|
||||
get outputsViewModels() {
|
||||
|
|
|
@ -128,6 +128,7 @@ export interface IGenericCellViewModel {
|
|||
metadata: NotebookCellMetadata;
|
||||
outputIsHovered: boolean;
|
||||
outputIsFocused: boolean;
|
||||
inputInOutputIsFocused: boolean;
|
||||
outputsViewModels: ICellOutputViewModel[];
|
||||
getOutputOffset(index: number): number;
|
||||
updateOutputHeight(index: number, height: number, source?: string): void;
|
||||
|
@ -587,6 +588,11 @@ export interface INotebookEditor {
|
|||
* Implementation of Ctrl+A for an output item.
|
||||
*/
|
||||
selectOutputContent(cell: ICellViewModel): void;
|
||||
/**
|
||||
* Select the active input element of the first focused output of the cell.
|
||||
* Implementation of Ctrl+A for an input element in an output item.
|
||||
*/
|
||||
selectInputContents(cell: ICellViewModel): void;
|
||||
|
||||
readonly onDidReceiveMessage: Event<INotebookWebviewMessage>;
|
||||
|
||||
|
|
|
@ -1961,6 +1961,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
|||
this._webview?.selectOutputContents(cell);
|
||||
}
|
||||
|
||||
selectInputContents(cell: ICellViewModel) {
|
||||
this._webview?.selectInputContents(cell);
|
||||
}
|
||||
|
||||
onWillHide() {
|
||||
this._isVisible = false;
|
||||
this._editorFocus.set(false);
|
||||
|
@ -2402,12 +2406,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
|||
return;
|
||||
}
|
||||
|
||||
const focusElementId = options?.outputId ?? cell.id;
|
||||
const firstOutputId = cell.outputsViewModels.find(o => o.model.alternativeOutputId)?.model.alternativeOutputId;
|
||||
const focusElementId = options?.outputId ?? firstOutputId ?? cell.id;
|
||||
this._webview.focusOutput(focusElementId, options?.altOutputId, options?.outputWebviewFocused || this._webviewFocused);
|
||||
|
||||
cell.updateEditState(CellEditState.Preview, 'focusNotebookCell');
|
||||
cell.focusMode = CellFocusMode.Output;
|
||||
cell.focusedOutputId = options?.outputId;
|
||||
this._outputFocus.set(true);
|
||||
if (!options?.skipReveal) {
|
||||
this.revealInCenterIfOutsideViewport(cell);
|
||||
}
|
||||
|
|
|
@ -686,6 +686,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
|
|||
const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo);
|
||||
if (latestCell) {
|
||||
latestCell.outputIsFocused = false;
|
||||
latestCell.inputInOutputIsFocused = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -911,6 +912,13 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
|
|||
break;
|
||||
}
|
||||
case 'outputInputFocus': {
|
||||
const resolvedResult = this.resolveOutputId(data.id);
|
||||
if (resolvedResult) {
|
||||
const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo);
|
||||
if (latestCell) {
|
||||
latestCell.inputInOutputIsFocused = data.inputFocused;
|
||||
}
|
||||
}
|
||||
this.notebookEditor.didFocusOutputInputChange(data.inputFocused);
|
||||
}
|
||||
}
|
||||
|
@ -1693,6 +1701,18 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
|
|||
});
|
||||
}
|
||||
|
||||
selectInputContents(cell: ICellViewModel) {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
const output = cell.outputsViewModels.find(o => o.model.outputId === cell.focusedOutputId);
|
||||
const outputId = output ? this.insetMapping.get(output)?.outputId : undefined;
|
||||
this._sendMessageToWebview({
|
||||
type: 'select-input-contents',
|
||||
cellOrOutputId: outputId || cell.id
|
||||
});
|
||||
}
|
||||
|
||||
focusOutput(cellOrOutputId: string, alternateId: string | undefined, viewFocused: boolean) {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
|
|
|
@ -50,6 +50,7 @@ export interface IOutputBlurMessage extends BaseToWebviewMessage {
|
|||
export interface IOutputInputFocusMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'outputInputFocus';
|
||||
readonly inputFocused: boolean;
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export interface IScrollToRevealMessage extends BaseToWebviewMessage {
|
||||
|
@ -463,6 +464,10 @@ export interface ISelectOutputItemMessage {
|
|||
readonly type: 'select-output-contents';
|
||||
readonly cellOrOutputId: string;
|
||||
}
|
||||
export interface ISelectInputOutputItemMessage {
|
||||
readonly type: 'select-input-contents';
|
||||
readonly cellOrOutputId: string;
|
||||
}
|
||||
|
||||
export interface ILogRendererDebugMessage extends BaseToWebviewMessage {
|
||||
readonly type: 'logRendererDebugMessage';
|
||||
|
@ -544,7 +549,8 @@ export type ToWebviewMessage = IClearMessage |
|
|||
IFindUnHighlightCurrentMessage |
|
||||
IFindStopMessage |
|
||||
IReturnOutputItemMessage |
|
||||
ISelectOutputItemMessage;
|
||||
ISelectOutputItemMessage |
|
||||
ISelectInputOutputItemMessage;
|
||||
|
||||
|
||||
export type AnyMessage = FromWebviewMessage | ToWebviewMessage;
|
||||
|
|
|
@ -194,11 +194,12 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA') {
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused: true });
|
||||
const id = lastFocusedOutput?.id;
|
||||
if (id && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')) {
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused: true, id });
|
||||
|
||||
activeElement.addEventListener('blur', () => {
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused: false });
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused: false, id });
|
||||
}, { once: true });
|
||||
}
|
||||
};
|
||||
|
@ -286,6 +287,17 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
|
||||
};
|
||||
|
||||
const selectInputContents = (cellOrOutputId: string) => {
|
||||
const cellOutputContainer = window.document.getElementById(cellOrOutputId);
|
||||
if (!cellOutputContainer) {
|
||||
return;
|
||||
}
|
||||
const activeElement = window.document.activeElement;
|
||||
if (activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA') {
|
||||
(activeElement as HTMLInputElement).select();
|
||||
}
|
||||
};
|
||||
|
||||
const onPageUpDownSelectionHandler = (e: KeyboardEvent) => {
|
||||
if (!lastFocusedOutput?.id || !e.shiftKey) {
|
||||
return;
|
||||
|
@ -299,6 +311,11 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
if (!outputContainer || !selection?.anchorNode) {
|
||||
return;
|
||||
}
|
||||
const activeElement = window.document.activeElement;
|
||||
if (activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA') {
|
||||
// Leave for default behavior.
|
||||
return;
|
||||
}
|
||||
|
||||
// These should change the scroll position, not adjust the selected cell in the notebook
|
||||
e.stopPropagation(); // We don't want the notebook to handle this.
|
||||
|
@ -318,6 +335,22 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
selection.addRange(range);
|
||||
};
|
||||
|
||||
const disableNativeSelectAll = (e: KeyboardEvent) => {
|
||||
if (!lastFocusedOutput?.id) {
|
||||
return;
|
||||
}
|
||||
const activeElement = window.document.activeElement;
|
||||
if (activeElement?.tagName === 'INPUT' || activeElement?.tagName === 'TEXTAREA') {
|
||||
e.preventDefault(); // We will handle selection in editor code.
|
||||
return;
|
||||
}
|
||||
|
||||
if ((e.key === 'a' && e.ctrlKey) || (e.metaKey && e.key === 'a')) {
|
||||
e.preventDefault(); // We will handle selection in editor code.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDataUrl = async (data: string | ArrayBuffer | null, downloadName: string) => {
|
||||
postNotebookMessage<webviewMessages.IClickedDataUrlMessage>('clicked-data-url', {
|
||||
data,
|
||||
|
@ -343,6 +376,7 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
window.document.body.addEventListener('focusin', checkOutputInputFocus);
|
||||
window.document.body.addEventListener('focusout', handleOutputFocusOut);
|
||||
window.document.body.addEventListener('keydown', onPageUpDownSelectionHandler);
|
||||
window.document.body.addEventListener('keydown', disableNativeSelectAll);
|
||||
|
||||
interface RendererContext extends rendererApi.RendererContext<unknown> {
|
||||
readonly onDidChangeSettings: Event<RenderOptions>;
|
||||
|
@ -633,13 +667,19 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
if (cellOutputContainer.contains(window.document.activeElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = cellOutputContainer.id;
|
||||
let focusableElement = cellOutputContainer.querySelector('[tabindex="0"], [href], button, input, option, select, textarea') as HTMLElement | null;
|
||||
if (!focusableElement) {
|
||||
focusableElement = cellOutputContainer;
|
||||
focusableElement.tabIndex = -1;
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused: false, id });
|
||||
} else {
|
||||
const inputFocused = focusableElement.tagName === 'INPUT' || focusableElement.tagName === 'TEXTAREA';
|
||||
postNotebookMessage<webviewMessages.IOutputInputFocusMessage>('outputInputFocus', { inputFocused, id });
|
||||
}
|
||||
|
||||
lastFocusedOutput = cellOutputContainer;
|
||||
postNotebookMessage<webviewMessages.IOutputFocusMessage>('outputFocus', { id: cellOutputContainer.id });
|
||||
focusableElement.focus();
|
||||
}
|
||||
}
|
||||
|
@ -1695,6 +1735,9 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
case 'select-output-contents':
|
||||
selectOutputContents(event.data.cellOrOutputId);
|
||||
break;
|
||||
case 'select-input-contents':
|
||||
selectInputContents(event.data.cellOrOutputId);
|
||||
break;
|
||||
case 'decorations': {
|
||||
let outputContainer = window.document.getElementById(event.data.cellId);
|
||||
if (!outputContainer) {
|
||||
|
|
|
@ -115,6 +115,15 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
|||
this._onDidChangeState.fire({ outputIsFocusedChanged: true });
|
||||
}
|
||||
|
||||
private _focusInputInOutput: boolean = false;
|
||||
public get inputInOutputIsFocused(): boolean {
|
||||
return this._focusInputInOutput;
|
||||
}
|
||||
|
||||
public set inputInOutputIsFocused(v: boolean) {
|
||||
this._focusInputInOutput = v;
|
||||
}
|
||||
|
||||
private _outputMinHeight: number = 0;
|
||||
|
||||
private get outputMinHeight() {
|
||||
|
|
|
@ -93,6 +93,14 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
|
|||
this._focusOnOutput = v;
|
||||
}
|
||||
|
||||
public get inputInOutputIsFocused(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public set inputInOutputIsFocused(_: boolean) {
|
||||
//
|
||||
}
|
||||
|
||||
private _hoveringCell = false;
|
||||
public get cellIsHovered(): boolean {
|
||||
return this._hoveringCell;
|
||||
|
|
Loading…
Reference in a new issue