mirror of
https://github.com/stackblitz/bolt.new
synced 2024-11-27 22:42:21 +00:00
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import { indentLess } from '@codemirror/commands';
|
|
import { indentUnit } from '@codemirror/language';
|
|
import { EditorSelection, EditorState, Line, type ChangeSpec } from '@codemirror/state';
|
|
import { EditorView, type KeyBinding } from '@codemirror/view';
|
|
|
|
export const indentKeyBinding: KeyBinding = {
|
|
key: 'Tab',
|
|
run: indentMore,
|
|
shift: indentLess,
|
|
};
|
|
|
|
function indentMore({ state, dispatch }: EditorView) {
|
|
if (state.readOnly) {
|
|
return false;
|
|
}
|
|
|
|
dispatch(
|
|
state.update(
|
|
changeBySelectedLine(state, (from, to, changes) => {
|
|
changes.push({ from, to, insert: state.facet(indentUnit) });
|
|
}),
|
|
{ userEvent: 'input.indent' },
|
|
),
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
function changeBySelectedLine(
|
|
state: EditorState,
|
|
cb: (from: number, to: number | undefined, changes: ChangeSpec[], line: Line) => void,
|
|
) {
|
|
return state.changeByRange((range) => {
|
|
const changes: ChangeSpec[] = [];
|
|
|
|
const line = state.doc.lineAt(range.from);
|
|
|
|
// just insert single indent unit at the current cursor position
|
|
if (range.from === range.to) {
|
|
cb(range.from, undefined, changes, line);
|
|
}
|
|
// handle the case when multiple characters are selected in a single line
|
|
else if (range.from < range.to && range.to <= line.to) {
|
|
cb(range.from, range.to, changes, line);
|
|
} else {
|
|
let atLine = -1;
|
|
|
|
// handle the case when selection spans multiple lines
|
|
for (let pos = range.from; pos <= range.to; ) {
|
|
const line = state.doc.lineAt(pos);
|
|
|
|
if (line.number > atLine && (range.empty || range.to > line.from)) {
|
|
cb(line.from, undefined, changes, line);
|
|
atLine = line.number;
|
|
}
|
|
|
|
pos = line.to + 1;
|
|
}
|
|
}
|
|
|
|
const changeSet = state.changes(changes);
|
|
|
|
return {
|
|
changes,
|
|
range: EditorSelection.range(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1)),
|
|
};
|
|
});
|
|
}
|