Path: blob/main/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IBulkEditService, ResourceTextEdit } from '../../../../../editor/browser/services/bulkEditService.js';6import { localize, localize2 } from '../../../../../nls.js';7import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';8import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';9import { ContextKeyExpr, ContextKeyExpression } from '../../../../../platform/contextkey/common/contextkey.js';10import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';11import { ActiveEditorContext } from '../../../../common/contextkeys.js';12import { DiffElementCellViewModelBase, NotebookDocumentMetadataViewModel, SideBySideDiffElementViewModel } from './diffElementViewModel.js';13import { INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_IGNORE_WHITESPACE_KEY, NOTEBOOK_DIFF_CELL_INPUT, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED, NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS, NOTEBOOK_DIFF_ITEM_DIFF_STATE, NOTEBOOK_DIFF_ITEM_KIND, NOTEBOOK_DIFF_METADATA, NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN } from './notebookDiffEditorBrowser.js';14import { NotebookTextDiffEditor } from './notebookDiffEditor.js';15import { NotebookDiffEditorInput } from '../../common/notebookDiffEditorInput.js';16import { nextChangeIcon, openAsTextIcon, previousChangeIcon, renderOutputIcon, revertIcon, toggleWhitespace } from '../notebookIcons.js';17import { IEditorService } from '../../../../services/editor/common/editorService.js';18import { Registry } from '../../../../../platform/registry/common/platform.js';19import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../../../platform/configuration/common/configurationRegistry.js';20import { ICommandActionTitle } from '../../../../../platform/action/common/action.js';21import { DEFAULT_EDITOR_ASSOCIATION } from '../../../../common/editor.js';22import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';23import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';24import { CellEditType, ICellEditOperation, NOTEBOOK_DIFF_EDITOR_ID } from '../../common/notebookCommon.js';25import { ITextResourceConfigurationService } from '../../../../../editor/common/services/textResourceConfiguration.js';26import { NotebookMultiTextDiffEditor } from './notebookMultiDiffEditor.js';27import { Codicon } from '../../../../../base/common/codicons.js';28import type { URI } from '../../../../../base/common/uri.js';29import { TextEditorSelectionRevealType, type ITextEditorOptions } from '../../../../../platform/editor/common/editor.js';30import product from '../../../../../platform/product/common/product.js';31import { ctxHasEditorModification, ctxHasRequestInProgress } from '../../../chat/browser/chatEditing/chatEditingEditorContextKeys.js';3233// ActiveEditorContext.isEqualTo(SearchEditorConstants.SearchEditorID)3435registerAction2(class extends Action2 {36constructor() {37super({38id: 'notebook.diff.openFile',39icon: Codicon.goToFile,40title: localize2('notebook.diff.openFile', 'Open File'),41precondition: ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),42menu: [{43id: MenuId.EditorTitle,44group: 'navigation',45when: ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),46}]47});48}4950async run(accessor: ServicesAccessor): Promise<void> {51const editorService = accessor.get(IEditorService);5253const activeEditor = editorService.activeEditorPane;54if (!activeEditor) {55return;56}57if (activeEditor instanceof NotebookTextDiffEditor || activeEditor instanceof NotebookMultiTextDiffEditor) {58const diffEditorInput = activeEditor.input as NotebookDiffEditorInput;59const resource = diffEditorInput.modified.resource;60await editorService.openEditor({ resource });61}62}63});6465registerAction2(class extends Action2 {66constructor() {67super({68id: 'notebook.diff.cell.toggleCollapseUnchangedRegions',69title: localize2('notebook.diff.cell.toggleCollapseUnchangedRegions', 'Toggle Collapse Unchanged Regions'),70icon: Codicon.map,71toggled: ContextKeyExpr.has('config.diffEditor.hideUnchangedRegions.enabled'),72precondition: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID),73menu: {74id: MenuId.EditorTitle,75group: 'navigation',76when: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID),77},78});79}8081run(accessor: ServicesAccessor, ...args: unknown[]): void {82const configurationService = accessor.get(IConfigurationService);83const newValue = !configurationService.getValue<boolean>('diffEditor.hideUnchangedRegions.enabled');84configurationService.updateValue('diffEditor.hideUnchangedRegions.enabled', newValue);85}86});878889registerAction2(class extends Action2 {90constructor() {91super({92id: 'notebook.diff.switchToText',93icon: openAsTextIcon,94title: localize2('notebook.diff.switchToText', 'Open Text Diff Editor'),95precondition: ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),96menu: [{97id: MenuId.EditorTitle,98group: 'navigation',99when: ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),100}]101});102}103104async run(accessor: ServicesAccessor): Promise<void> {105const editorService = accessor.get(IEditorService);106107const activeEditor = editorService.activeEditorPane;108if (!activeEditor) {109return;110}111if (activeEditor instanceof NotebookTextDiffEditor || activeEditor instanceof NotebookMultiTextDiffEditor) {112const diffEditorInput = activeEditor.input as NotebookDiffEditorInput;113114await editorService.openEditor(115{116original: { resource: diffEditorInput.original.resource },117modified: { resource: diffEditorInput.resource },118label: diffEditorInput.getName(),119options: {120preserveFocus: false,121override: DEFAULT_EDITOR_ASSOCIATION.id122}123});124}125}126});127128129registerAction2(class extends Action2 {130constructor() {131super({132id: 'notebook.diffEditor.showUnchangedCells',133title: localize2('showUnchangedCells', 'Show Unchanged Cells'),134icon: Codicon.unfold,135precondition: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.has(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key)),136menu: {137when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.has(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key), ContextKeyExpr.equals(NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN.key, true)),138id: MenuId.EditorTitle,139order: 22,140group: 'navigation',141},142});143}144145run(accessor: ServicesAccessor, ...args: unknown[]): void {146const activeEditor = accessor.get(IEditorService).activeEditorPane;147if (!activeEditor) {148return;149}150if (activeEditor instanceof NotebookMultiTextDiffEditor) {151activeEditor.showUnchanged();152}153}154});155156registerAction2(class extends Action2 {157constructor() {158super({159id: 'notebook.diffEditor.hideUnchangedCells',160title: localize2('hideUnchangedCells', 'Hide Unchanged Cells'),161icon: Codicon.fold,162precondition: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.has(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key)),163menu: {164when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.has(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key), ContextKeyExpr.equals(NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN.key, false)),165id: MenuId.EditorTitle,166order: 22,167group: 'navigation',168},169});170}171172run(accessor: ServicesAccessor, ...args: unknown[]): void {173const activeEditor = accessor.get(IEditorService).activeEditorPane;174if (!activeEditor) {175return;176}177if (activeEditor instanceof NotebookMultiTextDiffEditor) {178activeEditor.hideUnchanged();179}180}181});182183registerAction2(class GoToFileAction extends Action2 {184constructor() {185super({186id: 'notebook.diffEditor.2.goToCell',187title: localize2('goToCell', 'Go To Cell'),188icon: Codicon.goToFile,189menu: {190when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Cell'), ContextKeyExpr.notEquals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'delete')),191id: MenuId.MultiDiffEditorFileToolbar,192order: 0,193group: 'navigation',194},195});196}197198async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {199const uri = args[0] as URI;200const editorService = accessor.get(IEditorService);201const activeEditorPane = editorService.activeEditorPane;202if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {203return;204}205206await editorService.openEditor({207resource: uri,208options: {209selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,210} satisfies ITextEditorOptions,211});212}213});214215216registerAction2(class extends Action2 {217constructor() {218super(219{220id: 'notebook.diff.revertMetadata',221title: localize('notebook.diff.revertMetadata', "Revert Notebook Metadata"),222icon: revertIcon,223f1: false,224menu: {225id: MenuId.NotebookDiffDocumentMetadata,226when: NOTEBOOK_DIFF_METADATA,227},228precondition: NOTEBOOK_DIFF_METADATA229230}231);232}233run(accessor: ServicesAccessor, context?: NotebookDocumentMetadataViewModel) {234if (!context) {235return;236}237238const editorService = accessor.get(IEditorService);239const activeEditorPane = editorService.activeEditorPane;240if (!(activeEditorPane instanceof NotebookTextDiffEditor)) {241return;242}243244context.modifiedDocumentTextModel.applyEdits([{245editType: CellEditType.DocumentMetadata,246metadata: context.originalMetadata.metadata,247}], true, undefined, () => undefined, undefined, true);248}249});250251const revertInput = localize('notebook.diff.cell.revertInput', "Revert Input");252253registerAction2(class extends Action2 {254constructor() {255super({256id: 'notebook.diffEditor.2.cell.revertInput',257title: revertInput,258icon: revertIcon,259menu: {260when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Cell'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),261id: MenuId.MultiDiffEditorFileToolbar,262order: 2,263group: 'navigation',264},265});266}267268async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {269const uri = args[0] as URI;270const editorService = accessor.get(IEditorService);271const activeEditorPane = editorService.activeEditorPane;272if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {273return;274}275276const item = activeEditorPane.getDiffElementViewModel(uri);277if (item && item instanceof SideBySideDiffElementViewModel) {278const modified = item.modified;279const original = item.original;280281if (!original || !modified) {282return;283}284285const bulkEditService = accessor.get(IBulkEditService);286await bulkEditService.apply([287new ResourceTextEdit(modified.uri, { range: modified.textModel.getFullModelRange(), text: original.textModel.getValue() }),288], { quotableLabel: 'Revert Notebook Cell Content Change' });289}290}291});292293const revertOutputs = localize('notebook.diff.cell.revertOutputs', "Revert Outputs");294295registerAction2(class extends Action2 {296constructor() {297super(298{299id: 'notebook.diffEditor.2.cell.revertOutputs',300title: revertOutputs,301icon: revertIcon,302f1: false,303menu: {304when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Output'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),305id: MenuId.MultiDiffEditorFileToolbar,306order: 2,307group: 'navigation',308},309}310);311}312async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {313const uri = args[0] as URI;314const editorService = accessor.get(IEditorService);315const activeEditorPane = editorService.activeEditorPane;316if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {317return;318}319320const item = activeEditorPane.getDiffElementViewModel(uri);321if (item && item instanceof SideBySideDiffElementViewModel) {322const original = item.original;323324const modifiedCellIndex = item.modifiedDocument.cells.findIndex(cell => cell.handle === item.modified.handle);325if (modifiedCellIndex === -1) {326return;327}328329item.mainDocumentTextModel.applyEdits([{330editType: CellEditType.Output, index: modifiedCellIndex, outputs: original.outputs331}], true, undefined, () => undefined, undefined, true);332}333}334});335336const revertMetadata = localize('notebook.diff.cell.revertMetadata', "Revert Metadata");337338registerAction2(class extends Action2 {339constructor() {340super(341{342id: 'notebook.diffEditor.2.cell.revertMetadata',343title: revertMetadata,344icon: revertIcon,345f1: false,346menu: {347when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Metadata'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),348id: MenuId.MultiDiffEditorFileToolbar,349order: 2,350group: 'navigation',351},352}353);354}355async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {356const uri = args[0] as URI;357const editorService = accessor.get(IEditorService);358const activeEditorPane = editorService.activeEditorPane;359if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {360return;361}362363const item = activeEditorPane.getDiffElementViewModel(uri);364if (item && item instanceof SideBySideDiffElementViewModel) {365const original = item.original;366367const modifiedCellIndex = item.modifiedDocument.cells.findIndex(cell => cell.handle === item.modified.handle);368if (modifiedCellIndex === -1) {369return;370}371372item.mainDocumentTextModel.applyEdits([{373editType: CellEditType.Metadata, index: modifiedCellIndex, metadata: original.metadata374}], true, undefined, () => undefined, undefined, true);375}376}377});378379380registerAction2(class extends Action2 {381constructor() {382super(383{384id: 'notebook.diff.cell.revertMetadata',385title: revertMetadata,386icon: revertIcon,387f1: false,388menu: {389id: MenuId.NotebookDiffCellMetadataTitle,390when: NOTEBOOK_DIFF_CELL_PROPERTY391},392precondition: NOTEBOOK_DIFF_CELL_PROPERTY393}394);395}396run(accessor: ServicesAccessor, context?: DiffElementCellViewModelBase) {397if (!context) {398return;399}400401if (!(context instanceof SideBySideDiffElementViewModel)) {402return;403}404405const original = context.original;406const modified = context.modified;407408const modifiedCellIndex = context.mainDocumentTextModel.cells.indexOf(modified.textModel);409if (modifiedCellIndex === -1) {410return;411}412413const rawEdits: ICellEditOperation[] = [{ editType: CellEditType.Metadata, index: modifiedCellIndex, metadata: original.metadata }];414if (context.original.language && context.modified.language !== context.original.language) {415rawEdits.push({ editType: CellEditType.CellLanguage, index: modifiedCellIndex, language: context.original.language });416}417418context.modifiedDocument.applyEdits(rawEdits, true, undefined, () => undefined, undefined, true);419}420});421422// registerAction2(class extends Action2 {423// constructor() {424// super(425// {426// id: 'notebook.diff.cell.switchOutputRenderingStyle',427// title: localize('notebook.diff.cell.switchOutputRenderingStyle', "Switch Outputs Rendering"),428// icon: renderOutputIcon,429// f1: false,430// menu: {431// id: MenuId.NotebookDiffCellOutputsTitle432// }433// }434// );435// }436// run(accessor: ServicesAccessor, context?: DiffElementViewModelBase) {437// if (!context) {438// return;439// }440441// context.renderOutput = true;442// }443// });444445446registerAction2(class extends Action2 {447constructor() {448super(449{450id: 'notebook.diff.cell.switchOutputRenderingStyleToText',451title: localize('notebook.diff.cell.switchOutputRenderingStyleToText', "Switch Output Rendering"),452icon: renderOutputIcon,453f1: false,454menu: {455id: MenuId.NotebookDiffCellOutputsTitle,456when: NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED457}458}459);460}461run(accessor: ServicesAccessor, context?: DiffElementCellViewModelBase) {462if (!context) {463return;464}465466context.renderOutput = !context.renderOutput;467}468});469470registerAction2(class extends Action2 {471constructor() {472super(473{474id: 'notebook.diff.cell.revertOutputs',475title: localize('notebook.diff.cell.revertOutputs', "Revert Outputs"),476icon: revertIcon,477f1: false,478menu: {479id: MenuId.NotebookDiffCellOutputsTitle,480when: NOTEBOOK_DIFF_CELL_PROPERTY481},482precondition: NOTEBOOK_DIFF_CELL_PROPERTY483}484);485}486run(accessor: ServicesAccessor, context?: DiffElementCellViewModelBase) {487if (!context) {488return;489}490491if (!(context instanceof SideBySideDiffElementViewModel)) {492return;493}494495const original = context.original;496const modified = context.modified;497498const modifiedCellIndex = context.mainDocumentTextModel.cells.indexOf(modified.textModel);499if (modifiedCellIndex === -1) {500return;501}502503context.mainDocumentTextModel.applyEdits([{504editType: CellEditType.Output, index: modifiedCellIndex, outputs: original.outputs505}], true, undefined, () => undefined, undefined, true);506}507});508509510registerAction2(class extends Action2 {511constructor() {512super(513{514id: 'notebook.toggle.diff.cell.ignoreTrimWhitespace',515title: localize('ignoreTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"),516icon: toggleWhitespace,517f1: false,518menu: {519id: MenuId.NotebookDiffCellInputTitle,520when: NOTEBOOK_DIFF_CELL_INPUT,521order: 1,522},523precondition: NOTEBOOK_DIFF_CELL_INPUT,524toggled: ContextKeyExpr.equals(NOTEBOOK_DIFF_CELL_IGNORE_WHITESPACE_KEY, false),525}526);527}528run(accessor: ServicesAccessor, context?: DiffElementCellViewModelBase) {529const cell = context;530if (!cell?.modified) {531return;532}533const uri = cell.modified.uri;534const configService = accessor.get(ITextResourceConfigurationService);535const key = 'diffEditor.ignoreTrimWhitespace';536const val = configService.getValue(uri, key);537configService.updateValue(uri, key, !val);538}539});540541registerAction2(class extends Action2 {542constructor() {543super(544{545id: 'notebook.diff.cell.revertInput',546title: revertInput,547icon: revertIcon,548f1: false,549menu: {550id: MenuId.NotebookDiffCellInputTitle,551when: NOTEBOOK_DIFF_CELL_INPUT,552order: 2553},554precondition: NOTEBOOK_DIFF_CELL_INPUT555556}557);558}559run(accessor: ServicesAccessor, context?: DiffElementCellViewModelBase) {560if (!context) {561return;562}563564const original = context.original;565const modified = context.modified;566567if (!original || !modified) {568return;569}570571const bulkEditService = accessor.get(IBulkEditService);572return bulkEditService.apply([573new ResourceTextEdit(modified.uri, { range: modified.textModel.getFullModelRange(), text: original.textModel.getValue() }),574], { quotableLabel: 'Revert Notebook Cell Content Change' });575}576});577578class ToggleRenderAction extends Action2 {579constructor(id: string, title: string | ICommandActionTitle, precondition: ContextKeyExpression | undefined, toggled: ContextKeyExpression | undefined, order: number, private readonly toggleOutputs?: boolean, private readonly toggleMetadata?: boolean) {580super({581id: id,582title,583precondition: precondition,584menu: [{585id: MenuId.EditorTitle,586group: 'notebook',587when: precondition,588order: order,589}],590toggled: toggled591});592}593594async run(accessor: ServicesAccessor): Promise<void> {595const configurationService = accessor.get(IConfigurationService);596597if (this.toggleOutputs !== undefined) {598const oldValue = configurationService.getValue('notebook.diff.ignoreOutputs');599configurationService.updateValue('notebook.diff.ignoreOutputs', !oldValue);600}601602if (this.toggleMetadata !== undefined) {603const oldValue = configurationService.getValue('notebook.diff.ignoreMetadata');604configurationService.updateValue('notebook.diff.ignoreMetadata', !oldValue);605}606}607}608609registerAction2(class extends ToggleRenderAction {610constructor() {611super('notebook.diff.showOutputs',612localize2('notebook.diff.showOutputs', 'Show Outputs Differences'),613ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),614ContextKeyExpr.notEquals('config.notebook.diff.ignoreOutputs', true),6152,616true,617undefined618);619}620});621622registerAction2(class extends ToggleRenderAction {623constructor() {624super('notebook.diff.showMetadata',625localize2('notebook.diff.showMetadata', 'Show Metadata Differences'),626ContextKeyExpr.or(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID), ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID)),627ContextKeyExpr.notEquals('config.notebook.diff.ignoreMetadata', true),6281,629undefined,630true631);632}633});634635registerAction2(class extends Action2 {636constructor() {637super(638{639id: 'notebook.diff.action.previous',640title: localize('notebook.diff.action.previous.title', "Show Previous Change"),641icon: previousChangeIcon,642f1: false,643keybinding: {644primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F3,645weight: KeybindingWeight.WorkbenchContrib,646when: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID)647},648menu: {649id: MenuId.EditorTitle,650group: 'navigation',651when: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID)652}653}654);655}656run(accessor: ServicesAccessor) {657const editorService: IEditorService = accessor.get(IEditorService);658if (editorService.activeEditorPane?.getId() !== NOTEBOOK_DIFF_EDITOR_ID) {659return;660}661662const editor = editorService.activeEditorPane.getControl() as INotebookTextDiffEditor | undefined;663editor?.previousChange();664}665});666667registerAction2(class extends Action2 {668constructor() {669super(670{671id: 'notebook.diff.action.next',672title: localize('notebook.diff.action.next.title', "Show Next Change"),673icon: nextChangeIcon,674f1: false,675keybinding: {676primary: KeyMod.Alt | KeyCode.F3,677weight: KeybindingWeight.WorkbenchContrib,678when: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID)679},680menu: {681id: MenuId.EditorTitle,682group: 'navigation',683when: ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID)684}685}686);687}688run(accessor: ServicesAccessor) {689const editorService: IEditorService = accessor.get(IEditorService);690if (editorService.activeEditorPane?.getId() !== NOTEBOOK_DIFF_EDITOR_ID) {691return;692}693694const editor = editorService.activeEditorPane.getControl() as INotebookTextDiffEditor | undefined;695editor?.nextChange();696}697});698699registerAction2(class extends Action2 {700constructor() {701super(702{703id: 'notebook.diff.inline.toggle',704title: localize('notebook.diff.inline.toggle.title', "Toggle Inline View"),705menu: {706id: MenuId.EditorTitle,707group: '1_diff',708order: 10,709when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookTextDiffEditor.ID),710ContextKeyExpr.equals('config.notebook.diff.experimental.toggleInline', true),711ctxHasEditorModification.negate(), ctxHasRequestInProgress.negate())712}713}714);715}716run(accessor: ServicesAccessor) {717const editorService: IEditorService = accessor.get(IEditorService);718if (editorService.activeEditorPane?.getId() !== NOTEBOOK_DIFF_EDITOR_ID) {719return;720}721722const editor = editorService.activeEditorPane.getControl() as INotebookTextDiffEditor | undefined;723editor?.toggleInlineView();724}725});726727728729Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({730id: 'notebook',731order: 100,732type: 'object',733'properties': {734'notebook.diff.ignoreMetadata': {735type: 'boolean',736default: false,737markdownDescription: localize('notebook.diff.ignoreMetadata', "Hide Metadata Differences")738},739'notebook.diff.ignoreOutputs': {740type: 'boolean',741default: false,742markdownDescription: localize('notebook.diff.ignoreOutputs', "Hide Outputs Differences")743},744'notebook.diff.experimental.toggleInline': {745type: 'boolean',746default: typeof product.quality === 'string' && product.quality !== 'stable', // only enable as default in insiders747markdownDescription: localize('notebook.diff.toggleInline', "Enable the command to toggle the experimental notebook inline diff editor.")748},749}750});751752753