annotate .cms/lib/codemirror/src/edit/commands.js @ 1:1d486627aa1e draft default tip

24.10
author Coffee CMS <info@coffee-cms.ru>
date Sat, 12 Oct 2024 02:51:39 +0000
parents 78edf6b517a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
1 import { deleteNearSelection } from "./deleteNearSelection.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 import { runInOp } from "../display/operations.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3 import { ensureCursorVisible } from "../display/scrolling.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4 import { endOfLine } from "../input/movement.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5 import { clipPos, Pos } from "../line/pos.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 import { visualLine, visualLineEnd } from "../line/spans.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7 import { getLine, lineNo } from "../line/utils_line.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 import { Range } from "../model/selection.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9 import { selectAll } from "../model/selection_updates.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 import { countColumn, sel_dontScroll, sel_move, spaceStr } from "../util/misc.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11 import { getOrder } from "../util/bidi.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13 // Commands are parameter-less actions that can be performed on an
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14 // editor, mostly used for keybindings.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 export let commands = {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 selectAll: selectAll,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17 singleSelection: cm => cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18 killLine: cm => deleteNearSelection(cm, range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19 if (range.empty()) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20 let len = getLine(cm.doc, range.head.line).text.length
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 if (range.head.ch == len && range.head.line < cm.lastLine())
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 return {from: range.head, to: Pos(range.head.line + 1, 0)}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 else
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24 return {from: range.head, to: Pos(range.head.line, len)}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 return {from: range.from(), to: range.to()}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 }),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29 deleteLine: cm => deleteNearSelection(cm, range => ({
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30 from: Pos(range.from().line, 0),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32 })),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 delLineLeft: cm => deleteNearSelection(cm, range => ({
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34 from: Pos(range.from().line, 0), to: range.from()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 })),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 delWrappedLineLeft: cm => deleteNearSelection(cm, range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37 let top = cm.charCoords(range.head, "div").top + 5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38 let leftPos = cm.coordsChar({left: 0, top: top}, "div")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39 return {from: leftPos, to: range.from()}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 }),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 delWrappedLineRight: cm => deleteNearSelection(cm, range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42 let top = cm.charCoords(range.head, "div").top + 5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 let rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44 return {from: range.from(), to: rightPos }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 }),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 undo: cm => cm.undo(),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47 redo: cm => cm.redo(),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 undoSelection: cm => cm.undoSelection(),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49 redoSelection: cm => cm.redoSelection(),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 goDocStart: cm => cm.extendSelection(Pos(cm.firstLine(), 0)),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51 goDocEnd: cm => cm.extendSelection(Pos(cm.lastLine())),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 goLineStart: cm => cm.extendSelectionsBy(range => lineStart(cm, range.head.line),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 {origin: "+move", bias: 1}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54 ),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 goLineStartSmart: cm => cm.extendSelectionsBy(range => lineStartSmart(cm, range.head),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 {origin: "+move", bias: 1}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57 ),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58 goLineEnd: cm => cm.extendSelectionsBy(range => lineEnd(cm, range.head.line),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 {origin: "+move", bias: -1}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 ),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 goLineRight: cm => cm.extendSelectionsBy(range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62 let top = cm.cursorCoords(range.head, "div").top + 5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 }, sel_move),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 goLineLeft: cm => cm.extendSelectionsBy(range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 let top = cm.cursorCoords(range.head, "div").top + 5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67 return cm.coordsChar({left: 0, top: top}, "div")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68 }, sel_move),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 goLineLeftSmart: cm => cm.extendSelectionsBy(range => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 let top = cm.cursorCoords(range.head, "div").top + 5
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71 let pos = cm.coordsChar({left: 0, top: top}, "div")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73 return pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 }, sel_move),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75 goLineUp: cm => cm.moveV(-1, "line"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 goLineDown: cm => cm.moveV(1, "line"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 goPageUp: cm => cm.moveV(-1, "page"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 goPageDown: cm => cm.moveV(1, "page"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79 goCharLeft: cm => cm.moveH(-1, "char"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80 goCharRight: cm => cm.moveH(1, "char"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 goColumnLeft: cm => cm.moveH(-1, "column"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 goColumnRight: cm => cm.moveH(1, "column"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 goWordLeft: cm => cm.moveH(-1, "word"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84 goGroupRight: cm => cm.moveH(1, "group"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85 goGroupLeft: cm => cm.moveH(-1, "group"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 goWordRight: cm => cm.moveH(1, "word"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87 delCharBefore: cm => cm.deleteH(-1, "codepoint"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 delCharAfter: cm => cm.deleteH(1, "char"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 delWordBefore: cm => cm.deleteH(-1, "word"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 delWordAfter: cm => cm.deleteH(1, "word"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 delGroupBefore: cm => cm.deleteH(-1, "group"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92 delGroupAfter: cm => cm.deleteH(1, "group"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 indentAuto: cm => cm.indentSelection("smart"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 indentMore: cm => cm.indentSelection("add"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 indentLess: cm => cm.indentSelection("subtract"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 insertTab: cm => cm.replaceSelection("\t"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97 insertSoftTab: cm => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 let spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99 for (let i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100 let pos = ranges[i].from()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 let col = countColumn(cm.getLine(pos.line), pos.ch, tabSize)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102 spaces.push(spaceStr(tabSize - col % tabSize))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 cm.replaceSelections(spaces)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105 },
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 defaultTab: cm => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107 if (cm.somethingSelected()) cm.indentSelection("add")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108 else cm.execCommand("insertTab")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 },
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110 // Swap the two chars left and right of each selection's head.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 // Move cursor behind the two swapped characters afterwards.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 //
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 // Doesn't consider line feeds a character.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 // Doesn't scan more than one line above to find a character.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 // Doesn't do anything on an empty line.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116 // Doesn't do anything with non-empty selections.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117 transposeChars: cm => runInOp(cm, () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 let ranges = cm.listSelections(), newSel = []
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 for (let i = 0; i < ranges.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120 if (!ranges[i].empty()) continue
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121 let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 if (line) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123 if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124 if (cur.ch > 0) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 cur = new Pos(cur.line, cur.ch + 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 Pos(cur.line, cur.ch - 2), cur, "+transpose")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128 } else if (cur.line > cm.doc.first) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 let prev = getLine(cm.doc, cur.line - 1).text
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130 if (prev) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 cur = new Pos(cur.line, 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133 prev.charAt(prev.length - 1),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 Pos(cur.line - 1, prev.length - 1), cur, "+transpose")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138 newSel.push(new Range(cur, cur))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 cm.setSelections(newSel)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141 }),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 newlineAndIndent: cm => runInOp(cm, () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 let sels = cm.listSelections()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144 for (let i = sels.length - 1; i >= 0; i--)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 sels = cm.listSelections()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
147 for (let i = 0; i < sels.length; i++)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
148 cm.indentLine(sels[i].from().line, null, true)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
149 ensureCursorVisible(cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
150 }),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
151 openLine: cm => cm.replaceSelection("\n", "start"),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
152 toggleOverwrite: cm => cm.toggleOverwrite()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
153 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
154
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
155
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
156 function lineStart(cm, lineN) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
157 let line = getLine(cm.doc, lineN)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
158 let visual = visualLine(line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
159 if (visual != line) lineN = lineNo(visual)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
160 return endOfLine(true, cm, visual, lineN, 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
161 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
162 function lineEnd(cm, lineN) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
163 let line = getLine(cm.doc, lineN)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
164 let visual = visualLineEnd(line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
165 if (visual != line) lineN = lineNo(visual)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
166 return endOfLine(true, cm, line, lineN, -1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
167 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
168 function lineStartSmart(cm, pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
169 let start = lineStart(cm, pos.line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
170 let line = getLine(cm.doc, start.line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
171 let order = getOrder(line, cm.doc.direction)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
172 if (!order || order[0].level == 0) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
173 let firstNonWS = Math.max(start.ch, line.text.search(/\S/))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
174 let inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
175 return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
176 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
177 return start
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
178 }