Skip to content

Commit

Permalink
Set a read-only message from an extension (#185216)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Alex Dima <[email protected]>
  • Loading branch information
3 people authored Jun 21, 2023
1 parent 76cc1fc commit 1a4e466
Show file tree
Hide file tree
Showing 31 changed files with 349 additions and 151 deletions.
1 change: 1 addition & 0 deletions extensions/vscode-api-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"notebookMime",
"portsAttributes",
"quickPickSortByLabel",
"readonlyMessage",
"resolvers",
"saveEditor",
"scmActionButton",
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
});
});
31 changes: 31 additions & 0 deletions src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

/**
Expand Down Expand Up @@ -5024,6 +5053,7 @@ export const enum EditorOption {
quickSuggestions,
quickSuggestionsDelay,
readOnly,
readOnlyMessage,
renameOnType,
renderControlCharacters,
renderFinalNewline,
Expand Down Expand Up @@ -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.") }
Expand Down
3 changes: 2 additions & 1 deletion src/vs/editor/common/services/resolverService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.
Expand Down
113 changes: 57 additions & 56 deletions src/vs/editor/common/standalone/standaloneEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/**
Expand Down Expand Up @@ -920,4 +921,4 @@ export enum WrappingIndent {
* DeepIndent => wrapped lines get +2 indentation toward the parent.
*/
DeepIndent = 3
}
}
9 changes: 9 additions & 0 deletions src/vs/editor/contrib/message/browser/messageController.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 1a4e466

Please sign in to comment.