@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,81 @@
1
+ import { Injectable, Autowired } from '@opensumi/di';
2
+ import { URI, Domain, WithEventBus, OnEvent } from '@opensumi/ide-core-browser';
3
+ import { LabelService } from '@opensumi/ide-core-browser/lib/services';
4
+
5
+ import { IResourceProvider, IDiffResource, ResourceService, ResourceDecorationChangeEvent } from '../../common';
6
+ import { BrowserEditorContribution, EditorComponentRegistry, EditorOpenType } from '../types';
7
+
8
+ // diff URI:
9
+ // diff://?name=tabName&original=uri1&modified=uri2
10
+ // 例子:
11
+ // diff://?name=a.ts(on disk)<=>a.ts&original=file://path/to/a.ts&modified=fileOnDisk://path/to/a.ts
12
+
13
+ @Injectable()
14
+ export class DiffResourceProvider extends WithEventBus implements IResourceProvider {
15
+ @Autowired()
16
+ labelService: LabelService;
17
+
18
+ @Autowired(ResourceService)
19
+ resourceService: ResourceService;
20
+
21
+ scheme = 'diff';
22
+
23
+ private modifiedToResource = new Map<string, URI>();
24
+
25
+ @OnEvent(ResourceDecorationChangeEvent)
26
+ onResourceDecorationChangeEvent(e: ResourceDecorationChangeEvent) {
27
+ if (e.payload.uri && this.modifiedToResource.has(e.payload.uri.toString())) {
28
+ this.eventBus.fire(
29
+ new ResourceDecorationChangeEvent({
30
+ uri: this.modifiedToResource.get(e.payload.uri.toString())!,
31
+ decoration: e.payload.decoration,
32
+ }),
33
+ );
34
+ }
35
+ }
36
+
37
+ async provideResource(uri: URI): Promise<IDiffResource> {
38
+ const { original, modified, name } = uri.getParsedQuery();
39
+ const originalUri = new URI(original);
40
+ const modifiedUri = new URI(modified);
41
+ const icon = await this.labelService.getIcon(originalUri);
42
+ this.modifiedToResource.set(modifiedUri.toString(), uri);
43
+ return {
44
+ name,
45
+ icon,
46
+ uri,
47
+ metadata: {
48
+ original: originalUri,
49
+ modified: modifiedUri,
50
+ },
51
+ };
52
+ }
53
+
54
+ async shouldCloseResource(resource, openedResources): Promise<boolean> {
55
+ const { modified } = resource.uri.getParsedQuery();
56
+ const modifiedUri = new URI(modified);
57
+ const modifiedResource = await this.resourceService.getResource(modifiedUri);
58
+ if (modifiedResource) {
59
+ return await this.resourceService.shouldCloseResource(modifiedResource, openedResources);
60
+ }
61
+ return true;
62
+ }
63
+ }
64
+
65
+ @Domain(BrowserEditorContribution)
66
+ export class DefaultDiffEditorContribution implements BrowserEditorContribution {
67
+ @Autowired()
68
+ diffResourceProvider: DiffResourceProvider;
69
+
70
+ registerResource(resourceService: ResourceService): void {
71
+ resourceService.registerResourceProvider(this.diffResourceProvider);
72
+ }
73
+
74
+ registerEditorComponent(registry: EditorComponentRegistry) {
75
+ registry.registerEditorComponentResolver('diff', (resource: IDiffResource, results) => {
76
+ results.push({
77
+ type: EditorOpenType.diff,
78
+ });
79
+ });
80
+ }
81
+ }
@@ -0,0 +1,26 @@
1
+ import { Injectable } from '@opensumi/di';
2
+ import { URI } from '@opensumi/ide-core-browser';
3
+
4
+ import { IDocPersistentCacheProvider, IDocStatus } from '../../common/doc-cache';
5
+
6
+ /**
7
+ * 一个空的,什么都不做的缓存对象,提供一个空的缓存对象实现
8
+ */
9
+ @Injectable()
10
+ export class EmptyDocCacheImpl implements IDocPersistentCacheProvider {
11
+ hasCache(_uri: URI) {
12
+ return false;
13
+ }
14
+
15
+ isFlushed() {
16
+ return true;
17
+ }
18
+
19
+ getCache(_uri: URI) {
20
+ return null;
21
+ }
22
+
23
+ persistCache(_uri: URI, _status: IDocStatus) {
24
+ // nothing
25
+ }
26
+ }
@@ -0,0 +1,2 @@
1
+ export * from './empty-doc-cache';
2
+ export * from './local-storage-cache';
@@ -0,0 +1,67 @@
1
+ import { Injectable, Autowired } from '@opensumi/di';
2
+ import { URI } from '@opensumi/ide-core-common';
3
+ import { IWorkspaceStorageService } from '@opensumi/ide-workspace';
4
+
5
+ import { IDocPersistentCacheProvider, IDocStatus, IDocCache, parseCacheValueFrom } from '../../common/doc-cache';
6
+
7
+ /**
8
+ * 使用 LocalStorage 实现的文档缓存对象
9
+ */
10
+ @Injectable()
11
+ export class LocalStorageDocCacheImpl implements IDocPersistentCacheProvider {
12
+ @Autowired(IWorkspaceStorageService)
13
+ private storageService: IWorkspaceStorageService;
14
+
15
+ hasCache(_uri: URI) {
16
+ return true;
17
+ }
18
+
19
+ /**
20
+ * LocalStorage 的存储都是瞬间完成的,始终返回 true
21
+ */
22
+ isFlushed() {
23
+ return true;
24
+ }
25
+
26
+ /**
27
+ * 从 LocalStorage 获取缓存数据,
28
+ * 因为底层对象设计是异步的,所以这里也是异步的,实际上是立即返回的
29
+ * @param uri
30
+ */
31
+ async getCache(uri: URI) {
32
+ const key = this.parseKeyFrom(uri);
33
+ const result = await this.storageService.getData<IDocCache>(key);
34
+ return result || null;
35
+ }
36
+
37
+ /**
38
+ * 持久化缓存对象到 LocalStorage 中
39
+ * @param uri
40
+ * @param status
41
+ */
42
+ persistCache(uri: URI, status: IDocStatus) {
43
+ const key = this.parseKeyFrom(uri);
44
+ const cache = this.parseCacheFrom(uri, status);
45
+ this.storageService.setData(key, cache);
46
+ }
47
+
48
+ /**
49
+ * 从文档状态解析缓存对象
50
+ * @param status
51
+ */
52
+ private parseCacheFrom(uri: URI, status: IDocStatus): IDocCache | undefined {
53
+ if (!status.dirty || !status.changeMatrix.length) {
54
+ return undefined;
55
+ }
56
+
57
+ return {
58
+ path: uri.path.toString(),
59
+ startMD5: status.startMD5,
60
+ changeMatrix: status.changeMatrix.map((changes) => changes.map((change) => parseCacheValueFrom(change))),
61
+ };
62
+ }
63
+
64
+ private parseKeyFrom(uri: URI): string {
65
+ return `LocalStorageDocCacheImpl_${uri.toString()}`;
66
+ }
67
+ }
@@ -0,0 +1,10 @@
1
+ export enum EditorDocumentError {
2
+ // 读取缓存异常
3
+ READ_CACHE_ERROR = 'EditorDocumentError:READ_CACHE_ERROR',
4
+ // 在应用缓存内容之前,编辑器发生了内容变化
5
+ APPLY_CACHE_TO_DIRTY_DOCUMENT = 'EditorDocumentError:APPLY_CACHE_TO_DIRTY_DOCUMENT',
6
+ // 在应用缓存内容到一个不匹配的文档版本,通常发生在 MD5 计算不一样的时候
7
+ APPLY_CACHE_TO_DIFFERENT_DOCUMENT = 'EditorDocumentError:APPLY_CACHE_TO_DIFFERENT_DOCUMENT',
8
+ // Format 失败
9
+ FORMAT_ERROR = 'EditorDocumentError:FORMAT_ERROR',
10
+ }
@@ -0,0 +1,346 @@
1
+ import { Injectable, Autowired, INJECTOR_TOKEN, Injector } from '@opensumi/di';
2
+ import {
3
+ URI,
4
+ IRef,
5
+ ReferenceManager,
6
+ IEditorDocumentChange,
7
+ IEditorDocumentModelSaveResult,
8
+ WithEventBus,
9
+ OnEvent,
10
+ StorageProvider,
11
+ IStorage,
12
+ STORAGE_SCHEMA,
13
+ ILogger,
14
+ PreferenceService,
15
+ ReadyEvent,
16
+ memoize,
17
+ mapToSerializable,
18
+ serializableToMap,
19
+ } from '@opensumi/ide-core-browser';
20
+ import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate';
21
+ import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types';
22
+
23
+ import { EditorDocumentModel } from './editor-document-model';
24
+ import {
25
+ IEditorDocumentModel,
26
+ IEditorDocumentModelContentRegistry,
27
+ IEditorDocumentModelService,
28
+ EditorDocumentModelOptionExternalUpdatedEvent,
29
+ EditorDocumentModelCreationEvent,
30
+ IPreferredModelOptions,
31
+ } from './types';
32
+
33
+ export const EDITOR_DOCUMENT_MODEL_STORAGE: URI = new URI('editor-doc').withScheme(STORAGE_SCHEMA.SCOPE);
34
+
35
+ export const EDITOR_DOC_OPTIONS_PREF_KEY = 'editor_doc_pref';
36
+
37
+ @Injectable()
38
+ export class EditorDocumentModelServiceImpl extends WithEventBus implements IEditorDocumentModelService {
39
+ @Autowired(IEditorDocumentModelContentRegistry)
40
+ contentRegistry: IEditorDocumentModelContentRegistry;
41
+
42
+ @Autowired(INJECTOR_TOKEN)
43
+ injector: Injector;
44
+
45
+ @Autowired(StorageProvider)
46
+ getStorage: StorageProvider;
47
+
48
+ @Autowired(ILogger)
49
+ logger: ILogger;
50
+
51
+ @Autowired(PreferenceService)
52
+ preferenceService: PreferenceService;
53
+
54
+ @Autowired(IHashCalculateService)
55
+ private readonly hashCalculateService: IHashCalculateService;
56
+
57
+ private storage: IStorage;
58
+
59
+ private editorDocModels = new Map<string, EditorDocumentModel>();
60
+
61
+ private creatingEditorModels = new Map<string, Promise<EditorDocumentModel>>();
62
+
63
+ private _modelReferenceManager: ReferenceManager<EditorDocumentModel>;
64
+
65
+ private _modelsToDispose = new Set<string>();
66
+
67
+ private preferredModelOptions = new Map<string, IPreferredModelOptions>();
68
+
69
+ private _ready = new ReadyEvent<void>();
70
+
71
+ constructor() {
72
+ super();
73
+ this._modelReferenceManager = new ReferenceManager<EditorDocumentModel>((key: string) => {
74
+ if (this._modelsToDispose.has(key)) {
75
+ this._modelsToDispose.delete(key);
76
+ }
77
+ // this.getOrCreateModel 的第二个参数是 encoding, 实际上没地方能传进去
78
+ // ReferenceManager 的构造参数 factory 只有一个入参
79
+ return this.getOrCreateModel(key);
80
+ });
81
+ this._modelReferenceManager.onReferenceAllDisposed((key: string) => {
82
+ this._delete(key);
83
+ });
84
+ this._modelReferenceManager.onInstanceCreated((model) => {
85
+ this.eventBus.fire(
86
+ new EditorDocumentModelCreationEvent({
87
+ uri: model.uri,
88
+ languageId: model.languageId,
89
+ eol: model.eol,
90
+ encoding: model.encoding,
91
+ content: model.getText(),
92
+ readonly: model.readonly,
93
+ versionId: model.getMonacoModel().getVersionId(),
94
+ }),
95
+ );
96
+ });
97
+ this.addDispose(
98
+ this.preferenceService.onPreferenceChanged((e) => {
99
+ if (e.preferenceName === 'editor.detectIndentation') {
100
+ this.editorDocModels.forEach((m) => {
101
+ m.updateOptions({});
102
+ });
103
+ }
104
+ }),
105
+ );
106
+ }
107
+
108
+ private _delete(uri: string | URI): void {
109
+ const modelDisposeDebounceTime = this.preferenceService.get<number>('editor.modelDisposeTime', 3000);
110
+ // debounce
111
+ this._modelsToDispose.add(uri.toString());
112
+ let timer: number | null = null;
113
+ const disposer = this.addDispose({
114
+ dispose: () => {
115
+ if (timer) {
116
+ clearTimeout(timer);
117
+ }
118
+ },
119
+ });
120
+ timer = window.setTimeout(() => {
121
+ disposer.dispose();
122
+ timer = null;
123
+ if (this._modelsToDispose.has(uri.toString())) {
124
+ this._doDelete(uri.toString());
125
+ }
126
+ }, modelDisposeDebounceTime);
127
+ }
128
+
129
+ private _doDelete(uri: string) {
130
+ const doc = this.editorDocModels.get(uri);
131
+ // dirty 的 document 不 dispose
132
+ if (doc && (!doc.dirty || doc.disposeEvenDirty)) {
133
+ doc.dispose();
134
+ this.editorDocModels.delete(uri);
135
+ return doc;
136
+ }
137
+ this._modelsToDispose.delete(uri);
138
+ }
139
+
140
+ async changeModelOptions(uri: URI, options: IPreferredModelOptions) {
141
+ return this.onceReady(() => {
142
+ if (this.preferredModelOptions.has(uri.toString())) {
143
+ options = {
144
+ ...this.preferredModelOptions.get(uri.toString()),
145
+ ...options,
146
+ };
147
+ }
148
+ this.preferredModelOptions.set(uri.toString(), options);
149
+ const docRef = this.getModelReference(uri);
150
+ if (docRef) {
151
+ if (options.encoding && options.encoding !== docRef.instance.encoding) {
152
+ docRef.instance.updateEncoding(options.encoding);
153
+ }
154
+ if (options.languageId && options.languageId !== docRef.instance.languageId) {
155
+ docRef.instance.languageId = options.languageId;
156
+ }
157
+ if (options.eol && options.eol !== docRef.instance.eol) {
158
+ docRef.instance.eol = options.eol;
159
+ }
160
+ docRef.dispose();
161
+ }
162
+ return this.persistOptionsPreference();
163
+ });
164
+ }
165
+
166
+ persistOptionsPreference() {
167
+ return this.storage.set(EDITOR_DOC_OPTIONS_PREF_KEY, JSON.stringify(mapToSerializable(this.preferredModelOptions)));
168
+ }
169
+
170
+ @memoize
171
+ async initialize() {
172
+ this.storage = await this.getStorage(EDITOR_DOCUMENT_MODEL_STORAGE);
173
+ if (this.storage.get(EDITOR_DOC_OPTIONS_PREF_KEY)) {
174
+ try {
175
+ this.preferredModelOptions = serializableToMap(JSON.parse(this.storage.get(EDITOR_DOC_OPTIONS_PREF_KEY)!));
176
+ } catch (e) {
177
+ this.logger.error(e);
178
+ }
179
+ }
180
+ this._ready.ready();
181
+ }
182
+
183
+ @OnEvent(EditorDocumentModelOptionExternalUpdatedEvent)
184
+ async acceptExternalChange(e: EditorDocumentModelOptionExternalUpdatedEvent) {
185
+ if (!this.hashCalculateService.initialized) {
186
+ await this.hashCalculateService.initialize();
187
+ }
188
+ const doc = this.editorDocModels.get(e.payload.toString());
189
+ if (doc) {
190
+ if (doc.dirty) {
191
+ // do nothing
192
+ } else {
193
+ const provider = await this.contentRegistry.getProvider(doc.uri);
194
+ if (provider) {
195
+ if (provider.provideEditorDocumentModelContentMd5) {
196
+ const nextMd5 = await provider.provideEditorDocumentModelContentMd5(doc.uri, doc.encoding);
197
+ if (nextMd5 !== doc.getBaseContentMd5()) {
198
+ doc.updateContent(await this.contentRegistry.getContentForUri(doc.uri, doc.encoding), undefined, true);
199
+ }
200
+ } else {
201
+ const content = await this.contentRegistry.getContentForUri(doc.uri, doc.encoding);
202
+ if (this.hashCalculateService.calculate(content) !== doc.getBaseContentMd5()) {
203
+ doc.updateContent(content, undefined, true);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ createModelReference(uri: URI, reason?: string | undefined): Promise<IRef<IEditorDocumentModel>> {
212
+ return this._modelReferenceManager.getReference(uri.toString(), reason);
213
+ }
214
+
215
+ getModelReference(uri: URI, reason?: string | undefined): IRef<IEditorDocumentModel> | null {
216
+ return this._modelReferenceManager.getReferenceIfHasInstance(uri.toString(), reason);
217
+ }
218
+
219
+ getAllModels(): IEditorDocumentModel[] {
220
+ return Array.from(this.editorDocModels.values());
221
+ }
222
+
223
+ hasLanguage(langaugeId) {
224
+ return this.getAllModels().findIndex((m) => m.languageId === langaugeId) !== -1;
225
+ }
226
+
227
+ async getOrCreateModel(uri: string, encoding?: string): Promise<EditorDocumentModel> {
228
+ if (this.editorDocModels.has(uri)) {
229
+ return this.editorDocModels.get(uri)!;
230
+ }
231
+ return this.createModel(uri, encoding);
232
+ }
233
+
234
+ private get onceReady() {
235
+ this.initialize();
236
+ return this._ready.onceReady.bind(this._ready);
237
+ }
238
+
239
+ private createModel(uri: string, encoding?: string): Promise<EditorDocumentModel> {
240
+ // 防止异步重复调用
241
+ if (!this.creatingEditorModels.has(uri)) {
242
+ const promise = this.doCreateModel(uri, encoding).then(
243
+ (model) => {
244
+ this.creatingEditorModels.delete(uri);
245
+ return model;
246
+ },
247
+ (e) => {
248
+ this.creatingEditorModels.delete(uri);
249
+ throw e;
250
+ },
251
+ );
252
+ this.creatingEditorModels.set(uri, promise);
253
+ }
254
+ return this.creatingEditorModels.get(uri)!;
255
+ }
256
+
257
+ private async doCreateModel(uriString: string, encoding?: string): Promise<EditorDocumentModel> {
258
+ const uri = new URI(uriString);
259
+ const provider = await this.contentRegistry.getProvider(uri);
260
+
261
+ if (!provider) {
262
+ throw new Error(`No document provider found for ${uri.toString()}`);
263
+ }
264
+
265
+ const [content, readonly, languageId, eol, alwaysDirty, closeAutoSave, disposeEvenDirty] = await Promise.all([
266
+ provider.provideEditorDocumentModelContent(uri, encoding),
267
+ provider.isReadonly ? provider.isReadonly(uri) : undefined,
268
+ provider.preferLanguageForUri ? provider.preferLanguageForUri(uri) : undefined,
269
+ provider.provideEOL ? provider.provideEOL(uri) : undefined,
270
+ provider.isAlwaysDirty ? provider.isAlwaysDirty(uri) : false,
271
+ provider.closeAutoSave ? provider.closeAutoSave(uri) : false,
272
+ provider.disposeEvenDirty ? provider.disposeEvenDirty(uri) : false,
273
+ ] as const);
274
+
275
+ // 优先使用 preferred encoding,然后用 detected encoding
276
+ if (!encoding && provider.provideEncoding) {
277
+ encoding = await provider.provideEncoding(uri);
278
+ }
279
+
280
+ const savable = !!provider.saveDocumentModel;
281
+
282
+ const model = this.injector.get(EditorDocumentModel, [
283
+ uri,
284
+ content,
285
+ {
286
+ readonly,
287
+ languageId,
288
+ savable,
289
+ eol,
290
+ encoding,
291
+ alwaysDirty,
292
+ closeAutoSave,
293
+ disposeEvenDirty,
294
+ },
295
+ ]);
296
+
297
+ this.onceReady(() => {
298
+ if (this.preferredModelOptions.has(uri.toString())) {
299
+ const preferedOptions = this.preferredModelOptions.get(uri.toString());
300
+ if (preferedOptions?.encoding) {
301
+ model.updateEncoding(preferedOptions.encoding);
302
+ }
303
+
304
+ if (preferedOptions?.eol) {
305
+ model.eol = preferedOptions.eol;
306
+ }
307
+
308
+ if (preferedOptions?.languageId) {
309
+ model.languageId = preferedOptions.languageId;
310
+ }
311
+ }
312
+ });
313
+
314
+ this.editorDocModels.set(uri.toString(), model);
315
+ return model;
316
+ }
317
+
318
+ async saveEditorDocumentModel(
319
+ uri: URI,
320
+ content: string,
321
+ baseContent: string,
322
+ changes: IEditorDocumentChange[],
323
+ encoding?: string,
324
+ ignoreDiff?: boolean,
325
+ eol?: EOL,
326
+ ): Promise<IEditorDocumentModelSaveResult> {
327
+ const provider = await this.contentRegistry.getProvider(uri);
328
+
329
+ if (!provider) {
330
+ throw new Error(`No document provider found for ${uri.toString()}`);
331
+ }
332
+ if (!provider.saveDocumentModel) {
333
+ throw new Error(`The document provider of ${uri.toString()} does not have a save method`);
334
+ }
335
+
336
+ const result = await provider.saveDocumentModel(uri, content, baseContent, changes, encoding, ignoreDiff, eol);
337
+ return result;
338
+ }
339
+
340
+ dispose() {
341
+ super.dispose();
342
+ this.getAllModels().forEach((model) => {
343
+ model.getMonacoModel().dispose();
344
+ });
345
+ }
346
+ }