|
1 | | -import { insertTab } from "@codemirror/commands"; |
2 | | -import { countColumn, EditorSelection } from "@codemirror/state"; |
3 | | -import { EditorView, KeyBinding } from "@codemirror/view"; |
| 1 | +import { indentLess, indentMore, insertTab } from "@codemirror/commands"; |
| 2 | +import { KeyBinding } from "@codemirror/view"; |
4 | 3 |
|
5 | | -function tab(view: EditorView): boolean { |
6 | | - const tabSize = view.state.tabSize; |
7 | | - view.dispatch(view.state.changeByRange(sel => { |
8 | | - const startLine = view.state.doc.lineAt(sel.from); |
9 | | - const endLine = view.state.doc.lineAt(sel.to); |
10 | | - if (sel.empty) { |
11 | | - // Cursor only: insert spaces to next tab stop |
12 | | - const col = sel.head - startLine.from; |
13 | | - const spaces = tabSize - (col % tabSize); |
14 | | - const insert = " ".repeat(spaces); |
15 | | - return { |
16 | | - changes: { from: sel.from, insert }, |
17 | | - range: EditorSelection.cursor(sel.from + spaces), |
18 | | - }; |
19 | | - } else if (startLine.number === endLine.number) { |
20 | | - // Single-line selection: replace with spaces, cursor at end of whitespace |
21 | | - const col = sel.from - startLine.from; |
22 | | - const spaces = tabSize - (col % tabSize); |
23 | | - const insert = " ".repeat(spaces); |
24 | | - return { |
25 | | - changes: { from: sel.from, to: sel.to, insert }, |
26 | | - range: EditorSelection.cursor(sel.from + spaces), |
27 | | - }; |
28 | | - } else { |
29 | | - // Multi-line selection: move first non-ws char to next tab stop on each line |
30 | | - const changes = []; |
31 | | - for (let i = startLine.number; i <= endLine.number; i++) { |
32 | | - const line = view.state.doc.line(i); |
33 | | - const firstNonWs = line.text.search(/\S/); |
34 | | - if (firstNonWs < 0) continue; |
35 | | - const newCol = (Math.floor(firstNonWs / tabSize) + 1) * tabSize; |
36 | | - const spaces = newCol - firstNonWs; |
37 | | - changes.push({ from: line.from + firstNonWs, insert: " ".repeat(spaces) }); |
38 | | - } |
39 | | - const changeSet = view.state.changes(changes); |
40 | | - return { |
41 | | - changes: changeSet, |
42 | | - range: EditorSelection.range(changeSet.mapPos(sel.from), changeSet.mapPos(sel.to)), |
43 | | - }; |
44 | | - } |
45 | | - })); |
46 | | - return true; |
47 | | -} |
48 | | - |
49 | | -function shiftTab(view: EditorView): boolean { |
50 | | - const tabSize = view.state.tabSize; |
51 | | - const changes = []; |
52 | | - const seen = new Set<number>(); |
53 | | - for (const sel of view.state.selection.ranges) { |
54 | | - const startLine = view.state.doc.lineAt(sel.from); |
55 | | - const endLine = view.state.doc.lineAt(sel.to); |
56 | | - for (let i = startLine.number; i <= endLine.number; i++) { |
57 | | - if (seen.has(i)) continue; |
58 | | - seen.add(i); |
59 | | - const line = view.state.doc.line(i); |
60 | | - const text = line.text; |
61 | | - const firstNonWs = text.search(/\S|$/); |
62 | | - if (firstNonWs == -1) continue; |
63 | | - const wsVisualCol = countColumn(text, tabSize, firstNonWs); |
64 | | - const targetCol = Math.floor((wsVisualCol - 1) / tabSize) * tabSize; |
65 | | - |
66 | | - // Find the character index at targetCol |
67 | | - let col = 0; |
68 | | - let idx = 0; |
69 | | - while (idx < firstNonWs && col < targetCol) { |
70 | | - if (text[idx] === '\t') { |
71 | | - const nextStop = (Math.floor(col / tabSize) + 1) * tabSize; |
72 | | - if (nextStop > targetCol) break; |
73 | | - col = nextStop; |
74 | | - } else { |
75 | | - col++; |
76 | | - } |
77 | | - idx++; |
78 | | - } |
79 | | - changes.push({ from: line.from + idx, to: line.from + firstNonWs }); |
80 | | - } |
81 | | - } |
82 | | - if (changes.length) view.dispatch({ changes }); |
83 | | - return true; |
84 | | -} |
85 | | - |
86 | | -export const spacesSpacesKeymap: KeyBinding[] = [ |
87 | | - { key: "Tab", run: tab }, |
88 | | - { key: "Shift-Tab", run: shiftTab }, |
| 4 | +export const smartIndentKeymap: KeyBinding[] = [ |
| 5 | + { key: "Tab", run: indentMore }, |
| 6 | + { key: "Shift-Tab", run: indentLess }, |
89 | 7 | ]; |
90 | 8 |
|
91 | 9 | export const insertTabKeymap: KeyBinding[] = [ |
92 | 10 | { key: "Tab", run: insertTab }, |
93 | | - { key: "Shift-Tab", run: shiftTab }, |
| 11 | + { key: "Shift-Tab", run: indentLess }, |
94 | 12 | ]; |
0 commit comments