未验证 提交 fb80c0e4 编写于 作者: A Alexandru Dima 提交者: GitHub

Merge pull request #107126 from Timmmm/atomic_tabs

Add atomic tabs option
......@@ -18,6 +18,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
import * as dom from 'vs/base/browser/dom';
import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';
export interface IViewZoneData {
viewZoneId: string;
......@@ -239,6 +240,7 @@ export class HitTestContext {
public readonly layoutInfo: EditorLayoutInfo;
public readonly viewDomNode: HTMLElement;
public readonly lineHeight: number;
public readonly atomicSoftTabs: boolean;
public readonly typicalHalfwidthCharacterWidth: number;
public readonly lastRenderData: PointerHandlerLastRenderData;
......@@ -251,6 +253,7 @@ export class HitTestContext {
this.layoutInfo = options.get(EditorOption.layoutInfo);
this.viewDomNode = viewHelper.viewDomNode;
this.lineHeight = options.get(EditorOption.lineHeight);
this.atomicSoftTabs = options.get(EditorOption.atomicSoftTabs);
this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;
this.lastRenderData = lastRenderData;
this._context = context;
......@@ -1010,6 +1013,17 @@ export class MouseTargetFactory {
};
}
private static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position {
const minColumn = viewModel.getLineMinColumn(position.lineNumber);
const lineContent = viewModel.getLineContent(position.lineNumber);
const { tabSize } = viewModel.getTextModelOptions();
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - minColumn, tabSize, Direction.Nearest);
if (newPosition !== -1) {
return new Position(position.lineNumber, newPosition + minColumn);
}
return position;
}
private static _doHitTest(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult {
// State of the art (18.10.2012):
// The spec says browsers should support document.caretPositionFromPoint, but nobody implemented it (http://dev.w3.org/csswg/cssom-view/)
......@@ -1028,24 +1042,24 @@ export class MouseTargetFactory {
// Thank you browsers for making this so 'easy' :)
let result: IHitTestResult;
if (typeof document.caretRangeFromPoint === 'function') {
return this._doHitTestWithCaretRangeFromPoint(ctx, request);
result = this._doHitTestWithCaretRangeFromPoint(ctx, request);
} else if ((<any>document).caretPositionFromPoint) {
return this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates());
result = this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates());
} else if ((<any>document.body).createTextRange) {
return this._doHitTestWithMoveToPoint(ctx, request.pos.toClientCoordinates());
result = this._doHitTestWithMoveToPoint(ctx, request.pos.toClientCoordinates());
} else {
result = {
position: null,
hitTarget: null
};
}
return {
position: null,
hitTarget: null
};
// Snap to the nearest soft tab boundary if atomic soft tabs are enabled.
if (result.position && ctx.atomicSoftTabs) {
result.position = this._snapToSoftTabBoundary(result.position, ctx.model);
}
return result;
}
}
......
......@@ -420,6 +420,11 @@ export interface IEditorOptions {
* Defaults to advanced.
*/
autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
/**
* Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation.
* This means selection will snap to indentation boundaries.
*/
atomicSoftTabs?: boolean;
/**
* Enable format on type.
* Defaults to false.
......@@ -3631,6 +3636,7 @@ export const enum EditorOption {
autoIndent,
automaticLayout,
autoSurround,
atomicSoftTabs,
codeLens,
codeLensFontFamily,
codeLensFontSize,
......@@ -3859,6 +3865,10 @@ export const EditorOptions = {
description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections when typing quotes or brackets.")
}
)),
atomicSoftTabs: register(new EditorBooleanOption(
EditorOption.atomicSoftTabs, 'atomicSoftTabs', false,
{ description: nls.localize('atomicSoftTabs', "Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation. This means selection will snap to indentation boundaries.") }
)),
codeLens: register(new EditorBooleanOption(
EditorOption.codeLens, 'codeLens', true,
{ description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") }
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CharCode } from 'vs/base/common/charCode';
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
export const enum Direction {
Left,
Right,
Nearest,
}
export class AtomicTabMoveOperations {
/**
* Get the visible column at the position. If we get to a non-whitespace character first
* or past the end of string then return -1.
*
* **Note** `position` and the return value are 0-based.
*/
public static whitespaceVisibleColumn(lineContent: string, position: number, tabSize: number): [number, number, number] {
const lineLength = lineContent.length;
let visibleColumn = 0;
let prevTabStopPosition = -1;
let prevTabStopVisibleColumn = -1;
for (let i = 0; i < lineLength; i++) {
if (i === position) {
return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];
}
if (visibleColumn % tabSize === 0) {
prevTabStopPosition = i;
prevTabStopVisibleColumn = visibleColumn;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
visibleColumn += 1;
break;
case CharCode.Tab:
// Skip to the next multiple of tabSize.
visibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
break;
default:
return [-1, -1, -1];
}
}
if (position === lineLength) {
return [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];
}
return [-1, -1, -1];
}
/**
* Return the position that should result from a move left, right or to the
* nearest tab, if atomic tabs are enabled. Left and right are used for the
* arrow key movements, nearest is used for mouse selection. It returns
* -1 if atomic tabs are not relevant and you should fall back to normal
* behaviour.
*
* **Note**: `position` and the return value are 0-based.
*/
public static atomicPosition(lineContent: string, position: number, tabSize: number, direction: Direction): number {
const lineLength = lineContent.length;
// Get the 0-based visible column corresponding to the position, or return
// -1 if it is not in the initial whitespace.
const [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn] = AtomicTabMoveOperations.whitespaceVisibleColumn(lineContent, position, tabSize);
if (visibleColumn === -1) {
return -1;
}
// Is the output left or right of the current position. The case for nearest
// where it is the same as the current position is handled in the switch.
let left: boolean;
switch (direction) {
case Direction.Left:
left = true;
break;
case Direction.Right:
left = false;
break;
case Direction.Nearest:
// The code below assumes the output position is either left or right
// of the input position. If it is the same, return immediately.
if (visibleColumn % tabSize === 0) {
return position;
}
// Go to the nearest indentation.
left = visibleColumn % tabSize <= (tabSize / 2);
break;
}
// If going left, we can just use the info about the last tab stop position and
// last tab stop visible column that we computed in the first walk over the whitespace.
if (left) {
if (prevTabStopPosition === -1) {
return -1;
}
// If the direction is left, we need to keep scanning right to ensure
// that targetVisibleColumn + tabSize is before non-whitespace.
// This is so that when we press left at the end of a partial
// indentation it only goes one character. For example ' foo' with
// tabSize 4, should jump from position 6 to position 5, not 4.
let currentVisibleColumn = prevTabStopVisibleColumn;
for (let i = prevTabStopPosition; i < lineLength; ++i) {
if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {
// It is a full indentation.
return prevTabStopPosition;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
currentVisibleColumn += 1;
break;
case CharCode.Tab:
currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);
break;
default:
return -1;
}
}
if (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {
return prevTabStopPosition;
}
// It must have been a partial indentation.
return -1;
}
// We are going right.
const targetVisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
// We can just continue from where whitespaceVisibleColumn got to.
let currentVisibleColumn = visibleColumn;
for (let i = position; i < lineLength; i++) {
if (currentVisibleColumn === targetVisibleColumn) {
return i;
}
const chCode = lineContent.charCodeAt(i);
switch (chCode) {
case CharCode.Space:
currentVisibleColumn += 1;
break;
case CharCode.Tab:
currentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);
break;
default:
return -1;
}
}
// This condition handles when the target column is at the end of the line.
if (currentVisibleColumn === targetVisibleColumn) {
return lineLength;
}
return -1;
}
}
......@@ -62,6 +62,7 @@ export class CursorConfiguration {
public readonly tabSize: number;
public readonly indentSize: number;
public readonly insertSpaces: boolean;
public readonly atomicSoftTabs: boolean;
public readonly pageSize: number;
public readonly lineHeight: number;
public readonly useTabStops: boolean;
......@@ -113,6 +114,7 @@ export class CursorConfiguration {
this.tabSize = modelOptions.tabSize;
this.indentSize = modelOptions.indentSize;
this.insertSpaces = modelOptions.insertSpaces;
this.atomicSoftTabs = options.get(EditorOption.atomicSoftTabs);
this.lineHeight = options.get(EditorOption.lineHeight);
this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);
this.useTabStops = options.get(EditorOption.useTabStops);
......@@ -554,14 +556,14 @@ export class CursorColumns {
}
/**
* ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
* ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
*/
public static prevRenderTabStop(column: number, tabSize: number): number {
return column - 1 - (column - 1) % tabSize;
}
/**
* ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
* ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
*/
public static prevIndentTabStop(column: number, indentSize: number): number {
return column - 1 - (column - 1) % indentSize;
......
......@@ -8,6 +8,7 @@ import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import * as strings from 'vs/base/common/strings';
import { Constants } from 'vs/base/common/uint';
import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';
export class CursorPosition {
_cursorPositionBrand: void;
......@@ -35,8 +36,20 @@ export class MoveOperations {
return new Position(lineNumber, column);
}
public static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position {
const minColumn = model.getLineMinColumn(lineNumber);
const lineContent = model.getLineContent(lineNumber);
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Left);
if (newPosition === -1) {
return this.leftPosition(model, lineNumber, column);
}
return new Position(lineNumber, minColumn + newPosition);
}
public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
const pos = MoveOperations.leftPosition(model, lineNumber, column);
const pos = config.atomicSoftTabs
? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize)
: MoveOperations.leftPosition(model, lineNumber, column);
return new CursorPosition(pos.lineNumber, pos.column, 0);
}
......@@ -67,8 +80,20 @@ export class MoveOperations {
return new Position(lineNumber, column);
}
public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {
const minColumn = model.getLineMinColumn(lineNumber);
const lineContent = model.getLineContent(lineNumber);
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - minColumn, tabSize, Direction.Right);
if (newPosition === -1) {
return this.rightPosition(model, lineNumber, column);
}
return new Position(lineNumber, minColumn + newPosition);
}
public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {
const pos = MoveOperations.rightPosition(model, lineNumber, column);
const pos = config.atomicSoftTabs
? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize)
: MoveOperations.rightPosition(model, lineNumber, column);
return new CursorPosition(pos.lineNumber, pos.column, 0);
}
......
......@@ -178,117 +178,118 @@ export enum EditorOption {
autoIndent = 8,
automaticLayout = 9,
autoSurround = 10,
codeLens = 11,
codeLensFontFamily = 12,
codeLensFontSize = 13,
colorDecorators = 14,
columnSelection = 15,
comments = 16,
contextmenu = 17,
copyWithSyntaxHighlighting = 18,
cursorBlinking = 19,
cursorSmoothCaretAnimation = 20,
cursorStyle = 21,
cursorSurroundingLines = 22,
cursorSurroundingLinesStyle = 23,
cursorWidth = 24,
disableLayerHinting = 25,
disableMonospaceOptimizations = 26,
dragAndDrop = 27,
emptySelectionClipboard = 28,
extraEditorClassName = 29,
fastScrollSensitivity = 30,
find = 31,
fixedOverflowWidgets = 32,
folding = 33,
foldingStrategy = 34,
foldingHighlight = 35,
unfoldOnClickAfterEndOfLine = 36,
fontFamily = 37,
fontInfo = 38,
fontLigatures = 39,
fontSize = 40,
fontWeight = 41,
formatOnPaste = 42,
formatOnType = 43,
glyphMargin = 44,
gotoLocation = 45,
hideCursorInOverviewRuler = 46,
highlightActiveIndentGuide = 47,
hover = 48,
inDiffEditor = 49,
letterSpacing = 50,
lightbulb = 51,
lineDecorationsWidth = 52,
lineHeight = 53,
lineNumbers = 54,
lineNumbersMinChars = 55,
links = 56,
matchBrackets = 57,
minimap = 58,
mouseStyle = 59,
mouseWheelScrollSensitivity = 60,
mouseWheelZoom = 61,
multiCursorMergeOverlapping = 62,
multiCursorModifier = 63,
multiCursorPaste = 64,
occurrencesHighlight = 65,
overviewRulerBorder = 66,
overviewRulerLanes = 67,
padding = 68,
parameterHints = 69,
peekWidgetDefaultFocus = 70,
definitionLinkOpensInPeek = 71,
quickSuggestions = 72,
quickSuggestionsDelay = 73,
readOnly = 74,
renameOnType = 75,
renderControlCharacters = 76,
renderIndentGuides = 77,
renderFinalNewline = 78,
renderLineHighlight = 79,
renderLineHighlightOnlyWhenFocus = 80,
renderValidationDecorations = 81,
renderWhitespace = 82,
revealHorizontalRightPadding = 83,
roundedSelection = 84,
rulers = 85,
scrollbar = 86,
scrollBeyondLastColumn = 87,
scrollBeyondLastLine = 88,
scrollPredominantAxis = 89,
selectionClipboard = 90,
selectionHighlight = 91,
selectOnLineNumbers = 92,
showFoldingControls = 93,
showUnused = 94,
snippetSuggestions = 95,
smartSelect = 96,
smoothScrolling = 97,
stopRenderingLineAfter = 98,
suggest = 99,
suggestFontSize = 100,
suggestLineHeight = 101,
suggestOnTriggerCharacters = 102,
suggestSelection = 103,
tabCompletion = 104,
tabIndex = 105,
unusualLineTerminators = 106,
useTabStops = 107,
wordSeparators = 108,
wordWrap = 109,
wordWrapBreakAfterCharacters = 110,
wordWrapBreakBeforeCharacters = 111,
wordWrapColumn = 112,
wordWrapMinified = 113,
wrappingIndent = 114,
wrappingStrategy = 115,
showDeprecated = 116,
editorClassName = 117,
pixelRatio = 118,
tabFocusMode = 119,
layoutInfo = 120,
wrappingInfo = 121
atomicSoftTabs = 11,
codeLens = 12,
codeLensFontFamily = 13,
codeLensFontSize = 14,
colorDecorators = 15,
columnSelection = 16,
comments = 17,
contextmenu = 18,
copyWithSyntaxHighlighting = 19,
cursorBlinking = 20,
cursorSmoothCaretAnimation = 21,
cursorStyle = 22,
cursorSurroundingLines = 23,
cursorSurroundingLinesStyle = 24,
cursorWidth = 25,
disableLayerHinting = 26,
disableMonospaceOptimizations = 27,
dragAndDrop = 28,
emptySelectionClipboard = 29,
extraEditorClassName = 30,
fastScrollSensitivity = 31,
find = 32,
fixedOverflowWidgets = 33,
folding = 34,
foldingStrategy = 35,
foldingHighlight = 36,
unfoldOnClickAfterEndOfLine = 37,
fontFamily = 38,
fontInfo = 39,
fontLigatures = 40,
fontSize = 41,
fontWeight = 42,
formatOnPaste = 43,
formatOnType = 44,
glyphMargin = 45,
gotoLocation = 46,
hideCursorInOverviewRuler = 47,
highlightActiveIndentGuide = 48,
hover = 49,
inDiffEditor = 50,
letterSpacing = 51,
lightbulb = 52,
lineDecorationsWidth = 53,
lineHeight = 54,
lineNumbers = 55,
lineNumbersMinChars = 56,
links = 57,
matchBrackets = 58,
minimap = 59,
mouseStyle = 60,
mouseWheelScrollSensitivity = 61,
mouseWheelZoom = 62,
multiCursorMergeOverlapping = 63,
multiCursorModifier = 64,
multiCursorPaste = 65,
occurrencesHighlight = 66,
overviewRulerBorder = 67,
overviewRulerLanes = 68,
padding = 69,
parameterHints = 70,
peekWidgetDefaultFocus = 71,
definitionLinkOpensInPeek = 72,
quickSuggestions = 73,
quickSuggestionsDelay = 74,
readOnly = 75,
renameOnType = 76,
renderControlCharacters = 77,
renderIndentGuides = 78,
renderFinalNewline = 79,
renderLineHighlight = 80,
renderLineHighlightOnlyWhenFocus = 81,
renderValidationDecorations = 82,
renderWhitespace = 83,
revealHorizontalRightPadding = 84,
roundedSelection = 85,
rulers = 86,
scrollbar = 87,
scrollBeyondLastColumn = 88,
scrollBeyondLastLine = 89,
scrollPredominantAxis = 90,
selectionClipboard = 91,
selectionHighlight = 92,
selectOnLineNumbers = 93,
showFoldingControls = 94,
showUnused = 95,
snippetSuggestions = 96,
smartSelect = 97,
smoothScrolling = 98,
stopRenderingLineAfter = 99,
suggest = 100,
suggestFontSize = 101,
suggestLineHeight = 102,
suggestOnTriggerCharacters = 103,
suggestSelection = 104,
tabCompletion = 105,
tabIndex = 106,
unusualLineTerminators = 107,
useTabStops = 108,
wordSeparators = 109,
wordWrap = 110,
wordWrapBreakAfterCharacters = 111,
wordWrapBreakBeforeCharacters = 112,
wordWrapColumn = 113,
wordWrapMinified = 114,
wrappingIndent = 115,
wrappingStrategy = 116,
showDeprecated = 117,
editorClassName = 118,
pixelRatio = 119,
tabFocusMode = 120,
layoutInfo = 121,
wrappingInfo = 122
}
/**
......
/*---------------------------------------------------------------------------------------------
* 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 { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';
suite('Cursor move command test', () => {
test('Test whitespaceVisibleColumn', () => {
const testCases = [
{
lineContent: ' ',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1],
expectedVisibleColumn: [0, 1, 2, 3, 4, 5, 6, 7, 8, -1],
},
{
lineContent: ' ',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, 0, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, 0, -1],
expectedVisibleColumn: [0, 1, 2, -1],
},
{
lineContent: '\t',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, -1],
expectedVisibleColumn: [0, 4, -1],
},
{
lineContent: '\t ',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, 1, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, 4, -1],
expectedVisibleColumn: [0, 4, 5, -1],
},
{
lineContent: ' \t\t ',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, 0, 2, 3, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, 0, 4, 8, -1],
expectedVisibleColumn: [0, 1, 4, 8, 9, -1],
},
{
lineContent: ' \tA',
tabSize: 4,
expectedPrevTabStopPosition: [-1, 0, 0, -1, -1],
expectedPrevTabStopVisibleColumn: [-1, 0, 0, -1, -1],
expectedVisibleColumn: [0, 1, 4, -1, -1],
},
{
lineContent: 'A',
tabSize: 4,
expectedPrevTabStopPosition: [-1, -1, -1],
expectedPrevTabStopVisibleColumn: [-1, -1, -1],
expectedVisibleColumn: [0, -1, -1],
},
{
lineContent: '',
tabSize: 4,
expectedPrevTabStopPosition: [-1, -1],
expectedPrevTabStopVisibleColumn: [-1, -1],
expectedVisibleColumn: [0, -1],
},
];
for (const testCase of testCases) {
const maxPosition = testCase.expectedVisibleColumn.length;
for (let position = 0; position < maxPosition; position++) {
const actual = AtomicTabMoveOperations.whitespaceVisibleColumn(testCase.lineContent, position, testCase.tabSize);
const expected = [
testCase.expectedPrevTabStopPosition[position],
testCase.expectedPrevTabStopVisibleColumn[position],
testCase.expectedVisibleColumn[position]
];
assert.deepStrictEqual(actual, expected);
}
}
});
test('Test atomicPosition', () => {
const testCases = [
{
lineContent: ' ',
tabSize: 4,
expectedLeft: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1],
expectedRight: [4, 4, 4, 4, 8, 8, 8, 8, -1, -1],
expectedNearest: [0, 0, 0, 4, 4, 4, 4, 8, 8, -1],
},
{
lineContent: ' \t',
tabSize: 4,
expectedLeft: [-1, 0, 0, -1],
expectedRight: [2, 2, -1, -1],
expectedNearest: [0, 0, 2, -1],
},
{
lineContent: '\t ',
tabSize: 4,
expectedLeft: [-1, 0, -1, -1],
expectedRight: [1, -1, -1, -1],
expectedNearest: [0, 1, -1, -1],
},
{
lineContent: ' \t ',
tabSize: 4,
expectedLeft: [-1, 0, 0, -1, -1],
expectedRight: [2, 2, -1, -1, -1],
expectedNearest: [0, 0, 2, -1, -1],
},
{
lineContent: ' A',
tabSize: 4,
expectedLeft: [-1, 0, 0, 0, 0, 4, 4, 4, 4, -1, -1],
expectedRight: [4, 4, 4, 4, 8, 8, 8, 8, -1, -1, -1],
expectedNearest: [0, 0, 0, 4, 4, 4, 4, 8, 8, -1, -1],
},
{
lineContent: ' foo',
tabSize: 4,
expectedLeft: [-1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1],
expectedRight: [4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1],
expectedNearest: [0, 0, 0, 4, 4, -1, -1, -1, -1, -1, -1],
},
];
for (const testCase of testCases) {
for (const { direction, expected } of [
{
direction: Direction.Left,
expected: testCase.expectedLeft,
},
{
direction: Direction.Right,
expected: testCase.expectedRight,
},
{
direction: Direction.Nearest,
expected: testCase.expectedNearest,
},
]) {
const actual = expected.map((_, i) => AtomicTabMoveOperations.atomicPosition(testCase.lineContent, i, testCase.tabSize, direction));
assert.deepStrictEqual(actual, expected);
}
}
});
});
......@@ -2967,6 +2967,11 @@ declare namespace monaco.editor {
* Defaults to advanced.
*/
autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
/**
* Emulate selection behaviour of hard tabs when using soft tabs (spaces) for indentation.
* This means selection will snap to indentation boundaries.
*/
atomicSoftTabs?: boolean;
/**
* Enable format on type.
* Defaults to false.
......@@ -3898,117 +3903,118 @@ declare namespace monaco.editor {
autoIndent = 8,
automaticLayout = 9,
autoSurround = 10,
codeLens = 11,
codeLensFontFamily = 12,
codeLensFontSize = 13,
colorDecorators = 14,
columnSelection = 15,
comments = 16,
contextmenu = 17,
copyWithSyntaxHighlighting = 18,
cursorBlinking = 19,
cursorSmoothCaretAnimation = 20,
cursorStyle = 21,
cursorSurroundingLines = 22,
cursorSurroundingLinesStyle = 23,
cursorWidth = 24,
disableLayerHinting = 25,
disableMonospaceOptimizations = 26,
dragAndDrop = 27,
emptySelectionClipboard = 28,
extraEditorClassName = 29,
fastScrollSensitivity = 30,
find = 31,
fixedOverflowWidgets = 32,
folding = 33,
foldingStrategy = 34,
foldingHighlight = 35,
unfoldOnClickAfterEndOfLine = 36,
fontFamily = 37,
fontInfo = 38,
fontLigatures = 39,
fontSize = 40,
fontWeight = 41,
formatOnPaste = 42,
formatOnType = 43,
glyphMargin = 44,
gotoLocation = 45,
hideCursorInOverviewRuler = 46,
highlightActiveIndentGuide = 47,
hover = 48,
inDiffEditor = 49,
letterSpacing = 50,
lightbulb = 51,
lineDecorationsWidth = 52,
lineHeight = 53,
lineNumbers = 54,
lineNumbersMinChars = 55,
links = 56,
matchBrackets = 57,
minimap = 58,
mouseStyle = 59,
mouseWheelScrollSensitivity = 60,
mouseWheelZoom = 61,
multiCursorMergeOverlapping = 62,
multiCursorModifier = 63,
multiCursorPaste = 64,
occurrencesHighlight = 65,
overviewRulerBorder = 66,
overviewRulerLanes = 67,
padding = 68,
parameterHints = 69,
peekWidgetDefaultFocus = 70,
definitionLinkOpensInPeek = 71,
quickSuggestions = 72,
quickSuggestionsDelay = 73,
readOnly = 74,
renameOnType = 75,
renderControlCharacters = 76,
renderIndentGuides = 77,
renderFinalNewline = 78,
renderLineHighlight = 79,
renderLineHighlightOnlyWhenFocus = 80,
renderValidationDecorations = 81,
renderWhitespace = 82,
revealHorizontalRightPadding = 83,
roundedSelection = 84,
rulers = 85,
scrollbar = 86,
scrollBeyondLastColumn = 87,
scrollBeyondLastLine = 88,
scrollPredominantAxis = 89,
selectionClipboard = 90,
selectionHighlight = 91,
selectOnLineNumbers = 92,
showFoldingControls = 93,
showUnused = 94,
snippetSuggestions = 95,
smartSelect = 96,
smoothScrolling = 97,
stopRenderingLineAfter = 98,
suggest = 99,
suggestFontSize = 100,
suggestLineHeight = 101,
suggestOnTriggerCharacters = 102,
suggestSelection = 103,
tabCompletion = 104,
tabIndex = 105,
unusualLineTerminators = 106,
useTabStops = 107,
wordSeparators = 108,
wordWrap = 109,
wordWrapBreakAfterCharacters = 110,
wordWrapBreakBeforeCharacters = 111,
wordWrapColumn = 112,
wordWrapMinified = 113,
wrappingIndent = 114,
wrappingStrategy = 115,
showDeprecated = 116,
editorClassName = 117,
pixelRatio = 118,
tabFocusMode = 119,
layoutInfo = 120,
wrappingInfo = 121
atomicSoftTabs = 11,
codeLens = 12,
codeLensFontFamily = 13,
codeLensFontSize = 14,
colorDecorators = 15,
columnSelection = 16,
comments = 17,
contextmenu = 18,
copyWithSyntaxHighlighting = 19,
cursorBlinking = 20,
cursorSmoothCaretAnimation = 21,
cursorStyle = 22,
cursorSurroundingLines = 23,
cursorSurroundingLinesStyle = 24,
cursorWidth = 25,
disableLayerHinting = 26,
disableMonospaceOptimizations = 27,
dragAndDrop = 28,
emptySelectionClipboard = 29,
extraEditorClassName = 30,
fastScrollSensitivity = 31,
find = 32,
fixedOverflowWidgets = 33,
folding = 34,
foldingStrategy = 35,
foldingHighlight = 36,
unfoldOnClickAfterEndOfLine = 37,
fontFamily = 38,
fontInfo = 39,
fontLigatures = 40,
fontSize = 41,
fontWeight = 42,
formatOnPaste = 43,
formatOnType = 44,
glyphMargin = 45,
gotoLocation = 46,
hideCursorInOverviewRuler = 47,
highlightActiveIndentGuide = 48,
hover = 49,
inDiffEditor = 50,
letterSpacing = 51,
lightbulb = 52,
lineDecorationsWidth = 53,
lineHeight = 54,
lineNumbers = 55,
lineNumbersMinChars = 56,
links = 57,
matchBrackets = 58,
minimap = 59,
mouseStyle = 60,
mouseWheelScrollSensitivity = 61,
mouseWheelZoom = 62,
multiCursorMergeOverlapping = 63,
multiCursorModifier = 64,
multiCursorPaste = 65,
occurrencesHighlight = 66,
overviewRulerBorder = 67,
overviewRulerLanes = 68,
padding = 69,
parameterHints = 70,
peekWidgetDefaultFocus = 71,
definitionLinkOpensInPeek = 72,
quickSuggestions = 73,
quickSuggestionsDelay = 74,
readOnly = 75,
renameOnType = 76,
renderControlCharacters = 77,
renderIndentGuides = 78,
renderFinalNewline = 79,
renderLineHighlight = 80,
renderLineHighlightOnlyWhenFocus = 81,
renderValidationDecorations = 82,
renderWhitespace = 83,
revealHorizontalRightPadding = 84,
roundedSelection = 85,
rulers = 86,
scrollbar = 87,
scrollBeyondLastColumn = 88,
scrollBeyondLastLine = 89,
scrollPredominantAxis = 90,
selectionClipboard = 91,
selectionHighlight = 92,
selectOnLineNumbers = 93,
showFoldingControls = 94,
showUnused = 95,
snippetSuggestions = 96,
smartSelect = 97,
smoothScrolling = 98,
stopRenderingLineAfter = 99,
suggest = 100,
suggestFontSize = 101,
suggestLineHeight = 102,
suggestOnTriggerCharacters = 103,
suggestSelection = 104,
tabCompletion = 105,
tabIndex = 106,
unusualLineTerminators = 107,
useTabStops = 108,
wordSeparators = 109,
wordWrap = 110,
wordWrapBreakAfterCharacters = 111,
wordWrapBreakBeforeCharacters = 112,
wordWrapColumn = 113,
wordWrapMinified = 114,
wrappingIndent = 115,
wrappingStrategy = 116,
showDeprecated = 117,
editorClassName = 118,
pixelRatio = 119,
tabFocusMode = 120,
layoutInfo = 121,
wrappingInfo = 122
}
export const EditorOptions: {
acceptSuggestionOnCommitCharacter: IEditorOption<EditorOption.acceptSuggestionOnCommitCharacter, boolean>;
......@@ -4022,6 +4028,7 @@ declare namespace monaco.editor {
autoIndent: IEditorOption<EditorOption.autoIndent, EditorAutoIndentStrategy>;
automaticLayout: IEditorOption<EditorOption.automaticLayout, boolean>;
autoSurround: IEditorOption<EditorOption.autoSurround, EditorAutoSurroundStrategy>;
atomicSoftTabs: IEditorOption<EditorOption.atomicSoftTabs, boolean>;
codeLens: IEditorOption<EditorOption.codeLens, boolean>;
codeLensFontFamily: IEditorOption<EditorOption.codeLensFontFamily, string>;
codeLensFontSize: IEditorOption<EditorOption.codeLensFontSize, number>;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册