Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/widget/diffEditor/commands.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { getActiveElement } from '../../../../base/browser/dom.js';
7
import { Codicon } from '../../../../base/common/codicons.js';
8
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
9
import { ICodeEditor, IDiffEditor } from '../../editorBrowser.js';
10
import { EditorAction2, ServicesAccessor } from '../../editorExtensions.js';
11
import { ICodeEditorService } from '../../services/codeEditorService.js';
12
import { DiffEditorWidget } from './diffEditorWidget.js';
13
import { EditorContextKeys } from '../../../common/editorContextKeys.js';
14
import { localize2 } from '../../../../nls.js';
15
import { ILocalizedString } from '../../../../platform/action/common/action.js';
16
import { Action2, MenuId } from '../../../../platform/actions/common/actions.js';
17
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
18
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
19
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
20
import './registrations.contribution.js';
21
import { DiffEditorSelectionHunkToolbarContext } from './features/gutterFeature.js';
22
import { URI } from '../../../../base/common/uri.js';
23
import { EditorOption } from '../../../common/config/editorOptions.js';
24
25
export class ToggleCollapseUnchangedRegions extends Action2 {
26
constructor() {
27
super({
28
id: 'diffEditor.toggleCollapseUnchangedRegions',
29
title: localize2('toggleCollapseUnchangedRegions', 'Toggle Collapse Unchanged Regions'),
30
icon: Codicon.map,
31
toggled: ContextKeyExpr.has('config.diffEditor.hideUnchangedRegions.enabled'),
32
precondition: ContextKeyExpr.has('isInDiffEditor'),
33
menu: {
34
when: ContextKeyExpr.has('isInDiffEditor'),
35
id: MenuId.EditorTitle,
36
order: 22,
37
group: 'navigation',
38
},
39
});
40
}
41
42
run(accessor: ServicesAccessor, ...args: unknown[]): void {
43
const configurationService = accessor.get(IConfigurationService);
44
const newValue = !configurationService.getValue<boolean>('diffEditor.hideUnchangedRegions.enabled');
45
configurationService.updateValue('diffEditor.hideUnchangedRegions.enabled', newValue);
46
}
47
}
48
49
export class ToggleShowMovedCodeBlocks extends Action2 {
50
constructor() {
51
super({
52
id: 'diffEditor.toggleShowMovedCodeBlocks',
53
title: localize2('toggleShowMovedCodeBlocks', 'Toggle Show Moved Code Blocks'),
54
precondition: ContextKeyExpr.has('isInDiffEditor'),
55
});
56
}
57
58
run(accessor: ServicesAccessor, ...args: unknown[]): void {
59
const configurationService = accessor.get(IConfigurationService);
60
const newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');
61
configurationService.updateValue('diffEditor.experimental.showMoves', newValue);
62
}
63
}
64
65
export class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {
66
constructor() {
67
super({
68
id: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',
69
title: localize2('toggleUseInlineViewWhenSpaceIsLimited', 'Toggle Use Inline View When Space Is Limited'),
70
precondition: ContextKeyExpr.has('isInDiffEditor'),
71
});
72
}
73
74
run(accessor: ServicesAccessor, ...args: unknown[]): void {
75
const configurationService = accessor.get(IConfigurationService);
76
const newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');
77
configurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);
78
}
79
}
80
81
const diffEditorCategory: ILocalizedString = localize2('diffEditor', "Diff Editor");
82
83
export class SwitchSide extends EditorAction2 {
84
constructor() {
85
super({
86
id: 'diffEditor.switchSide',
87
title: localize2('switchSide', 'Switch Side'),
88
icon: Codicon.arrowSwap,
89
precondition: ContextKeyExpr.has('isInDiffEditor'),
90
f1: true,
91
category: diffEditorCategory,
92
});
93
}
94
95
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, arg?: { dryRun: boolean }): unknown {
96
const diffEditor = findFocusedDiffEditor(accessor);
97
if (diffEditor instanceof DiffEditorWidget) {
98
if (arg && arg.dryRun) {
99
return { destinationSelection: diffEditor.mapToOtherSide().destinationSelection };
100
} else {
101
diffEditor.switchSide();
102
}
103
}
104
return undefined;
105
}
106
}
107
export class ExitCompareMove extends EditorAction2 {
108
constructor() {
109
super({
110
id: 'diffEditor.exitCompareMove',
111
title: localize2('exitCompareMove', 'Exit Compare Move'),
112
icon: Codicon.close,
113
precondition: EditorContextKeys.comparingMovedCode,
114
f1: false,
115
category: diffEditorCategory,
116
keybinding: {
117
weight: 10000,
118
primary: KeyCode.Escape,
119
}
120
});
121
}
122
123
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
124
const diffEditor = findFocusedDiffEditor(accessor);
125
if (diffEditor instanceof DiffEditorWidget) {
126
diffEditor.exitCompareMove();
127
}
128
}
129
}
130
131
export class CollapseAllUnchangedRegions extends EditorAction2 {
132
constructor() {
133
super({
134
id: 'diffEditor.collapseAllUnchangedRegions',
135
title: localize2('collapseAllUnchangedRegions', 'Collapse All Unchanged Regions'),
136
icon: Codicon.fold,
137
precondition: ContextKeyExpr.has('isInDiffEditor'),
138
f1: true,
139
category: diffEditorCategory,
140
});
141
}
142
143
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
144
const diffEditor = findFocusedDiffEditor(accessor);
145
if (diffEditor instanceof DiffEditorWidget) {
146
diffEditor.collapseAllUnchangedRegions();
147
}
148
}
149
}
150
151
export class ShowAllUnchangedRegions extends EditorAction2 {
152
constructor() {
153
super({
154
id: 'diffEditor.showAllUnchangedRegions',
155
title: localize2('showAllUnchangedRegions', 'Show All Unchanged Regions'),
156
icon: Codicon.unfold,
157
precondition: ContextKeyExpr.has('isInDiffEditor'),
158
f1: true,
159
category: diffEditorCategory,
160
});
161
}
162
163
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
164
const diffEditor = findFocusedDiffEditor(accessor);
165
if (diffEditor instanceof DiffEditorWidget) {
166
diffEditor.showAllUnchangedRegions();
167
}
168
}
169
}
170
171
export class RevertHunkOrSelection extends Action2 {
172
constructor() {
173
super({
174
id: 'diffEditor.revert',
175
title: localize2('revert', 'Revert'),
176
f1: false,
177
category: diffEditorCategory,
178
});
179
}
180
181
run(accessor: ServicesAccessor, arg: DiffEditorSelectionHunkToolbarContext): unknown {
182
const diffEditor = findDiffEditor(accessor, arg.originalUri, arg.modifiedUri);
183
if (diffEditor instanceof DiffEditorWidget) {
184
diffEditor.revertRangeMappings(arg.mapping.innerChanges ?? []);
185
}
186
return undefined;
187
}
188
}
189
190
const accessibleDiffViewerCategory: ILocalizedString = localize2('accessibleDiffViewer', "Accessible Diff Viewer");
191
192
export class AccessibleDiffViewerNext extends Action2 {
193
public static id = 'editor.action.accessibleDiffViewer.next';
194
195
constructor() {
196
super({
197
id: AccessibleDiffViewerNext.id,
198
title: localize2('editor.action.accessibleDiffViewer.next', 'Go to Next Difference'),
199
category: accessibleDiffViewerCategory,
200
precondition: ContextKeyExpr.has('isInDiffEditor'),
201
keybinding: {
202
primary: KeyCode.F7,
203
weight: KeybindingWeight.EditorContrib
204
},
205
f1: true,
206
});
207
}
208
209
public override run(accessor: ServicesAccessor): void {
210
const diffEditor = findFocusedDiffEditor(accessor);
211
diffEditor?.accessibleDiffViewerNext();
212
}
213
}
214
215
export class AccessibleDiffViewerPrev extends Action2 {
216
public static id = 'editor.action.accessibleDiffViewer.prev';
217
218
constructor() {
219
super({
220
id: AccessibleDiffViewerPrev.id,
221
title: localize2('editor.action.accessibleDiffViewer.prev', 'Go to Previous Difference'),
222
category: accessibleDiffViewerCategory,
223
precondition: ContextKeyExpr.has('isInDiffEditor'),
224
keybinding: {
225
primary: KeyMod.Shift | KeyCode.F7,
226
weight: KeybindingWeight.EditorContrib
227
},
228
f1: true,
229
});
230
}
231
232
public override run(accessor: ServicesAccessor): void {
233
const diffEditor = findFocusedDiffEditor(accessor);
234
diffEditor?.accessibleDiffViewerPrev();
235
}
236
}
237
238
export function findDiffEditor(accessor: ServicesAccessor, originalUri: URI, modifiedUri: URI): IDiffEditor | null {
239
const codeEditorService = accessor.get(ICodeEditorService);
240
const diffEditors = codeEditorService.listDiffEditors();
241
242
return diffEditors.find(diffEditor => {
243
const modified = diffEditor.getModifiedEditor();
244
const original = diffEditor.getOriginalEditor();
245
246
return modified && modified.getModel()?.uri.toString() === modifiedUri.toString()
247
&& original && original.getModel()?.uri.toString() === originalUri.toString();
248
}) || null;
249
}
250
251
export function findFocusedDiffEditor(accessor: ServicesAccessor): IDiffEditor | null {
252
const codeEditorService = accessor.get(ICodeEditorService);
253
const diffEditors = codeEditorService.listDiffEditors();
254
255
const activeElement = getActiveElement();
256
if (activeElement) {
257
for (const d of diffEditors) {
258
const container = d.getContainerDomNode();
259
if (container.contains(activeElement)) {
260
return d;
261
}
262
}
263
}
264
265
return null;
266
}
267
268
269
/**
270
* If `editor` is the original or modified editor of a diff editor, it returns it.
271
* It returns null otherwise.
272
*/
273
export function findDiffEditorContainingCodeEditor(accessor: ServicesAccessor, editor: ICodeEditor): IDiffEditor | null {
274
if (!editor.getOption(EditorOption.inDiffEditor)) {
275
return null;
276
}
277
278
const codeEditorService = accessor.get(ICodeEditorService);
279
280
for (const diffEditor of codeEditorService.listDiffEditors()) {
281
const originalEditor = diffEditor.getOriginalEditor();
282
const modifiedEditor = diffEditor.getModifiedEditor();
283
if (originalEditor === editor || modifiedEditor === editor) {
284
return diffEditor;
285
}
286
}
287
return null;
288
}
289
290