@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,690 @@
1
+ import debounce from 'lodash/debounce';
2
+
3
+ import { Autowired, Injectable } from '@opensumi/di';
4
+ import {
5
+ CommandService,
6
+ Disposable,
7
+ Emitter,
8
+ formatLocalize,
9
+ IEventBus,
10
+ ILogger,
11
+ IRange,
12
+ IReporterService,
13
+ isThenable,
14
+ isUndefinedOrNull,
15
+ localize,
16
+ PreferenceService,
17
+ REPORT_NAME,
18
+ SaveTaskErrorCause,
19
+ SaveTaskResponseState,
20
+ URI,
21
+ } from '@opensumi/ide-core-browser';
22
+ import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate';
23
+ import { monaco, URI as MonacoURI } from '@opensumi/ide-monaco/lib/browser/monaco-api';
24
+ import { EOL, EndOfLineSequence, ITextModel } from '@opensumi/ide-monaco/lib/browser/monaco-api/types';
25
+ import { IMessageService } from '@opensumi/ide-overlay';
26
+ import {
27
+ EditOperation,
28
+ ISingleEditOperation,
29
+ } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
30
+ import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
31
+ import {
32
+ ITextBuffer,
33
+ EndOfLinePreference,
34
+ DefaultEndOfLine,
35
+ } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model';
36
+ import { createTextBuffer } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
37
+
38
+ import {
39
+ IDocCache,
40
+ IDocPersistentCacheProvider,
41
+ isDocContentCache,
42
+ parseRangeFrom,
43
+ SaveReason,
44
+ IEditorDocumentModelContentChange,
45
+ } from '../../common';
46
+ import { EditorPreferences } from '../preference/schema';
47
+ import { createEditorPreferenceProxy } from '../preference/util';
48
+ import { CompareResult, ICompareService } from '../types';
49
+
50
+ import { EditorDocumentError } from './editor-document-error';
51
+ import { IEditorDocumentModelServiceImpl, SaveTask } from './save-task';
52
+ import {
53
+ EditorDocumentModelContentChangedEvent,
54
+ EditorDocumentModelOptionChangedEvent,
55
+ EditorDocumentModelRemovalEvent,
56
+ EditorDocumentModelSavedEvent,
57
+ IEditorDocumentModel,
58
+ IEditorDocumentModelContentRegistry,
59
+ IEditorDocumentModelService,
60
+ ORIGINAL_DOC_SCHEME,
61
+ EditorDocumentModelWillSaveEvent,
62
+ } from './types';
63
+
64
+ export interface EditorDocumentModelConstructionOptions {
65
+ eol?: EOL;
66
+ encoding?: string;
67
+ languageId?: string;
68
+ readonly?: boolean;
69
+ savable?: boolean;
70
+ alwaysDirty?: boolean;
71
+ closeAutoSave?: boolean;
72
+ disposeEvenDirty?: boolean;
73
+ }
74
+
75
+ export interface IDirtyChange {
76
+ fromVersionId: number;
77
+ toVersionId: number;
78
+ changes: IEditorDocumentModelContentChange[];
79
+ }
80
+
81
+ @Injectable({ multiple: true })
82
+ export class EditorDocumentModel extends Disposable implements IEditorDocumentModel {
83
+ @Autowired(IEditorDocumentModelContentRegistry)
84
+ contentRegistry: IEditorDocumentModelContentRegistry;
85
+
86
+ @Autowired(IEditorDocumentModelService)
87
+ service: IEditorDocumentModelServiceImpl;
88
+
89
+ @Autowired(ICompareService)
90
+ compareService: ICompareService;
91
+
92
+ @Autowired(IDocPersistentCacheProvider)
93
+ cacheProvider: IDocPersistentCacheProvider;
94
+
95
+ editorPreferences: EditorPreferences;
96
+
97
+ @Autowired(IMessageService)
98
+ messageService: IMessageService;
99
+
100
+ @Autowired(IEventBus)
101
+ eventBus: IEventBus;
102
+
103
+ @Autowired(ILogger)
104
+ logger: ILogger;
105
+
106
+ @Autowired(CommandService)
107
+ private commandService: CommandService;
108
+
109
+ @Autowired(IReporterService)
110
+ private reporter: IReporterService;
111
+
112
+ @Autowired(PreferenceService)
113
+ preferences: PreferenceService;
114
+
115
+ @Autowired(IHashCalculateService)
116
+ private readonly hashCalculateService: IHashCalculateService;
117
+
118
+ private monacoModel: ITextModel;
119
+
120
+ public _encoding = 'utf8';
121
+
122
+ public readonly readonly: boolean = false;
123
+
124
+ public readonly savable: boolean = false;
125
+
126
+ public readonly alwaysDirty: boolean = false;
127
+
128
+ public readonly closeAutoSave: boolean = false;
129
+
130
+ public readonly disposeEvenDirty: boolean = false;
131
+
132
+ private _originalEncoding: string = this._encoding;
133
+
134
+ private _persistVersionId = 0;
135
+
136
+ private _baseContent = '';
137
+
138
+ private _baseContentMd5: string | null;
139
+
140
+ private savingTasks: SaveTask[] = [];
141
+
142
+ private dirtyChanges: IDirtyChange[] = [];
143
+
144
+ private _previousVersionId: number;
145
+
146
+ private _tryAutoSaveAfterDelay: (() => any) | undefined;
147
+
148
+ private _isInitOption = true;
149
+
150
+ private readonly _onDidChangeEncoding = new Emitter<void>();
151
+ readonly onDidChangeEncoding = this._onDidChangeEncoding.event;
152
+
153
+ constructor(public readonly uri: URI, content: string, options: EditorDocumentModelConstructionOptions = {}) {
154
+ super();
155
+
156
+ this.onDispose(() => {
157
+ this.eventBus.fire(new EditorDocumentModelRemovalEvent(this.uri));
158
+ });
159
+ if (options.encoding) {
160
+ this._encoding = options.encoding;
161
+ }
162
+ this.readonly = !!options.readonly;
163
+ this.savable = !!options.savable;
164
+ this.alwaysDirty = !!options.alwaysDirty;
165
+ this.disposeEvenDirty = !!options.disposeEvenDirty;
166
+ this.closeAutoSave = !!options.closeAutoSave;
167
+
168
+ this.monacoModel = monaco.editor.createModel(content, options.languageId, MonacoURI.parse(uri.toString()));
169
+ this.editorPreferences = createEditorPreferenceProxy(this.preferences, this.uri.toString(), this.languageId);
170
+ this.updateOptions({});
171
+ if (options.eol) {
172
+ this.eol = options.eol;
173
+ }
174
+ this._originalEncoding = this._encoding;
175
+ this._previousVersionId = this.monacoModel.getVersionId();
176
+ this._persistVersionId = this.monacoModel.getAlternativeVersionId();
177
+ this.baseContent = content;
178
+
179
+ this._isInitOption = false;
180
+ this.listenTo(this.monacoModel);
181
+ this.readCacheToApply();
182
+
183
+ this.addDispose(this._onDidChangeEncoding);
184
+
185
+ this.addDispose(
186
+ this.monacoModel.onDidChangeLanguage((e) => {
187
+ this.eventBus.fire(
188
+ new EditorDocumentModelOptionChangedEvent({
189
+ uri: this.uri,
190
+ languageId: e.newLanguage,
191
+ }),
192
+ );
193
+ }),
194
+ );
195
+ }
196
+
197
+ updateOptions(options) {
198
+ const finalOptions = {
199
+ tabSize: this.editorPreferences['editor.tabSize'] || 1,
200
+ insertSpaces: this.editorPreferences['editor.insertSpaces'],
201
+ detectIndentation: this.editorPreferences['editor.detectIndentation'],
202
+ ...options,
203
+ };
204
+ if (finalOptions.detectIndentation) {
205
+ this.monacoModel.detectIndentation(finalOptions.insertSpaces, finalOptions.tabSize);
206
+ } else {
207
+ this.monacoModel.updateOptions(finalOptions);
208
+ }
209
+ }
210
+
211
+ private listenTo(monacoModel: ITextModel) {
212
+ this.addDispose(
213
+ monacoModel.onDidChangeContent((e) => {
214
+ if (e.changes && e.changes.length > 0) {
215
+ this.dirtyChanges.push({
216
+ fromVersionId: this._previousVersionId,
217
+ toVersionId: e.versionId,
218
+ changes: e.changes,
219
+ });
220
+ }
221
+ this._previousVersionId = e.versionId;
222
+ this.notifyChangeEvent(e.changes, e.isRedoing, e.isUndoing);
223
+ }),
224
+ );
225
+
226
+ this.addDispose(monacoModel);
227
+ }
228
+
229
+ private readCacheToApply() {
230
+ if (!this.cacheProvider.hasCache(this.uri)) {
231
+ return;
232
+ }
233
+
234
+ const maybePromiseCache = this.cacheProvider.getCache(this.uri, this.encoding);
235
+ if (maybePromiseCache) {
236
+ if (isThenable(maybePromiseCache)) {
237
+ maybePromiseCache
238
+ .then((cache) => {
239
+ if (cache) {
240
+ this.applyCache(cache);
241
+ }
242
+ })
243
+ .catch((err) => {
244
+ this.logger.error(`${EditorDocumentError.READ_CACHE_ERROR} ${err && err.message}`);
245
+ });
246
+ } else {
247
+ this.applyCache(maybePromiseCache as IDocCache);
248
+ }
249
+ }
250
+ }
251
+
252
+ private applyCache(cache: IDocCache) {
253
+ if (this.dirty) {
254
+ this.logger.error(EditorDocumentError.APPLY_CACHE_TO_DIRTY_DOCUMENT);
255
+ return;
256
+ }
257
+
258
+ if (this.baseContentMd5 !== cache.startMD5) {
259
+ this.logger.error(EditorDocumentError.APPLY_CACHE_TO_DIFFERENT_DOCUMENT);
260
+ return;
261
+ }
262
+
263
+ if (isDocContentCache(cache)) {
264
+ this.monacoModel.setValue(cache.content);
265
+ } else {
266
+ for (const changes of cache.changeMatrix) {
267
+ const operations = changes.map((change) => ({
268
+ range: parseRangeFrom(change),
269
+ text: change[0],
270
+ }));
271
+ this.monacoModel.applyEdits(operations);
272
+ }
273
+ }
274
+ }
275
+
276
+ cleanAndUpdateContent(content) {
277
+ this.monacoModel.setValue(content);
278
+ (this.monacoModel as any)._commandManager.clear();
279
+ this._persistVersionId = this.monacoModel.getAlternativeVersionId();
280
+ this.savingTasks = [];
281
+ this.notifyChangeEvent([], false, false);
282
+ this.baseContent = content;
283
+ }
284
+
285
+ async updateEncoding(encoding: string) {
286
+ let shouldFireChange = false;
287
+ if (this._encoding !== encoding) {
288
+ shouldFireChange = true;
289
+ }
290
+ this._encoding = encoding;
291
+ await this.reload();
292
+ if (shouldFireChange) {
293
+ this.eventBus.fire(
294
+ new EditorDocumentModelOptionChangedEvent({
295
+ uri: this.uri,
296
+ encoding: this._encoding,
297
+ }),
298
+ );
299
+ this._onDidChangeEncoding.fire();
300
+ }
301
+ }
302
+
303
+ get encoding() {
304
+ return this._encoding;
305
+ }
306
+
307
+ set eol(eol) {
308
+ this.monacoModel.setEOL(eol === EOL.LF ? EndOfLineSequence.LF : (EndOfLineSequence.CRLF as any));
309
+ if (!this._isInitOption) {
310
+ this.eventBus.fire(
311
+ new EditorDocumentModelOptionChangedEvent({
312
+ uri: this.uri,
313
+ eol,
314
+ }),
315
+ );
316
+ }
317
+ }
318
+
319
+ get eol() {
320
+ return this.monacoModel.getEOL() as EOL;
321
+ }
322
+
323
+ get dirty() {
324
+ if (this.alwaysDirty) {
325
+ return true;
326
+ }
327
+ if (!this.savable) {
328
+ return false;
329
+ }
330
+ if (this.monacoModel.isDisposed()) {
331
+ return false;
332
+ }
333
+ return this._persistVersionId !== this.monacoModel.getAlternativeVersionId();
334
+ }
335
+
336
+ set languageId(languageId) {
337
+ monaco.editor.setModelLanguage(this.monacoModel, languageId);
338
+ this.eventBus.fire(
339
+ new EditorDocumentModelOptionChangedEvent({
340
+ uri: this.uri,
341
+ languageId,
342
+ }),
343
+ );
344
+ }
345
+
346
+ get languageId() {
347
+ return this.monacoModel.getLanguageId();
348
+ }
349
+
350
+ get id() {
351
+ return this.monacoModel.id;
352
+ }
353
+
354
+ getMonacoModel(): ITextModel {
355
+ return this.monacoModel;
356
+ }
357
+
358
+ async save(force = false, reason: SaveReason = SaveReason.Manual): Promise<boolean> {
359
+ await this.formatOnSave(reason);
360
+ // 发送willSave并等待完成
361
+ await this.eventBus.fireAndAwait(
362
+ new EditorDocumentModelWillSaveEvent({
363
+ uri: this.uri,
364
+ reason,
365
+ language: this.languageId,
366
+ }),
367
+ );
368
+ if (!this.editorPreferences['editor.askIfDiff']) {
369
+ force = true;
370
+ }
371
+ if (!this.dirty) {
372
+ return false;
373
+ }
374
+ const versionId = this.monacoModel.getVersionId();
375
+ const lastSavingTask = this.savingTasks[this.savingTasks.length - 1];
376
+ if (lastSavingTask && lastSavingTask.versionId === versionId) {
377
+ lastSavingTask.cancel();
378
+ const task = this.savingTasks.pop();
379
+ task?.dispose();
380
+ }
381
+ const task = new SaveTask(this.uri, versionId, this.monacoModel.getAlternativeVersionId(), this.getText(), force);
382
+ this.savingTasks.push(task);
383
+ if (this.savingTasks.length > 0) {
384
+ this.initSave();
385
+ }
386
+ const res = await task.finished;
387
+ if (res.state === SaveTaskResponseState.SUCCESS) {
388
+ this.monacoModel.pushStackElement();
389
+ return true;
390
+ } else if (res.state === SaveTaskResponseState.ERROR) {
391
+ if (res.errorMessage !== SaveTaskErrorCause.CANCEL) {
392
+ this.logger.error(res.errorMessage);
393
+ this.messageService.error(localize('doc.saveError.failed') + '\n' + res.errorMessage);
394
+ }
395
+ return false;
396
+ } else if (res.state === SaveTaskResponseState.DIFF) {
397
+ this.messageService
398
+ .error(formatLocalize('doc.saveError.diff', this.uri.toString()), [localize('doc.saveError.diffAndSave')])
399
+ .then((res) => {
400
+ if (res) {
401
+ this.compareAndSave();
402
+ }
403
+ });
404
+ this.logger.error('文件无法保存,版本和磁盘不一致');
405
+ return false;
406
+ }
407
+ return false;
408
+ }
409
+
410
+ private async compareAndSave() {
411
+ const originalUri = URI.from({
412
+ scheme: ORIGINAL_DOC_SCHEME,
413
+ query: URI.stringifyQuery({
414
+ target: this.uri.toString(),
415
+ }),
416
+ });
417
+ const fileName = this.uri.path.base;
418
+ const res = await this.compareService.compare(
419
+ originalUri,
420
+ this.uri,
421
+ formatLocalize('editor.compareAndSave.title', fileName, fileName),
422
+ );
423
+ if (res === CompareResult.revert) {
424
+ this.revert();
425
+ } else if (res === CompareResult.accept) {
426
+ this.save(true);
427
+ }
428
+ }
429
+
430
+ async initSave() {
431
+ while (this.savingTasks.length > 0) {
432
+ const changes = this.dirtyChanges;
433
+ this.dirtyChanges = [];
434
+ const res = await this.savingTasks[0].run(this.service, this.baseContent, changes, this.encoding, this.eol);
435
+ if (res.state === 'success' && this.savingTasks[0]) {
436
+ this.baseContent = this.savingTasks[0].content;
437
+
438
+ this.eventBus.fire(new EditorDocumentModelSavedEvent(this.uri));
439
+ this.setPersist(this.savingTasks[0].alternativeVersionId);
440
+ } else {
441
+ // 回滚 changes
442
+ this.dirtyChanges.unshift(...changes);
443
+ }
444
+ this.savingTasks.shift();
445
+ }
446
+ }
447
+
448
+ setPersist(versionId: number) {
449
+ this._persistVersionId = versionId;
450
+ this.notifyChangeEvent([], false, false);
451
+ }
452
+
453
+ async reload() {
454
+ try {
455
+ const content = await this.contentRegistry.getContentForUri(this.uri, this._encoding);
456
+ if (!isUndefinedOrNull(content)) {
457
+ this.cleanAndUpdateContent(content);
458
+ }
459
+ } catch (e) {
460
+ this._persistVersionId = this.monacoModel.getAlternativeVersionId();
461
+ }
462
+ }
463
+
464
+ async revert(notOnDisk?: boolean) {
465
+ if (notOnDisk) {
466
+ // FIXME: 暂时就让它不 dirty, 不是真正的 revert
467
+ this._persistVersionId = this.monacoModel.getAlternativeVersionId();
468
+ } else {
469
+ // 利用修改编码的副作用
470
+ await this.updateEncoding(this._originalEncoding);
471
+ }
472
+ }
473
+
474
+ getText(range?: IRange) {
475
+ if (range) {
476
+ return this.monacoModel.getValueInRange(range);
477
+ } else {
478
+ return this.monacoModel.getValue();
479
+ }
480
+ }
481
+
482
+ updateContent(content: string, eol?: EOL, setPersist = false) {
483
+ if (eol) {
484
+ this.eol = eol;
485
+ }
486
+
487
+ const defaultEOL = this.eol === EOL.CRLF ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF;
488
+ const { textBuffer, disposable } = createTextBuffer(content, defaultEOL);
489
+ // 计算新旧 Monaco 文档的差异,避免全量更新导致的高亮闪烁问题
490
+ const singleEditOperation = EditorDocumentModel._computeEdits(this.monacoModel, textBuffer);
491
+ this.monacoModel.pushEditOperations([], singleEditOperation, () => []);
492
+
493
+ if (setPersist) {
494
+ this.setPersist(this.monacoModel.getAlternativeVersionId());
495
+ this.baseContent = content;
496
+ this.dirtyChanges = [];
497
+ }
498
+ disposable.dispose();
499
+ }
500
+
501
+ /**
502
+ * Compute edits to bring `model` to the state of `textSource`.
503
+ */
504
+ public static _computeEdits(model: ITextModel, textBuffer: ITextBuffer): ISingleEditOperation[] {
505
+ const modelLineCount = model.getLineCount();
506
+ const textBufferLineCount = textBuffer.getLineCount();
507
+ const commonPrefix = this._commonPrefix(model, modelLineCount, 1, textBuffer, textBufferLineCount, 1);
508
+
509
+ if (modelLineCount === textBufferLineCount && commonPrefix === modelLineCount) {
510
+ // equality case
511
+ return [];
512
+ }
513
+
514
+ const commonSuffix = this._commonSuffix(
515
+ model,
516
+ modelLineCount - commonPrefix,
517
+ commonPrefix,
518
+ textBuffer,
519
+ textBufferLineCount - commonPrefix,
520
+ commonPrefix,
521
+ );
522
+
523
+ let oldRange: Range;
524
+ let newRange: Range;
525
+ if (commonSuffix > 0) {
526
+ oldRange = new Range(commonPrefix + 1, 1, modelLineCount - commonSuffix + 1, 1);
527
+ newRange = new Range(commonPrefix + 1, 1, textBufferLineCount - commonSuffix + 1, 1);
528
+ } else if (commonPrefix > 0) {
529
+ oldRange = new Range(
530
+ commonPrefix,
531
+ model.getLineMaxColumn(commonPrefix),
532
+ modelLineCount,
533
+ model.getLineMaxColumn(modelLineCount),
534
+ );
535
+ newRange = new Range(
536
+ commonPrefix,
537
+ 1 + textBuffer.getLineLength(commonPrefix),
538
+ textBufferLineCount,
539
+ 1 + textBuffer.getLineLength(textBufferLineCount),
540
+ );
541
+ } else {
542
+ oldRange = new Range(1, 1, modelLineCount, model.getLineMaxColumn(modelLineCount));
543
+ newRange = new Range(1, 1, textBufferLineCount, 1 + textBuffer.getLineLength(textBufferLineCount));
544
+ }
545
+
546
+ return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
547
+ }
548
+
549
+ private static _commonPrefix(
550
+ a: ITextModel,
551
+ aLen: number,
552
+ aDelta: number,
553
+ b: ITextBuffer,
554
+ bLen: number,
555
+ bDelta: number,
556
+ ): number {
557
+ const maxResult = Math.min(aLen, bLen);
558
+
559
+ let result = 0;
560
+ for (let i = 0; i < maxResult && a.getLineContent(aDelta + i) === b.getLineContent(bDelta + i); i++) {
561
+ result++;
562
+ }
563
+ return result;
564
+ }
565
+
566
+ private static _commonSuffix(
567
+ a: ITextModel,
568
+ aLen: number,
569
+ aDelta: number,
570
+ b: ITextBuffer,
571
+ bLen: number,
572
+ bDelta: number,
573
+ ): number {
574
+ const maxResult = Math.min(aLen, bLen);
575
+
576
+ let result = 0;
577
+ for (let i = 0; i < maxResult && a.getLineContent(aDelta + aLen - i) === b.getLineContent(bDelta + bLen - i); i++) {
578
+ result++;
579
+ }
580
+ return result;
581
+ }
582
+
583
+ set baseContent(content: string) {
584
+ this._baseContent = content;
585
+ this._baseContentMd5 = null;
586
+ }
587
+
588
+ get baseContent() {
589
+ return this._baseContent;
590
+ }
591
+
592
+ get baseContentMd5() {
593
+ if (!this._baseContentMd5) {
594
+ this._baseContentMd5 = this.hashCalculateService.calculate(this._baseContent);
595
+ }
596
+ return this._baseContentMd5;
597
+ }
598
+
599
+ get tryAutoSaveAfterDelay() {
600
+ if (!this._tryAutoSaveAfterDelay) {
601
+ this._tryAutoSaveAfterDelay = debounce(() => {
602
+ this.save(undefined, SaveReason.AfterDelay);
603
+ }, this.editorPreferences['editor.autoSaveDelay'] || 1000);
604
+ this.addDispose(
605
+ this.editorPreferences.onPreferenceChanged((change) => {
606
+ if (change.preferenceName === 'editor.autoSaveDelay') {
607
+ this._tryAutoSaveAfterDelay = debounce(() => {
608
+ this.save(undefined, SaveReason.AfterDelay);
609
+ }, this.editorPreferences['editor.autoSaveDelay'] || 1000);
610
+ }
611
+ }),
612
+ );
613
+ }
614
+ return this._tryAutoSaveAfterDelay;
615
+ }
616
+
617
+ getBaseContentMd5(): string {
618
+ if (!this._baseContentMd5) {
619
+ this._baseContentMd5 = this.hashCalculateService.calculate(this._baseContent);
620
+ }
621
+ return this._baseContentMd5!;
622
+ }
623
+
624
+ private notifyChangeEvent(changes: IEditorDocumentModelContentChange[] = [], isRedoing: boolean, isUndoing: boolean) {
625
+ if (!this.closeAutoSave && this.savable && this.editorPreferences['editor.autoSave'] === 'afterDelay') {
626
+ this.tryAutoSaveAfterDelay();
627
+ }
628
+ // 发出内容变化的事件
629
+ this.eventBus.fire(
630
+ new EditorDocumentModelContentChangedEvent({
631
+ uri: this.uri,
632
+ dirty: this.dirty,
633
+ changes,
634
+ eol: this.eol,
635
+ isRedoing,
636
+ isUndoing,
637
+ versionId: this.monacoModel.getVersionId(),
638
+ }),
639
+ );
640
+
641
+ const self = this;
642
+ this.cacheProvider.persistCache(this.uri, {
643
+ // 使用 getter 让需要计算的数据变成 lazy 获取的
644
+ get dirty() {
645
+ return self.dirty;
646
+ },
647
+ get startMD5() {
648
+ return self.getBaseContentMd5();
649
+ },
650
+ get content() {
651
+ return self.getText();
652
+ },
653
+ get changeMatrix() {
654
+ // 计算从起始版本到现在所有的 change 内容,然后让缓存对象进行持久化
655
+ return self.dirtyChanges.map(({ changes }) => changes);
656
+ },
657
+ encoding: this.encoding,
658
+ });
659
+ }
660
+
661
+ protected async formatOnSave(reason: SaveReason) {
662
+ const formatOnSave = this.editorPreferences['editor.formatOnSave'];
663
+
664
+ // 和 vscode 逻辑保持一致,如果是 AfterDelay 则不执行 formatOnSave
665
+ if (formatOnSave && reason !== SaveReason.AfterDelay) {
666
+ const formatOnSaveTimeout = this.editorPreferences['editor.formatOnSaveTimeout'] || 3000;
667
+ const timer = this.reporter.time(REPORT_NAME.FORMAT_ON_SAVE);
668
+ try {
669
+ await Promise.race([
670
+ new Promise((_, reject) => {
671
+ setTimeout(() => {
672
+ const err = new Error(formatLocalize('preference.editor.formatOnSaveTimeoutError', formatOnSaveTimeout));
673
+ err.name = 'FormatOnSaveTimeoutError';
674
+ reject(err);
675
+ }, formatOnSaveTimeout);
676
+ }),
677
+ this.commandService.executeCommand('editor.action.formatDocument'),
678
+ ]);
679
+ } catch (err) {
680
+ if (err.name === 'FormatOnSaveTimeoutError') {
681
+ this.reporter.point(REPORT_NAME.FORMAT_ON_SAVE_TIMEOUT_ERROR, this.uri.toString());
682
+ }
683
+ // 目前 command 没有读取到 contextkey,在不支持 format 的地方执行 format 命令会报错,先警告下,后续要接入 contextkey 来判断
684
+ this.logger.warn(`${EditorDocumentError.FORMAT_ERROR} ${err && err.message}`);
685
+ } finally {
686
+ timer.timeEnd(this.uri.path.ext);
687
+ }
688
+ }
689
+ }
690
+ }