@opensumi/ide-editor 2.21.13 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/lib/browser/breadcrumb/default.js.map +1 -1
  2. package/lib/browser/breadcrumb/document-symbol.js.map +1 -1
  3. package/lib/browser/breadcrumb/index.js.map +1 -1
  4. package/lib/browser/component.js.map +1 -1
  5. package/lib/browser/decoration-applier.js.map +1 -1
  6. package/lib/browser/diff/compare.js.map +1 -1
  7. package/lib/browser/diff/index.d.ts.map +1 -1
  8. package/lib/browser/diff/index.js +1 -1
  9. package/lib/browser/diff/index.js.map +1 -1
  10. package/lib/browser/doc-cache/empty-doc-cache.js.map +1 -1
  11. package/lib/browser/doc-cache/local-storage-cache.js.map +1 -1
  12. package/lib/browser/doc-model/editor-document-model-service.js +3 -3
  13. package/lib/browser/doc-model/editor-document-model-service.js.map +1 -1
  14. package/lib/browser/doc-model/editor-document-model.d.ts +8 -0
  15. package/lib/browser/doc-model/editor-document-model.d.ts.map +1 -1
  16. package/lib/browser/doc-model/editor-document-model.js +61 -11
  17. package/lib/browser/doc-model/editor-document-model.js.map +1 -1
  18. package/lib/browser/doc-model/editor-document-registry.js.map +1 -1
  19. package/lib/browser/doc-model/override.js.map +1 -1
  20. package/lib/browser/doc-model/save-task.js +1 -1
  21. package/lib/browser/doc-model/save-task.js.map +1 -1
  22. package/lib/browser/doc-model/saveParticipants.d.ts +7 -7
  23. package/lib/browser/doc-model/saveParticipants.d.ts.map +1 -1
  24. package/lib/browser/doc-model/saveParticipants.js +69 -38
  25. package/lib/browser/doc-model/saveParticipants.js.map +1 -1
  26. package/lib/browser/doc-model/types.d.ts +1 -1
  27. package/lib/browser/doc-model/types.d.ts.map +1 -1
  28. package/lib/browser/editor-collection.service.d.ts +8 -3
  29. package/lib/browser/editor-collection.service.d.ts.map +1 -1
  30. package/lib/browser/editor-collection.service.js +75 -66
  31. package/lib/browser/editor-collection.service.js.map +1 -1
  32. package/lib/browser/editor-opener.js.map +1 -1
  33. package/lib/browser/editor.contribution.d.ts.map +1 -1
  34. package/lib/browser/editor.contribution.js +31 -3
  35. package/lib/browser/editor.contribution.js.map +1 -1
  36. package/lib/browser/editor.decoration.service.d.ts +5 -6
  37. package/lib/browser/editor.decoration.service.d.ts.map +1 -1
  38. package/lib/browser/editor.decoration.service.js +9 -1
  39. package/lib/browser/editor.decoration.service.js.map +1 -1
  40. package/lib/browser/editor.override.js +2 -2
  41. package/lib/browser/editor.override.js.map +1 -1
  42. package/lib/browser/editor.status-bar.service.js.map +1 -1
  43. package/lib/browser/editor.view.d.ts.map +1 -1
  44. package/lib/browser/editor.view.js +20 -23
  45. package/lib/browser/editor.view.js.map +1 -1
  46. package/lib/browser/error.d.ts +1 -1
  47. package/lib/browser/error.d.ts.map +1 -1
  48. package/lib/browser/feature.js.map +1 -1
  49. package/lib/browser/format/format.service.js.map +1 -1
  50. package/lib/browser/format/formatterSelect.js.map +1 -1
  51. package/lib/browser/fs-resource/file-tree-set.js +6 -6
  52. package/lib/browser/fs-resource/file-tree-set.js.map +1 -1
  53. package/lib/browser/fs-resource/fs-editor-doc.js +1 -1
  54. package/lib/browser/fs-resource/fs-editor-doc.js.map +1 -1
  55. package/lib/browser/fs-resource/fs-resource.js.map +1 -1
  56. package/lib/browser/fs-resource/index.js.map +1 -1
  57. package/lib/browser/history/index.d.ts.map +1 -1
  58. package/lib/browser/history/index.js +2 -1
  59. package/lib/browser/history/index.js.map +1 -1
  60. package/lib/browser/index.d.ts.map +1 -1
  61. package/lib/browser/index.js +2 -0
  62. package/lib/browser/index.js.map +1 -1
  63. package/lib/browser/language/diagnostic-collection.d.ts +5 -5
  64. package/lib/browser/language/diagnostic-collection.d.ts.map +1 -1
  65. package/lib/browser/language/diagnostic-collection.js +1 -1
  66. package/lib/browser/language/diagnostic-collection.js.map +1 -1
  67. package/lib/browser/language/language-status.contribution.js.map +1 -1
  68. package/lib/browser/language/language-status.service.js.map +1 -1
  69. package/lib/browser/language/language.service.d.ts +4 -3
  70. package/lib/browser/language/language.service.d.ts.map +1 -1
  71. package/lib/browser/language/language.service.js +8 -2
  72. package/lib/browser/language/language.service.js.map +1 -1
  73. package/lib/browser/menu/editor.context.js +3 -3
  74. package/lib/browser/menu/editor.context.js.map +1 -1
  75. package/lib/browser/menu/editor.menu.d.ts +2 -2
  76. package/lib/browser/menu/editor.menu.d.ts.map +1 -1
  77. package/lib/browser/menu/editor.menu.js +6 -8
  78. package/lib/browser/menu/editor.menu.js.map +1 -1
  79. package/lib/browser/menu/open-type-menu.contribution.js +9 -9
  80. package/lib/browser/menu/open-type-menu.contribution.js.map +1 -1
  81. package/lib/browser/menu/title-context.menu.js.map +1 -1
  82. package/lib/browser/merge-editor/merge-editor.contribution.d.ts +8 -0
  83. package/lib/browser/merge-editor/merge-editor.contribution.d.ts.map +1 -0
  84. package/lib/browser/merge-editor/merge-editor.contribution.js +29 -0
  85. package/lib/browser/merge-editor/merge-editor.contribution.js.map +1 -0
  86. package/lib/browser/merge-editor/merge-editor.provider.d.ts +8 -0
  87. package/lib/browser/merge-editor/merge-editor.provider.d.ts.map +1 -0
  88. package/lib/browser/merge-editor/merge-editor.provider.js +44 -0
  89. package/lib/browser/merge-editor/merge-editor.provider.js.map +1 -0
  90. package/lib/browser/monaco-contrib/callHierarchy/callHierarchy.contribution.js.map +1 -1
  91. package/lib/browser/monaco-contrib/callHierarchy/callHierarchy.service.js +7 -7
  92. package/lib/browser/monaco-contrib/callHierarchy/callHierarchy.service.js.map +1 -1
  93. package/lib/browser/monaco-contrib/command/command.service.d.ts +1 -1
  94. package/lib/browser/monaco-contrib/command/command.service.d.ts.map +1 -1
  95. package/lib/browser/monaco-contrib/command/command.service.js.map +1 -1
  96. package/lib/browser/monaco-contrib/tokenizer/textmate-registry.js.map +1 -1
  97. package/lib/browser/monaco-contrib/tokenizer/textmate.service.d.ts +2 -1
  98. package/lib/browser/monaco-contrib/tokenizer/textmate.service.d.ts.map +1 -1
  99. package/lib/browser/monaco-contrib/tokenizer/textmate.service.js +5 -2
  100. package/lib/browser/monaco-contrib/tokenizer/textmate.service.js.map +1 -1
  101. package/lib/browser/monaco-contrib/typeHierarchy/typeHierarchy.contribution.js.map +1 -1
  102. package/lib/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.js +7 -7
  103. package/lib/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.js.map +1 -1
  104. package/lib/browser/navigation.module.less +1 -1
  105. package/lib/browser/navigation.view.d.ts.map +1 -1
  106. package/lib/browser/navigation.view.js +26 -15
  107. package/lib/browser/navigation.view.js.map +1 -1
  108. package/lib/browser/preference/contribution.js.map +1 -1
  109. package/lib/browser/preference/converter.d.ts +3 -3
  110. package/lib/browser/preference/converter.d.ts.map +1 -1
  111. package/lib/browser/preference/schema.d.ts +1 -1
  112. package/lib/browser/preference/schema.d.ts.map +1 -1
  113. package/lib/browser/preference/schema.js +8 -8
  114. package/lib/browser/preference/schema.js.map +1 -1
  115. package/lib/browser/quick-open/go-to-line.js.map +1 -1
  116. package/lib/browser/quick-open/workspace-symbol-quickopen.d.ts.map +1 -1
  117. package/lib/browser/quick-open/workspace-symbol-quickopen.js +2 -2
  118. package/lib/browser/quick-open/workspace-symbol-quickopen.js.map +1 -1
  119. package/lib/browser/resource.service.js.map +1 -1
  120. package/lib/browser/tab.view.d.ts +1 -1
  121. package/lib/browser/tab.view.d.ts.map +1 -1
  122. package/lib/browser/tab.view.js +2 -2
  123. package/lib/browser/tab.view.js.map +1 -1
  124. package/lib/browser/types.d.ts +5 -5
  125. package/lib/browser/types.d.ts.map +1 -1
  126. package/lib/browser/untitled-resource.js +1 -1
  127. package/lib/browser/untitled-resource.js.map +1 -1
  128. package/lib/browser/view/suggest-widget.js.map +1 -1
  129. package/lib/browser/workbench-editor.service.d.ts +17 -0
  130. package/lib/browser/workbench-editor.service.d.ts.map +1 -1
  131. package/lib/browser/workbench-editor.service.js +259 -176
  132. package/lib/browser/workbench-editor.service.js.map +1 -1
  133. package/lib/common/doc-cache.d.ts +2 -2
  134. package/lib/common/doc-cache.d.ts.map +1 -1
  135. package/lib/common/editor.d.ts +20 -6
  136. package/lib/common/editor.d.ts.map +1 -1
  137. package/lib/common/editor.js +12 -1
  138. package/lib/common/editor.js.map +1 -1
  139. package/lib/common/language.d.ts +18 -7
  140. package/lib/common/language.d.ts.map +1 -1
  141. package/lib/common/language.js +15 -7
  142. package/lib/common/language.js.map +1 -1
  143. package/lib/common/mocks/workbench-editor.service.js.map +1 -1
  144. package/lib/common/resource.d.ts +8 -2
  145. package/lib/common/resource.d.ts.map +1 -1
  146. package/lib/common/resource.js +1 -0
  147. package/lib/common/resource.js.map +1 -1
  148. package/package.json +17 -16
  149. package/src/browser/breadcrumb/default.ts +299 -0
  150. package/src/browser/breadcrumb/document-symbol.ts +187 -0
  151. package/src/browser/breadcrumb/index.ts +96 -0
  152. package/src/browser/component.ts +204 -0
  153. package/src/browser/decoration-applier.ts +256 -0
  154. package/src/browser/diff/compare.ts +99 -0
  155. package/src/browser/diff/index.ts +81 -0
  156. package/src/browser/doc-cache/empty-doc-cache.ts +26 -0
  157. package/src/browser/doc-cache/index.ts +2 -0
  158. package/src/browser/doc-cache/local-storage-cache.ts +67 -0
  159. package/src/browser/doc-model/editor-document-error.ts +10 -0
  160. package/src/browser/doc-model/editor-document-model-service.ts +346 -0
  161. package/src/browser/doc-model/editor-document-model.ts +690 -0
  162. package/src/browser/doc-model/editor-document-registry.ts +119 -0
  163. package/src/browser/doc-model/editor-is-fn.ts +9 -0
  164. package/src/browser/doc-model/main.ts +4 -0
  165. package/src/browser/doc-model/override.ts +49 -0
  166. package/src/browser/doc-model/save-task.ts +88 -0
  167. package/src/browser/doc-model/saveParticipants.ts +227 -0
  168. package/src/browser/doc-model/types.ts +350 -0
  169. package/src/browser/editor-collection.service.ts +790 -0
  170. package/src/browser/editor-opener.ts +44 -0
  171. package/src/browser/editor.contribution.ts +1438 -0
  172. package/src/browser/editor.decoration.service.ts +247 -0
  173. package/src/browser/editor.less +4 -0
  174. package/src/browser/editor.module.less +548 -0
  175. package/src/browser/editor.override.ts +133 -0
  176. package/src/browser/editor.status-bar.service.ts +116 -0
  177. package/src/browser/editor.view.tsx +623 -0
  178. package/src/browser/error.ts +21 -0
  179. package/src/browser/feature.ts +63 -0
  180. package/src/browser/format/format.service.ts +95 -0
  181. package/src/browser/format/formatterSelect.ts +82 -0
  182. package/src/browser/fs-resource/file-tree-set.ts +126 -0
  183. package/src/browser/fs-resource/fs-editor-doc.ts +213 -0
  184. package/src/browser/fs-resource/fs-resource.ts +247 -0
  185. package/src/browser/fs-resource/index.ts +27 -0
  186. package/src/browser/grid/grid.service.ts +288 -0
  187. package/src/browser/history/index.ts +228 -0
  188. package/src/browser/index.ts +236 -0
  189. package/src/browser/language/diagnostic-collection.ts +83 -0
  190. package/src/browser/language/language-status.contribution.ts +81 -0
  191. package/src/browser/language/language-status.service.ts +32 -0
  192. package/src/browser/language/language.service.ts +185 -0
  193. package/src/browser/menu/editor.context.ts +186 -0
  194. package/src/browser/menu/editor.menu.ts +45 -0
  195. package/src/browser/menu/open-type-menu.contribution.ts +90 -0
  196. package/src/browser/menu/title-context.menu.ts +54 -0
  197. package/src/browser/merge-editor/merge-editor.contribution.ts +25 -0
  198. package/src/browser/merge-editor/merge-editor.provider.ts +36 -0
  199. package/src/browser/monaco-contrib/callHierarchy/callHierarchy.contribution.ts +78 -0
  200. package/src/browser/monaco-contrib/callHierarchy/callHierarchy.service.ts +160 -0
  201. package/src/browser/monaco-contrib/command/command.service.ts +438 -0
  202. package/src/browser/monaco-contrib/index.ts +4 -0
  203. package/src/browser/monaco-contrib/tokenizer/textmate-registry.ts +107 -0
  204. package/src/browser/monaco-contrib/tokenizer/textmate-tokenizer.ts +104 -0
  205. package/src/browser/monaco-contrib/tokenizer/textmate.service.ts +925 -0
  206. package/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.contribution.ts +78 -0
  207. package/src/browser/monaco-contrib/typeHierarchy/typeHierarchy.service.ts +154 -0
  208. package/src/browser/navigation.module.less +96 -0
  209. package/src/browser/navigation.view.tsx +254 -0
  210. package/src/browser/preference/contribution.ts +8 -0
  211. package/src/browser/preference/converter.ts +793 -0
  212. package/src/browser/preference/schema.ts +1896 -0
  213. package/src/browser/preference/util.ts +14 -0
  214. package/src/browser/quick-open/go-to-line.ts +164 -0
  215. package/src/browser/quick-open/workspace-symbol-quickopen.ts +276 -0
  216. package/src/browser/resource.service.ts +263 -0
  217. package/src/browser/tab.view.tsx +514 -0
  218. package/src/browser/types.ts +467 -0
  219. package/src/browser/untitled-resource.ts +223 -0
  220. package/src/browser/view/editor.react.tsx +82 -0
  221. package/src/browser/view/react-hook.tsx +7 -0
  222. package/src/browser/view/suggest-widget.ts +77 -0
  223. package/src/browser/view/topPadding.ts +18 -0
  224. package/src/browser/workbench-editor.service.ts +2291 -0
  225. package/src/common/doc-cache.ts +117 -0
  226. package/src/common/editor.ts +799 -0
  227. package/src/common/index.ts +6 -0
  228. package/src/common/language-status.ts +33 -0
  229. package/src/common/language.ts +206 -0
  230. package/src/common/mocks/workbench-editor.service.ts +52 -0
  231. package/src/common/resource.ts +147 -0
  232. package/src/common/utils.ts +10 -0
  233. package/src/index.ts +1 -0
  234. package/lib/browser/component/scroll/scroll.d.ts +0 -2
  235. package/lib/browser/component/scroll/scroll.d.ts.map +0 -1
  236. package/lib/browser/component/scroll/scroll.js +0 -5
  237. package/lib/browser/component/scroll/scroll.js.map +0 -1
  238. package/lib/browser/component/scroll/scroll.module.less +0 -86
@@ -0,0 +1,514 @@
1
+ import classnames from 'classnames';
2
+ import React, {
3
+ useEffect,
4
+ useState,
5
+ useCallback,
6
+ useRef,
7
+ useContext,
8
+ useMemo,
9
+ forwardRef,
10
+ DragEvent,
11
+ HTMLAttributes,
12
+ Ref,
13
+ MouseEvent,
14
+ } from 'react';
15
+
16
+ import { Scrollbars } from '@opensumi/ide-components';
17
+ import {
18
+ getIcon,
19
+ MaybeNull,
20
+ IEventBus,
21
+ getSlotLocation,
22
+ ConfigContext,
23
+ ResizeEvent,
24
+ URI,
25
+ Disposable,
26
+ DomListener,
27
+ PreferenceService,
28
+ DisposableCollection,
29
+ Event,
30
+ } from '@opensumi/ide-core-browser';
31
+ import { InlineMenuBar } from '@opensumi/ide-core-browser/lib/components/actions';
32
+ import { LAYOUT_VIEW_SIZE } from '@opensumi/ide-core-browser/lib/layout/constants';
33
+ import { VIEW_CONTAINERS } from '@opensumi/ide-core-browser/lib/layout/view-id';
34
+ import { IMenuRegistry, MenuId } from '@opensumi/ide-core-browser/lib/menu/next';
35
+ import { useInjectable, useUpdateOnEventBusEvent } from '@opensumi/ide-core-browser/lib/react-hooks';
36
+
37
+ import { IResource, ResourceService, IEditorGroup, WorkbenchEditorService, ResourceDidUpdateEvent } from '../common';
38
+
39
+ import styles from './editor.module.less';
40
+ import { TabTitleMenuService } from './menu/title-context.menu';
41
+ import { GridResizeEvent, IEditorActionRegistry, DragOverPosition, EditorGroupFileDropEvent } from './types';
42
+ import { useUpdateOnGroupTabChange } from './view/react-hook';
43
+ import { EditorGroup, WorkbenchEditorServiceImpl } from './workbench-editor.service';
44
+
45
+ const pkgName = require('../../package.json').name;
46
+
47
+ export interface ITabsProps {
48
+ group: EditorGroup;
49
+ }
50
+
51
+ export const Tabs = ({ group }: ITabsProps) => {
52
+ const tabContainer = useRef<HTMLDivElement | null>();
53
+ const tabWrapperRef = useRef<HTMLDivElement | null>();
54
+ const contentRef = useRef<HTMLDivElement | null>();
55
+ const editorActionUpdateTimer = useRef<any>(null);
56
+ const editorActionRef = useRef<typeof EditorActions>(null);
57
+ const resourceService = useInjectable(ResourceService) as ResourceService;
58
+ const eventBus = useInjectable(IEventBus) as IEventBus;
59
+ const configContext = useContext(ConfigContext);
60
+ const editorService: WorkbenchEditorServiceImpl = useInjectable(WorkbenchEditorService);
61
+ const tabTitleMenuService = useInjectable(TabTitleMenuService) as TabTitleMenuService;
62
+ const preferenceService = useInjectable<PreferenceService>(PreferenceService);
63
+ const menuRegistry = useInjectable<IMenuRegistry>(IMenuRegistry);
64
+
65
+ const [tabsLoadingMap, setTabsLoadingMap] = useState<{ [resource: string]: boolean }>({});
66
+ const [wrapMode, setWrapMode] = useState<boolean>(!!preferenceService.get<boolean>('editor.wrapTab'));
67
+ const [tabMap, setTabMap] = useState<Map<number, boolean>>(new Map());
68
+ const [lastMarginRight, setLastMarginRight] = useState<number | undefined>();
69
+
70
+ const slotLocation = useMemo(() => getSlotLocation(pkgName, configContext.layoutConfig), []);
71
+
72
+ useUpdateOnGroupTabChange(group);
73
+ useUpdateOnEventBusEvent(
74
+ ResourceDidUpdateEvent,
75
+ [group.resources],
76
+ (uri) => !!contentRef && group.resources.findIndex((r) => r.uri.isEqual(uri)) !== -1,
77
+ );
78
+
79
+ useEffect(() => {
80
+ const disposer = new Disposable();
81
+ disposer.addDispose(
82
+ group.onDidEditorGroupContentLoading((resource) => {
83
+ group.resourceStatus.get(resource)?.finally(() => {
84
+ setTabsLoadingMap(
85
+ Object.assign({}, tabsLoadingMap, {
86
+ [resource.uri.toString()]: false,
87
+ }),
88
+ );
89
+ });
90
+ setTabsLoadingMap(
91
+ Object.assign({}, tabsLoadingMap, {
92
+ [resource.uri.toString()]: true,
93
+ }),
94
+ );
95
+ }),
96
+ );
97
+ disposer.addDispose(
98
+ group.onDidEditorGroupTabChanged(() => {
99
+ if (!wrapMode) {
100
+ scrollToCurrent();
101
+ }
102
+ }),
103
+ );
104
+ return () => {
105
+ disposer.dispose();
106
+ };
107
+ }, [group]);
108
+
109
+ const onDrop = useCallback(
110
+ (e: DragEvent, index: number, target?: IResource) => {
111
+ if (e.dataTransfer.getData('uri')) {
112
+ const uri = new URI(e.dataTransfer.getData('uri'));
113
+ let sourceGroup: EditorGroup | undefined;
114
+ if (e.dataTransfer.getData('uri-source-group')) {
115
+ sourceGroup = editorService.getEditorGroup(e.dataTransfer.getData('uri-source-group'));
116
+ }
117
+ group.dropUri(uri, DragOverPosition.CENTER, sourceGroup, target);
118
+ }
119
+ if (e.dataTransfer.files.length > 0) {
120
+ eventBus.fire(
121
+ new EditorGroupFileDropEvent({
122
+ group,
123
+ tabIndex: index,
124
+ files: e.dataTransfer.files,
125
+ }),
126
+ );
127
+ }
128
+ },
129
+ [group],
130
+ );
131
+
132
+ const scrollToCurrent = useCallback(() => {
133
+ if (tabContainer.current) {
134
+ if (group.currentResource) {
135
+ try {
136
+ const currentTab = tabContainer.current.querySelector(
137
+ '.' + styles.kt_editor_tab + "[data-uri='" + group.currentResource.uri.toString() + "']",
138
+ );
139
+ if (currentTab) {
140
+ currentTab.scrollIntoView();
141
+ }
142
+ } catch (e) {
143
+ // noop
144
+ }
145
+ }
146
+ }
147
+ }, [group, tabContainer.current]);
148
+
149
+ const updateTabMarginRight = useCallback(() => {
150
+ if (editorActionUpdateTimer.current) {
151
+ clearTimeout(editorActionUpdateTimer.current);
152
+ editorActionUpdateTimer.current = null;
153
+ }
154
+ const timer = setTimeout(() => {
155
+ if (editorActionRef.current?.offsetWidth !== lastMarginRight) {
156
+ setLastMarginRight(editorActionRef.current?.offsetWidth);
157
+ }
158
+ }, 200);
159
+ editorActionUpdateTimer.current = timer;
160
+ }, [editorActionRef.current, editorActionUpdateTimer.current, lastMarginRight]);
161
+
162
+ useEffect(() => {
163
+ if (!wrapMode) {
164
+ queueMicrotask(() => {
165
+ scrollToCurrent();
166
+ });
167
+ }
168
+ }, [wrapMode, tabContainer.current]);
169
+
170
+ useEffect(() => {
171
+ if (!wrapMode) {
172
+ const disposer = new Disposable();
173
+ if (tabContainer.current) {
174
+ disposer.addDispose(new DomListener(tabContainer.current, 'mousewheel', preventNavigation));
175
+ }
176
+ disposer.addDispose(
177
+ eventBus.on(ResizeEvent, (event) => {
178
+ if (event.payload.slotLocation === slotLocation) {
179
+ scrollToCurrent();
180
+ }
181
+ }),
182
+ );
183
+ disposer.addDispose(
184
+ eventBus.on(GridResizeEvent, (event) => {
185
+ if (event.payload.gridId === group.grid.uid) {
186
+ scrollToCurrent();
187
+ }
188
+ }),
189
+ );
190
+ return () => {
191
+ disposer.dispose();
192
+ };
193
+ }
194
+ }, [wrapMode]);
195
+
196
+ const layoutLastInRow = useCallback(() => {
197
+ if (contentRef.current && wrapMode) {
198
+ const newMap: Map<number, boolean> = new Map();
199
+
200
+ let currentTabY: number | undefined;
201
+ let lastTab: HTMLDivElement | undefined;
202
+ const tabs = Array.from(contentRef.current.children);
203
+ // 最后一个元素是editorAction
204
+ tabs.pop();
205
+ tabs.forEach((child: HTMLDivElement) => {
206
+ if (child.offsetTop !== currentTabY) {
207
+ currentTabY = child.offsetTop;
208
+ if (lastTab) {
209
+ newMap.set(tabs.indexOf(lastTab), true);
210
+ }
211
+ }
212
+ lastTab = child;
213
+ newMap.set(tabs.indexOf(child), false);
214
+ });
215
+ // 最后一个 tab 不做 grow 处理
216
+ setTabMap(newMap);
217
+ }
218
+ }, [contentRef.current, wrapMode]);
219
+
220
+ useEffect(() => {
221
+ updateTabMarginRight();
222
+ }, [editorActionRef.current, wrapMode]);
223
+
224
+ useEffect(layoutLastInRow, [wrapMode, contentRef.current, group, group.resources.length]);
225
+ useEffect(() => {
226
+ const disposable = new DisposableCollection();
227
+ disposable.push(
228
+ eventBus.on(ResizeEvent, (e) => {
229
+ if (e.payload.slotLocation === slotLocation) {
230
+ layoutLastInRow();
231
+ }
232
+ }),
233
+ );
234
+ disposable.push(
235
+ preferenceService.onPreferenceChanged((e) => {
236
+ if (e.preferenceName === 'editor.wrapTab') {
237
+ setWrapMode(!!e.newValue);
238
+ }
239
+ }),
240
+ );
241
+ // 当前选中的group变化时宽度变化
242
+ disposable.push(
243
+ editorService.onDidCurrentEditorGroupChanged(() => {
244
+ window.requestAnimationFrame(updateTabMarginRight);
245
+ }),
246
+ );
247
+ // editorMenu变化时宽度可能变化
248
+ disposable.push(
249
+ Event.debounce(
250
+ Event.filter(menuRegistry.onDidChangeMenu, (menuId) => menuId === MenuId.EditorTitle),
251
+ () => {},
252
+ 200,
253
+ )(() => {
254
+ window.requestAnimationFrame(updateTabMarginRight);
255
+ }),
256
+ );
257
+
258
+ return () => {
259
+ disposable.dispose();
260
+ };
261
+ }, []);
262
+
263
+ useEffect(() => {
264
+ const disposableCollection = new DisposableCollection();
265
+ disposableCollection.push(
266
+ group.onDidEditorFocusChange((event) => {
267
+ updateTabMarginRight();
268
+ }),
269
+ );
270
+ return () => {
271
+ disposableCollection.dispose();
272
+ };
273
+ }, [group]);
274
+
275
+ const handleWrapperDragOver = useCallback(
276
+ (e: DragEvent) => {
277
+ e.preventDefault();
278
+ e.stopPropagation();
279
+ if (tabWrapperRef.current) {
280
+ tabWrapperRef.current.classList.add(styles.kt_on_drag_over);
281
+ }
282
+ },
283
+ [tabWrapperRef.current],
284
+ );
285
+
286
+ const handleWrapperDragLeave = useCallback(
287
+ (e: DragEvent) => {
288
+ if (tabWrapperRef.current) {
289
+ tabWrapperRef.current.classList.remove(styles.kt_on_drag_over);
290
+ }
291
+ },
292
+ [tabWrapperRef.current],
293
+ );
294
+
295
+ const handleWrapperDrag = useCallback(
296
+ (e: DragEvent) => {
297
+ if (tabWrapperRef.current) {
298
+ tabWrapperRef.current.classList.remove(styles.kt_on_drag_over);
299
+ }
300
+ if (onDrop) {
301
+ onDrop(e, -1);
302
+ }
303
+ },
304
+ [onDrop, tabWrapperRef.current],
305
+ );
306
+
307
+ const handleEmptyDBClick = useCallback(
308
+ (e: MouseEvent) => {
309
+ if (e.target === e.currentTarget) {
310
+ editorService.createUntitledResource();
311
+ }
312
+ },
313
+ [editorService],
314
+ );
315
+
316
+ const renderTabContent = () => (
317
+ <div className={styles.kt_editor_tabs_content} ref={contentRef as any}>
318
+ {group.resources.map((resource, i) => {
319
+ let ref: HTMLDivElement | null;
320
+ const decoration = resourceService.getResourceDecoration(resource.uri);
321
+ const subname = resourceService.getResourceSubname(resource, group.resources);
322
+ return (
323
+ <div
324
+ draggable={true}
325
+ className={classnames({
326
+ [styles.kt_editor_tab]: true,
327
+ [styles.last_in_row]: tabMap.get(i),
328
+ [styles.kt_editor_tab_current]: group.currentResource === resource,
329
+ [styles.kt_editor_tab_preview]: group.previewURI && group.previewURI.isEqual(resource.uri),
330
+ })}
331
+ style={
332
+ wrapMode && i === group.resources.length - 1
333
+ ? { marginRight: lastMarginRight, height: LAYOUT_VIEW_SIZE.EDITOR_TABS_HEIGHT }
334
+ : { height: LAYOUT_VIEW_SIZE.EDITOR_TABS_HEIGHT }
335
+ }
336
+ onContextMenu={(event) => {
337
+ tabTitleMenuService.show(event.nativeEvent.x, event.nativeEvent.y, resource && resource.uri, group);
338
+ event.preventDefault();
339
+ }}
340
+ key={resource.uri.toString()}
341
+ onMouseUp={(e) => {
342
+ if (e.nativeEvent.which === 2) {
343
+ e.preventDefault();
344
+ e.stopPropagation();
345
+ group.close(resource.uri);
346
+ }
347
+ }}
348
+ onMouseDown={(e) => {
349
+ if (e.nativeEvent.which === 1) {
350
+ group.open(resource.uri, { focus: true });
351
+ }
352
+ }}
353
+ data-uri={resource.uri.toString()}
354
+ onDragOver={(e) => {
355
+ e.preventDefault();
356
+ e.stopPropagation();
357
+ if (ref) {
358
+ ref.classList.add(styles.kt_on_drag_over);
359
+ }
360
+ }}
361
+ onDragLeave={(e) => {
362
+ if (ref) {
363
+ ref.classList.remove(styles.kt_on_drag_over);
364
+ }
365
+ }}
366
+ onDrop={(e) => {
367
+ if (ref) {
368
+ ref.classList.remove(styles.kt_on_drag_over);
369
+ }
370
+ if (onDrop) {
371
+ onDrop(e, i, resource);
372
+ }
373
+ }}
374
+ onDoubleClick={(e) => {
375
+ group.pinPreviewed(resource.uri);
376
+ }}
377
+ ref={(el) => (ref = el)}
378
+ onDragStart={(e) => {
379
+ e.dataTransfer.setData('uri', resource.uri.toString());
380
+ e.dataTransfer.setData('uri-source-group', group.name);
381
+ }}
382
+ >
383
+ <div className={tabsLoadingMap[resource.uri.toString()] ? 'loading_indicator' : classnames(resource.icon)}>
384
+ {' '}
385
+ </div>
386
+ <div>{resource.name}</div>
387
+ {subname ? <div className={styles.subname}>{subname}</div> : null}
388
+ <div className={styles.tab_right}>
389
+ <div
390
+ className={classnames({
391
+ [styles.kt_hidden]: !decoration.dirty,
392
+ [styles.dirty]: true,
393
+ })}
394
+ ></div>
395
+ <div
396
+ className={styles.close_tab}
397
+ onMouseDown={(e) => {
398
+ e.stopPropagation();
399
+ group.close(resource.uri);
400
+ }}
401
+ >
402
+ <div className={classnames(getIcon('close'), styles.kt_editor_close_icon)} />
403
+ </div>
404
+ </div>
405
+ </div>
406
+ );
407
+ })}
408
+ {wrapMode && <EditorActions className={styles.kt_editor_wrap_mode_action} ref={editorActionRef} group={group} />}
409
+ </div>
410
+ );
411
+
412
+ return (
413
+ <div id={VIEW_CONTAINERS.EDITOR_TABS} className={styles.kt_editor_tabs}>
414
+ <div
415
+ className={styles.kt_editor_tabs_scroll_wrapper}
416
+ ref={tabWrapperRef as any}
417
+ onDragOver={handleWrapperDragOver}
418
+ onDragLeave={handleWrapperDragLeave}
419
+ onDrop={handleWrapperDrag}
420
+ onDoubleClick={handleEmptyDBClick}
421
+ >
422
+ {!wrapMode ? (
423
+ <Scrollbars
424
+ tabBarMode
425
+ forwardedRef={(el) => (el ? (tabContainer.current = el) : null)}
426
+ className={styles.kt_editor_tabs_scroll}
427
+ >
428
+ {renderTabContent()}
429
+ </Scrollbars>
430
+ ) : (
431
+ <div className={styles.kt_editor_wrap_container}>{renderTabContent()}</div>
432
+ )}
433
+ </div>
434
+ {!wrapMode && <EditorActions ref={editorActionRef} group={group} />}
435
+ </div>
436
+ );
437
+ };
438
+
439
+ export interface IEditorActionsBaseProps {
440
+ group: EditorGroup;
441
+ className?: string;
442
+ }
443
+
444
+ export type IEditorActionsProps = IEditorActionsBaseProps & HTMLAttributes<HTMLDivElement>;
445
+
446
+ export const EditorActions = forwardRef<HTMLDivElement, IEditorActionsProps>(
447
+ (props: IEditorActionsProps, ref: Ref<typeof EditorActions>) => {
448
+ const { group, className } = props;
449
+
450
+ const acquireArgs = useCallback(
451
+ () =>
452
+ (group.currentResource
453
+ ? [
454
+ group.currentResource.uri,
455
+ group,
456
+ group.currentOrPreviousFocusedEditor?.currentUri || group.currentEditor?.currentUri,
457
+ ]
458
+ : undefined) as [URI, IEditorGroup, MaybeNull<URI>] | undefined,
459
+ [group],
460
+ );
461
+
462
+ const editorActionRegistry = useInjectable<IEditorActionRegistry>(IEditorActionRegistry);
463
+ const editorService: WorkbenchEditorServiceImpl = useInjectable(WorkbenchEditorService);
464
+ const menu = editorActionRegistry.getMenu(group);
465
+ const [hasFocus, setHasFocus] = useState<boolean>(editorService.currentEditorGroup === group);
466
+ const [args, setArgs] = useState<[URI, IEditorGroup, MaybeNull<URI>] | undefined>(acquireArgs());
467
+
468
+ useEffect(() => {
469
+ const disposableCollection = new DisposableCollection();
470
+ disposableCollection.push(
471
+ editorService.onDidCurrentEditorGroupChanged(() => {
472
+ setHasFocus(editorService.currentEditorGroup === group);
473
+ }),
474
+ );
475
+ disposableCollection.push(
476
+ editorService.onActiveResourceChange(() => {
477
+ setArgs(acquireArgs());
478
+ }),
479
+ );
480
+ disposableCollection.push(
481
+ group.onDidEditorGroupTabChanged(() => {
482
+ setArgs(acquireArgs());
483
+ }),
484
+ );
485
+ return () => {
486
+ disposableCollection.dispose();
487
+ };
488
+ }, [group]);
489
+
490
+ // 第三个参数是当前编辑器的URI(如果有)
491
+ return (
492
+ <div
493
+ ref={ref}
494
+ className={classnames(styles.editor_actions, className)}
495
+ style={{ height: LAYOUT_VIEW_SIZE.EDITOR_TABS_HEIGHT }}
496
+ >
497
+ <InlineMenuBar<URI, IEditorGroup, MaybeNull<URI>>
498
+ menus={menu}
499
+ context={args as any}
500
+ // 不 focus 的时候只展示 more 菜单
501
+ regroup={(nav, more) => (hasFocus ? [nav, more] : [[], more])}
502
+ />
503
+ </div>
504
+ );
505
+ },
506
+ );
507
+
508
+ function preventNavigation(this: HTMLDivElement, e: WheelEvent) {
509
+ if (this.offsetWidth + this.scrollLeft + e.deltaX > this.scrollWidth) {
510
+ e.preventDefault();
511
+ } else if (this.scrollLeft + e.deltaX < 0) {
512
+ e.preventDefault();
513
+ }
514
+ }