提交 af7765c0 编写于 作者: S Stepan Repin

Add 'trailing' option to render whitespace

上级 6d913c4c
......@@ -72,7 +72,7 @@ export class DomReadingContext {
export class ViewLineOptions {
public readonly themeType: ThemeType;
public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
public readonly renderControlCharacters: boolean;
public readonly spaceWidth: number;
public readonly middotWidth: number;
......
......@@ -529,7 +529,7 @@ export interface IEditorOptions {
* Enable rendering of whitespace.
* Defaults to none.
*/
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
/**
* Enable rendering of control characters.
* Defaults to false.
......@@ -4037,13 +4037,14 @@ export const EditorOptions = {
)),
renderWhitespace: register(new EditorStringEnumOption(
EditorOption.renderWhitespace, 'renderWhitespace',
'selection' as 'selection' | 'none' | 'boundary' | 'all',
['none', 'boundary', 'selection', 'all'] as const,
'selection' as 'selection' | 'none' | 'boundary' | 'trailing' | 'all',
['none', 'boundary', 'selection', 'trailing', 'all'] as const,
{
enumDescriptions: [
'',
nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."),
nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."),
nls.localize('renderWhitespace.trailing', "Render only trailing whitespace characters"),
''
],
description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.")
......
......@@ -14,7 +14,8 @@ export const enum RenderWhitespace {
None = 0,
Boundary = 1,
Selection = 2,
All = 3
Trailing = 3,
All = 4
}
export const enum LinePartMetadata {
......@@ -113,7 +114,7 @@ export class RenderLineInput {
middotWidth: number,
wsmiddotWidth: number,
stopRenderingLineAfter: number,
renderWhitespace: 'none' | 'boundary' | 'selection' | 'all',
renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all',
renderControlCharacters: boolean,
fontLigatures: boolean,
selectionsOnLine: LineRange[] | null
......@@ -138,7 +139,9 @@ export class RenderLineInput {
? RenderWhitespace.Boundary
: renderWhitespace === 'selection'
? RenderWhitespace.Selection
: RenderWhitespace.None
: renderWhitespace === 'trailing'
? RenderWhitespace.Trailing
: RenderWhitespace.None
);
this.renderControlCharacters = renderControlCharacters;
this.fontLigatures = fontLigatures;
......@@ -435,7 +438,11 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
}
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) {
if (input.renderWhitespace === RenderWhitespace.All ||
input.renderWhitespace === RenderWhitespace.Boundary ||
(input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine) ||
input.renderWhitespace === RenderWhitespace.Trailing) {
tokens = _applyRenderWhitespace(input, lineContent, len, tokens);
}
let containsForeignElements = ForeignElementType.None;
......@@ -592,6 +599,7 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
const useMonospaceOptimizations = input.useMonospaceOptimizations;
const selections = input.selectionsOnLine;
const onlyBoundary = (input.renderWhitespace === RenderWhitespace.Boundary);
const onlyTrailing = (input.renderWhitespace === RenderWhitespace.Trailing);
const generateLinePartForEachWhitespace = (input.renderSpaceWidth !== input.spaceWidth);
let result: LinePart[] = [], resultLen = 0;
......@@ -600,10 +608,11 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
let tokenEndIndex = tokens[tokenIndex].endIndex;
const tokensLength = tokens.length;
let lineIsEmptyOrWhitespace = false;
let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
let lastNonWhitespaceIndex: number;
if (firstNonWhitespaceIndex === -1) {
// The entire line is whitespace
lineIsEmptyOrWhitespace = true;
firstNonWhitespaceIndex = len;
lastNonWhitespaceIndex = len;
} else {
......@@ -651,6 +660,11 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;
}
// If rendering only trailing whitespace, check that the charIndex points to trailing whitespace.
if (isInWhitespace && onlyTrailing) {
isInWhitespace = lineIsEmptyOrWhitespace || charIndex > lastNonWhitespaceIndex;
}
if (wasInWhitespace) {
// was in whitespace token
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {
......
......@@ -869,7 +869,7 @@ suite('viewLineRenderer.renderLine', () => {
suite('viewLineRenderer.renderLine 2', () => {
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', selections: LineRange[] | null, expected: string): void {
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all', selections: LineRange[] | null, expected: string): void {
let actual = renderViewLine(new RenderLineInput(
fontIsMonospace,
true,
......@@ -1355,6 +1355,95 @@ suite('viewLineRenderer.renderLine 2', () => {
);
});
test('createLineParts render whitespace for trailing with leading, inner, and without trailing whitespace', () => {
testCreateLineParts(
false,
' Hello world!',
[
createPart(4, 0),
createPart(6, 1),
createPart(14, 2)
],
0,
'trailing',
null,
[
'<span>',
'<span class="mtk0">\u00a0Hel</span>',
'<span class="mtk1">lo</span>',
'<span class="mtk2">\u00a0world!</span>',
'</span>',
].join('')
);
});
test('createLineParts render whitespace for trailing with leading, inner, and trailing whitespace', () => {
testCreateLineParts(
false,
' Hello world! \t',
[
createPart(4, 0),
createPart(6, 1),
createPart(15, 2)
],
0,
'trailing',
null,
[
'<span>',
'<span class="mtk0">\u00a0Hel</span>',
'<span class="mtk1">lo</span>',
'<span class="mtk2">\u00a0world!</span>',
'<span class="mtkz" style="width:30px">\u00b7\u2192\u00a0</span>',
'</span>',
].join('')
);
});
test('createLineParts render whitespace for trailing with 8 leading and 8 trailing whitespaces', () => {
testCreateLineParts(
false,
' Hello world! ',
[
createPart(8, 1),
createPart(10, 2),
createPart(28, 3)
],
0,
'trailing',
null,
[
'<span>',
'<span class="mtk1">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
'<span class="mtk2">He</span>',
'<span class="mtk3">llo\u00a0world!</span>',
'<span class="mtkz" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
'<span class="mtkz" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
'</span>',
].join('')
);
});
test('createLineParts render whitespace for trailing with line containing only whitespaces', () => {
testCreateLineParts(
false,
' \t ',
[
createPart(2, 0),
createPart(3, 1),
],
0,
'trailing',
null,
[
'<span>',
'<span class="mtkz" style="width:40px">\u00b7\u2192\u00a0\u00a0</span>',
'<span class="mtkz" style="width:10px">\u00b7</span>',
'</span>',
].join('')
);
});
test('createLineParts can handle unsorted inline decorations', () => {
let actual = renderViewLine(new RenderLineInput(
false,
......
......@@ -3068,7 +3068,7 @@ declare namespace monaco.editor {
* Enable rendering of whitespace.
* Defaults to none.
*/
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
/**
* Enable rendering of control characters.
* Defaults to false.
......@@ -4048,7 +4048,7 @@ declare namespace monaco.editor {
renderLineHighlight: IEditorOption<EditorOption.renderLineHighlight, 'all' | 'line' | 'none' | 'gutter'>;
renderLineHighlightOnlyWhenFocus: IEditorOption<EditorOption.renderLineHighlightOnlyWhenFocus, boolean>;
renderValidationDecorations: IEditorOption<EditorOption.renderValidationDecorations, 'on' | 'off' | 'editable'>;
renderWhitespace: IEditorOption<EditorOption.renderWhitespace, 'all' | 'none' | 'boundary' | 'selection'>;
renderWhitespace: IEditorOption<EditorOption.renderWhitespace, 'all' | 'none' | 'boundary' | 'selection' | 'trailing'>;
revealHorizontalRightPadding: IEditorOption<EditorOption.revealHorizontalRightPadding, number>;
roundedSelection: IEditorOption<EditorOption.roundedSelection, boolean>;
rulers: IEditorOption<EditorOption.rulers, {}>;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册