mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-30 02:02:41 +01:00
Merge pull request #5423 from outcoldman/vscode and improve the proposed changes
- add `editor.useTabStops` for tab/backspace behaviour - add `editor.trimAutoWhitespace` for auto inserted whitespace cleanup
This commit is contained in:
@@ -303,8 +303,8 @@ export function getLeadingWhitespace(str: string): string {
|
||||
* Returns last index of the string that is not whitespace.
|
||||
* If string is empty or contains only whitespaces, returns -1
|
||||
*/
|
||||
export function lastNonWhitespaceIndex(str: string): number {
|
||||
for (let i = str.length - 1; i >= 0; i--) {
|
||||
export function lastNonWhitespaceIndex(str: string, startIndex: number = str.length - 1): number {
|
||||
for (let i = startIndex; i >= 0; i--) {
|
||||
if (str.charAt(i) !== ' ' && str.charAt(i) !== '\t') {
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -157,4 +157,15 @@ suite('Strings', () => {
|
||||
assert.strictEqual(strings.repeat(' ', 0), '');
|
||||
assert.strictEqual(strings.repeat('abc', 2), 'abcabc');
|
||||
});
|
||||
|
||||
test('lastNonWhitespaceIndex', () => {
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc'), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc\t'), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t '), 11);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t ', 8), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex(' \t \t '), -1);
|
||||
});
|
||||
});
|
||||
@@ -107,6 +107,8 @@ export class InternalEditorOptions implements editorCommon.IInternalEditorOption
|
||||
folding: boolean;
|
||||
renderWhitespace: boolean;
|
||||
indentGuides: boolean;
|
||||
useTabStops: boolean;
|
||||
trimAutoWhitespace: boolean;
|
||||
layoutInfo: editorCommon.IEditorLayoutInfo;
|
||||
fontInfo: editorCommon.FontInfo;
|
||||
editorClassName: string;
|
||||
@@ -173,6 +175,8 @@ export class InternalEditorOptions implements editorCommon.IInternalEditorOption
|
||||
this.folding = Boolean(input.folding);
|
||||
this.renderWhitespace = Boolean(input.renderWhitespace);
|
||||
this.indentGuides = Boolean(input.indentGuides);
|
||||
this.useTabStops = Boolean(input.useTabStops);
|
||||
this.trimAutoWhitespace = Boolean(input.trimAutoWhitespace);
|
||||
this.layoutInfo = {
|
||||
width: Number(input.layoutInfo.width)|0,
|
||||
height: Number(input.layoutInfo.height)|0,
|
||||
@@ -359,6 +363,8 @@ class InternalEditorOptionsHelper {
|
||||
folding: toBoolean(opts.folding),
|
||||
renderWhitespace: toBoolean(opts.renderWhitespace),
|
||||
indentGuides: toBoolean(opts.indentGuides),
|
||||
useTabStops: toBoolean(opts.useTabStops),
|
||||
trimAutoWhitespace: toBoolean(opts.trimAutoWhitespace),
|
||||
|
||||
layoutInfo: layoutInfo,
|
||||
fontInfo: fontInfo,
|
||||
@@ -443,9 +449,11 @@ class InternalEditorOptionsHelper {
|
||||
folding: (prevOpts.folding !== newOpts.folding),
|
||||
renderWhitespace: (prevOpts.renderWhitespace !== newOpts.renderWhitespace),
|
||||
indentGuides: (prevOpts.indentGuides !== newOpts.indentGuides),
|
||||
useTabStops: (prevOpts.useTabStops !== newOpts.useTabStops),
|
||||
trimAutoWhitespace: (prevOpts.trimAutoWhitespace !== newOpts.trimAutoWhitespace),
|
||||
|
||||
layoutInfo: (!EditorLayoutProvider.layoutEqual(prevOpts.layoutInfo, newOpts.layoutInfo)),
|
||||
fontInfo: (!prevOpts.fontInfo.equals(newOpts.fontInfo)),
|
||||
fontInfo: (!prevOpts.fontInfo.equals(newOpts.fontInfo)),
|
||||
editorClassName: (prevOpts.editorClassName !== newOpts.editorClassName),
|
||||
wrappingInfo: (!this._wrappingInfoEqual(prevOpts.wrappingInfo, newOpts.wrappingInfo)),
|
||||
observedOuterWidth: (prevOpts.observedOuterWidth !== newOpts.observedOuterWidth),
|
||||
@@ -926,6 +934,16 @@ let editorConfiguration:IConfigurationNode = {
|
||||
'default': DefaultConfig.editor.folding,
|
||||
'description': nls.localize('folding', "Controls whether the editor has code folding enabled")
|
||||
},
|
||||
'editor.useTabStops' : {
|
||||
'type': 'boolean',
|
||||
'default': DefaultConfig.editor.useTabStops,
|
||||
'description': nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops")
|
||||
},
|
||||
'editor.trimAutoWhitespace' : {
|
||||
'type': 'boolean',
|
||||
'default': DefaultConfig.editor.trimAutoWhitespace,
|
||||
'description': nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace")
|
||||
},
|
||||
'diffEditor.renderSideBySide' : {
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
|
||||
@@ -90,6 +90,8 @@ class ConfigClass implements IConfiguration {
|
||||
folding: true,
|
||||
renderWhitespace: false,
|
||||
indentGuides: false,
|
||||
useTabStops: true,
|
||||
trimAutoWhitespace: true,
|
||||
|
||||
fontFamily: (
|
||||
platform.isMacintosh ? DEFAULT_MAC_FONT_FAMILY : (platform.isLinux ? DEFAULT_LINUX_FONT_FAMILY : DEFAULT_WINDOWS_FONT_FAMILY)
|
||||
|
||||
@@ -40,6 +40,7 @@ interface IMultipleCursorOperationContext {
|
||||
hasExecutedCommands: boolean;
|
||||
isCursorUndo: boolean;
|
||||
executeCommands: editorCommon.ICommand[];
|
||||
isAutoWhitespaceCommand: boolean[];
|
||||
postOperationRunnables: IPostOperationRunnable[];
|
||||
requestScrollDeltaLines: number;
|
||||
setColumnSelectToLineNumber: number;
|
||||
@@ -313,6 +314,7 @@ export class Cursor extends EventEmitter {
|
||||
eventSource: eventSource,
|
||||
eventData: eventData,
|
||||
executeCommands: [],
|
||||
isAutoWhitespaceCommand: [],
|
||||
hasExecutedCommands: false,
|
||||
isCursorUndo: false,
|
||||
postOperationRunnables: [],
|
||||
@@ -440,7 +442,7 @@ export class Cursor extends EventEmitter {
|
||||
this._columnSelectToLineNumber = ctx.setColumnSelectToLineNumber;
|
||||
this._columnSelectToVisualColumn = ctx.setColumnSelectToVisualColumn;
|
||||
|
||||
ctx.hasExecutedCommands = this._internalExecuteCommands(ctx.executeCommands, ctx.postOperationRunnables) || ctx.hasExecutedCommands;
|
||||
ctx.hasExecutedCommands = this._internalExecuteCommands(ctx.executeCommands, ctx.isAutoWhitespaceCommand, ctx.postOperationRunnables) || ctx.hasExecutedCommands;
|
||||
ctx.executeCommands = [];
|
||||
|
||||
if (ctx.shouldPushStackElementAfter) {
|
||||
@@ -480,7 +482,7 @@ export class Cursor extends EventEmitter {
|
||||
return true;
|
||||
}
|
||||
|
||||
private _getEditOperationsFromCommand(ctx: IExecContext, majorIdentifier: number, command: editorCommon.ICommand): ICommandData {
|
||||
private _getEditOperationsFromCommand(ctx: IExecContext, majorIdentifier: number, command: editorCommon.ICommand, isAutoWhitespaceCommand:boolean): ICommandData {
|
||||
// This method acts as a transaction, if the command fails
|
||||
// everything it has done is ignored
|
||||
var operations: editorCommon.IIdentifiedSingleEditOperation[] = [],
|
||||
@@ -498,7 +500,8 @@ export class Cursor extends EventEmitter {
|
||||
},
|
||||
range: selection,
|
||||
text: text,
|
||||
forceMoveMarkers: false
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: isAutoWhitespaceCommand
|
||||
});
|
||||
};
|
||||
|
||||
@@ -560,7 +563,7 @@ export class Cursor extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
private _getEditOperations(ctx: IExecContext, commands: editorCommon.ICommand[]): ICommandsData {
|
||||
private _getEditOperations(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand:boolean[]): ICommandsData {
|
||||
var oneResult: ICommandData;
|
||||
var operations: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
var hadTrackedRanges: boolean[] = [];
|
||||
@@ -568,7 +571,7 @@ export class Cursor extends EventEmitter {
|
||||
|
||||
for (var i = 0; i < commands.length; i++) {
|
||||
if (commands[i]) {
|
||||
oneResult = this._getEditOperationsFromCommand(ctx, i, commands[i]);
|
||||
oneResult = this._getEditOperationsFromCommand(ctx, i, commands[i], isAutoWhitespaceCommand[i]);
|
||||
operations = operations.concat(oneResult.operations);
|
||||
hadTrackedRanges[i] = oneResult.hadTrackedRange;
|
||||
anyoneHadTrackedRange = anyoneHadTrackedRange || hadTrackedRanges[i];
|
||||
@@ -634,7 +637,7 @@ export class Cursor extends EventEmitter {
|
||||
return loserCursorsMap;
|
||||
}
|
||||
|
||||
private _collapseDeleteCommands(rawCmds: editorCommon.ICommand[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
private _collapseDeleteCommands(rawCmds: editorCommon.ICommand[], isAutoWhitespaceCommand:boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
if (rawCmds.length === 1) {
|
||||
return ;
|
||||
}
|
||||
@@ -690,15 +693,15 @@ export class Cursor extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
private _internalExecuteCommands(commands: editorCommon.ICommand[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
private _internalExecuteCommands(commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
var ctx:IExecContext = {
|
||||
selectionStartMarkers: [],
|
||||
positionMarkers: []
|
||||
};
|
||||
|
||||
this._collapseDeleteCommands(commands, postOperationRunnables);
|
||||
this._collapseDeleteCommands(commands, isAutoWhitespaceCommand, postOperationRunnables);
|
||||
|
||||
var r = this._innerExecuteCommands(ctx, commands, postOperationRunnables);
|
||||
var r = this._innerExecuteCommands(ctx, commands, isAutoWhitespaceCommand, postOperationRunnables);
|
||||
for (var i = 0; i < ctx.selectionStartMarkers.length; i++) {
|
||||
this.model._removeMarker(ctx.selectionStartMarkers[i]);
|
||||
this.model._removeMarker(ctx.positionMarkers[i]);
|
||||
@@ -719,7 +722,7 @@ export class Cursor extends EventEmitter {
|
||||
return true;
|
||||
}
|
||||
|
||||
private _innerExecuteCommands(ctx: IExecContext, commands: editorCommon.ICommand[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
private _innerExecuteCommands(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean {
|
||||
|
||||
if (this.configuration.editor.readOnly) {
|
||||
return false;
|
||||
@@ -731,7 +734,7 @@ export class Cursor extends EventEmitter {
|
||||
|
||||
var selectionsBefore = this.cursors.getSelections();
|
||||
|
||||
var commandsData = this._getEditOperations(ctx, commands);
|
||||
var commandsData = this._getEditOperations(ctx, commands, isAutoWhitespaceCommand);
|
||||
if (commandsData.operations.length === 0 && !commandsData.anyoneHadTrackedRange) {
|
||||
return false;
|
||||
}
|
||||
@@ -771,6 +774,10 @@ export class Cursor extends EventEmitter {
|
||||
}
|
||||
for (var i = 0; i < inverseEditOperations.length; i++) {
|
||||
var op = inverseEditOperations[i];
|
||||
if (!op.identifier) {
|
||||
// perhaps auto whitespace trim edits
|
||||
continue;
|
||||
}
|
||||
groupedInverseEditOperations[op.identifier.major].push(op);
|
||||
}
|
||||
var minorBasedSorter = (a:editorCommon.IIdentifiedSingleEditOperation, b:editorCommon.IIdentifiedSingleEditOperation) => {
|
||||
@@ -1080,6 +1087,7 @@ export class Cursor extends EventEmitter {
|
||||
shouldRevealVerticalInCenter: false,
|
||||
shouldRevealHorizontal: true,
|
||||
executeCommand: null,
|
||||
isAutoWhitespaceCommand: false,
|
||||
postOperationRunnable: null,
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: false,
|
||||
@@ -1100,6 +1108,7 @@ export class Cursor extends EventEmitter {
|
||||
ctx.shouldPushStackElementAfter = ctx.shouldPushStackElementAfter || context.shouldPushStackElementAfter;
|
||||
|
||||
ctx.executeCommands[i] = context.executeCommand;
|
||||
ctx.isAutoWhitespaceCommand[i] = context.isAutoWhitespaceCommand;
|
||||
ctx.postOperationRunnables[i] = context.postOperationRunnable;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface IOneCursorOperationContext {
|
||||
shouldPushStackElementBefore: boolean;
|
||||
shouldPushStackElementAfter: boolean;
|
||||
executeCommand: editorCommon.ICommand;
|
||||
isAutoWhitespaceCommand: boolean;
|
||||
postOperationRunnable: IPostOperationRunnable;
|
||||
requestScrollDeltaLines: number;
|
||||
}
|
||||
@@ -145,7 +146,13 @@ export class OneCursor {
|
||||
private _selEndMarker: string;
|
||||
private _selDirection: editorCommon.SelectionDirection;
|
||||
|
||||
constructor(editorId: number, model: editorCommon.IModel, configuration: editorCommon.IConfiguration, modeConfiguration: IModeConfiguration, viewModelHelper:IViewModelHelper) {
|
||||
constructor(
|
||||
editorId: number,
|
||||
model: editorCommon.IModel,
|
||||
configuration: editorCommon.IConfiguration,
|
||||
modeConfiguration: IModeConfiguration,
|
||||
viewModelHelper:IViewModelHelper
|
||||
) {
|
||||
this.editorId = editorId;
|
||||
this.model = model;
|
||||
this.configuration = configuration;
|
||||
@@ -527,6 +534,9 @@ export class OneCursor {
|
||||
public getVisibleColumnFromColumn(lineNumber:number, column:number): number {
|
||||
return this.helper.visibleColumnFromColumn(this.model, lineNumber, column);
|
||||
}
|
||||
public getColumnFromVisibleColumn(lineNumber:number, column:number): number {
|
||||
return this.helper.columnFromVisibleColumn(this.model, lineNumber, column);
|
||||
}
|
||||
public getViewVisibleColumnFromColumn(viewLineNumber:number, viewColumn:number): number {
|
||||
return this.helper.visibleColumnFromColumn(this.viewModelHelper.viewModel, viewLineNumber, viewColumn);
|
||||
}
|
||||
@@ -1185,6 +1195,7 @@ export class OneCursorOp {
|
||||
var enterAction = r.enterAction;
|
||||
var indentation = r.indentation;
|
||||
|
||||
ctx.isAutoWhitespaceCommand = true;
|
||||
if (enterAction.indentAction === IndentAction.None) {
|
||||
// Nothing special
|
||||
this.actualType(cursor, '\n' + cursor.model.normalizeIndentation(indentation + enterAction.appendText), keepPosition, ctx, range);
|
||||
@@ -1500,6 +1511,8 @@ export class OneCursorOp {
|
||||
|
||||
if (selection.isEmpty()) {
|
||||
|
||||
ctx.isAutoWhitespaceCommand = true;
|
||||
|
||||
let typeText = '';
|
||||
|
||||
if (cursor.model.getLineMaxColumn(selection.startLineNumber) === 1) {
|
||||
@@ -1626,13 +1639,34 @@ export class OneCursorOp {
|
||||
|
||||
if (deleteSelection.isEmpty()) {
|
||||
var position = cursor.getPosition();
|
||||
var leftOfPosition = cursor.getLeftOfPosition(position.lineNumber, position.column);
|
||||
deleteSelection = new Range(
|
||||
leftOfPosition.lineNumber,
|
||||
leftOfPosition.column,
|
||||
position.lineNumber,
|
||||
position.column
|
||||
);
|
||||
|
||||
if (cursor.configuration.editor.useTabStops && position.column > 1) {
|
||||
let lineContent = cursor.getLineContent(position.lineNumber);
|
||||
|
||||
let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
|
||||
let lastIndentationColumn = (
|
||||
firstNonWhitespaceIndex === -1
|
||||
? /* entire string is whitespace */lineContent.length + 1
|
||||
: firstNonWhitespaceIndex + 1
|
||||
);
|
||||
|
||||
if (position.column <= lastIndentationColumn) {
|
||||
let fromVisibleColumn = cursor.getVisibleColumnFromColumn(position.lineNumber, position.column);
|
||||
let toVisibleColumn = CursorMoveHelper.prevTabColumn(fromVisibleColumn, cursor.model.getOptions().tabSize);
|
||||
let toColumn = cursor.getColumnFromVisibleColumn(position.lineNumber, toVisibleColumn);
|
||||
deleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column);
|
||||
} else {
|
||||
deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column);
|
||||
}
|
||||
} else {
|
||||
var leftOfPosition = cursor.getLeftOfPosition(position.lineNumber, position.column);
|
||||
deleteSelection = new Range(
|
||||
leftOfPosition.lineNumber,
|
||||
leftOfPosition.column,
|
||||
position.lineNumber,
|
||||
position.column
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteSelection.isEmpty()) {
|
||||
@@ -1648,21 +1682,11 @@ export class OneCursorOp {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static _findLastNonWhitespaceChar(str:string, startIndex:number): number {
|
||||
for (let chIndex = startIndex; chIndex >= 0; chIndex--) {
|
||||
let ch = str.charAt(chIndex);
|
||||
if (ch !== ' ' && ch !== '\t') {
|
||||
return chIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static deleteWordLeftWhitespace(cursor:OneCursor, ctx: IOneCursorOperationContext): boolean {
|
||||
let position = cursor.getPosition();
|
||||
let lineContent = cursor.getLineContent(position.lineNumber);
|
||||
let startIndex = position.column - 2;
|
||||
let lastNonWhitespace = this._findLastNonWhitespaceChar(lineContent, startIndex);
|
||||
let lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex);
|
||||
if (lastNonWhitespace + 1 < startIndex) {
|
||||
// bingo
|
||||
ctx.executeCommand = new ReplaceCommand(new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column), '');
|
||||
@@ -1982,6 +2006,10 @@ class CursorHelper {
|
||||
return this.moveHelper.visibleColumnFromColumn(model, lineNumber, column);
|
||||
}
|
||||
|
||||
public columnFromVisibleColumn(model:ICursorMoveHelperModel, lineNumber:number, column:number): number {
|
||||
return this.moveHelper.columnFromVisibleColumn(model, lineNumber, column);
|
||||
}
|
||||
|
||||
private _createWord(lineContent: string, wordType:WordType, start: number, end: number): IFindWordResult {
|
||||
// console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>');
|
||||
return { start: start, end: end, wordType: wordType };
|
||||
|
||||
@@ -513,6 +513,14 @@ export interface IEditorOptions {
|
||||
* Defaults to true.
|
||||
*/
|
||||
indentGuides?: boolean;
|
||||
/**
|
||||
* Inserting and deleting whitespace follows tab stops.
|
||||
*/
|
||||
useTabStops?: boolean;
|
||||
/**
|
||||
* Remove trailing auto inserted whitespace.
|
||||
*/
|
||||
trimAutoWhitespace?: boolean;
|
||||
/**
|
||||
* The font family
|
||||
*/
|
||||
@@ -624,6 +632,8 @@ export interface IInternalEditorOptions {
|
||||
folding: boolean;
|
||||
renderWhitespace: boolean;
|
||||
indentGuides: boolean;
|
||||
useTabStops: boolean;
|
||||
trimAutoWhitespace: boolean;
|
||||
|
||||
// ---- Options that are computed
|
||||
|
||||
@@ -702,6 +712,8 @@ export interface IConfigurationChangedEvent {
|
||||
folding: boolean;
|
||||
renderWhitespace: boolean;
|
||||
indentGuides: boolean;
|
||||
useTabStops: boolean;
|
||||
trimAutoWhitespace: boolean;
|
||||
|
||||
// ---- Options that are computed
|
||||
layoutInfo: boolean;
|
||||
@@ -1121,6 +1133,11 @@ export interface IIdentifiedSingleEditOperation {
|
||||
* i.e. forceMoveMarkers = true => if `range` is collapsed, all markers at the position will be moved.
|
||||
*/
|
||||
forceMoveMarkers: boolean;
|
||||
/**
|
||||
* This indicates that this operation is inserting automatic whitespace
|
||||
* that can be removed on next model edit operation if `config.trimAutoWhitespace` is true.
|
||||
*/
|
||||
isAutoWhitespaceEdit?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1168,23 +1185,27 @@ export interface ITextModelResolvedOptions {
|
||||
tabSize: number;
|
||||
insertSpaces: boolean;
|
||||
defaultEOL: DefaultEndOfLine;
|
||||
trimAutoWhitespace: boolean;
|
||||
}
|
||||
|
||||
export interface ITextModelCreationOptions {
|
||||
tabSize: number;
|
||||
insertSpaces: boolean;
|
||||
detectIndentation: boolean;
|
||||
trimAutoWhitespace: boolean;
|
||||
defaultEOL: DefaultEndOfLine;
|
||||
}
|
||||
|
||||
export interface ITextModelUpdateOptions {
|
||||
tabSize?: number;
|
||||
insertSpaces?: boolean;
|
||||
trimAutoWhitespace?: boolean;
|
||||
}
|
||||
|
||||
export interface IModelOptionsChangedEvent {
|
||||
tabSize: boolean;
|
||||
insertSpaces: boolean;
|
||||
trimAutoWhitespace: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ import {EditStack} from 'vs/editor/common/model/editStack';
|
||||
import {ILineEdit, ILineMarker, ModelLine} from 'vs/editor/common/model/modelLine';
|
||||
import {DeferredEventsBuilder, TextModelWithDecorations} from 'vs/editor/common/model/textModelWithDecorations';
|
||||
import {IMode} from 'vs/editor/common/modes';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
||||
export interface IValidatedEditOperation {
|
||||
sortIndex: number;
|
||||
@@ -19,6 +20,7 @@ export interface IValidatedEditOperation {
|
||||
rangeLength: number;
|
||||
lines: string[];
|
||||
forceMoveMarkers: boolean;
|
||||
isAutoWhitespaceEdit: boolean;
|
||||
}
|
||||
|
||||
interface IIdentifiedLineEdit extends ILineEdit{
|
||||
@@ -37,6 +39,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
private _hasEditableRange:boolean;
|
||||
private _editableRangeId:string;
|
||||
|
||||
private _trimAutoWhitespaceLines: number[];
|
||||
|
||||
constructor(allowedEventTypes:string[], rawText:editorCommon.IRawText, modeOrPromise:IMode|TPromise<IMode>) {
|
||||
allowedEventTypes.push(editorCommon.EventType.ModelContentChanged);
|
||||
allowedEventTypes.push(editorCommon.EventType.ModelContentChanged2);
|
||||
@@ -49,6 +53,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
|
||||
this._hasEditableRange = false;
|
||||
this._editableRangeId = null;
|
||||
this._trimAutoWhitespaceLines = null;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -63,6 +68,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
this._commandManager = new EditStack(this);
|
||||
this._hasEditableRange = false;
|
||||
this._editableRangeId = null;
|
||||
this._trimAutoWhitespaceLines = null;
|
||||
}
|
||||
|
||||
public pushStackElement(): void {
|
||||
@@ -71,6 +77,61 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
|
||||
public pushEditOperations(beforeCursorState:editorCommon.IEditorSelection[], editOperations:editorCommon.IIdentifiedSingleEditOperation[], cursorStateComputer:editorCommon.ICursorStateComputer): editorCommon.IEditorSelection[] {
|
||||
return this.deferredEmit(() => {
|
||||
if (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {
|
||||
// Go through each saved line number and insert a trim whitespace edit
|
||||
// if it is safe to do so (no conflicts with other edits).
|
||||
|
||||
let incomingEdits = editOperations.map((op) => {
|
||||
return {
|
||||
range: this.validateRange(op.range),
|
||||
text: op.text
|
||||
};
|
||||
});
|
||||
|
||||
for (let i = 0, len = this._trimAutoWhitespaceLines.length; i < len; i++) {
|
||||
let trimLineNumber = this._trimAutoWhitespaceLines[i];
|
||||
let maxLineColumn = this.getLineMaxColumn(trimLineNumber);
|
||||
|
||||
let allowTrimLine = true;
|
||||
for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
|
||||
let editRange = incomingEdits[i].range;
|
||||
let editText = incomingEdits[i].text;
|
||||
|
||||
if (trimLineNumber < editRange.startLineNumber || trimLineNumber > editRange.endLineNumber) {
|
||||
// `trimLine` is completely outside this edit
|
||||
continue;
|
||||
}
|
||||
|
||||
// At this point:
|
||||
// editRange.startLineNumber <= trimLine <= editRange.endLineNumber
|
||||
|
||||
if (
|
||||
trimLineNumber === editRange.startLineNumber && editRange.startColumn === maxLineColumn
|
||||
&& editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(0) === '\n'
|
||||
) {
|
||||
// This edit inserts a new line (and maybe other text) after `trimLine`
|
||||
continue;
|
||||
}
|
||||
|
||||
// Looks like we can't trim this line as it would interfere with an incoming edit
|
||||
allowTrimLine = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (allowTrimLine) {
|
||||
editOperations.push({
|
||||
identifier: null,
|
||||
range: new Range(trimLineNumber, 1, trimLineNumber, maxLineColumn),
|
||||
text: null,
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this._trimAutoWhitespaceLines = null;
|
||||
}
|
||||
return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
|
||||
});
|
||||
}
|
||||
@@ -145,7 +206,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
range: entireEditRange,
|
||||
rangeLength: this.getValueLengthInRange(entireEditRange),
|
||||
lines: result.join('').split('\n'),
|
||||
forceMoveMarkers: forceMoveMarkers
|
||||
forceMoveMarkers: forceMoveMarkers,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,7 +242,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
range: validatedRange,
|
||||
rangeLength: this.getValueLengthInRange(validatedRange),
|
||||
lines: op.text ? op.text.split(/\r\n|\r|\n/) : null,
|
||||
forceMoveMarkers: op.forceMoveMarkers
|
||||
forceMoveMarkers: op.forceMoveMarkers,
|
||||
isAutoWhitespaceEdit: op.isAutoWhitespaceEdit || false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -212,17 +275,61 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
// Delta encode operations
|
||||
let reverseRanges = EditableTextModel._getInverseEditRanges(operations);
|
||||
let reverseOperations: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
let newTrimAutoWhitespaceCandidates: { lineNumber:number,oldContent:string }[] = [];
|
||||
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
let op = operations[i];
|
||||
let reverseRange = reverseRanges[i];
|
||||
|
||||
reverseOperations[i] = {
|
||||
identifier: operations[i].identifier,
|
||||
range: reverseRanges[i],
|
||||
text: this.getValueInRange(operations[i].range),
|
||||
forceMoveMarkers: operations[i].forceMoveMarkers
|
||||
identifier: op.identifier,
|
||||
range: reverseRange,
|
||||
text: this.getValueInRange(op.range),
|
||||
forceMoveMarkers: op.forceMoveMarkers
|
||||
};
|
||||
|
||||
if (this._options.trimAutoWhitespace && op.isAutoWhitespaceEdit && op.range.isEmpty()) {
|
||||
// Record already the future line numbers that might be auto whitespace removal candidates on next edit
|
||||
for (let lineNumber = reverseRange.startLineNumber; lineNumber <= reverseRange.endLineNumber; lineNumber++) {
|
||||
let currentLineContent = '';
|
||||
if (lineNumber === reverseRange.startLineNumber) {
|
||||
currentLineContent = this.getLineContent(op.range.startLineNumber);
|
||||
if (strings.firstNonWhitespaceIndex(currentLineContent) !== -1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
newTrimAutoWhitespaceCandidates.push({ lineNumber:lineNumber, oldContent:currentLineContent });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._applyEdits(operations);
|
||||
|
||||
this._trimAutoWhitespaceLines = null;
|
||||
if (this._options.trimAutoWhitespace && newTrimAutoWhitespaceCandidates.length > 0) {
|
||||
// sort line numbers auto whitespace removal candidates for next edit descending
|
||||
newTrimAutoWhitespaceCandidates.sort((a,b) => b.lineNumber - a.lineNumber);
|
||||
|
||||
this._trimAutoWhitespaceLines = [];
|
||||
for (let i = 0, len = newTrimAutoWhitespaceCandidates.length; i < len; i++) {
|
||||
let lineNumber = newTrimAutoWhitespaceCandidates[i].lineNumber;
|
||||
if (i > 0 && newTrimAutoWhitespaceCandidates[i - 1].lineNumber === lineNumber) {
|
||||
// Do not have the same line number twice
|
||||
continue;
|
||||
}
|
||||
|
||||
let prevContent = newTrimAutoWhitespaceCandidates[i].oldContent;
|
||||
let lineContent = this.getLineContent(lineNumber);
|
||||
|
||||
if (lineContent.length === 0 || lineContent === prevContent || strings.firstNonWhitespaceIndex(lineContent) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._trimAutoWhitespaceLines.push(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return reverseOperations;
|
||||
}
|
||||
|
||||
@@ -311,7 +418,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
|
||||
lineEditsQueue.reverse();
|
||||
|
||||
// `lineEditsQueue` now contains edits from smaller (line number,column) to larger (line number,column)
|
||||
let currentLineNumber = lineEditsQueue[0].lineNumber, currentLineNumberStart = 0;
|
||||
let currentLineNumber = lineEditsQueue[0].lineNumber;
|
||||
let currentLineNumberStart = 0;
|
||||
|
||||
for (let i = 1, len = lineEditsQueue.length; i < len; i++) {
|
||||
let lineNumber = lineEditsQueue[i].lineNumber;
|
||||
|
||||
@@ -222,7 +222,8 @@ export class MirrorModelEmbedded extends AbstractMirrorModel implements editorCo
|
||||
tabSize: actualModelOptions.tabSize,
|
||||
insertSpaces: actualModelOptions.insertSpaces,
|
||||
detectIndentation: false,
|
||||
defaultEOL: actualModelOptions.defaultEOL
|
||||
defaultEOL: actualModelOptions.defaultEOL,
|
||||
trimAutoWhitespace: actualModelOptions.trimAutoWhitespace
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {Range} from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import {ModelLine} from 'vs/editor/common/model/modelLine';
|
||||
import {guessIndentation} from 'vs/editor/common/model/indentationGuesser';
|
||||
import {DEFAULT_INDENTATION} from 'vs/editor/common/config/defaultConfig';
|
||||
import {DEFAULT_INDENTATION, DefaultConfig} from 'vs/editor/common/config/defaultConfig';
|
||||
|
||||
var LIMIT_FIND_COUNT = 999;
|
||||
|
||||
@@ -21,6 +21,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
|
||||
tabSize: DEFAULT_INDENTATION.tabSize,
|
||||
insertSpaces: DEFAULT_INDENTATION.insertSpaces,
|
||||
detectIndentation: false,
|
||||
trimAutoWhitespace: DefaultConfig.editor.trimAutoWhitespace,
|
||||
defaultEOL: editorCommon.DefaultEndOfLine.LF
|
||||
};
|
||||
|
||||
@@ -56,7 +57,8 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
|
||||
let somethingChanged = false;
|
||||
let changed:editorCommon.IModelOptionsChangedEvent = {
|
||||
tabSize: false,
|
||||
insertSpaces: false
|
||||
insertSpaces: false,
|
||||
trimAutoWhitespace: false
|
||||
};
|
||||
|
||||
if (typeof newOpts.insertSpaces !== 'undefined') {
|
||||
@@ -73,6 +75,13 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
|
||||
this._options.tabSize = newOpts.tabSize;
|
||||
}
|
||||
}
|
||||
if (typeof newOpts.trimAutoWhitespace !== 'undefined') {
|
||||
if (this._options.trimAutoWhitespace !== newOpts.trimAutoWhitespace) {
|
||||
somethingChanged = true;
|
||||
changed.trimAutoWhitespace = true;
|
||||
this._options.trimAutoWhitespace = newOpts.trimAutoWhitespace;
|
||||
}
|
||||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
this.emit(editorCommon.EventType.ModelOptionsChanged, changed);
|
||||
@@ -244,6 +253,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
|
||||
rawText = TextModel.toRawText(value, {
|
||||
tabSize: this._options.tabSize,
|
||||
insertSpaces: this._options.insertSpaces,
|
||||
trimAutoWhitespace: this._options.trimAutoWhitespace,
|
||||
detectIndentation: false,
|
||||
defaultEOL: this._options.defaultEOL
|
||||
});
|
||||
@@ -624,12 +634,14 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
|
||||
resolvedOpts = {
|
||||
tabSize: guessedIndentation.tabSize,
|
||||
insertSpaces: guessedIndentation.insertSpaces,
|
||||
trimAutoWhitespace: opts.trimAutoWhitespace,
|
||||
defaultEOL: opts.defaultEOL
|
||||
};
|
||||
} else {
|
||||
resolvedOpts = {
|
||||
tabSize: opts.tabSize,
|
||||
insertSpaces: opts.insertSpaces,
|
||||
trimAutoWhitespace: opts.trimAutoWhitespace,
|
||||
defaultEOL: opts.defaultEOL
|
||||
};
|
||||
}
|
||||
@@ -832,6 +844,7 @@ export class RawText {
|
||||
return TextModel.toRawText(rawText, {
|
||||
tabSize: opts.tabSize,
|
||||
insertSpaces: opts.insertSpaces,
|
||||
trimAutoWhitespace: opts.trimAutoWhitespace,
|
||||
detectIndentation: false,
|
||||
defaultEOL: opts.defaultEOL
|
||||
});
|
||||
|
||||
@@ -443,7 +443,8 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
|
||||
tabSize: this._options.tabSize,
|
||||
insertSpaces: this._options.insertSpaces,
|
||||
detectIndentation: false,
|
||||
defaultEOL: this._options.defaultEOL
|
||||
defaultEOL: this._options.defaultEOL,
|
||||
trimAutoWhitespace: this._options.trimAutoWhitespace
|
||||
});
|
||||
}
|
||||
this.setValueFromRawText(rawText, newModeOrPromise);
|
||||
|
||||
@@ -26,7 +26,7 @@ import {IModelService} from 'vs/editor/common/services/modelService';
|
||||
import {IResourceService} from 'vs/editor/common/services/resourceService';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
|
||||
import {DEFAULT_INDENTATION} from 'vs/editor/common/config/defaultConfig';
|
||||
import {DEFAULT_INDENTATION, DefaultConfig} from 'vs/editor/common/config/defaultConfig';
|
||||
import {IMessageService} from 'vs/platform/message/common/message';
|
||||
|
||||
export interface IRawModelData {
|
||||
@@ -180,6 +180,7 @@ interface IRawConfig {
|
||||
tabSize?: any;
|
||||
insertSpaces?: any;
|
||||
detectIndentation?: any;
|
||||
trimAutoWhitespace?: any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -219,7 +220,8 @@ export class ModelServiceImpl implements IModelService {
|
||||
tabSize: DEFAULT_INDENTATION.tabSize,
|
||||
insertSpaces: DEFAULT_INDENTATION.insertSpaces,
|
||||
detectIndentation: DEFAULT_INDENTATION.detectIndentation,
|
||||
defaultEOL: (platform.isLinux || platform.isMacintosh) ? editorCommon.DefaultEndOfLine.LF : editorCommon.DefaultEndOfLine.CRLF
|
||||
defaultEOL: (platform.isLinux || platform.isMacintosh) ? editorCommon.DefaultEndOfLine.LF : editorCommon.DefaultEndOfLine.CRLF,
|
||||
trimAutoWhitespace: DefaultConfig.editor.trimAutoWhitespace
|
||||
};
|
||||
this._threadService = threadService;
|
||||
this._markerService = markerService;
|
||||
@@ -240,7 +242,6 @@ export class ModelServiceImpl implements IModelService {
|
||||
}
|
||||
|
||||
let readConfig = (config: IRawConfig) => {
|
||||
const eol = config.files && config.files.eol;
|
||||
|
||||
let shouldShowMigrationMessage = false;
|
||||
|
||||
@@ -260,12 +261,18 @@ export class ModelServiceImpl implements IModelService {
|
||||
}
|
||||
|
||||
let newDefaultEOL = this._modelCreationOptions.defaultEOL;
|
||||
const eol = config.files && config.files.eol;
|
||||
if (eol === '\r\n') {
|
||||
newDefaultEOL = editorCommon.DefaultEndOfLine.CRLF;
|
||||
} else if (eol === '\n') {
|
||||
newDefaultEOL = editorCommon.DefaultEndOfLine.LF;
|
||||
}
|
||||
|
||||
let trimAutoWhitespace = this._modelCreationOptions.trimAutoWhitespace;
|
||||
if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') {
|
||||
trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace));
|
||||
}
|
||||
|
||||
let detectIndentation = DEFAULT_INDENTATION.detectIndentation;
|
||||
if (config.editor && typeof config.editor.detectIndentation !== 'undefined') {
|
||||
detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation));
|
||||
@@ -275,7 +282,8 @@ export class ModelServiceImpl implements IModelService {
|
||||
tabSize: tabSize,
|
||||
insertSpaces: insertSpaces,
|
||||
detectIndentation: detectIndentation,
|
||||
defaultEOL: newDefaultEOL
|
||||
defaultEOL: newDefaultEOL,
|
||||
trimAutoWhitespace: trimAutoWhitespace
|
||||
});
|
||||
|
||||
|
||||
@@ -300,6 +308,7 @@ export class ModelServiceImpl implements IModelService {
|
||||
(this._modelCreationOptions.detectIndentation === newOpts.detectIndentation)
|
||||
&& (this._modelCreationOptions.insertSpaces === newOpts.insertSpaces)
|
||||
&& (this._modelCreationOptions.tabSize === newOpts.tabSize)
|
||||
&& (this._modelCreationOptions.trimAutoWhitespace === newOpts.trimAutoWhitespace)
|
||||
) {
|
||||
// Same indent opts, no need to touch created models
|
||||
this._modelCreationOptions = newOpts;
|
||||
@@ -315,10 +324,14 @@ export class ModelServiceImpl implements IModelService {
|
||||
|
||||
if (this._modelCreationOptions.detectIndentation) {
|
||||
modelData.model.detectIndentation(this._modelCreationOptions.insertSpaces, this._modelCreationOptions.tabSize);
|
||||
modelData.model.updateOptions({
|
||||
trimAutoWhitespace: this._modelCreationOptions.trimAutoWhitespace
|
||||
});
|
||||
} else {
|
||||
modelData.model.updateOptions({
|
||||
insertSpaces: this._modelCreationOptions.insertSpaces,
|
||||
tabSize: this._modelCreationOptions.tabSize
|
||||
tabSize: this._modelCreationOptions.tabSize,
|
||||
trimAutoWhitespace: this._modelCreationOptions.trimAutoWhitespace
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,7 +1111,8 @@ suite('Editor Controller - Regression tests', () => {
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
detectIndentation: false,
|
||||
insertSpaces: false,
|
||||
tabSize: 4
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: false
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
@@ -1198,7 +1199,8 @@ suite('Editor Controller - Regression tests', () => {
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
detectIndentation: false,
|
||||
insertSpaces: false,
|
||||
tabSize: 4
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true
|
||||
},
|
||||
mode: new OnEnterMode(IndentAction.Indent),
|
||||
}, (model, cursor) => {
|
||||
@@ -1219,7 +1221,8 @@ suite('Editor Controller - Regression tests', () => {
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
detectIndentation: false,
|
||||
insertSpaces: false,
|
||||
tabSize: 4
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true
|
||||
},
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 2, false);
|
||||
@@ -1240,7 +1243,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
' function baz() {'
|
||||
],
|
||||
mode: new OnEnterMode(IndentAction.IndentOutdent),
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 6, false);
|
||||
cursorEqual(cursor, 1, 6, 1, 6);
|
||||
@@ -1256,7 +1259,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
text: [
|
||||
' '
|
||||
],
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 7, false);
|
||||
cursorEqual(cursor, 1, 7, 1, 7);
|
||||
@@ -1282,7 +1285,8 @@ suite('Editor Controller - Regression tests', () => {
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
detectIndentation: false,
|
||||
insertSpaces: false,
|
||||
tabSize: 4
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true
|
||||
},
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 7, 1, false);
|
||||
@@ -1342,7 +1346,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
'hello'
|
||||
],
|
||||
mode: new SurroundingMode(),
|
||||
modelOpts: { tabSize: 4, insertSpaces: true, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { tabSize: 4, insertSpaces: true, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 3, false);
|
||||
moveTo(cursor, 1, 5, true);
|
||||
@@ -1364,7 +1368,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
'};'
|
||||
],
|
||||
mode: new SurroundingMode(),
|
||||
modelOpts: { tabSize: 4, insertSpaces: true, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { tabSize: 4, insertSpaces: true, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 3, 2, false);
|
||||
moveTo(cursor, 1, 14, true);
|
||||
@@ -1413,7 +1417,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
'just some text',
|
||||
],
|
||||
mode: null,
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 1, false);
|
||||
moveTo(cursor, 3, 4, true);
|
||||
@@ -1456,7 +1460,7 @@ suite('Editor Controller - Regression tests', () => {
|
||||
'\t};',
|
||||
'}',
|
||||
],
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 3, 2, false);
|
||||
cursorCommand(cursor, H.Tab);
|
||||
@@ -1871,7 +1875,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
'',
|
||||
'1'
|
||||
],
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
cursorCommand(cursor, H.MoveTo, { position: new Position(1, 21) }, null, 'keyboard');
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
@@ -1889,7 +1893,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
'',
|
||||
'1'
|
||||
],
|
||||
modelOpts: { insertSpaces: true, tabSize: 13, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 13, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
// Tab on column 1
|
||||
cursorCommand(cursor, H.MoveTo, { position: new Position(2, 1) }, null, 'keyboard');
|
||||
@@ -1953,7 +1957,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
'\thello'
|
||||
],
|
||||
mode: new OnEnterMode(IndentAction.Indent),
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 7, false);
|
||||
cursorEqual(cursor, 1, 7, 1, 7);
|
||||
@@ -1969,7 +1973,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
'\thello'
|
||||
],
|
||||
mode: new OnEnterMode(IndentAction.None),
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 7, false);
|
||||
cursorEqual(cursor, 1, 7, 1, 7);
|
||||
@@ -1985,7 +1989,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
'\thell()'
|
||||
],
|
||||
mode: new OnEnterMode(IndentAction.IndentOutdent),
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF }
|
||||
modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true }
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, 7, false);
|
||||
cursorEqual(cursor, 1, 7, 1, 7);
|
||||
@@ -2078,6 +2082,324 @@ suite('Editor Controller - Cursor Configuration', () => {
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
});
|
||||
});
|
||||
|
||||
test('removeAutoWhitespace off', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' some line abc '
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: false
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
|
||||
// Move cursor to the end, verify that we do not trim whitespaces if line has values
|
||||
moveTo(cursor, 1, model.getLineContent(1).length + 1);
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
|
||||
// Try to enter again, we should trimmed previous line
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.equal(model.getLineContent(3), ' ');
|
||||
});
|
||||
});
|
||||
|
||||
test('removeAutoWhitespace on: removes only whitespace the cursor added 1', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' '
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
moveTo(cursor, 1, model.getLineContent(1).length + 1);
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' ');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' ');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), ' ');
|
||||
});
|
||||
});
|
||||
|
||||
test('removeAutoWhitespace on: removes only whitespace the cursor added 2', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' if (a) {',
|
||||
' ',
|
||||
'',
|
||||
'',
|
||||
' }'
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
|
||||
moveTo(cursor, 3, 1);
|
||||
cursorCommand(cursor, H.Tab, null, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' if (a) {');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.equal(model.getLineContent(3), ' ');
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
assert.equal(model.getLineContent(5), ' }');
|
||||
|
||||
moveTo(cursor, 4, 1);
|
||||
cursorCommand(cursor, H.Tab, null, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' if (a) {');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), ' ');
|
||||
assert.equal(model.getLineContent(5), ' }');
|
||||
|
||||
moveTo(cursor, 5, model.getLineMaxColumn(5));
|
||||
cursorCommand(cursor, H.Type, { text: 'something' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' if (a) {');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
assert.equal(model.getLineContent(5), ' }something');
|
||||
});
|
||||
});
|
||||
|
||||
test('removeAutoWhitespace on: test 1', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' some line abc '
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
|
||||
// Move cursor to the end, verify that we do not trim whitespaces if line has values
|
||||
moveTo(cursor, 1, model.getLineContent(1).length + 1);
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
|
||||
// Try to enter again, we should trimmed previous line
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), ' ');
|
||||
|
||||
// More whitespaces
|
||||
cursorCommand(cursor, H.Tab, null, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), ' ');
|
||||
|
||||
// Enter and verify that trimmed again
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' some line abc ');
|
||||
assert.equal(model.getLineContent(2), '');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), ' ');
|
||||
|
||||
// Trimmed if we will keep only text
|
||||
moveTo(cursor, 1, 5);
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' ');
|
||||
assert.equal(model.getLineContent(2), ' some line abc ');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
assert.equal(model.getLineContent(5), '');
|
||||
|
||||
// Trimmed if we will keep only text by selection
|
||||
moveTo(cursor, 2, 5);
|
||||
moveTo(cursor, 3, 1, true);
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getLineContent(1), ' ');
|
||||
assert.equal(model.getLineContent(2), ' ');
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
assert.equal(model.getLineContent(4), '');
|
||||
assert.equal(model.getLineContent(5), '');
|
||||
});
|
||||
});
|
||||
|
||||
test('UseTabStops is off', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' x',
|
||||
' a ',
|
||||
' '
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
cursor.configuration.editor.useTabStops = false;
|
||||
|
||||
// DeleteLeft removes just one whitespace
|
||||
moveTo(cursor, 2, 9);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(2), ' a ');
|
||||
});
|
||||
});
|
||||
|
||||
test('Backspace removes whitespaces with tab size', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
' \t \t x',
|
||||
' a ',
|
||||
' '
|
||||
],
|
||||
modelOpts: {
|
||||
insertSpaces: true,
|
||||
tabSize: 4,
|
||||
detectIndentation: false,
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
cursor.configuration.editor.useTabStops = true;
|
||||
|
||||
// DeleteLeft does not remove tab size, because some text exists before
|
||||
moveTo(cursor, 2, model.getLineContent(2).length + 1);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(2), ' a ');
|
||||
|
||||
// DeleteLeft removes tab size = 4
|
||||
moveTo(cursor, 2, 9);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(2), ' a ');
|
||||
|
||||
// DeleteLeft removes tab size = 4
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(2), 'a ');
|
||||
|
||||
// Undo DeleteLeft - get us back to original indentation
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getLineContent(2), ' a ');
|
||||
|
||||
// Nothing is broken when cursor is in (1,1)
|
||||
moveTo(cursor, 1, 1);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(1), ' \t \t x');
|
||||
|
||||
// DeleteLeft stops at tab stops even in mixed whitespace case
|
||||
moveTo(cursor, 1, 10);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(1), ' \t \t x');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(1), ' \t \tx');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(1), ' \tx');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(1), 'x');
|
||||
|
||||
// DeleteLeft on last line
|
||||
moveTo(cursor, 3, model.getLineContent(3).length + 1);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(3), '');
|
||||
|
||||
// DeleteLeft with removing new line symbol
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x\n a ');
|
||||
|
||||
// In case of selection DeleteLeft only deletes selected text
|
||||
moveTo(cursor, 2, 3);
|
||||
moveTo(cursor, 2, 4, true);
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getLineContent(2), ' a ');
|
||||
});
|
||||
});
|
||||
|
||||
test('PR #5423: Auto indent + undo + redo is funky', () => {
|
||||
usingCursor({
|
||||
text: [
|
||||
''
|
||||
],
|
||||
modelOpts: {
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
detectIndentation: false,
|
||||
insertSpaces: false,
|
||||
tabSize: 4,
|
||||
trimAutoWhitespace: true
|
||||
}
|
||||
}, (model, cursor) => {
|
||||
cursorCommand(cursor, H.Type, { text: '\n' }, null, 'keyboard');
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n', 'assert1');
|
||||
|
||||
cursorCommand(cursor, H.Tab, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t', 'assert2');
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: 'y'}, null, 'keyboard');
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty', 'assert2');
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: '\n'}, null, 'keyboard');
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\t', 'assert3');
|
||||
|
||||
cursorCommand(cursor, H.Type, { text: 'x' });
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert4');
|
||||
|
||||
cursorCommand(cursor, H.CursorLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert5');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert6');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\tyx', 'assert7');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\tx', 'assert8');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert9');
|
||||
|
||||
cursorCommand(cursor, H.DeleteLeft, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert10');
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert11');
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert12');
|
||||
|
||||
cursorCommand(cursor, H.Undo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert13');
|
||||
|
||||
cursorCommand(cursor, H.Redo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert14');
|
||||
|
||||
cursorCommand(cursor, H.Redo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert15');
|
||||
|
||||
cursorCommand(cursor, H.Redo, {});
|
||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert16');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
interface ICursorOpts {
|
||||
|
||||
@@ -21,7 +21,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeLength: rangeLength,
|
||||
lines: text,
|
||||
forceMoveMarkers: false
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -270,7 +271,8 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => {
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
rangeLength: rangeLength,
|
||||
lines: text,
|
||||
forceMoveMarkers: false
|
||||
forceMoveMarkers: false,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ suite('Editor Model - MirrorModel', () => {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: editorCommon.DefaultEndOfLine.LF
|
||||
}
|
||||
})]));
|
||||
@@ -336,6 +337,7 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: editorCommon.DefaultEndOfLine.LF
|
||||
}
|
||||
})]));
|
||||
|
||||
@@ -15,7 +15,8 @@ function testGuessIndentation(defaultInsertSpaces:boolean, defaultTabSize:number
|
||||
tabSize: defaultTabSize,
|
||||
insertSpaces: defaultInsertSpaces,
|
||||
detectIndentation: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
defaultEOL: DefaultEndOfLine.LF,
|
||||
trimAutoWhitespace: true
|
||||
}));
|
||||
var r = m.getOptions();
|
||||
m.dispose();
|
||||
@@ -473,6 +474,7 @@ suite('Editor Model - TextModel', () => {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
}
|
||||
});
|
||||
@@ -511,6 +513,7 @@ suite('Editor Model - TextModel', () => {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: DefaultEndOfLine.LF
|
||||
}
|
||||
});
|
||||
|
||||
@@ -89,6 +89,7 @@ suite('ExtHostLanguageFeatureCommands', function() {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: EditorCommon.DefaultEndOfLine.LF
|
||||
}
|
||||
},
|
||||
|
||||
@@ -77,6 +77,7 @@ suite('ExtHostLanguageFeatures', function() {
|
||||
options: {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
trimAutoWhitespace: true,
|
||||
defaultEOL: EditorCommon.DefaultEndOfLine.LF
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user