indent.js (2757B)
1 import { getContextBefore } from "../line/highlight.js" 2 import { Pos } from "../line/pos.js" 3 import { getLine } from "../line/utils_line.js" 4 import { replaceRange } from "../model/changes.js" 5 import { Range } from "../model/selection.js" 6 import { replaceOneSelection } from "../model/selection_updates.js" 7 import { countColumn, Pass, spaceStr } from "../util/misc.js" 8 9 // Indent the given line. The how parameter can be "smart", 10 // "add"/null, "subtract", or "prev". When aggressive is false 11 // (typically set to true for forced single-line indents), empty 12 // lines are not indented, and places where the mode returns Pass 13 // are left alone. 14 export function indentLine(cm, n, how, aggressive) { 15 let doc = cm.doc, state 16 if (how == null) how = "add" 17 if (how == "smart") { 18 // Fall back to "prev" when the mode doesn't have an indentation 19 // method. 20 if (!doc.mode.indent) how = "prev" 21 else state = getContextBefore(cm, n).state 22 } 23 24 let tabSize = cm.options.tabSize 25 let line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) 26 if (line.stateAfter) line.stateAfter = null 27 let curSpaceString = line.text.match(/^\s*/)[0], indentation 28 if (!aggressive && !/\S/.test(line.text)) { 29 indentation = 0 30 how = "not" 31 } else if (how == "smart") { 32 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) 33 if (indentation == Pass || indentation > 150) { 34 if (!aggressive) return 35 how = "prev" 36 } 37 } 38 if (how == "prev") { 39 if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize) 40 else indentation = 0 41 } else if (how == "add") { 42 indentation = curSpace + cm.options.indentUnit 43 } else if (how == "subtract") { 44 indentation = curSpace - cm.options.indentUnit 45 } else if (typeof how == "number") { 46 indentation = curSpace + how 47 } 48 indentation = Math.max(0, indentation) 49 50 let indentString = "", pos = 0 51 if (cm.options.indentWithTabs) 52 for (let i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} 53 if (pos < indentation) indentString += spaceStr(indentation - pos) 54 55 if (indentString != curSpaceString) { 56 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") 57 line.stateAfter = null 58 return true 59 } else { 60 // Ensure that, if the cursor was in the whitespace at the start 61 // of the line, it is moved to the end of that space. 62 for (let i = 0; i < doc.sel.ranges.length; i++) { 63 let range = doc.sel.ranges[i] 64 if (range.head.line == n && range.head.ch < curSpaceString.length) { 65 let pos = Pos(n, curSpaceString.length) 66 replaceOneSelection(doc, i, new Range(pos, pos)) 67 break 68 } 69 } 70 } 71 }