mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
add a toolbar item to open cell diagnostic actions (#208358)
* add a toolbar item to open cell diagnostic actions * fix updated diagnostic handling * prioritize to be next to cell result * dispose status bar items, better handling of non-code cell
This commit is contained in:
parent
9d6c275fb7
commit
a832f9955c
|
@ -357,7 +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';
|
||||
export const OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID = 'notebook.cell.openFailureActions';
|
||||
|
||||
registerAction2(class CollapseCellInputAction extends NotebookMultiCellAction {
|
||||
constructor() {
|
||||
|
@ -601,7 +601,7 @@ registerAction2(class ExpandAllCellOutputsAction extends NotebookCellAction {
|
|||
|
||||
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
|
||||
if (context.cell instanceof CodeCellViewModel) {
|
||||
const error = context.cell.cellErrorDetails;
|
||||
const error = context.cell.cellDiagnostics.ErrorDetails;
|
||||
if (error?.location) {
|
||||
const location = Range.lift({
|
||||
startLineNumber: error.location.startLineNumber + 1,
|
||||
|
|
|
@ -12,10 +12,14 @@ import { Iterable } from 'vs/base/common/iterator';
|
|||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
|
||||
export class CellDiagnostics extends Disposable {
|
||||
|
||||
private readonly _onDidDiagnosticsChange = new Emitter<void>();
|
||||
readonly onDidDiagnosticsChange: Event<void> = this._onDidDiagnosticsChange.event;
|
||||
|
||||
static ID: string = 'workbench.notebook.cellDiagnostics';
|
||||
|
||||
private enabled = false;
|
||||
|
@ -48,7 +52,7 @@ export class CellDiagnostics extends Disposable {
|
|||
const settingEnabled = this.configurationService.getValue(NotebookSetting.cellFailureDiagnostics);
|
||||
if (this.enabled && (!settingEnabled || Iterable.isEmpty(this.inlineChatService.getAllProvider()))) {
|
||||
this.enabled = false;
|
||||
this.clearDiagnostics();
|
||||
this.clear();
|
||||
} else if (!this.enabled && settingEnabled && !Iterable.isEmpty(this.inlineChatService.getAllProvider())) {
|
||||
this.enabled = true;
|
||||
if (!this.listening) {
|
||||
|
@ -62,7 +66,7 @@ export class CellDiagnostics extends Disposable {
|
|||
if (this.enabled && e.type === NotebookExecutionType.cell && e.affectsCell(this.cell.uri)) {
|
||||
if (!!e.changed) {
|
||||
// cell is running
|
||||
this.clearDiagnostics();
|
||||
this.clear();
|
||||
} else {
|
||||
this.setDiagnostics();
|
||||
}
|
||||
|
@ -71,21 +75,19 @@ export class CellDiagnostics extends Disposable {
|
|||
|
||||
public clear() {
|
||||
if (this.ErrorDetails) {
|
||||
this.clearDiagnostics();
|
||||
this.markerService.changeOne(CellDiagnostics.ID, this.cell.uri, []);
|
||||
this.errorDetails = undefined;
|
||||
this._onDidDiagnosticsChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private clearDiagnostics() {
|
||||
this.markerService.changeOne(CellDiagnostics.ID, this.cell.uri, []);
|
||||
this.errorDetails = undefined;
|
||||
}
|
||||
|
||||
private setDiagnostics() {
|
||||
const metadata = this.cell.model.internalMetadata;
|
||||
if (!metadata.lastRunSuccess && metadata?.error?.location) {
|
||||
const marker = this.createMarkerData(metadata.error.message, metadata.error.location);
|
||||
this.markerService.changeOne(CellDiagnostics.ID, this.cell.uri, [marker]);
|
||||
this.errorDetails = metadata.error;
|
||||
this._onDidDiagnosticsChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ import { CellStatusbarAlignment, INotebookCellStatusBarItem, NotebookCellExecuti
|
|||
import { INotebookCellExecution, INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
||||
export function formatCellDuration(duration: number, showMilliseconds: boolean = true): string {
|
||||
if (showMilliseconds && duration < 1000) {
|
||||
|
@ -333,3 +336,60 @@ class TimerCellStatusBarItem extends Disposable {
|
|||
this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items: [] }]);
|
||||
}
|
||||
}
|
||||
|
||||
export class DiagnosticCellStatusBarContrib extends Disposable implements INotebookEditorContribution {
|
||||
static id: string = 'workbench.notebook.statusBar.diagtnostic';
|
||||
|
||||
constructor(
|
||||
notebookEditor: INotebookEditor,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) =>
|
||||
cell instanceof CodeCellViewModel ?
|
||||
instantiationService.createInstance(DiagnosticCellStatusBarItem, vm, cell) :
|
||||
Disposable.None
|
||||
));
|
||||
}
|
||||
}
|
||||
registerNotebookContribution(DiagnosticCellStatusBarContrib.id, DiagnosticCellStatusBarContrib);
|
||||
|
||||
|
||||
class DiagnosticCellStatusBarItem extends Disposable {
|
||||
private _currentItemIds: string[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _notebookViewModel: INotebookViewModel,
|
||||
private readonly cell: CodeCellViewModel,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
this._update();
|
||||
this._register(this.cell.cellDiagnostics.onDidDiagnosticsChange(() => this._update()));
|
||||
}
|
||||
|
||||
private async _update() {
|
||||
let item: INotebookCellStatusBarItem | undefined;
|
||||
|
||||
if (!!this.cell.cellDiagnostics.ErrorDetails) {
|
||||
const keybinding = this.keybindingService.lookupKeybinding(OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID)?.getLabel();
|
||||
const tooltip = localize('notebook.cell.status.diagnostic', "Quick Actions {0}", `(${keybinding})`);
|
||||
|
||||
item = {
|
||||
text: `$(sparkle)`,
|
||||
tooltip,
|
||||
alignment: CellStatusbarAlignment.Left,
|
||||
command: OPEN_CELL_FAILURE_ACTIONS_COMMAND_ID,
|
||||
priority: Number.MAX_SAFE_INTEGER - 1
|
||||
};
|
||||
}
|
||||
|
||||
const items = item ? [item] : [];
|
||||
this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this.cell.handle, items }]);
|
||||
}
|
||||
|
||||
override dispose() {
|
||||
super.dispose();
|
||||
this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this.cell.handle, items: [] }]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1101,9 +1101,9 @@ configurationRegistry.registerConfiguration({
|
|||
default: false
|
||||
},
|
||||
[NotebookSetting.cellFailureDiagnostics]: {
|
||||
markdownDescription: nls.localize('notebook.cellFailureDiagnostics', "Enable experimental diagnostics for cell failures."),
|
||||
markdownDescription: nls.localize('notebook.cellFailureDiagnostics', "Show available diagnostics for cell failures."),
|
||||
type: 'boolean',
|
||||
default: false
|
||||
default: true
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
@ -101,6 +101,7 @@ export class CellContextKeyManager extends Disposable {
|
|||
|
||||
if (element instanceof CodeCellViewModel) {
|
||||
this.elementDisposables.add(element.onDidChangeOutputs(() => this.updateForOutputs()));
|
||||
this.elementDisposables.add(element.cellDiagnostics.onDidDiagnosticsChange(() => this.updateForDiagnostics()));
|
||||
}
|
||||
|
||||
this.elementDisposables.add(this.notebookEditor.onDidChangeActiveCell(() => this.updateForFocusState()));
|
||||
|
@ -118,6 +119,7 @@ export class CellContextKeyManager extends Disposable {
|
|||
this.updateForCollapseState();
|
||||
this.updateForOutputs();
|
||||
this.updateForChat();
|
||||
this.updateForDiagnostics();
|
||||
|
||||
this.cellLineNumbers.set(this.element!.lineNumbers);
|
||||
this.cellResource.set(this.element!.uri.toString());
|
||||
|
@ -202,10 +204,6 @@ 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() {
|
||||
|
@ -247,4 +245,10 @@ export class CellContextKeyManager extends Disposable {
|
|||
|
||||
this.cellGeneratedByChat.set(chatController.isCellGeneratedByChat(this.element));
|
||||
}
|
||||
|
||||
private updateForDiagnostics() {
|
||||
if (this.element instanceof CodeCellViewModel) {
|
||||
this.cellHasErrorDiagnostics.set(!!this.element.cellDiagnostics.ErrorDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
|||
private _outputCollection: number[] = [];
|
||||
|
||||
private readonly _cellDiagnostics: CellDiagnostics;
|
||||
get cellErrorDetails() {
|
||||
return this._cellDiagnostics.ErrorDetails;
|
||||
get cellDiagnostics() {
|
||||
return this._cellDiagnostics;
|
||||
}
|
||||
|
||||
private _outputsTop: PrefixSumComputer | null = null;
|
||||
|
@ -436,10 +436,10 @@ 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 });
|
||||
}
|
||||
this._cellDiagnostics.clear();
|
||||
}
|
||||
|
||||
onDeselect() {
|
||||
|
|
|
@ -956,7 +956,7 @@ export const NotebookSetting = {
|
|||
cellChat: 'notebook.experimental.cellChat',
|
||||
notebookVariablesView: 'notebook.experimental.variablesView',
|
||||
InteractiveWindowPromptToSave: 'interactiveWindow.promptToSaveOnClose',
|
||||
cellFailureDiagnostics: 'notebook.experimental.cellFailureDiagnostics',
|
||||
cellFailureDiagnostics: 'notebook.cellFailureDiagnostics',
|
||||
} as const;
|
||||
|
||||
export const enum CellStatusbarAlignment {
|
||||
|
|
Loading…
Reference in a new issue