Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 (#6460)

* Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385

* fix servers icon

* fix tests
This commit is contained in:
Anthony Dresser
2019-07-22 18:28:21 -07:00
committed by GitHub
parent f2afacd8b2
commit 15fc7a077a
91 changed files with 2562 additions and 972 deletions

View File

@@ -901,10 +901,11 @@ const editorConfiguration: IConfigurationNode = {
},
'editor.renderWhitespace': {
'type': 'string',
'enum': ['none', 'boundary', 'all'],
'enum': ['none', 'boundary', 'selection', 'all'],
'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."),
''
],
default: EDITOR_DEFAULTS.viewInfo.renderWhitespace,

View File

@@ -664,7 +664,7 @@ export interface IEditorOptions {
* Enable rendering of whitespace.
* Defaults to none.
*/
renderWhitespace?: 'none' | 'boundary' | 'all';
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
/**
* Enable rendering of control characters.
* Defaults to false.
@@ -1005,7 +1005,7 @@ export interface InternalEditorViewOptions {
readonly scrollBeyondLastColumn: number;
readonly smoothScrolling: boolean;
readonly stopRenderingLineAfter: number;
readonly renderWhitespace: 'none' | 'boundary' | 'all';
readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
readonly renderControlCharacters: boolean;
readonly fontLigatures: boolean;
readonly renderIndentGuides: boolean;
@@ -2023,7 +2023,7 @@ export class EditorOptionsValidator {
} else if (<any>renderWhitespace === false) {
renderWhitespace = 'none';
}
renderWhitespace = _stringSet<'none' | 'boundary' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'all']);
renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']);
}
let renderLineHighlight = opts.renderLineHighlight;

View File

@@ -314,9 +314,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
}
const primaryCursor = this._cursors.getPrimaryCursor();
const primaryPos = primaryCursor.viewState.position;
const viewLineNumber = primaryPos.lineNumber;
const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos);
return {
toViewLineNumber: primaryPos.lineNumber,
toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos)
isReal: false,
fromViewLineNumber: viewLineNumber,
fromViewVisualColumn: viewVisualColumn,
toViewLineNumber: viewLineNumber,
toViewVisualColumn: viewVisualColumn,
};
}

View File

@@ -3,21 +3,22 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData } from 'vs/editor/common/controller/cursorCommon';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
export interface IColumnSelectResult {
viewStates: SingleCursorState[];
reversed: boolean;
fromLineNumber: number;
fromVisualColumn: number;
toLineNumber: number;
toVisualColumn: number;
}
export class ColumnSelection {
private static _columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {
public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {
let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1;
let reversed = (fromLineNumber > toLineNumber);
let isRTL = (fromVisibleColumn > toVisibleColumn);
@@ -61,64 +62,65 @@ export class ColumnSelection {
));
}
if (result.length === 0) {
// We are after all the lines, so add cursor at the end of each line
for (let i = 0; i < lineCount; i++) {
const lineNumber = fromLineNumber + (reversed ? -i : i);
const maxColumn = model.getLineMaxColumn(lineNumber);
result.push(new SingleCursorState(
new Range(lineNumber, maxColumn, lineNumber, maxColumn), 0,
new Position(lineNumber, maxColumn), 0
));
}
}
return {
viewStates: result,
reversed: reversed,
fromLineNumber: fromLineNumber,
fromVisualColumn: fromVisibleColumn,
toLineNumber: toLineNumber,
toVisualColumn: toVisibleColumn
};
}
public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromViewSelection: Selection, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
const fromViewPosition = new Position(fromViewSelection.selectionStartLineNumber, fromViewSelection.selectionStartColumn);
const fromViewVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, fromViewPosition);
return ColumnSelection._columnSelect(config, model, fromViewPosition.lineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisualColumn);
}
public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {
let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;
if (toViewVisualColumn > 1) {
toViewVisualColumn--;
}
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
return ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);
}
public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {
let maxVisualViewColumn = 0;
let minViewLineNumber = Math.min(cursor.position.lineNumber, toViewLineNumber);
let maxViewLineNumber = Math.max(cursor.position.lineNumber, toViewLineNumber);
const minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);
const maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);
for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) {
let lineMaxViewColumn = model.getLineMaxColumn(lineNumber);
let lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn));
const lineMaxViewColumn = model.getLineMaxColumn(lineNumber);
const lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn));
maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn);
}
let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;
if (toViewVisualColumn < maxVisualViewColumn) {
toViewVisualColumn++;
}
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);
}
public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
let linesCount = isPaged ? config.pageSize : 1;
toViewLineNumber -= linesCount;
if (toViewLineNumber < 1) {
toViewLineNumber = 1;
}
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {
const linesCount = isPaged ? config.pageSize : 1;
const toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount);
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
}
public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
let linesCount = isPaged ? config.pageSize : 1;
toViewLineNumber += linesCount;
if (toViewLineNumber > model.getLineCount()) {
toViewLineNumber = model.getLineCount();
}
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {
const linesCount = isPaged ? config.pageSize : 1;
const toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount);
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
}
}

View File

@@ -21,6 +21,9 @@ import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
export interface IColumnSelectData {
isReal: boolean;
fromViewLineNumber: number;
fromViewVisualColumn: number;
toViewLineNumber: number;
toViewVisualColumn: number;
}

View File

@@ -13,7 +13,8 @@ import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
export const enum RenderWhitespace {
None = 0,
Boundary = 1,
All = 2
Selection = 2,
All = 3
}
class LinePart {
@@ -31,6 +32,28 @@ class LinePart {
}
}
export class LineRange {
/**
* Zero-based offset on which the range starts, inclusive.
*/
public readonly startOffset: number;
/**
* Zero-based offset on which the range ends, inclusive.
*/
public readonly endOffset: number;
constructor(startIndex: number, endIndex: number) {
this.startOffset = startIndex;
this.endOffset = endIndex;
}
public equals(otherLineRange: LineRange) {
return this.startOffset === otherLineRange.startOffset
&& this.endOffset === otherLineRange.endOffset;
}
}
export class RenderLineInput {
public readonly useMonospaceOptimizations: boolean;
@@ -49,6 +72,12 @@ export class RenderLineInput {
public readonly renderControlCharacters: boolean;
public readonly fontLigatures: boolean;
/**
* Defined only when renderWhitespace is 'selection'. Selections are non-overlapping,
* and ordered by position within the line.
*/
public readonly selectionsOnLine: LineRange[] | null;
constructor(
useMonospaceOptimizations: boolean,
canUseHalfwidthRightwardsArrow: boolean,
@@ -62,9 +91,10 @@ export class RenderLineInput {
tabSize: number,
spaceWidth: number,
stopRenderingLineAfter: number,
renderWhitespace: 'none' | 'boundary' | 'all',
renderWhitespace: 'none' | 'boundary' | 'selection' | 'all',
renderControlCharacters: boolean,
fontLigatures: boolean
fontLigatures: boolean,
selectionsOnLine: LineRange[] | null
) {
this.useMonospaceOptimizations = useMonospaceOptimizations;
this.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow;
@@ -83,10 +113,35 @@ export class RenderLineInput {
? RenderWhitespace.All
: renderWhitespace === 'boundary'
? RenderWhitespace.Boundary
: RenderWhitespace.None
: renderWhitespace === 'selection'
? RenderWhitespace.Selection
: RenderWhitespace.None
);
this.renderControlCharacters = renderControlCharacters;
this.fontLigatures = fontLigatures;
this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1);
}
private sameSelection(otherSelections: LineRange[] | null): boolean {
if (this.selectionsOnLine === null) {
return otherSelections === null;
}
if (otherSelections === null) {
return false;
}
if (otherSelections.length !== this.selectionsOnLine.length) {
return false;
}
for (let i = 0; i < this.selectionsOnLine.length; i++) {
if (!this.selectionsOnLine[i].equals(otherSelections[i])) {
return false;
}
}
return true;
}
public equals(other: RenderLineInput): boolean {
@@ -106,6 +161,7 @@ export class RenderLineInput {
&& this.fontLigatures === other.fontLigatures
&& LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations)
&& this.lineTokens.equals(other.lineTokens)
&& this.sameSelection(other.selectionsOnLine)
);
}
}
@@ -338,8 +394,8 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
}
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary) {
tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.renderWhitespace === RenderWhitespace.Boundary);
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) {
tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.selectionsOnLine, input.renderWhitespace === RenderWhitespace.Boundary);
}
let containsForeignElements = ForeignElementType.None;
if (input.lineDecorations.length > 0) {
@@ -481,7 +537,7 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces:
* Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (&rarr; or &middot;) do not have the same width as &nbsp;.
* The rendering phase will generate `style="width:..."` for these tokens.
*/
function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, onlyBoundary: boolean): LinePart[] {
function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, selections: LineRange[] | null, onlyBoundary: boolean): LinePart[] {
let result: LinePart[] = [], resultLen = 0;
let tokenIndex = 0;
@@ -511,11 +567,17 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
}
}
tmpIndent = tmpIndent % tabSize;
let wasInWhitespace = false;
let currentSelectionIndex = 0;
let currentSelection = selections && selections[currentSelectionIndex];
for (let charIndex = fauxIndentLength; charIndex < len; charIndex++) {
const chCode = lineContent.charCodeAt(charIndex);
if (currentSelection && charIndex >= currentSelection.endOffset) {
currentSelectionIndex++;
currentSelection = selections && selections[currentSelectionIndex];
}
let isInWhitespace: boolean;
if (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) {
// in leading or trailing whitespace
@@ -540,6 +602,11 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
isInWhitespace = false;
}
// If rendering whitespace on selection, check that the charIndex falls within a selection
if (isInWhitespace && selections) {
isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;
}
if (wasInWhitespace) {
// was in whitespace token
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {