Skip to content

Commit

Permalink
Fix tab-to-tab-stop for offside-rule languages
Browse files Browse the repository at this point in the history
  • Loading branch information
whitphx committed May 7, 2024
1 parent 2965f6a commit 800fca5
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/commands/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,60 @@ import * as vscode from "vscode";
import { Selection, TextEditor } from "vscode";
import { makeParallel, EmacsCommand } from ".";

const offsideRuleLanguageIds = ["python"];

export class TabToTabStop extends EmacsCommand {
public readonly id = "tabToTabStop";

public run(textEditor: TextEditor, isInMarkMode: boolean, prefixArgument: number | undefined): Thenable<unknown> {
if (offsideRuleLanguageIds.includes(textEditor.document.languageId)) {
const tabSize = textEditor.options.tabSize as number;
const insertSpaces = textEditor.options.insertSpaces as boolean;

const indentChars = insertSpaces ? tabSize : 1;

const editsAndMoves = textEditor.selections.map((selection) => {
let prevNonEmptyLine: vscode.TextLine | undefined;
for (let i = selection.active.line - 1; i >= 0; i--) {
const line = textEditor.document.lineAt(i);
if (line.isEmptyOrWhitespace) {
continue;
}
prevNonEmptyLine = line;
break;
}
const prevIndentHeadChar = prevNonEmptyLine?.firstNonWhitespaceCharacterIndex ?? 0;
const newIndentUnits = Math.floor(prevIndentHeadChar / tabSize) + 1;
const newIndentChars = newIndentUnits * indentChars;

const curLine = textEditor.document.lineAt(selection.active.line);
const charsToInsert = Math.max(newIndentChars - curLine.firstNonWhitespaceCharacterIndex, 0);
const charsToMoveCurAfterIndent = Math.max(
selection.active.character - curLine.firstNonWhitespaceCharacterIndex,
0,
);

return {
line: selection.active.line,
charsToInsert,
cursorChars: newIndentChars + charsToMoveCurAfterIndent,
};
});

const indentChar = insertSpaces ? " " : "\t";
textEditor.edit((editBuilder) => {
editsAndMoves.forEach((editAndMove) => {
const lineHead = new vscode.Position(editAndMove.line, 0);
editBuilder.insert(lineHead, indentChar.repeat(editAndMove.charsToInsert));
});
});
textEditor.selections = editsAndMoves.map((editAndMove) => {
const active = new vscode.Position(editAndMove.line, editAndMove.cursorChars);
return new vscode.Selection(active, active);
});
this.emacsController.exitMarkMode();
}

// A single call of `editor.action.reindentselectedlines`
// only affects a first selection which has a not indented line.
// So we need to call it as many times as the number of selections.
Expand All @@ -20,6 +70,7 @@ export class TabToTabStop extends EmacsCommand {
const indentHeadPos = new vscode.Position(selection.active.line, indentHeadChar);
return new Selection(indentHeadPos, indentHeadPos);
});
this.emacsController.exitMarkMode();
});
}
}

0 comments on commit 800fca5

Please sign in to comment.