@codingame/monaco-vscode-files-service-override 3.2.3 → 4.1.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.
- package/files.js +5 -4
- package/index.js +1 -1
- package/package.json +2 -2
- package/vscode/src/vs/workbench/services/files/browser/elevatedFileService.js +2 -0
- package/override/vs/platform/dialogs/common/dialogs.js +0 -8
- package/vscode/src/vs/platform/files/browser/indexedDBFileSystemProvider.js +0 -406
- package/vscode/src/vs/platform/files/common/fileService.js +0 -988
- package/vscode/src/vs/platform/files/common/io.js +0 -77
- package/vscode/src/vs/workbench/services/textfile/browser/browserTextFileService.js +0 -58
- package/vscode/src/vs/workbench/services/textfile/browser/textFileService.js +0 -644
- package/vscode/src/vs/workbench/services/textfile/common/textFileEditorModelManager.js +0 -404
- package/vscode/src/vs/workbench/services/textfile/common/textFileSaveParticipant.js +0 -64
|
@@ -1,644 +0,0 @@
|
|
|
1
|
-
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
-
import { localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
3
|
-
import { TextFileOperationError, toBufferOrReadable, stringToSnapshot } from 'vscode/vscode/vs/workbench/services/textfile/common/textfiles';
|
|
4
|
-
import { SaveSourceRegistry } from 'vscode/vscode/vs/workbench/common/editor';
|
|
5
|
-
import { ILifecycleService } from 'vscode/vscode/vs/workbench/services/lifecycle/common/lifecycle';
|
|
6
|
-
import { IFileService } from 'vscode/vscode/vs/platform/files/common/files';
|
|
7
|
-
import { Disposable } from 'vscode/vscode/vs/base/common/lifecycle';
|
|
8
|
-
import { extname } from 'vscode/vscode/vs/base/common/path';
|
|
9
|
-
import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService';
|
|
10
|
-
import { IUntitledTextEditorService } from 'vscode/vscode/vs/workbench/services/untitled/common/untitledTextEditorService';
|
|
11
|
-
import { UntitledTextEditorModel } from 'vscode/vscode/vs/workbench/services/untitled/common/untitledTextEditorModel';
|
|
12
|
-
import { TextFileEditorModelManager } from '../common/textFileEditorModelManager.js';
|
|
13
|
-
import { IInstantiationService } from 'vscode/vscode/vs/platform/instantiation/common/instantiation';
|
|
14
|
-
import { Schemas } from 'vscode/vscode/vs/base/common/network';
|
|
15
|
-
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vscode/vscode/vs/editor/common/model/textModel';
|
|
16
|
-
import { IModelService } from 'vscode/vscode/vs/editor/common/services/model';
|
|
17
|
-
import { isEqual, toLocalResource, basename, dirname, joinPath, extname as extname$1 } from 'vscode/vscode/vs/base/common/resources';
|
|
18
|
-
import '../../../../../../../override/vs/platform/dialogs/common/dialogs.js';
|
|
19
|
-
import { bufferToStream } from 'vscode/vscode/vs/base/common/buffer';
|
|
20
|
-
import { ITextResourceConfigurationService } from 'vscode/vscode/vs/editor/common/services/textResourceConfiguration';
|
|
21
|
-
import { PLAINTEXT_LANGUAGE_ID } from 'vscode/vscode/vs/editor/common/languages/modesRegistry';
|
|
22
|
-
import { IFilesConfigurationService } from 'vscode/vscode/vs/workbench/services/filesConfiguration/common/filesConfigurationService';
|
|
23
|
-
import { BaseTextEditorModel } from 'vscode/vscode/vs/workbench/common/editor/textEditorModel';
|
|
24
|
-
import { ICodeEditorService } from 'vscode/vscode/vs/editor/browser/services/codeEditorService';
|
|
25
|
-
import { IPathService } from 'vscode/vscode/vs/workbench/services/path/common/pathService';
|
|
26
|
-
import { IWorkingCopyFileService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyFileService';
|
|
27
|
-
import { IUriIdentityService } from 'vscode/vscode/vs/platform/uriIdentity/common/uriIdentity';
|
|
28
|
-
import { WORKSPACE_EXTENSION, IWorkspaceContextService } from 'vscode/vscode/vs/platform/workspace/common/workspace';
|
|
29
|
-
import { UTF8, toEncodeReadable, toDecodeStream, UTF16be, UTF16le, UTF8_with_bom, encodingExists } from 'vscode/vscode/vs/workbench/services/textfile/common/encoding';
|
|
30
|
-
import { consumeStream } from 'vscode/vscode/vs/base/common/stream';
|
|
31
|
-
import { ILanguageService } from 'vscode/vscode/vs/editor/common/languages/language';
|
|
32
|
-
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log';
|
|
33
|
-
import { CancellationTokenSource, CancellationToken } from 'vscode/vscode/vs/base/common/cancellation';
|
|
34
|
-
import { IElevatedFileService } from 'vscode/vscode/vs/workbench/services/files/common/elevatedFileService';
|
|
35
|
-
import { IDecorationsService } from 'vscode/vscode/vs/workbench/services/decorations/common/decorations';
|
|
36
|
-
import { Emitter } from 'vscode/vscode/vs/base/common/event';
|
|
37
|
-
import { Codicon } from 'vscode/vscode/vs/base/common/codicons';
|
|
38
|
-
import { listErrorForeground } from 'vscode/vscode/vs/platform/theme/common/colorRegistry';
|
|
39
|
-
import { firstOrDefault } from 'vscode/vscode/vs/base/common/arrays';
|
|
40
|
-
import { IDialogService, IFileDialogService } from 'vscode/vscode/vs/platform/dialogs/common/dialogs';
|
|
41
|
-
|
|
42
|
-
var AbstractTextFileService_1;
|
|
43
|
-
let AbstractTextFileService = class AbstractTextFileService extends Disposable {
|
|
44
|
-
static { AbstractTextFileService_1 = this; }
|
|
45
|
-
static { this.TEXTFILE_SAVE_CREATE_SOURCE = SaveSourceRegistry.registerSource('textFileCreate.source', ( localizeWithPath(
|
|
46
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
47
|
-
'textFileCreate.source',
|
|
48
|
-
"File Created"
|
|
49
|
-
))); }
|
|
50
|
-
static { this.TEXTFILE_SAVE_REPLACE_SOURCE = SaveSourceRegistry.registerSource('textFileOverwrite.source', ( localizeWithPath(
|
|
51
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
52
|
-
'textFileOverwrite.source',
|
|
53
|
-
"File Replaced"
|
|
54
|
-
))); }
|
|
55
|
-
constructor(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, codeEditorService, pathService, workingCopyFileService, uriIdentityService, languageService, logService, elevatedFileService, decorationsService) {
|
|
56
|
-
super();
|
|
57
|
-
this.fileService = fileService;
|
|
58
|
-
this.untitledTextEditorService = untitledTextEditorService;
|
|
59
|
-
this.lifecycleService = lifecycleService;
|
|
60
|
-
this.instantiationService = instantiationService;
|
|
61
|
-
this.modelService = modelService;
|
|
62
|
-
this.environmentService = environmentService;
|
|
63
|
-
this.dialogService = dialogService;
|
|
64
|
-
this.fileDialogService = fileDialogService;
|
|
65
|
-
this.textResourceConfigurationService = textResourceConfigurationService;
|
|
66
|
-
this.filesConfigurationService = filesConfigurationService;
|
|
67
|
-
this.codeEditorService = codeEditorService;
|
|
68
|
-
this.pathService = pathService;
|
|
69
|
-
this.workingCopyFileService = workingCopyFileService;
|
|
70
|
-
this.uriIdentityService = uriIdentityService;
|
|
71
|
-
this.languageService = languageService;
|
|
72
|
-
this.logService = logService;
|
|
73
|
-
this.elevatedFileService = elevatedFileService;
|
|
74
|
-
this.decorationsService = decorationsService;
|
|
75
|
-
this.files = this._register(this.instantiationService.createInstance(TextFileEditorModelManager));
|
|
76
|
-
this.untitled = this.untitledTextEditorService;
|
|
77
|
-
this.provideDecorations();
|
|
78
|
-
}
|
|
79
|
-
provideDecorations() {
|
|
80
|
-
const provider = this._register(new (class extends Disposable {
|
|
81
|
-
constructor(files) {
|
|
82
|
-
super();
|
|
83
|
-
this.files = files;
|
|
84
|
-
this.label = ( localizeWithPath(
|
|
85
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
86
|
-
'textFileModelDecorations',
|
|
87
|
-
"Text File Model Decorations"
|
|
88
|
-
));
|
|
89
|
-
this._onDidChange = this._register(( new Emitter()));
|
|
90
|
-
this.onDidChange = this._onDidChange.event;
|
|
91
|
-
this.registerListeners();
|
|
92
|
-
}
|
|
93
|
-
registerListeners() {
|
|
94
|
-
this._register(this.files.onDidResolve(({ model }) => {
|
|
95
|
-
if (model.isReadonly() || model.hasState(4 )) {
|
|
96
|
-
this._onDidChange.fire([model.resource]);
|
|
97
|
-
}
|
|
98
|
-
}));
|
|
99
|
-
this._register(this.files.onDidRemove(modelUri => this._onDidChange.fire([modelUri])));
|
|
100
|
-
this._register(this.files.onDidChangeReadonly(model => this._onDidChange.fire([model.resource])));
|
|
101
|
-
this._register(this.files.onDidChangeOrphaned(model => this._onDidChange.fire([model.resource])));
|
|
102
|
-
}
|
|
103
|
-
provideDecorations(uri) {
|
|
104
|
-
const model = this.files.get(uri);
|
|
105
|
-
if (!model || model.isDisposed()) {
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
|
-
const isReadonly = model.isReadonly();
|
|
109
|
-
const isOrphaned = model.hasState(4 );
|
|
110
|
-
if (isReadonly && isOrphaned) {
|
|
111
|
-
return {
|
|
112
|
-
color: listErrorForeground,
|
|
113
|
-
letter: Codicon.lockSmall,
|
|
114
|
-
strikethrough: true,
|
|
115
|
-
tooltip: ( localizeWithPath(
|
|
116
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
117
|
-
'readonlyAndDeleted',
|
|
118
|
-
"Deleted, Read-only"
|
|
119
|
-
)),
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
else if (isReadonly) {
|
|
123
|
-
return {
|
|
124
|
-
letter: Codicon.lockSmall,
|
|
125
|
-
tooltip: ( localizeWithPath(
|
|
126
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
127
|
-
'readonly',
|
|
128
|
-
"Read-only"
|
|
129
|
-
)),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
else if (isOrphaned) {
|
|
133
|
-
return {
|
|
134
|
-
color: listErrorForeground,
|
|
135
|
-
strikethrough: true,
|
|
136
|
-
tooltip: ( localizeWithPath(
|
|
137
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
138
|
-
'deleted',
|
|
139
|
-
"Deleted"
|
|
140
|
-
)),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
})(this.files));
|
|
146
|
-
this._register(this.decorationsService.registerDecorationsProvider(provider));
|
|
147
|
-
}
|
|
148
|
-
get encoding() {
|
|
149
|
-
if (!this._encoding) {
|
|
150
|
-
this._encoding = this._register(this.instantiationService.createInstance(EncodingOracle));
|
|
151
|
-
}
|
|
152
|
-
return this._encoding;
|
|
153
|
-
}
|
|
154
|
-
async read(resource, options) {
|
|
155
|
-
const [bufferStream, decoder] = await this.doRead(resource, {
|
|
156
|
-
...options,
|
|
157
|
-
preferUnbuffered: true
|
|
158
|
-
});
|
|
159
|
-
return {
|
|
160
|
-
...bufferStream,
|
|
161
|
-
encoding: decoder.detected.encoding || UTF8,
|
|
162
|
-
value: await consumeStream(decoder.stream, strings => strings.join(''))
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
async readStream(resource, options) {
|
|
166
|
-
const [bufferStream, decoder] = await this.doRead(resource, options);
|
|
167
|
-
return {
|
|
168
|
-
...bufferStream,
|
|
169
|
-
encoding: decoder.detected.encoding || UTF8,
|
|
170
|
-
value: await createTextBufferFactoryFromStream(decoder.stream)
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
async doRead(resource, options) {
|
|
174
|
-
const cts = ( new CancellationTokenSource());
|
|
175
|
-
let bufferStream;
|
|
176
|
-
if (options?.preferUnbuffered) {
|
|
177
|
-
const content = await this.fileService.readFile(resource, options, cts.token);
|
|
178
|
-
bufferStream = {
|
|
179
|
-
...content,
|
|
180
|
-
value: bufferToStream(content.value)
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
bufferStream = await this.fileService.readFileStream(resource, options, cts.token);
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
const decoder = await this.doGetDecodedStream(resource, bufferStream.value, options);
|
|
188
|
-
return [bufferStream, decoder];
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
cts.dispose(true);
|
|
192
|
-
if (error.decodeStreamErrorKind === 1 ) {
|
|
193
|
-
throw new TextFileOperationError(localizeWithPath('vs/workbench/services/textfile/browser/textFileService', 'fileBinaryError', "File seems to be binary and cannot be opened as text"), 0 , options);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
throw error;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
async create(operations, undoInfo) {
|
|
201
|
-
const operationsWithContents = await Promise.all(( operations.map(async (operation) => {
|
|
202
|
-
const contents = await this.getEncodedReadable(operation.resource, operation.value);
|
|
203
|
-
return {
|
|
204
|
-
resource: operation.resource,
|
|
205
|
-
contents,
|
|
206
|
-
overwrite: operation.options?.overwrite
|
|
207
|
-
};
|
|
208
|
-
})));
|
|
209
|
-
return this.workingCopyFileService.create(operationsWithContents, CancellationToken.None, undoInfo);
|
|
210
|
-
}
|
|
211
|
-
async write(resource, value, options) {
|
|
212
|
-
const readable = await this.getEncodedReadable(resource, value, options);
|
|
213
|
-
if (options?.writeElevated && this.elevatedFileService.isSupported(resource)) {
|
|
214
|
-
return this.elevatedFileService.writeFileElevated(resource, readable, options);
|
|
215
|
-
}
|
|
216
|
-
return this.fileService.writeFile(resource, readable, options);
|
|
217
|
-
}
|
|
218
|
-
async getEncodedReadable(resource, value, options) {
|
|
219
|
-
const { encoding, addBOM } = await this.encoding.getWriteEncoding(resource, options);
|
|
220
|
-
if (encoding === UTF8 && !addBOM) {
|
|
221
|
-
return typeof value === 'undefined'
|
|
222
|
-
? undefined
|
|
223
|
-
: toBufferOrReadable(value);
|
|
224
|
-
}
|
|
225
|
-
value = value || '';
|
|
226
|
-
const snapshot = typeof value === 'string' ? stringToSnapshot(value) : value;
|
|
227
|
-
return toEncodeReadable(snapshot, encoding, { addBOM });
|
|
228
|
-
}
|
|
229
|
-
async getDecodedStream(resource, value, options) {
|
|
230
|
-
return (await this.doGetDecodedStream(resource, value, options)).stream;
|
|
231
|
-
}
|
|
232
|
-
doGetDecodedStream(resource, stream, options) {
|
|
233
|
-
return toDecodeStream(stream, {
|
|
234
|
-
acceptTextOnly: options?.acceptTextOnly ?? false,
|
|
235
|
-
guessEncoding: options?.autoGuessEncoding || this.textResourceConfigurationService.getValue(resource, 'files.autoGuessEncoding'),
|
|
236
|
-
overwriteEncoding: async (detectedEncoding) => {
|
|
237
|
-
const { encoding } = await this.encoding.getPreferredReadEncoding(resource, options, detectedEncoding ?? undefined);
|
|
238
|
-
return encoding;
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
async save(resource, options) {
|
|
243
|
-
if (resource.scheme === Schemas.untitled) {
|
|
244
|
-
const model = this.untitled.get(resource);
|
|
245
|
-
if (model) {
|
|
246
|
-
let targetUri;
|
|
247
|
-
if (model.hasAssociatedFilePath) {
|
|
248
|
-
targetUri = await this.suggestSavePath(resource);
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
targetUri = await this.fileDialogService.pickFileToSave(await this.suggestSavePath(resource), options?.availableFileSystems);
|
|
252
|
-
}
|
|
253
|
-
if (targetUri) {
|
|
254
|
-
return this.saveAs(resource, targetUri, options);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
const model = this.files.get(resource);
|
|
260
|
-
if (model) {
|
|
261
|
-
return (await model.save(options)) ? resource : undefined;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return undefined;
|
|
265
|
-
}
|
|
266
|
-
async saveAs(source, target, options) {
|
|
267
|
-
if (!target) {
|
|
268
|
-
target = await this.fileDialogService.pickFileToSave(await this.suggestSavePath(options?.suggestedTarget ?? source), options?.availableFileSystems);
|
|
269
|
-
}
|
|
270
|
-
if (!target) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
if (this.filesConfigurationService.isReadonly(target)) {
|
|
274
|
-
const confirmed = await this.confirmMakeWriteable(target);
|
|
275
|
-
if (!confirmed) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
this.filesConfigurationService.updateReadonly(target, false);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (isEqual(source, target)) {
|
|
283
|
-
return this.save(source, { ...options, force: true });
|
|
284
|
-
}
|
|
285
|
-
if (this.fileService.hasProvider(source) && this.uriIdentityService.extUri.isEqual(source, target) && (await this.fileService.exists(source))) {
|
|
286
|
-
await this.workingCopyFileService.move([{ file: { source, target } }], CancellationToken.None);
|
|
287
|
-
const success = await this.save(source, options);
|
|
288
|
-
if (!success) {
|
|
289
|
-
await this.save(target, options);
|
|
290
|
-
}
|
|
291
|
-
return target;
|
|
292
|
-
}
|
|
293
|
-
return this.doSaveAs(source, target, options);
|
|
294
|
-
}
|
|
295
|
-
async doSaveAs(source, target, options) {
|
|
296
|
-
let success = false;
|
|
297
|
-
const textFileModel = this.files.get(source);
|
|
298
|
-
if (textFileModel?.isResolved()) {
|
|
299
|
-
success = await this.doSaveAsTextFile(textFileModel, source, target, options);
|
|
300
|
-
}
|
|
301
|
-
else if (this.fileService.hasProvider(source)) {
|
|
302
|
-
await this.fileService.copy(source, target, true);
|
|
303
|
-
success = true;
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
const textModel = this.modelService.getModel(source);
|
|
307
|
-
if (textModel) {
|
|
308
|
-
success = await this.doSaveAsTextFile(textModel, source, target, options);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (!success) {
|
|
312
|
-
return undefined;
|
|
313
|
-
}
|
|
314
|
-
try {
|
|
315
|
-
await this.revert(source);
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
this.logService.error(error);
|
|
319
|
-
}
|
|
320
|
-
return target;
|
|
321
|
-
}
|
|
322
|
-
async doSaveAsTextFile(sourceModel, source, target, options) {
|
|
323
|
-
let sourceModelEncoding = undefined;
|
|
324
|
-
const sourceModelWithEncodingSupport = sourceModel;
|
|
325
|
-
if (typeof sourceModelWithEncodingSupport.getEncoding === 'function') {
|
|
326
|
-
sourceModelEncoding = sourceModelWithEncodingSupport.getEncoding();
|
|
327
|
-
}
|
|
328
|
-
let targetExists = false;
|
|
329
|
-
let targetModel = this.files.get(target);
|
|
330
|
-
if (targetModel?.isResolved()) {
|
|
331
|
-
targetExists = true;
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
targetExists = await this.fileService.exists(target);
|
|
335
|
-
if (!targetExists) {
|
|
336
|
-
await this.create([{ resource: target, value: '' }]);
|
|
337
|
-
}
|
|
338
|
-
try {
|
|
339
|
-
targetModel = await this.files.resolve(target, { encoding: sourceModelEncoding });
|
|
340
|
-
}
|
|
341
|
-
catch (error) {
|
|
342
|
-
if (targetExists) {
|
|
343
|
-
if (error.textFileOperationResult === 0 ||
|
|
344
|
-
error.fileOperationResult === 7 ) {
|
|
345
|
-
await this.fileService.del(target);
|
|
346
|
-
return this.doSaveAsTextFile(sourceModel, source, target, options);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
throw error;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
let write;
|
|
353
|
-
if (sourceModel instanceof UntitledTextEditorModel && sourceModel.hasAssociatedFilePath && targetExists && this.uriIdentityService.extUri.isEqual(target, toLocalResource(sourceModel.resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme))) {
|
|
354
|
-
write = await this.confirmOverwrite(target);
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
write = true;
|
|
358
|
-
}
|
|
359
|
-
if (!write) {
|
|
360
|
-
return false;
|
|
361
|
-
}
|
|
362
|
-
let sourceTextModel = undefined;
|
|
363
|
-
if (sourceModel instanceof BaseTextEditorModel) {
|
|
364
|
-
if (sourceModel.isResolved()) {
|
|
365
|
-
sourceTextModel = sourceModel.textEditorModel ?? undefined;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
sourceTextModel = sourceModel;
|
|
370
|
-
}
|
|
371
|
-
let targetTextModel = undefined;
|
|
372
|
-
if (targetModel.isResolved()) {
|
|
373
|
-
targetTextModel = targetModel.textEditorModel;
|
|
374
|
-
}
|
|
375
|
-
if (sourceTextModel && targetTextModel) {
|
|
376
|
-
targetModel.updatePreferredEncoding(sourceModelEncoding);
|
|
377
|
-
this.modelService.updateModel(targetTextModel, createTextBufferFactoryFromSnapshot(sourceTextModel.createSnapshot()));
|
|
378
|
-
const sourceLanguageId = sourceTextModel.getLanguageId();
|
|
379
|
-
const targetLanguageId = targetTextModel.getLanguageId();
|
|
380
|
-
if (sourceLanguageId !== PLAINTEXT_LANGUAGE_ID && targetLanguageId === PLAINTEXT_LANGUAGE_ID) {
|
|
381
|
-
targetTextModel.setLanguage(sourceLanguageId);
|
|
382
|
-
}
|
|
383
|
-
const sourceTransientProperties = this.codeEditorService.getTransientModelProperties(sourceTextModel);
|
|
384
|
-
if (sourceTransientProperties) {
|
|
385
|
-
for (const [key, value] of sourceTransientProperties) {
|
|
386
|
-
this.codeEditorService.setTransientModelProperty(targetTextModel, key, value);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
if (!options?.source) {
|
|
391
|
-
options = {
|
|
392
|
-
...options,
|
|
393
|
-
source: targetExists ? AbstractTextFileService_1.TEXTFILE_SAVE_REPLACE_SOURCE : AbstractTextFileService_1.TEXTFILE_SAVE_CREATE_SOURCE
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
return targetModel.save({
|
|
397
|
-
...options,
|
|
398
|
-
from: source
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
async confirmOverwrite(resource) {
|
|
402
|
-
const { confirmed } = await this.dialogService.confirm({
|
|
403
|
-
type: 'warning',
|
|
404
|
-
message: ( localizeWithPath(
|
|
405
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
406
|
-
'confirmOverwrite',
|
|
407
|
-
"'{0}' already exists. Do you want to replace it?",
|
|
408
|
-
basename(resource)
|
|
409
|
-
)),
|
|
410
|
-
detail: ( localizeWithPath(
|
|
411
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
412
|
-
'overwriteIrreversible',
|
|
413
|
-
"A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.",
|
|
414
|
-
basename(resource),
|
|
415
|
-
basename(dirname(resource))
|
|
416
|
-
)),
|
|
417
|
-
primaryButton: ( localizeWithPath(
|
|
418
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
419
|
-
{ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] },
|
|
420
|
-
"&&Replace"
|
|
421
|
-
)),
|
|
422
|
-
});
|
|
423
|
-
return confirmed;
|
|
424
|
-
}
|
|
425
|
-
async confirmMakeWriteable(resource) {
|
|
426
|
-
const { confirmed } = await this.dialogService.confirm({
|
|
427
|
-
type: 'warning',
|
|
428
|
-
message: ( localizeWithPath(
|
|
429
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
430
|
-
'confirmMakeWriteable',
|
|
431
|
-
"'{0}' is marked as read-only. Do you want to save anyway?",
|
|
432
|
-
basename(resource)
|
|
433
|
-
)),
|
|
434
|
-
detail: ( localizeWithPath(
|
|
435
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
436
|
-
'confirmMakeWriteableDetail',
|
|
437
|
-
"Paths can be configured as read-only via settings."
|
|
438
|
-
)),
|
|
439
|
-
primaryButton: ( localizeWithPath(
|
|
440
|
-
'vs/workbench/services/textfile/browser/textFileService',
|
|
441
|
-
{ key: 'makeWriteableButtonLabel', comment: ['&& denotes a mnemonic'] },
|
|
442
|
-
"&&Save Anyway"
|
|
443
|
-
))
|
|
444
|
-
});
|
|
445
|
-
return confirmed;
|
|
446
|
-
}
|
|
447
|
-
async suggestSavePath(resource) {
|
|
448
|
-
if (this.fileService.hasProvider(resource)) {
|
|
449
|
-
return resource;
|
|
450
|
-
}
|
|
451
|
-
const remoteAuthority = this.environmentService.remoteAuthority;
|
|
452
|
-
const defaultFilePath = await this.fileDialogService.defaultFilePath();
|
|
453
|
-
let suggestedFilename = undefined;
|
|
454
|
-
if (resource.scheme === Schemas.untitled) {
|
|
455
|
-
const model = this.untitled.get(resource);
|
|
456
|
-
if (model) {
|
|
457
|
-
if (model.hasAssociatedFilePath) {
|
|
458
|
-
return toLocalResource(resource, remoteAuthority, this.pathService.defaultUriScheme);
|
|
459
|
-
}
|
|
460
|
-
let nameCandidate;
|
|
461
|
-
if (await this.pathService.hasValidBasename(joinPath(defaultFilePath, model.name), model.name)) {
|
|
462
|
-
nameCandidate = model.name;
|
|
463
|
-
}
|
|
464
|
-
else {
|
|
465
|
-
nameCandidate = basename(resource);
|
|
466
|
-
}
|
|
467
|
-
const languageId = model.getLanguageId();
|
|
468
|
-
if (languageId && languageId !== PLAINTEXT_LANGUAGE_ID) {
|
|
469
|
-
suggestedFilename = this.suggestFilename(languageId, nameCandidate);
|
|
470
|
-
}
|
|
471
|
-
else {
|
|
472
|
-
suggestedFilename = nameCandidate;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
if (!suggestedFilename) {
|
|
477
|
-
suggestedFilename = basename(resource);
|
|
478
|
-
}
|
|
479
|
-
return joinPath(defaultFilePath, suggestedFilename);
|
|
480
|
-
}
|
|
481
|
-
suggestFilename(languageId, untitledName) {
|
|
482
|
-
const languageName = this.languageService.getLanguageName(languageId);
|
|
483
|
-
if (!languageName) {
|
|
484
|
-
return untitledName;
|
|
485
|
-
}
|
|
486
|
-
const untitledExtension = extname(untitledName);
|
|
487
|
-
const extensions = this.languageService.getExtensions(languageId);
|
|
488
|
-
if (extensions.includes(untitledExtension)) {
|
|
489
|
-
return untitledName;
|
|
490
|
-
}
|
|
491
|
-
const primaryExtension = firstOrDefault(extensions);
|
|
492
|
-
if (primaryExtension) {
|
|
493
|
-
if (untitledExtension) {
|
|
494
|
-
return `${untitledName.substring(0, untitledName.indexOf(untitledExtension))}${primaryExtension}`;
|
|
495
|
-
}
|
|
496
|
-
return `${untitledName}${primaryExtension}`;
|
|
497
|
-
}
|
|
498
|
-
const filenames = this.languageService.getFilenames(languageId);
|
|
499
|
-
if (filenames.includes(untitledName)) {
|
|
500
|
-
return untitledName;
|
|
501
|
-
}
|
|
502
|
-
return firstOrDefault(filenames) ?? untitledName;
|
|
503
|
-
}
|
|
504
|
-
async revert(resource, options) {
|
|
505
|
-
if (resource.scheme === Schemas.untitled) {
|
|
506
|
-
const model = this.untitled.get(resource);
|
|
507
|
-
if (model) {
|
|
508
|
-
return model.revert(options);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
const model = this.files.get(resource);
|
|
513
|
-
if (model && (model.isDirty() || options?.force)) {
|
|
514
|
-
return model.revert(options);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
isDirty(resource) {
|
|
519
|
-
const model = resource.scheme === Schemas.untitled ? this.untitled.get(resource) : this.files.get(resource);
|
|
520
|
-
if (model) {
|
|
521
|
-
return model.isDirty();
|
|
522
|
-
}
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
AbstractTextFileService = AbstractTextFileService_1 = ( __decorate([
|
|
527
|
-
( __param(0, IFileService)),
|
|
528
|
-
( __param(1, IUntitledTextEditorService)),
|
|
529
|
-
( __param(2, ILifecycleService)),
|
|
530
|
-
( __param(3, IInstantiationService)),
|
|
531
|
-
( __param(4, IModelService)),
|
|
532
|
-
( __param(5, IWorkbenchEnvironmentService)),
|
|
533
|
-
( __param(6, IDialogService)),
|
|
534
|
-
( __param(7, IFileDialogService)),
|
|
535
|
-
( __param(8, ITextResourceConfigurationService)),
|
|
536
|
-
( __param(9, IFilesConfigurationService)),
|
|
537
|
-
( __param(10, ICodeEditorService)),
|
|
538
|
-
( __param(11, IPathService)),
|
|
539
|
-
( __param(12, IWorkingCopyFileService)),
|
|
540
|
-
( __param(13, IUriIdentityService)),
|
|
541
|
-
( __param(14, ILanguageService)),
|
|
542
|
-
( __param(15, ILogService)),
|
|
543
|
-
( __param(16, IElevatedFileService)),
|
|
544
|
-
( __param(17, IDecorationsService))
|
|
545
|
-
], AbstractTextFileService));
|
|
546
|
-
let EncodingOracle = class EncodingOracle extends Disposable {
|
|
547
|
-
get encodingOverrides() { return this._encodingOverrides; }
|
|
548
|
-
set encodingOverrides(value) { this._encodingOverrides = value; }
|
|
549
|
-
constructor(textResourceConfigurationService, environmentService, contextService, uriIdentityService) {
|
|
550
|
-
super();
|
|
551
|
-
this.textResourceConfigurationService = textResourceConfigurationService;
|
|
552
|
-
this.environmentService = environmentService;
|
|
553
|
-
this.contextService = contextService;
|
|
554
|
-
this.uriIdentityService = uriIdentityService;
|
|
555
|
-
this._encodingOverrides = this.getDefaultEncodingOverrides();
|
|
556
|
-
this.registerListeners();
|
|
557
|
-
}
|
|
558
|
-
registerListeners() {
|
|
559
|
-
this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.encodingOverrides = this.getDefaultEncodingOverrides()));
|
|
560
|
-
}
|
|
561
|
-
getDefaultEncodingOverrides() {
|
|
562
|
-
const defaultEncodingOverrides = [];
|
|
563
|
-
defaultEncodingOverrides.push({ parent: this.environmentService.userRoamingDataHome, encoding: UTF8 });
|
|
564
|
-
defaultEncodingOverrides.push({ extension: WORKSPACE_EXTENSION, encoding: UTF8 });
|
|
565
|
-
defaultEncodingOverrides.push({ parent: this.environmentService.untitledWorkspacesHome, encoding: UTF8 });
|
|
566
|
-
this.contextService.getWorkspace().folders.forEach(folder => {
|
|
567
|
-
defaultEncodingOverrides.push({ parent: joinPath(folder.uri, '.vscode'), encoding: UTF8 });
|
|
568
|
-
});
|
|
569
|
-
return defaultEncodingOverrides;
|
|
570
|
-
}
|
|
571
|
-
async getWriteEncoding(resource, options) {
|
|
572
|
-
const { encoding, hasBOM } = await this.getPreferredWriteEncoding(resource, options ? options.encoding : undefined);
|
|
573
|
-
return { encoding, addBOM: hasBOM };
|
|
574
|
-
}
|
|
575
|
-
async getPreferredWriteEncoding(resource, preferredEncoding) {
|
|
576
|
-
const resourceEncoding = await this.getEncodingForResource(resource, preferredEncoding);
|
|
577
|
-
return {
|
|
578
|
-
encoding: resourceEncoding,
|
|
579
|
-
hasBOM: resourceEncoding === UTF16be || resourceEncoding === UTF16le || resourceEncoding === UTF8_with_bom
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
async getPreferredReadEncoding(resource, options, detectedEncoding) {
|
|
583
|
-
let preferredEncoding;
|
|
584
|
-
if (options?.encoding) {
|
|
585
|
-
if (detectedEncoding === UTF8_with_bom && options.encoding === UTF8) {
|
|
586
|
-
preferredEncoding = UTF8_with_bom;
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
preferredEncoding = options.encoding;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
else if (typeof detectedEncoding === 'string') {
|
|
593
|
-
preferredEncoding = detectedEncoding;
|
|
594
|
-
}
|
|
595
|
-
else if (this.textResourceConfigurationService.getValue(resource, 'files.encoding') === UTF8_with_bom) {
|
|
596
|
-
preferredEncoding = UTF8;
|
|
597
|
-
}
|
|
598
|
-
const encoding = await this.getEncodingForResource(resource, preferredEncoding);
|
|
599
|
-
return {
|
|
600
|
-
encoding,
|
|
601
|
-
hasBOM: encoding === UTF16be || encoding === UTF16le || encoding === UTF8_with_bom
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
async getEncodingForResource(resource, preferredEncoding) {
|
|
605
|
-
let fileEncoding;
|
|
606
|
-
const override = this.getEncodingOverride(resource);
|
|
607
|
-
if (override) {
|
|
608
|
-
fileEncoding = override;
|
|
609
|
-
}
|
|
610
|
-
else if (preferredEncoding) {
|
|
611
|
-
fileEncoding = preferredEncoding;
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
fileEncoding = this.textResourceConfigurationService.getValue(resource, 'files.encoding');
|
|
615
|
-
}
|
|
616
|
-
if (fileEncoding !== UTF8) {
|
|
617
|
-
if (!fileEncoding || !(await encodingExists(fileEncoding))) {
|
|
618
|
-
fileEncoding = UTF8;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
return fileEncoding;
|
|
622
|
-
}
|
|
623
|
-
getEncodingOverride(resource) {
|
|
624
|
-
if (this.encodingOverrides?.length) {
|
|
625
|
-
for (const override of this.encodingOverrides) {
|
|
626
|
-
if (override.parent && this.uriIdentityService.extUri.isEqualOrParent(resource, override.parent)) {
|
|
627
|
-
return override.encoding;
|
|
628
|
-
}
|
|
629
|
-
if (override.extension && extname$1(resource) === `.${override.extension}`) {
|
|
630
|
-
return override.encoding;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
return undefined;
|
|
635
|
-
}
|
|
636
|
-
};
|
|
637
|
-
EncodingOracle = ( __decorate([
|
|
638
|
-
( __param(0, ITextResourceConfigurationService)),
|
|
639
|
-
( __param(1, IWorkbenchEnvironmentService)),
|
|
640
|
-
( __param(2, IWorkspaceContextService)),
|
|
641
|
-
( __param(3, IUriIdentityService))
|
|
642
|
-
], EncodingOracle));
|
|
643
|
-
|
|
644
|
-
export { AbstractTextFileService, EncodingOracle };
|