cell diagnostic actions (#208261)

* add command to open cell error diagnostic quickfix menu

* add keybinding, filter actions

* context key for has cell diagnostics

* clear diagnostics on content change
This commit is contained in:
Aaron Munger 2024-03-20 15:45:50 -07:00 committed by GitHub
parent 78d4f34a94
commit 7eb5c6cff3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 62 additions and 5 deletions

View file

@ -14,14 +14,18 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
import { changeCellToKind, computeCellLinesContents, copyCellRange, joinCellsWithSurrounds, joinSelectedCells, moveCellRange } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
import { cellExecutionArgs, CellOverflowToolbarGroups, CellToolbarOrder, CELL_TITLE_CELL_GROUP_ID, INotebookCellActionContext, INotebookCellToolbarActionContext, INotebookCommandContext, NotebookCellAction, NotebookMultiCellAction, parseMultiCellExecutionArgs } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
import { cellExecutionArgs, CellOverflowToolbarGroups, CellToolbarOrder, CELL_TITLE_CELL_GROUP_ID, INotebookCellActionContext, INotebookCellToolbarActionContext, INotebookCommandContext, NotebookCellAction, NotebookMultiCellAction, parseMultiCellExecutionArgs, findTargetCellEditor } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
import { CellFocusMode, EXPAND_CELL_INPUT_COMMAND_ID, EXPAND_CELL_OUTPUT_COMMAND_ID, ICellOutputViewModel, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
import { CellEditType, CellKind, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { Range } from 'vs/editor/common/core/range';
import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeActionController';
import { CodeActionKind, CodeActionTriggerSource } from 'vs/editor/contrib/codeAction/common/types';
//#region Move/Copy cells
const MOVE_CELL_UP_COMMAND_ID = 'notebook.cell.moveUp';
@ -353,6 +357,7 @@ const COLLAPSE_ALL_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.collapseAllCellOutpu
const EXPAND_ALL_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.expandAllCellOutputs';
const TOGGLE_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.toggleOutputs';
const TOGGLE_CELL_OUTPUT_SCROLLING = 'notebook.cell.toggleOutputScrolling';
const OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID = 'notebook.cell.openFailureActions';
registerAction2(class CollapseCellInputAction extends NotebookMultiCellAction {
constructor() {
@ -579,6 +584,45 @@ registerAction2(class ToggleCellOutputScrolling extends NotebookMultiCellAction
}
});
registerAction2(class ExpandAllCellOutputsAction extends NotebookCellAction {
constructor() {
super({
id: OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID,
title: localize2('notebookActions.cellFailureActions', "Show Cell Failure Actions"),
precondition: ContextKeyExpr.and(NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS, NOTEBOOK_CELL_EDITOR_FOCUSED.toNegated()),
f1: true,
keybinding: {
when: ContextKeyExpr.and(NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS, NOTEBOOK_CELL_EDITOR_FOCUSED.toNegated()),
primary: KeyMod.CtrlCmd | KeyCode.Period,
weight: KeybindingWeight.WorkbenchContrib
}
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
if (context.cell instanceof CodeCellViewModel) {
const error = context.cell.cellErrorDetails;
if (error?.location) {
const location = Range.lift({
startLineNumber: error.location.startLineNumber + 1,
startColumn: error.location.startColumn + 1,
endLineNumber: error.location.endLineNumber + 1,
endColumn: error.location.endColumn + 1
});
context.notebookEditor.setCellEditorSelection(context.cell, Range.lift(location));
const editor = findTargetCellEditor(context, context.cell);
if (editor) {
const controller = CodeActionController.get(editor);
controller?.manualTriggerAtCurrentPosition(
localize('cellCommands.quickFix.noneMessage', "No code actions available"),
CodeActionTriggerSource.Default,
{ include: CodeActionKind.QuickFix });
}
}
}
}
});
//#endregion
function forEachCell(editor: INotebookEditor, callback: (cell: ICellViewModel, index: number) => void) {

View file

@ -70,7 +70,9 @@ export class CellDiagnostics extends Disposable {
}
public clear() {
this.clearDiagnostics();
if (this.ErrorDetails) {
this.clearDiagnostics();
}
}
private clearDiagnostics() {

View file

@ -13,7 +13,7 @@ import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cell
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookCellExecutionStateContext, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_RESOURCE, NOTEBOOK_CELL_TYPE, NOTEBOOK_CELL_GENERATED_BY_CHAT } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { NotebookCellExecutionStateContext, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_RESOURCE, NOTEBOOK_CELL_TYPE, NOTEBOOK_CELL_GENERATED_BY_CHAT, NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
export class CellContextKeyPart extends CellContentPart {
@ -47,6 +47,7 @@ export class CellContextKeyManager extends Disposable {
private cellLineNumbers!: IContextKey<'on' | 'off' | 'inherit'>;
private cellResource!: IContextKey<string>;
private cellGeneratedByChat!: IContextKey<boolean>;
private cellHasErrorDiagnostics!: IContextKey<boolean>;
private markdownEditMode!: IContextKey<boolean>;
@ -74,6 +75,7 @@ export class CellContextKeyManager extends Disposable {
this.cellLineNumbers = NOTEBOOK_CELL_LINE_NUMBERS.bindTo(this._contextKeyService);
this.cellGeneratedByChat = NOTEBOOK_CELL_GENERATED_BY_CHAT.bindTo(this._contextKeyService);
this.cellResource = NOTEBOOK_CELL_RESOURCE.bindTo(this._contextKeyService);
this.cellHasErrorDiagnostics = NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS.bindTo(this._contextKeyService);
if (element) {
this.updateForElement(element);
@ -200,6 +202,10 @@ export class CellContextKeyManager extends Disposable {
this.cellRunState.set('idle');
this.cellExecuting.set(false);
}
if (this.element instanceof CodeCellViewModel) {
this.cellHasErrorDiagnostics.set(!!this.element.cellErrorDetails);
}
}
private updateForEditState() {

View file

@ -47,6 +47,9 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
private _outputCollection: number[] = [];
private readonly _cellDiagnostics: CellDiagnostics;
get cellErrorDetails() {
return this._cellDiagnostics.ErrorDetails;
}
private _outputsTop: PrefixSumComputer | null = null;
@ -171,7 +174,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
if (outputLayoutChange) {
this.layoutChange({ outputHeight: true }, 'CodeCellViewModel#model.onDidChangeOutputs');
}
if (this._outputCollection.length === 0 && this._cellDiagnostics.ErrorDetails) {
if (this._outputCollection.length === 0) {
this._cellDiagnostics.clear();
}
dispose(removedOutputs);
@ -433,6 +436,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
protected onDidChangeTextModelContent(): void {
if (this.getEditState() !== CellEditState.Editing) {
this._cellDiagnostics.clear();
this.updateEditState(CellEditState.Editing, 'onDidChangeTextModelContent');
this._onDidChangeState.fire({ contentChanged: true });
}

View file

@ -47,6 +47,7 @@ export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey<boolean>('noteboo
export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey<boolean>('notebookCellOutputIsCollapsed', false);
export const NOTEBOOK_CELL_RESOURCE = new RawContextKey<string>('notebookCellResource', '');
export const NOTEBOOK_CELL_GENERATED_BY_CHAT = new RawContextKey<boolean>('notebookCellGenerateByChat', false);
export const NOTEBOOK_CELL_HAS_ERROR_DIAGNOSTICS = new RawContextKey<boolean>('notebookCellHasErrorDiagnostics', false);
// Kernels
export const NOTEBOOK_KERNEL = new RawContextKey<string>('notebookKernel', undefined);