Skip to content

Commit d9dcad2

Browse files
committed
Adds an isReadonly field to TextDocument
For microsoft#91697 This new field tracks if the file is on a readonly file system or not. This can be helpful for text based custom editors
1 parent 1c4f6ac commit d9dcad2

14 files changed

+49
-10
lines changed

src/vs/vscode.proposed.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,4 +2119,19 @@ declare module 'vscode' {
21192119
}): Disposable;
21202120
}
21212121
//#endregion
2122+
2123+
//#region https://github.com/microsoft/vscode/issues/91697
2124+
2125+
export interface TextDocument {
2126+
2127+
/**
2128+
* True if the document is on a readonly file system.
2129+
*
2130+
* `isReadonly === false` does not guarantee that can write the file. There still may be permissions
2131+
* issues or other problems that prevent the file from actually being written.
2132+
*/
2133+
readonly isReadonly: boolean;
2134+
}
2135+
2136+
//#endregion
21222137
}

src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IEditor } from 'vs/editor/common/editorCommon';
1313
import { ITextModel } from 'vs/editor/common/model';
1414
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
1515
import { ITextModelService } from 'vs/editor/common/services/resolverService';
16-
import { IFileService } from 'vs/platform/files/common/files';
16+
import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
1717
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
1818
import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocuments';
1919
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
@@ -30,6 +30,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
3030
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
3131
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
3232
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
33+
import { Schemas } from 'vs/base/common/network';
3334

3435
namespace delta {
3536

@@ -334,6 +335,7 @@ export class MainThreadDocumentsAndEditors {
334335
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
335336
@IUriIdentityService uriIdentityService: IUriIdentityService,
336337
@IClipboardService private readonly _clipboardService: IClipboardService,
338+
@IFileService private readonly _fileService: IFileService,
337339
) {
338340
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
339341

@@ -425,10 +427,19 @@ export class MainThreadDocumentsAndEditors {
425427
lines: model.getLinesContent(),
426428
EOL: model.getEOL(),
427429
modeId: model.getLanguageIdentifier().language,
428-
isDirty: this._textFileService.isDirty(model.uri)
430+
isDirty: this._textFileService.isDirty(model.uri),
431+
isReadonly: this.isReadonly(model),
429432
};
430433
}
431434

435+
private isReadonly(model: ITextModel): boolean {
436+
if (model.uri.scheme === Schemas.untitled) {
437+
// untitled is never readonly
438+
return false;
439+
}
440+
return this._fileService.hasCapability(model.uri, FileSystemProviderCapabilities.Readonly);
441+
}
442+
432443
private _toTextEditorAddData(textEditor: MainThreadTextEditor): ITextEditorAddData {
433444
const props = textEditor.getProperties();
434445
return {

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ export interface IModelAddedData {
963963
EOL: string;
964964
modeId: string;
965965
isDirty: boolean;
966+
isReadonly: boolean;
966967
}
967968
export interface ExtHostDocumentsShape {
968969
$acceptModelModeChanged(strURL: UriComponents, oldModeId: string, newModeId: string): void;

src/vs/workbench/api/common/extHostDocumentData.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class ExtHostDocumentData extends MirrorTextModel {
3737
uri: URI, lines: string[], eol: string, versionId: number,
3838
private _languageId: string,
3939
private _isDirty: boolean,
40+
private readonly _isReadonly: boolean,
4041
private readonly _notebook?: vscode.NotebookDocument | undefined
4142
) {
4243
super(uri, lines, eol, versionId);
@@ -66,6 +67,7 @@ export class ExtHostDocumentData extends MirrorTextModel {
6667
get version() { return that._versionId; },
6768
get isClosed() { return that._isDisposed; },
6869
get isDirty() { return that._isDirty; },
70+
get isReadonly() { return that._isReadonly; },
6971
get notebook() { return that._notebook; },
7072
save() { return that._save(); },
7173
getText(range?) { return range ? that._getTextInRange(range) : that.getText(); },

src/vs/workbench/api/common/extHostDocumentsAndEditors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
104104
data.versionId,
105105
data.modeId,
106106
data.isDirty,
107+
data.isReadonly,
107108
data.notebook
108109
));
109110
this._documents.set(resource, ref);

src/vs/workbench/api/common/extHostNotebook.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class ExtHostCell extends Disposable {
6464
modeId: cell.language,
6565
uri: cell.uri,
6666
isDirty: false,
67+
isReadonly: false,
6768
versionId: 1,
6869
notebook
6970
};

src/vs/workbench/test/browser/api/extHostApiCommands.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
120120
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({
121121
addedDocuments: [{
122122
isDirty: false,
123+
isReadonly: false,
123124
versionId: model.getVersionId(),
124125
modeId: model.getLanguageIdentifier().language,
125126
uri: model.uri,

src/vs/workbench/test/browser/api/extHostDocumentData.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ suite('ExtHostDocumentData', () => {
3535
'and this is line number two', //27
3636
'it is followed by #3', //20
3737
'and finished with the fourth.', //29
38-
], '\n', 1, 'text', false);
38+
], '\n', 1, 'text', false, false);
3939
});
4040

4141
test('readonly-ness', () => {
@@ -55,7 +55,7 @@ suite('ExtHostDocumentData', () => {
5555
saved = uri;
5656
return Promise.resolve(true);
5757
}
58-
}, URI.parse('foo:bar'), [], '\n', 1, 'text', true);
58+
}, URI.parse('foo:bar'), [], '\n', 1, 'text', true, false);
5959

6060
return data.document.save().then(() => {
6161
assert.equal(saved.toString(), 'foo:bar');
@@ -242,7 +242,7 @@ suite('ExtHostDocumentData', () => {
242242
test('getWordRangeAtPosition', () => {
243243
data = new ExtHostDocumentData(undefined!, URI.file(''), [
244244
'aaaa bbbb+cccc abc'
245-
], '\n', 1, 'text', false);
245+
], '\n', 1, 'text', false, false);
246246

247247
let range = data.document.getWordRangeAtPosition(new Position(0, 2))!;
248248
assert.equal(range.start.line, 0);
@@ -276,7 +276,7 @@ suite('ExtHostDocumentData', () => {
276276
'function() {',
277277
' "far boo"',
278278
'}'
279-
], '\n', 1, 'text', false);
279+
], '\n', 1, 'text', false, false);
280280

281281
let range = data.document.getWordRangeAtPosition(new Position(0, 0), /\/\*.+\*\//);
282282
assert.equal(range, undefined);
@@ -304,7 +304,7 @@ suite('ExtHostDocumentData', () => {
304304

305305
data = new ExtHostDocumentData(undefined!, URI.file(''), [
306306
perfData._$_$_expensive
307-
], '\n', 1, 'text', false);
307+
], '\n', 1, 'text', false, false);
308308

309309
let range = data.document.getWordRangeAtPosition(new Position(0, 1_177_170), regex)!;
310310
assert.equal(range, undefined);
@@ -323,7 +323,7 @@ suite('ExtHostDocumentData', () => {
323323

324324
data = new ExtHostDocumentData(undefined!, URI.file(''), [
325325
line
326-
], '\n', 1, 'text', false);
326+
], '\n', 1, 'text', false, false);
327327

328328
let range = data.document.getWordRangeAtPosition(new Position(0, 27), regex)!;
329329
assert.equal(range.start.line, 0);
@@ -387,7 +387,7 @@ suite('ExtHostDocumentData updates line mapping', () => {
387387
}
388388

389389
function testLineMappingDirectionAfterEvents(lines: string[], eol: string, direction: AssertDocumentLineMappingDirection, e: IModelChangedEvent): void {
390-
let myDocument = new ExtHostDocumentData(undefined!, URI.file(''), lines.slice(0), eol, 1, 'text', false);
390+
let myDocument = new ExtHostDocumentData(undefined!, URI.file(''), lines.slice(0), eol, 1, 'text', false, false);
391391
assertDocumentLineMapping(myDocument, direction);
392392

393393
myDocument.onEvents(e);

src/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
4040
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
4141
addedDocuments: [{
4242
isDirty: false,
43+
isReadonly: false,
4344
modeId: 'foo',
4445
uri: resource,
4546
versionId: 1,

src/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ suite('ExtHostLanguageFeatures', function () {
9090
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({
9191
addedDocuments: [{
9292
isDirty: false,
93+
isReadonly: false,
9394
versionId: model.getVersionId(),
9495
modeId: model.getLanguageIdentifier().language,
9596
uri: model.uri,

src/vs/workbench/test/browser/api/extHostNotebook.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ suite('NotebookCell#Document', function () {
196196
addData.push({
197197
EOL: '\n',
198198
isDirty: doc.isDirty,
199+
isReadonly: false,
199200
lines: doc.getText().split('\n'),
200201
modeId: doc.languageId,
201202
uri: doc.uri,

src/vs/workbench/test/browser/api/extHostTextEditor.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ suite('ExtHostTextEditor', () => {
1717
let editor: ExtHostTextEditor;
1818
let doc = new ExtHostDocumentData(undefined!, URI.file(''), [
1919
'aaaa bbbb+cccc abc'
20-
], '\n', 1, 'text', false);
20+
], '\n', 1, 'text', false, false);
2121

2222
setup(() => {
2323
editor = new ExtHostTextEditor('fake', null!, new NullLogService(), doc, [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4, indentSize: 4 }, [], 1);

src/vs/workbench/test/browser/api/extHostTextEditors.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
3333
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
3434
addedDocuments: [{
3535
isDirty: false,
36+
isReadonly: false,
3637
modeId: 'foo',
3738
uri: resource,
3839
versionId: 1337,

src/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ suite('MainThreadDocumentsAndEditors', () => {
9999
readText() {
100100
return Promise.resolve('clipboard_contents');
101101
}
102+
},
103+
new class extends mock<IFileService>() {
104+
102105
}
103106
);
104107
});

0 commit comments

Comments
 (0)