135 lines
6.8 KiB
JavaScript
135 lines
6.8 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.startingWhitespaceLength = exports.trimCurrentLine = exports.currentLineDedentation = exports.extendCommentToNextLine = exports.editsToMake = exports.newlineAndIndent = void 0;
|
|
const vscode = require("vscode");
|
|
const parser_1 = require("./parser");
|
|
function newlineAndIndent(textEditor, edit, args) {
|
|
// Get rid of any user selected text, since a selection is
|
|
// always deleted whenever ENTER is pressed.
|
|
// This should always happen first
|
|
if (!textEditor.selection.isEmpty) {
|
|
edit.delete(textEditor.selection);
|
|
// Make sure we get rid of the selection range.
|
|
textEditor.selection = new vscode.Selection(textEditor.selection.end, textEditor.selection.end);
|
|
}
|
|
const position = textEditor.selection.active;
|
|
const tabSize = textEditor.options.tabSize;
|
|
const insertionPoint = new vscode.Position(position.line, position.character);
|
|
const currentLine = textEditor.document.lineAt(position).text;
|
|
let snippetCursor = '$0';
|
|
let settings = vscode.workspace.getConfiguration('pythonIndent');
|
|
if (settings.useTabOnHangingIndent) {
|
|
snippetCursor = '$1';
|
|
}
|
|
let hanging = parser_1.Hanging.none;
|
|
let toInsert = '\n';
|
|
try {
|
|
if (textEditor.document.languageId === 'python') {
|
|
const lines = textEditor.document.getText(new vscode.Range(0, 0, position.line, position.character)).split("\n");
|
|
const edits = editsToMake(lines, currentLine, tabSize, position.line, position.character, settings.trimLinesWithOnlyWhitespace, settings.keepHangingBracketOnLine);
|
|
toInsert = edits.insert;
|
|
edits.deletes.forEach(range => { edit.delete(range); });
|
|
hanging = edits.hanging;
|
|
}
|
|
}
|
|
finally {
|
|
// we never ever want to crash here, fallback on just inserting newline
|
|
if (hanging === parser_1.Hanging.full) {
|
|
// Hanging indents end up with the cursor in a bad place if we
|
|
// just use the edit.insert() function, snippets behave better.
|
|
// The VSCode snippet logic already does some indentation handling,
|
|
// so don't use the toInsert, just ' ' * tabSize.
|
|
// That behavior is not documented.
|
|
textEditor.insertSnippet(new vscode.SnippetString('\n' + ' '.repeat(tabSize) + snippetCursor + '\n'));
|
|
}
|
|
else {
|
|
edit.insert(insertionPoint, toInsert);
|
|
}
|
|
textEditor.revealRange(new vscode.Range(position, new vscode.Position(position.line + 2, 0)));
|
|
}
|
|
}
|
|
exports.newlineAndIndent = newlineAndIndent;
|
|
function editsToMake(lines, currentLine, tabSize, lineNum, charNum, trimLinesWithOnlyWhitespace, keepHangingBracketOnLine) {
|
|
let { nextIndentationLevel: indent, parseOutput: parseOut } = (0, parser_1.indentationInfo)(lines, tabSize);
|
|
let deletes = [];
|
|
// If cursor has whitespace to the right, followed by non-whitespace,
|
|
// and also has non-whitespace to the left, then trim the whitespace to the right
|
|
// of the cursor. E.g. in cases like "def f(x,| y):"
|
|
const numCharsToDelete = startingWhitespaceLength(currentLine.slice(charNum));
|
|
if ((numCharsToDelete > 0) && (/\S/.test(currentLine.slice(0, charNum)))) {
|
|
deletes.push(new vscode.Range(lineNum, charNum, lineNum, charNum + numCharsToDelete));
|
|
}
|
|
const dedentAmount = currentLineDedentation(lines, tabSize, parseOut);
|
|
const shouldTrim = trimCurrentLine(lines[lines.length - 1], trimLinesWithOnlyWhitespace);
|
|
if ((dedentAmount > 0) || shouldTrim) {
|
|
const totalDeleteAmount = shouldTrim ? lines[lines.length - 1].length : dedentAmount;
|
|
deletes.push(new vscode.Range(lineNum, 0, lineNum, totalDeleteAmount));
|
|
indent = Math.max(indent - dedentAmount, 0);
|
|
}
|
|
let hanging = (0, parser_1.shouldHang)(currentLine, charNum);
|
|
if (keepHangingBracketOnLine && hanging === parser_1.Hanging.full) {
|
|
// The only difference between partial and full is that
|
|
// full puts the closing bracket on its own line.
|
|
hanging = parser_1.Hanging.partial;
|
|
}
|
|
let toInsert = '\n';
|
|
if (hanging === parser_1.Hanging.partial) {
|
|
toInsert = '\n' + ' '.repeat((0, parser_1.indentationLevel)(currentLine) + tabSize);
|
|
}
|
|
else {
|
|
toInsert = '\n' + ' '.repeat(Math.max(indent, 0));
|
|
}
|
|
if (extendCommentToNextLine(currentLine, charNum)) {
|
|
toInsert = toInsert + '# ';
|
|
}
|
|
return { insert: toInsert, deletes: deletes, hanging: hanging };
|
|
}
|
|
exports.editsToMake = editsToMake;
|
|
// Current line is a comment line, and we should make the next one commented too.
|
|
function extendCommentToNextLine(line, pos) {
|
|
if (line.trim().startsWith('#') && line.slice(pos).trim().length && line.slice(0, pos).trim().length) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
exports.extendCommentToNextLine = extendCommentToNextLine;
|
|
// Returns the number of spaces that should be removed from the current line
|
|
function currentLineDedentation(lines, tabSize, parseOut) {
|
|
const dedentKeywords = { elif: ["if"], else: ["if", "try", "for", "while"], except: ["try"], finally: ["try"] };
|
|
// Reverse to help searching, use slice() to copy since reverse() is inplace
|
|
const line = lines[lines.length - 1];
|
|
const trimmed = line.trim();
|
|
if (trimmed.endsWith(":")) {
|
|
for (const keyword of Object.keys(dedentKeywords).filter((key) => trimmed.startsWith(key))) {
|
|
const matchingLineNumber = Math.max(...dedentKeywords[keyword].map((indentKeyword) => {
|
|
return parseOut.lastSeenIndenters[indentKeyword];
|
|
}));
|
|
if (matchingLineNumber >= 0) {
|
|
const currentIndent = (0, parser_1.indentationLevel)(line);
|
|
const matchedIndent = (0, parser_1.indentationLevel)(lines[matchingLineNumber]);
|
|
return Math.max(0, Math.min(tabSize, currentIndent, currentIndent - matchedIndent));
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
exports.currentLineDedentation = currentLineDedentation;
|
|
// Returns true if the current line should have all of its characters deleted.
|
|
function trimCurrentLine(line, trimLinesWithOnlyWhitespace) {
|
|
if (trimLinesWithOnlyWhitespace) {
|
|
if (line.trim().length === 0) {
|
|
// That means the string contained only whitespace.
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
exports.trimCurrentLine = trimCurrentLine;
|
|
// Returns the number of whitespace characters until the next non-whitespace char
|
|
// If there are no non-whitespace chars, returns 0, regardless of number of whitespace chars.
|
|
function startingWhitespaceLength(line) {
|
|
var _a, _b;
|
|
return (_b = (_a = /\S/.exec(line)) === null || _a === void 0 ? void 0 : _a.index) !== null && _b !== void 0 ? _b : 0;
|
|
}
|
|
exports.startingWhitespaceLength = startingWhitespaceLength;
|
|
//# sourceMappingURL=indent.js.map
|