|  | 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); | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | if (range.from === range.to) { | 
					
						
						|  | cb(range.from, undefined, changes, line); | 
					
						
						|  | } | 
					
						
						|  |  | 
					
						
						|  | else if (range.from < range.to && range.to <= line.to) { | 
					
						
						|  | cb(range.from, range.to, changes, line); | 
					
						
						|  | } else { | 
					
						
						|  | let atLine = -1; | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | 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)), | 
					
						
						|  | }; | 
					
						
						|  | }); | 
					
						
						|  | } | 
					
						
						|  |  |