mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
Set a read-only message from an extension (#185216)
* wip * Allow extensions to provide a readonly message Part of #166971 * Address feedback * Further address feedback * Fix some nits * Add test * Improve tests and respond to feedback * Don't render editor.readOnlyMessage in the settings UI * No need to validate the IMarkdownString --------- Co-authored-by: Benjamin Pasero <benjamin.pasero@microsoft.com> Co-authored-by: Alex Dima <alexdima@microsoft.com>
This commit is contained in:
parent
76cc1fc7cc
commit
1a4e466fc0
|
@ -26,6 +26,7 @@
|
|||
"notebookMime",
|
||||
"portsAttributes",
|
||||
"quickPickSortByLabel",
|
||||
"readonlyMessage",
|
||||
"resolvers",
|
||||
"saveEditor",
|
||||
"scmActionButton",
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { TestFS } from '../memfs';
|
||||
import { assertNoRpc, closeAllEditors } from '../utils';
|
||||
|
||||
suite('vscode API - file system', () => {
|
||||
|
||||
teardown(async function () {
|
||||
assertNoRpc();
|
||||
await closeAllEditors();
|
||||
});
|
||||
|
||||
test('readonly file system - boolean', async function () {
|
||||
const fs = new TestFS('this-fs', false);
|
||||
const reg = vscode.workspace.registerFileSystemProvider(fs.scheme, fs, { isReadonly: true });
|
||||
let error: any | undefined;
|
||||
try {
|
||||
await vscode.workspace.fs.writeFile(vscode.Uri.parse('this-fs:/foo.txt'), Buffer.from('Hello World'));
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
assert.strictEqual(vscode.workspace.fs.isWritableFileSystem('this-fs'), false);
|
||||
assert.strictEqual(error instanceof vscode.FileSystemError, true);
|
||||
const fileError: vscode.FileSystemError = error;
|
||||
assert.strictEqual(fileError.code, 'NoPermissions');
|
||||
reg.dispose();
|
||||
});
|
||||
|
||||
test('readonly file system - markdown', async function () {
|
||||
const fs = new TestFS('this-fs', false);
|
||||
const reg = vscode.workspace.registerFileSystemProvider(fs.scheme, fs, { isReadonly: new vscode.MarkdownString('This file is readonly.') });
|
||||
let error: any | undefined;
|
||||
try {
|
||||
await vscode.workspace.fs.writeFile(vscode.Uri.parse('this-fs:/foo.txt'), Buffer.from('Hello World'));
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
assert.strictEqual(vscode.workspace.fs.isWritableFileSystem('this-fs'), false);
|
||||
assert.strictEqual(error instanceof vscode.FileSystemError, true);
|
||||
const fileError: vscode.FileSystemError = error;
|
||||
assert.strictEqual(fileError.code, 'NoPermissions');
|
||||
reg.dispose();
|
||||
});
|
||||
|
||||
test('writeable file system', async function () {
|
||||
const fs = new TestFS('this-fs', false);
|
||||
const reg = vscode.workspace.registerFileSystemProvider(fs.scheme, fs);
|
||||
let error: any | undefined;
|
||||
try {
|
||||
await vscode.workspace.fs.writeFile(vscode.Uri.parse('this-fs:/foo.txt'), Buffer.from('Hello World'));
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
assert.strictEqual(vscode.workspace.fs.isWritableFileSystem('this-fs'), true);
|
||||
assert.strictEqual(error, undefined);
|
||||
reg.dispose();
|
||||
});
|
||||
});
|
|
@ -16,6 +16,7 @@ import * as arrays from 'vs/base/common/arrays';
|
|||
import * as objects from 'vs/base/common/objects';
|
||||
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/core/textModelDefaults';
|
||||
import { IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
//#region typed options
|
||||
|
||||
|
@ -151,6 +152,10 @@ export interface IEditorOptions {
|
|||
* Defaults to false.
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
/**
|
||||
* The message to display when the editor is readonly.
|
||||
*/
|
||||
readOnlyMessage?: IMarkdownString;
|
||||
/**
|
||||
* Should the textarea used for input use the DOM `readonly` attribute.
|
||||
* Defaults to false.
|
||||
|
@ -3459,6 +3464,30 @@ class EditorRulers extends BaseEditorOption<EditorOption.rulers, (number | IRule
|
|||
|
||||
//#endregion
|
||||
|
||||
//#region readonly
|
||||
|
||||
/**
|
||||
* Configuration options for readonly message
|
||||
*/
|
||||
class ReadonlyMessage extends BaseEditorOption<EditorOption.readOnlyMessage, IMarkdownString | undefined, IMarkdownString | undefined> {
|
||||
constructor() {
|
||||
const defaults = undefined;
|
||||
|
||||
super(
|
||||
EditorOption.readOnlyMessage, 'readOnlyMessage', defaults
|
||||
);
|
||||
}
|
||||
|
||||
public validate(_input: any): IMarkdownString | undefined {
|
||||
if (!_input || typeof _input !== 'object') {
|
||||
return this.defaultValue;
|
||||
}
|
||||
return _input as IMarkdownString;
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region scrollbar
|
||||
|
||||
/**
|
||||
|
@ -5024,6 +5053,7 @@ export const enum EditorOption {
|
|||
quickSuggestions,
|
||||
quickSuggestionsDelay,
|
||||
readOnly,
|
||||
readOnlyMessage,
|
||||
renameOnType,
|
||||
renderControlCharacters,
|
||||
renderFinalNewline,
|
||||
|
@ -5530,6 +5560,7 @@ export const EditorOptions = {
|
|||
readOnly: register(new EditorBooleanOption(
|
||||
EditorOption.readOnly, 'readOnly', false,
|
||||
)),
|
||||
readOnlyMessage: register(new ReadonlyMessage()),
|
||||
renameOnType: register(new EditorBooleanOption(
|
||||
EditorOption.renameOnType, 'renameOnType', false,
|
||||
{ description: nls.localize('renameOnType', "Controls whether the editor auto renames on type."), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', "Deprecated, use `editor.linkedEditing` instead.") }
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable, IReference } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModel, ITextSnapshot } from 'vs/editor/common/model';
|
||||
|
@ -55,7 +56,7 @@ export interface ITextEditorModel extends IEditorModel {
|
|||
/**
|
||||
* Signals if this model is readonly or not.
|
||||
*/
|
||||
isReadonly(): boolean;
|
||||
isReadonly(): boolean | IMarkdownString;
|
||||
|
||||
/**
|
||||
* The language id of the text model if known.
|
||||
|
|
|
@ -262,61 +262,62 @@ export enum EditorOption {
|
|||
quickSuggestions = 86,
|
||||
quickSuggestionsDelay = 87,
|
||||
readOnly = 88,
|
||||
renameOnType = 89,
|
||||
renderControlCharacters = 90,
|
||||
renderFinalNewline = 91,
|
||||
renderLineHighlight = 92,
|
||||
renderLineHighlightOnlyWhenFocus = 93,
|
||||
renderValidationDecorations = 94,
|
||||
renderWhitespace = 95,
|
||||
revealHorizontalRightPadding = 96,
|
||||
roundedSelection = 97,
|
||||
rulers = 98,
|
||||
scrollbar = 99,
|
||||
scrollBeyondLastColumn = 100,
|
||||
scrollBeyondLastLine = 101,
|
||||
scrollPredominantAxis = 102,
|
||||
selectionClipboard = 103,
|
||||
selectionHighlight = 104,
|
||||
selectOnLineNumbers = 105,
|
||||
showFoldingControls = 106,
|
||||
showUnused = 107,
|
||||
snippetSuggestions = 108,
|
||||
smartSelect = 109,
|
||||
smoothScrolling = 110,
|
||||
stickyScroll = 111,
|
||||
stickyTabStops = 112,
|
||||
stopRenderingLineAfter = 113,
|
||||
suggest = 114,
|
||||
suggestFontSize = 115,
|
||||
suggestLineHeight = 116,
|
||||
suggestOnTriggerCharacters = 117,
|
||||
suggestSelection = 118,
|
||||
tabCompletion = 119,
|
||||
tabIndex = 120,
|
||||
unicodeHighlighting = 121,
|
||||
unusualLineTerminators = 122,
|
||||
useShadowDOM = 123,
|
||||
useTabStops = 124,
|
||||
wordBreak = 125,
|
||||
wordSeparators = 126,
|
||||
wordWrap = 127,
|
||||
wordWrapBreakAfterCharacters = 128,
|
||||
wordWrapBreakBeforeCharacters = 129,
|
||||
wordWrapColumn = 130,
|
||||
wordWrapOverride1 = 131,
|
||||
wordWrapOverride2 = 132,
|
||||
wrappingIndent = 133,
|
||||
wrappingStrategy = 134,
|
||||
showDeprecated = 135,
|
||||
inlayHints = 136,
|
||||
editorClassName = 137,
|
||||
pixelRatio = 138,
|
||||
tabFocusMode = 139,
|
||||
layoutInfo = 140,
|
||||
wrappingInfo = 141,
|
||||
defaultColorDecorators = 142,
|
||||
colorDecoratorsActivatedOn = 143
|
||||
readOnlyMessage = 89,
|
||||
renameOnType = 90,
|
||||
renderControlCharacters = 91,
|
||||
renderFinalNewline = 92,
|
||||
renderLineHighlight = 93,
|
||||
renderLineHighlightOnlyWhenFocus = 94,
|
||||
renderValidationDecorations = 95,
|
||||
renderWhitespace = 96,
|
||||
revealHorizontalRightPadding = 97,
|
||||
roundedSelection = 98,
|
||||
rulers = 99,
|
||||
scrollbar = 100,
|
||||
scrollBeyondLastColumn = 101,
|
||||
scrollBeyondLastLine = 102,
|
||||
scrollPredominantAxis = 103,
|
||||
selectionClipboard = 104,
|
||||
selectionHighlight = 105,
|
||||
selectOnLineNumbers = 106,
|
||||
showFoldingControls = 107,
|
||||
showUnused = 108,
|
||||
snippetSuggestions = 109,
|
||||
smartSelect = 110,
|
||||
smoothScrolling = 111,
|
||||
stickyScroll = 112,
|
||||
stickyTabStops = 113,
|
||||
stopRenderingLineAfter = 114,
|
||||
suggest = 115,
|
||||
suggestFontSize = 116,
|
||||
suggestLineHeight = 117,
|
||||
suggestOnTriggerCharacters = 118,
|
||||
suggestSelection = 119,
|
||||
tabCompletion = 120,
|
||||
tabIndex = 121,
|
||||
unicodeHighlighting = 122,
|
||||
unusualLineTerminators = 123,
|
||||
useShadowDOM = 124,
|
||||
useTabStops = 125,
|
||||
wordBreak = 126,
|
||||
wordSeparators = 127,
|
||||
wordWrap = 128,
|
||||
wordWrapBreakAfterCharacters = 129,
|
||||
wordWrapBreakBeforeCharacters = 130,
|
||||
wordWrapColumn = 131,
|
||||
wordWrapOverride1 = 132,
|
||||
wordWrapOverride2 = 133,
|
||||
wrappingIndent = 134,
|
||||
wrappingStrategy = 135,
|
||||
showDeprecated = 136,
|
||||
inlayHints = 137,
|
||||
editorClassName = 138,
|
||||
pixelRatio = 139,
|
||||
tabFocusMode = 140,
|
||||
layoutInfo = 141,
|
||||
wrappingInfo = 142,
|
||||
defaultColorDecorators = 143,
|
||||
colorDecoratorsActivatedOn = 144
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -920,4 +921,4 @@ export enum WrappingIndent {
|
|||
* DeepIndent => wrapped lines get +2 indentation toward the parent.
|
||||
*/
|
||||
DeepIndent = 3
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,15 @@
|
|||
border: 1px solid var(--vscode-inputValidation-infoBorder);
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .message p {
|
||||
margin-block: 0px;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .message a {
|
||||
font-weight: bold;
|
||||
color: var(--vscode-inputValidation-infoForeground);
|
||||
}
|
||||
|
||||
.monaco-editor.hc-black .monaco-editor-overlaymessage .message,
|
||||
.monaco-editor.hc-light .monaco-editor-overlaymessage .message {
|
||||
border-width: 2px;
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { TimeoutTimer } from 'vs/base/common/async';
|
||||
import { IMarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import 'vs/css!./messageController';
|
||||
|
@ -14,9 +16,12 @@ import { IPosition } from 'vs/editor/common/core/position';
|
|||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { PositionAffinity } from 'vs/editor/common/model';
|
||||
import { openLinkFromMarkdown } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
|
||||
export class MessageController implements IEditorContribution {
|
||||
|
||||
|
@ -32,10 +37,13 @@ export class MessageController implements IEditorContribution {
|
|||
private readonly _visible: IContextKey<boolean>;
|
||||
private readonly _messageWidget = new MutableDisposable<MessageWidget>();
|
||||
private readonly _messageListeners = new DisposableStore();
|
||||
private _message: { element: HTMLElement; dispose: () => void } | undefined;
|
||||
private _focus: boolean = false;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService
|
||||
) {
|
||||
|
||||
this._editor = editor;
|
||||
|
@ -43,6 +51,7 @@ export class MessageController implements IEditorContribution {
|
|||
}
|
||||
|
||||
dispose(): void {
|
||||
this._message?.dispose();
|
||||
this._messageListeners.dispose();
|
||||
this._messageWidget.dispose();
|
||||
this._visible.reset();
|
||||
|
@ -52,20 +61,33 @@ export class MessageController implements IEditorContribution {
|
|||
return this._visible.get();
|
||||
}
|
||||
|
||||
showMessage(message: string, position: IPosition): void {
|
||||
showMessage(message: IMarkdownString | string, position: IPosition): void {
|
||||
|
||||
alert(message);
|
||||
alert(isMarkdownString(message) ? message.value : message);
|
||||
|
||||
this._visible.set(true);
|
||||
this._messageWidget.clear();
|
||||
this._messageListeners.clear();
|
||||
this._messageWidget.value = new MessageWidget(this._editor, position, message);
|
||||
this._message = isMarkdownString(message) ? renderMarkdown(message, {
|
||||
actionHandler: {
|
||||
callback: (url) => openLinkFromMarkdown(this._openerService, url, isMarkdownString(message) ? message.isTrusted : undefined),
|
||||
disposables: this._messageListeners
|
||||
},
|
||||
}) : undefined;
|
||||
this._messageWidget.value = new MessageWidget(this._editor, position, typeof message === 'string' ? message : this._message!.element);
|
||||
|
||||
// close on blur, cursor, model change, dispose
|
||||
this._messageListeners.add(this._editor.onDidBlurEditorText(() => this.closeMessage()));
|
||||
this._messageListeners.add(this._editor.onDidBlurEditorText(() => {
|
||||
if (!this._focus) {
|
||||
this.closeMessage();
|
||||
}
|
||||
}
|
||||
));
|
||||
this._messageListeners.add(this._editor.onDidChangeCursorPosition(() => this.closeMessage()));
|
||||
this._messageListeners.add(this._editor.onDidDispose(() => this.closeMessage()));
|
||||
this._messageListeners.add(this._editor.onDidChangeModel(() => this.closeMessage()));
|
||||
this._messageListeners.add(dom.addDisposableListener(this._messageWidget.value.getDomNode(), dom.EventType.MOUSE_ENTER, () => this._focus = true, true));
|
||||
this._messageListeners.add(dom.addDisposableListener(this._messageWidget.value.getDomNode(), dom.EventType.MOUSE_LEAVE, () => this._focus = false, true));
|
||||
|
||||
// 3sec
|
||||
this._messageListeners.add(new TimeoutTimer(() => this.closeMessage(), 3000));
|
||||
|
@ -132,7 +154,7 @@ class MessageWidget implements IContentWidget {
|
|||
return { dispose };
|
||||
}
|
||||
|
||||
constructor(editor: ICodeEditor, { lineNumber, column }: IPosition, text: string) {
|
||||
constructor(editor: ICodeEditor, { lineNumber, column }: IPosition, text: HTMLElement | string) {
|
||||
|
||||
this._editor = editor;
|
||||
this._editor.revealLinesInCenterIfOutsideViewport(lineNumber, lineNumber, ScrollType.Smooth);
|
||||
|
@ -147,8 +169,13 @@ class MessageWidget implements IContentWidget {
|
|||
this._domNode.appendChild(anchorTop);
|
||||
|
||||
const message = document.createElement('div');
|
||||
message.classList.add('message');
|
||||
message.textContent = text;
|
||||
if (typeof text === 'string') {
|
||||
message.classList.add('message');
|
||||
message.textContent = text;
|
||||
} else {
|
||||
text.classList.add('message');
|
||||
message.appendChild(text);
|
||||
}
|
||||
this._domNode.appendChild(message);
|
||||
|
||||
const anchorBottom = document.createElement('div');
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { MessageController } from 'vs/editor/contrib/message/browser/messageController';
|
||||
import * as nls from 'vs/nls';
|
||||
|
@ -24,11 +26,16 @@ export class ReadOnlyMessageController extends Disposable implements IEditorCont
|
|||
private _onDidAttemptReadOnlyEdit(): void {
|
||||
const messageController = MessageController.get(this.editor);
|
||||
if (messageController && this.editor.hasModel()) {
|
||||
if (this.editor.isSimpleWidget) {
|
||||
messageController.showMessage(nls.localize('editor.simple.readonly', "Cannot edit in read-only input"), this.editor.getPosition());
|
||||
} else {
|
||||
messageController.showMessage(nls.localize('editor.readonly', "Cannot edit in read-only editor"), this.editor.getPosition());
|
||||
let message = this.editor.getOptions().get(EditorOption.readOnlyMessage);
|
||||
if (!message) {
|
||||
if (this.editor.isSimpleWidget) {
|
||||
message = new MarkdownString(nls.localize('editor.simple.readonly', "Cannot edit in read-only input"));
|
||||
} else {
|
||||
message = new MarkdownString(nls.localize('editor.readonly', "Cannot edit in read-only editor"));
|
||||
}
|
||||
}
|
||||
|
||||
messageController.showMessage(message, this.editor.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
116
src/vs/monaco.d.ts
vendored
116
src/vs/monaco.d.ts
vendored
|
@ -3309,6 +3309,10 @@ declare namespace monaco.editor {
|
|||
* Defaults to false.
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
/**
|
||||
* The message to display when the editor is readonly.
|
||||
*/
|
||||
readOnlyMessage?: IMarkdownString;
|
||||
/**
|
||||
* Should the textarea used for input use the DOM `readonly` attribute.
|
||||
* Defaults to false.
|
||||
|
@ -4934,61 +4938,62 @@ declare namespace monaco.editor {
|
|||
quickSuggestions = 86,
|
||||
quickSuggestionsDelay = 87,
|
||||
readOnly = 88,
|
||||
renameOnType = 89,
|
||||
renderControlCharacters = 90,
|
||||
renderFinalNewline = 91,
|
||||
renderLineHighlight = 92,
|
||||
renderLineHighlightOnlyWhenFocus = 93,
|
||||
renderValidationDecorations = 94,
|
||||
renderWhitespace = 95,
|
||||
revealHorizontalRightPadding = 96,
|
||||
roundedSelection = 97,
|
||||
rulers = 98,
|
||||
scrollbar = 99,
|
||||
scrollBeyondLastColumn = 100,
|
||||
scrollBeyondLastLine = 101,
|
||||
scrollPredominantAxis = 102,
|
||||
selectionClipboard = 103,
|
||||
selectionHighlight = 104,
|
||||
selectOnLineNumbers = 105,
|
||||
showFoldingControls = 106,
|
||||
showUnused = 107,
|
||||
snippetSuggestions = 108,
|
||||
smartSelect = 109,
|
||||
smoothScrolling = 110,
|
||||
stickyScroll = 111,
|
||||
stickyTabStops = 112,
|
||||
stopRenderingLineAfter = 113,
|
||||
suggest = 114,
|
||||
suggestFontSize = 115,
|
||||
suggestLineHeight = 116,
|
||||
suggestOnTriggerCharacters = 117,
|
||||
suggestSelection = 118,
|
||||
tabCompletion = 119,
|
||||
tabIndex = 120,
|
||||
unicodeHighlighting = 121,
|
||||
unusualLineTerminators = 122,
|
||||
useShadowDOM = 123,
|
||||
useTabStops = 124,
|
||||
wordBreak = 125,
|
||||
wordSeparators = 126,
|
||||
wordWrap = 127,
|
||||
wordWrapBreakAfterCharacters = 128,
|
||||
wordWrapBreakBeforeCharacters = 129,
|
||||
wordWrapColumn = 130,
|
||||
wordWrapOverride1 = 131,
|
||||
wordWrapOverride2 = 132,
|
||||
wrappingIndent = 133,
|
||||
wrappingStrategy = 134,
|
||||
showDeprecated = 135,
|
||||
inlayHints = 136,
|
||||
editorClassName = 137,
|
||||
pixelRatio = 138,
|
||||
tabFocusMode = 139,
|
||||
layoutInfo = 140,
|
||||
wrappingInfo = 141,
|
||||
defaultColorDecorators = 142,
|
||||
colorDecoratorsActivatedOn = 143
|
||||
readOnlyMessage = 89,
|
||||
renameOnType = 90,
|
||||
renderControlCharacters = 91,
|
||||
renderFinalNewline = 92,
|
||||
renderLineHighlight = 93,
|
||||
renderLineHighlightOnlyWhenFocus = 94,
|
||||
renderValidationDecorations = 95,
|
||||
renderWhitespace = 96,
|
||||
revealHorizontalRightPadding = 97,
|
||||
roundedSelection = 98,
|
||||
rulers = 99,
|
||||
scrollbar = 100,
|
||||
scrollBeyondLastColumn = 101,
|
||||
scrollBeyondLastLine = 102,
|
||||
scrollPredominantAxis = 103,
|
||||
selectionClipboard = 104,
|
||||
selectionHighlight = 105,
|
||||
selectOnLineNumbers = 106,
|
||||
showFoldingControls = 107,
|
||||
showUnused = 108,
|
||||
snippetSuggestions = 109,
|
||||
smartSelect = 110,
|
||||
smoothScrolling = 111,
|
||||
stickyScroll = 112,
|
||||
stickyTabStops = 113,
|
||||
stopRenderingLineAfter = 114,
|
||||
suggest = 115,
|
||||
suggestFontSize = 116,
|
||||
suggestLineHeight = 117,
|
||||
suggestOnTriggerCharacters = 118,
|
||||
suggestSelection = 119,
|
||||
tabCompletion = 120,
|
||||
tabIndex = 121,
|
||||
unicodeHighlighting = 122,
|
||||
unusualLineTerminators = 123,
|
||||
useShadowDOM = 124,
|
||||
useTabStops = 125,
|
||||
wordBreak = 126,
|
||||
wordSeparators = 127,
|
||||
wordWrap = 128,
|
||||
wordWrapBreakAfterCharacters = 129,
|
||||
wordWrapBreakBeforeCharacters = 130,
|
||||
wordWrapColumn = 131,
|
||||
wordWrapOverride1 = 132,
|
||||
wordWrapOverride2 = 133,
|
||||
wrappingIndent = 134,
|
||||
wrappingStrategy = 135,
|
||||
showDeprecated = 136,
|
||||
inlayHints = 137,
|
||||
editorClassName = 138,
|
||||
pixelRatio = 139,
|
||||
tabFocusMode = 140,
|
||||
layoutInfo = 141,
|
||||
wrappingInfo = 142,
|
||||
defaultColorDecorators = 143,
|
||||
colorDecoratorsActivatedOn = 144
|
||||
}
|
||||
|
||||
export const EditorOptions: {
|
||||
|
@ -5083,6 +5088,7 @@ declare namespace monaco.editor {
|
|||
quickSuggestions: IEditorOption<EditorOption.quickSuggestions, InternalQuickSuggestionsOptions>;
|
||||
quickSuggestionsDelay: IEditorOption<EditorOption.quickSuggestionsDelay, number>;
|
||||
readOnly: IEditorOption<EditorOption.readOnly, boolean>;
|
||||
readOnlyMessage: IEditorOption<EditorOption.readOnlyMessage, any>;
|
||||
renameOnType: IEditorOption<EditorOption.renameOnType, boolean>;
|
||||
renderControlCharacters: IEditorOption<EditorOption.renderControlCharacters, boolean>;
|
||||
renderFinalNewline: IEditorOption<EditorOption.renderFinalNewline, 'on' | 'off' | 'dimmed'>;
|
||||
|
|
|
@ -18,6 +18,7 @@ import { localize } from 'vs/nls';
|
|||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
//#region file service & providers
|
||||
|
||||
|
@ -583,6 +584,7 @@ export const enum FileSystemProviderCapabilities {
|
|||
export interface IFileSystemProvider {
|
||||
|
||||
readonly capabilities: FileSystemProviderCapabilities;
|
||||
readonly readOnlyMessage?: IMarkdownString;
|
||||
readonly onDidChangeCapabilities: Event<void>;
|
||||
|
||||
readonly onDidChangeFile: Event<readonly IFileChange[]>;
|
||||
|
|
|
@ -17,6 +17,7 @@ import { IWorkbenchFileService } from 'vs/workbench/services/files/common/files'
|
|||
import { normalizeWatcherPattern } from 'vs/platform/files/common/watcher';
|
||||
import { GLOBSTAR } from 'vs/base/common/glob';
|
||||
import { rtrim } from 'vs/base/common/strings';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
|
@ -50,8 +51,8 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
|||
this._watches.dispose();
|
||||
}
|
||||
|
||||
async $registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): Promise<void> {
|
||||
this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, handle, this._proxy));
|
||||
async $registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities, readonlyMessage?: IMarkdownString): Promise<void> {
|
||||
this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, readonlyMessage, handle, this._proxy));
|
||||
}
|
||||
|
||||
$unregisterProvider(handle: number): void {
|
||||
|
@ -273,6 +274,7 @@ class RemoteFileSystemProvider implements IFileSystemProviderWithFileReadWriteCa
|
|||
fileService: IFileService,
|
||||
scheme: string,
|
||||
capabilities: FileSystemProviderCapabilities,
|
||||
public readonly readOnlyMessage: IMarkdownString | undefined,
|
||||
private readonly _handle: number,
|
||||
private readonly _proxy: ExtHostFileSystemShape
|
||||
) {
|
||||
|
|
|
@ -1236,7 +1236,7 @@ export interface IFileChangeDto {
|
|||
}
|
||||
|
||||
export interface MainThreadFileSystemShape extends IDisposable {
|
||||
$registerFileSystemProvider(handle: number, scheme: string, capabilities: files.FileSystemProviderCapabilities): Promise<void>;
|
||||
$registerFileSystemProvider(handle: number, scheme: string, capabilities: files.FileSystemProviderCapabilities, readonlyMessage?: IMarkdownString): Promise<void>;
|
||||
$unregisterProvider(handle: number): void;
|
||||
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { CharCode } from 'vs/base/common/charCode';
|
|||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IMarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
class FsLinkProvider {
|
||||
|
||||
|
@ -128,7 +129,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
|||
this._linkProviderRegistration?.dispose();
|
||||
}
|
||||
|
||||
registerFileSystemProvider(extension: IExtensionDescription, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean; isReadonly?: boolean } = {}) {
|
||||
registerFileSystemProvider(extension: IExtensionDescription, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean; isReadonly?: boolean | vscode.MarkdownString } = {}) {
|
||||
|
||||
// validate the given provider is complete
|
||||
ExtHostFileSystem._validateFileSystemProvider(provider);
|
||||
|
@ -164,7 +165,20 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
|||
capabilities += files.FileSystemProviderCapabilities.FileOpenReadWriteClose;
|
||||
}
|
||||
|
||||
this._proxy.$registerFileSystemProvider(handle, scheme, capabilities).catch(err => {
|
||||
let readOnlyMessage: IMarkdownString | undefined;
|
||||
if (options.isReadonly && isMarkdownString(options.isReadonly)) {
|
||||
checkProposedApiEnabled(extension, 'readonlyMessage');
|
||||
readOnlyMessage = {
|
||||
value: options.isReadonly.value,
|
||||
isTrusted: options.isReadonly.isTrusted,
|
||||
supportThemeIcons: options.isReadonly.supportThemeIcons,
|
||||
supportHtml: options.isReadonly.supportHtml,
|
||||
baseUri: options.isReadonly.baseUri,
|
||||
uris: options.isReadonly.uris
|
||||
};
|
||||
}
|
||||
|
||||
this._proxy.$registerFileSystemProvider(handle, scheme, capabilities, readOnlyMessage).catch(err => {
|
||||
console.error(`FAILED to register filesystem provider of ${extension.identifier.value}-extension for the scheme ${scheme}`);
|
||||
console.error(err);
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||
import { IExtUri } from 'vs/base/common/resources';
|
||||
import { IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
/**
|
||||
* Base class of editors that want to store and restore view state.
|
||||
|
@ -53,6 +54,12 @@ export abstract class AbstractEditorWithViewState<T extends object> extends Edit
|
|||
super.setEditorVisible(visible, group);
|
||||
}
|
||||
|
||||
protected readonlyValues(isReadonly: boolean | IMarkdownString | undefined): { readOnly: boolean; readOnlyMessage: IMarkdownString | undefined } {
|
||||
const readOnly = !!isReadonly;
|
||||
const readOnlyMessage = typeof isReadonly !== 'boolean' ? isReadonly : undefined;
|
||||
return { readOnly, readOnlyMessage };
|
||||
}
|
||||
|
||||
private onWillCloseEditor(e: IEditorCloseEvent): void {
|
||||
const editor = e.editor;
|
||||
if (editor === this.input) {
|
||||
|
|
|
@ -160,7 +160,7 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
|
|||
// a resolved model might have more specific information about being
|
||||
// readonly or not that the input did not have.
|
||||
control.updateOptions({
|
||||
readOnly: resolvedDiffEditorModel.modifiedModel?.isReadonly(),
|
||||
...this.readonlyValues(resolvedDiffEditorModel.modifiedModel?.isReadonly()),
|
||||
originalEditable: !resolvedDiffEditorModel.originalModel?.isReadonly()
|
||||
});
|
||||
|
||||
|
|
|
@ -144,13 +144,11 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
|
|||
}
|
||||
|
||||
protected getConfigurationOverrides(): ICodeEditorOptions {
|
||||
const readOnly = this.input?.hasCapability(EditorInputCapabilities.Readonly);
|
||||
|
||||
return {
|
||||
overviewRulerLanes: 3,
|
||||
lineNumbersMinChars: 3,
|
||||
fixedOverflowWidgets: true,
|
||||
readOnly,
|
||||
...this.readonlyValues(this.input?.isReadonly()),
|
||||
renderValidationDecorations: 'on' // render problems even in readonly editors (https://github.com/microsoft/vscode/issues/89057)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ export abstract class AbstractTextResourceEditor extends AbstractTextCodeEditor<
|
|||
// was already asked for being readonly or not. The rationale is that
|
||||
// a resolved model might have more specific information about being
|
||||
// readonly or not that the input did not have.
|
||||
control.updateOptions({ readOnly: resolvedModel.isReadonly() });
|
||||
control.updateOptions(this.readonlyValues(resolvedModel.isReadonly()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ import { firstOrDefault } from 'vs/base/common/arrays';
|
|||
import { EditorInputCapabilities, Verbosity, GroupIdentifier, ISaveOptions, IRevertOptions, IMoveResult, IEditorDescriptor, IEditorPane, IUntypedEditorInput, EditorResourceAccessor, AbstractEditorInput, isEditorInput, IEditorIdentifier } from 'vs/workbench/common/editor';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { ConfirmResult } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
export interface IEditorCloseHandler {
|
||||
|
||||
|
@ -124,6 +125,10 @@ export abstract class EditorInput extends AbstractEditorInput {
|
|||
return (this.capabilities & capability) !== 0;
|
||||
}
|
||||
|
||||
isReadonly(): boolean | IMarkdownString | undefined {
|
||||
return this.hasCapability(EditorInputCapabilities.Readonly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display name of this input.
|
||||
*/
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import { IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
/**
|
||||
* The base text editor model for the diff editor. It is made up of two text editor models, the original version
|
||||
|
@ -60,7 +61,7 @@ export class TextDiffEditorModel extends DiffEditorModel {
|
|||
return !!this._textDiffEditorModel;
|
||||
}
|
||||
|
||||
isReadonly(): boolean {
|
||||
isReadonly(): boolean | IMarkdownString {
|
||||
return !!this.modifiedModel && this.modifiedModel.isReadonly();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { ILanguageDetectionService, LanguageDetectionLanguageEventSource } from
|
|||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
/**
|
||||
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
|
||||
|
@ -71,7 +72,7 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel
|
|||
return this.textEditorModelHandle ? this.modelService.getModel(this.textEditorModelHandle) : null;
|
||||
}
|
||||
|
||||
isReadonly(): boolean {
|
||||
isReadonly(): boolean | IMarkdownString {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ export class CustomTextEditorModel extends Disposable implements ICustomEditorMo
|
|||
}
|
||||
|
||||
public isReadonly(): boolean {
|
||||
return this._model.object.isReadonly();
|
||||
return !!this._model.object.isReadonly();
|
||||
}
|
||||
|
||||
public get backupId() {
|
||||
|
|
|
@ -25,6 +25,7 @@ import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
|||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { isConfigured } from 'vs/platform/configuration/common/configuration';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
const enum ForceOpenAs {
|
||||
None,
|
||||
|
@ -192,6 +193,10 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements
|
|||
return this.preferredName;
|
||||
}
|
||||
|
||||
override isReadonly(): boolean | IMarkdownString | undefined {
|
||||
return this.model ? this.model.isReadonly() : super.isReadonly();
|
||||
}
|
||||
|
||||
override getDescription(verbosity?: Verbosity): string | undefined {
|
||||
return this.preferredDescription || super.getDescription(verbosity);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ export class TextFileEditor extends AbstractTextCodeEditor<ICodeEditorViewState>
|
|||
// was already asked for being readonly or not. The rationale is that
|
||||
// a resolved model might have more specific information about being
|
||||
// readonly or not that the input did not have.
|
||||
control.updateOptions({ readOnly: textFileModel.isReadonly() });
|
||||
control.updateOptions(this.readonlyValues(textFileModel.isReadonly()));
|
||||
} catch (error) {
|
||||
await this.handleSetInputError(error, input, options);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ export class ExplorerItem {
|
|||
}
|
||||
|
||||
get isReadonly(): boolean {
|
||||
return this.filesConfigService.isReadonly(this.resource, { resource: this.resource, name: this.name, readonly: this._readonly, locked: this._locked });
|
||||
return !!this.filesConfigService.isReadonly(this.resource, { resource: this.resource, name: this.name, readonly: this._readonly, locked: this._locked });
|
||||
}
|
||||
|
||||
get mtime(): number | undefined {
|
||||
|
|
|
@ -795,7 +795,7 @@ export interface INotebookEditorModel extends IEditorModel {
|
|||
readonly notebook: INotebookTextModel | undefined;
|
||||
isResolved(): this is IResolvedNotebookEditorModel;
|
||||
isDirty(): boolean;
|
||||
isReadonly(): boolean;
|
||||
isReadonly(): boolean | IMarkdownString;
|
||||
isOrphaned(): boolean;
|
||||
hasAssociatedFilePath(): boolean;
|
||||
load(options?: INotebookLoadOptions): Promise<IResolvedNotebookEditorModel>;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { VSBufferReadableStream, bufferToStream, streamToBuffer } from 'vs/base/
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { filter } from 'vs/base/common/objects';
|
||||
|
@ -100,13 +101,11 @@ export class SimpleNotebookEditorModel extends EditorModel implements INotebookE
|
|||
return !SimpleNotebookEditorModel._isStoredFileWorkingCopy(this._workingCopy) && !!this._workingCopy?.hasAssociatedFilePath;
|
||||
}
|
||||
|
||||
isReadonly(): boolean {
|
||||
isReadonly(): boolean | IMarkdownString {
|
||||
if (SimpleNotebookEditorModel._isStoredFileWorkingCopy(this._workingCopy)) {
|
||||
return this._workingCopy?.isReadonly();
|
||||
} else if (this._filesConfigurationService.isReadonly(this.resource)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
return this._filesConfigurationService.isReadonly(this.resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ export const allApiProposals = Object.freeze({
|
|||
quickPickItemIcon: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickItemIcon.d.ts',
|
||||
quickPickItemTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickItemTooltip.d.ts',
|
||||
quickPickSortByLabel: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts',
|
||||
readonlyMessage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.readonlyMessage.d.ts',
|
||||
resolvers: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.resolvers.d.ts',
|
||||
saveEditor: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.saveEditor.d.ts',
|
||||
scmActionButton: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmActionButton.d.ts',
|
||||
|
|
|
@ -20,6 +20,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
|
|||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
export const AutoSaveAfterShortDelayContext = new RawContextKey<boolean>('autoSaveAfterShortDelayContext', false, true);
|
||||
|
||||
|
@ -59,7 +60,7 @@ export interface IFilesConfigurationService {
|
|||
|
||||
readonly onReadonlyChange: Event<void>;
|
||||
|
||||
isReadonly(resource: URI, stat?: IBaseFileStat): boolean;
|
||||
isReadonly(resource: URI, stat?: IBaseFileStat): boolean | IMarkdownString;
|
||||
|
||||
updateReadonly(resource: URI, readonly: true | false | 'toggle' | 'reset'): Promise<void>;
|
||||
|
||||
|
@ -103,7 +104,7 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi
|
|||
private readonly readonlyExcludeMatcher = this._register(new IdleValue(() => this.createReadonlyMatcher(FILES_READONLY_EXCLUDE_CONFIG)));
|
||||
private configuredReadonlyFromPermissions: boolean | undefined;
|
||||
|
||||
private readonly sessionReadonlyOverrides = new ResourceMap<boolean>(resource => this.uriIdentityService.extUri.getComparisonKey(resource));
|
||||
private readonly sessionReadonlyOverrides = new ResourceMap<boolean | IMarkdownString>(resource => this.uriIdentityService.extUri.getComparisonKey(resource));
|
||||
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
|
@ -140,13 +141,13 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi
|
|||
return matcher;
|
||||
}
|
||||
|
||||
isReadonly(resource: URI, stat?: IBaseFileStat): boolean {
|
||||
isReadonly(resource: URI, stat?: IBaseFileStat): boolean | IMarkdownString {
|
||||
|
||||
// if the entire file system provider is readonly, we respect that
|
||||
// and do not allow to change readonly. we take this as a hint that
|
||||
// the provider has no capabilities of writing.
|
||||
if (this.fileService.hasCapability(resource, FileSystemProviderCapabilities.Readonly)) {
|
||||
return true;
|
||||
return this.fileService.getProvider(resource.scheme)?.readOnlyMessage ?? true;
|
||||
}
|
||||
|
||||
// session override always wins over the others
|
||||
|
|
|
@ -32,6 +32,7 @@ import { extUri } from 'vs/base/common/resources';
|
|||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
interface IBackupMetaData extends IWorkingCopyBackupMeta {
|
||||
mtime: number;
|
||||
|
@ -1163,7 +1164,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
return !!this.textEditorModel;
|
||||
}
|
||||
|
||||
override isReadonly(): boolean {
|
||||
override isReadonly(): boolean | IMarkdownString {
|
||||
return this.filesConfigurationService.isReadonly(this.resource, this.lastResolvedFileStat);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||
import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService';
|
||||
import { IResourceWorkingCopy, ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy';
|
||||
import { IFileWorkingCopy, IFileWorkingCopyModel, IFileWorkingCopyModelFactory } from 'vs/workbench/services/workingCopy/common/fileWorkingCopy';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
/**
|
||||
* Stored file specific working copy model factory.
|
||||
|
@ -145,7 +146,7 @@ export interface IStoredFileWorkingCopy<M extends IStoredFileWorkingCopyModel> e
|
|||
/**
|
||||
* Whether the stored file working copy is readonly or not.
|
||||
*/
|
||||
isReadonly(): boolean;
|
||||
isReadonly(): boolean | IMarkdownString;
|
||||
}
|
||||
|
||||
export interface IResolvedStoredFileWorkingCopy<M extends IStoredFileWorkingCopyModel> extends IStoredFileWorkingCopy<M> {
|
||||
|
@ -1247,7 +1248,7 @@ export class StoredFileWorkingCopy<M extends IStoredFileWorkingCopyModel> extend
|
|||
|
||||
//#region Utilities
|
||||
|
||||
isReadonly(): boolean {
|
||||
isReadonly(): boolean | IMarkdownString {
|
||||
return this.filesConfigurationService.isReadonly(this.resource, this.lastResolvedFileStat);
|
||||
}
|
||||
|
||||
|
|
14
src/vscode-dts/vscode.proposed.readonlyMessage.d.ts
vendored
Normal file
14
src/vscode-dts/vscode.proposed.readonlyMessage.d.ts
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// https://github.com/microsoft/vscode/issues/166971
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export namespace workspace {
|
||||
|
||||
export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider, options?: { readonly isCaseSensitive?: boolean; readonly isReadonly?: boolean | MarkdownString }): Disposable;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue