-
Notifications
You must be signed in to change notification settings - Fork 30.3k
/
Copy pathcodeEditorService.ts
116 lines (97 loc) · 5.6 KB
/
codeEditorService.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICodeEditor, isCodeEditor, isDiffEditor, isCompositeEditor, getCodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { AbstractCodeEditorService } from '../../../../editor/browser/services/abstractCodeEditorService.js';
import { ScrollType } from '../../../../editor/common/editorCommon.js';
import { IResourceEditorInput } from '../../../../platform/editor/common/editor.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { IWorkbenchEditorConfiguration } from '../../../common/editor.js';
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../common/editorService.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { isEqual } from '../../../../base/common/resources.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { applyTextEditorOptions } from '../../../common/editor/editorOptions.js';
export class CodeEditorService extends AbstractCodeEditorService {
constructor(
@IEditorService private readonly editorService: IEditorService,
@IThemeService themeService: IThemeService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super(themeService);
this._register(this.registerCodeEditorOpenHandler(this.doOpenCodeEditor.bind(this)));
this._register(this.registerCodeEditorOpenHandler(this.doOpenCodeEditorFromDiff.bind(this)));
}
getActiveCodeEditor(): ICodeEditor | null {
const activeTextEditorControl = this.editorService.activeTextEditorControl;
if (isCodeEditor(activeTextEditorControl)) {
return activeTextEditorControl;
}
if (isDiffEditor(activeTextEditorControl)) {
return activeTextEditorControl.getModifiedEditor();
}
const activeControl = this.editorService.activeEditorPane?.getControl();
if (isCompositeEditor(activeControl) && isCodeEditor(activeControl.activeCodeEditor)) {
return activeControl.activeCodeEditor;
}
return null;
}
private async doOpenCodeEditorFromDiff(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> {
// Special case: If the active editor is a diff editor and the request to open originates and
// targets the modified side of it, we just apply the request there to prevent opening the modified
// side as separate editor.
const activeTextEditorControl = this.editorService.activeTextEditorControl;
if (
!sideBySide && // we need the current active group to be the target
isDiffEditor(activeTextEditorControl) && // we only support this for active text diff editors
input.options && // we need options to apply
input.resource && // we need a request resource to compare with
source === activeTextEditorControl.getModifiedEditor() && // we need the source of this request to be the modified side of the diff editor
activeTextEditorControl.getModel() && // we need a target model to compare with
isEqual(input.resource, activeTextEditorControl.getModel()?.modified.uri) // we need the input resources to match with modified side
) {
const targetEditor = activeTextEditorControl.getModifiedEditor();
applyTextEditorOptions(input.options, targetEditor, ScrollType.Smooth);
return targetEditor;
}
return null;
}
// Open using our normal editor service
private async doOpenCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> {
// Special case: we want to detect the request to open an editor that
// is different from the current one to decide whether the current editor
// should be pinned or not. This ensures that the source of a navigation
// is not being replaced by the target. An example is "Goto definition"
// that otherwise would replace the editor everytime the user navigates.
const enablePreviewFromCodeNavigation = this.configurationService.getValue<IWorkbenchEditorConfiguration>().workbench?.editor?.enablePreviewFromCodeNavigation;
if (
!enablePreviewFromCodeNavigation && // we only need to do this if the configuration requires it
source && // we need to know the origin of the navigation
!input.options?.pinned && // we only need to look at preview editors that open
!sideBySide && // we only need to care if editor opens in same group
!isEqual(source.getModel()?.uri, input.resource) // we only need to do this if the editor is about to change
) {
for (const visiblePane of this.editorService.visibleEditorPanes) {
if (getCodeEditor(visiblePane.getControl()) === source) {
visiblePane.group.pinEditor();
break;
}
}
}
// Open as editor
const control = await this.editorService.openEditor(input, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
if (control) {
const widget = control.getControl();
if (isCodeEditor(widget)) {
return widget;
}
if (isCompositeEditor(widget) && isCodeEditor(widget.activeCodeEditor)) {
return widget.activeCodeEditor;
}
}
return null;
}
}
registerSingleton(ICodeEditorService, CodeEditorService, InstantiationType.Delayed);