import { getContextBefore } from "../line/highlight.js" import { Pos } from "../line/pos.js" import { getLine } from "../line/utils_line.js" import { replaceRange } from "../model/changes.js" import { Range } from "../model/selection.js" import { replaceOneSelection } from "../model/selection_updates.js" import { countColumn, Pass, spaceStr } from "../util/misc.js" // Indent the given line. The how parameter can be "smart", // "add"/null, "subtract", or "prev". When aggressive is false // (typically set to true for forced single-line indents), empty // lines are not indented, and places where the mode returns Pass // are left alone. export function indentLine(cm, n, how, aggressive) { let doc = cm.doc, state if (how == null) how = "add" if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation // method. if (!doc.mode.indent) how = "prev" else state = getContextBefore(cm, n).state } let tabSize = cm.options.tabSize let line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) if (line.stateAfter) line.stateAfter = null let curSpaceString = line.text.match(/^\s*/)[0], indentation if (!aggressive && !/\S/.test(line.text)) { indentation = 0 how = "not" } else if (how == "smart") { indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) if (indentation == Pass || indentation > 150) { if (!aggressive) return how = "prev" } } if (how == "prev") { if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize) else indentation = 0 } else if (how == "add") { indentation = curSpace + cm.options.indentUnit } else if (how == "subtract") { indentation = curSpace - cm.options.indentUnit } else if (typeof how == "number") { indentation = curSpace + how } indentation = Math.max(0, indentation) let indentString = "", pos = 0 if (cm.options.indentWithTabs) for (let i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} if (pos < indentation) indentString += spaceStr(indentation - pos) if (indentString != curSpaceString) { replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") line.stateAfter = null return true } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. for (let i = 0; i < doc.sel.ranges.length; i++) { let range = doc.sel.ranges[i] if (range.head.line == n && range.head.ch < curSpaceString.length) { let pos = Pos(n, curSpaceString.length) replaceOneSelection(doc, i, new Range(pos, pos)) break } } } }