diff --git a/src/vs/editor/common/commands/shiftCommand.ts b/src/vs/editor/common/commands/shiftCommand.ts index 3c0c9bea6fb29..3135f9e82c270 100644 --- a/src/vs/editor/common/commands/shiftCommand.ts +++ b/src/vs/editor/common/commands/shiftCommand.ts @@ -50,10 +50,12 @@ export class ShiftCommand implements ICommand { const indentCount = desiredTabStop / indentSize; // will be an integer return cachedStringRepeat(indent, indentCount); } else { - const indent = '\t'; - const desiredTabStop = CursorColumns.prevRenderTabStop(contentStartVisibleColumn, tabSize); - const indentCount = desiredTabStop / tabSize; // will be an integer - return cachedStringRepeat(indent, indentCount); + const desiredTabStop = CursorColumns.prevRenderTabStop(contentStartVisibleColumn, indentSize); + const tabCount = Math.floor(desiredTabStop / tabSize); + const spaceCount = desiredTabStop - tabCount * tabSize; + const tabString = cachedStringRepeat('\t', tabCount); + const spaceString = cachedStringRepeat(' ', spaceCount); + return tabString + spaceString; } } @@ -67,10 +69,12 @@ export class ShiftCommand implements ICommand { const indentCount = desiredTabStop / indentSize; // will be an integer return cachedStringRepeat(indent, indentCount); } else { - const indent = '\t'; - const desiredTabStop = CursorColumns.nextRenderTabStop(contentStartVisibleColumn, tabSize); - const indentCount = desiredTabStop / tabSize; // will be an integer - return cachedStringRepeat(indent, indentCount); + const desiredTabStop = CursorColumns.nextRenderTabStop(contentStartVisibleColumn, indentSize); + const tabCount = Math.floor(desiredTabStop / tabSize); + const spaceCount = desiredTabStop - tabCount * tabSize; + const tabString = cachedStringRepeat('\t', tabCount); + const spaceString = cachedStringRepeat(' ', spaceCount); + return tabString + spaceString; } } diff --git a/src/vs/editor/common/cursor/cursorTypeOperations.ts b/src/vs/editor/common/cursor/cursorTypeOperations.ts index e735c14056f35..7d9e4c1a7930a 100644 --- a/src/vs/editor/common/cursor/cursorTypeOperations.ts +++ b/src/vs/editor/common/cursor/cursorTypeOperations.ts @@ -200,18 +200,32 @@ export class TypeOperations { return indentation; } - private static _replaceJumpToNextIndent(config: CursorConfiguration, model: ICursorSimpleModel, selection: Selection, insertsAutoWhitespace: boolean): ReplaceCommand { + private static _replaceJumpToNextIndent(config: CursorConfiguration, model: ICursorSimpleModel, selection: Selection, insertsAutoWhitespace: boolean): ICommand { let typeText = ''; - const position = selection.getStartPosition(); if (config.insertSpaces) { - const visibleColumnFromColumn = config.visibleColumnFromColumn(model, position); + const visibleColumnFromColumn = config.visibleColumnFromColumn(model, selection.getStartPosition()); const indentSize = config.indentSize; const spacesCnt = indentSize - (visibleColumnFromColumn % indentSize); for (let i = 0; i < spacesCnt; i++) { typeText += ' '; } } else { + if (config.tabSize > config.indentSize) { + // If configured for mixed indentation and selection is at the front, do a shift instead, + // which will properly normalize existing leading whitespace + const firstNonWhitespace = model.getLineFirstNonWhitespaceColumn(selection.endLineNumber); + if (selection.endColumn <= firstNonWhitespace) { + return new ShiftCommand(selection, { + isUnshift: false, + tabSize: config.tabSize, + indentSize: config.indentSize, + insertSpaces: config.insertSpaces, + useTabStops: config.useTabStops, + autoIndent: config.autoIndent + }, config.languageConfigurationService); + } + } typeText = '\t'; }