mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 (#6460)
* Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 * fix servers icon * fix tests
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 (→ or ·) do not have the same width as .
|
||||
* 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)) {
|
||||
|
||||
Reference in New Issue
Block a user