/** * Wraps the current selection in CodeMirror with the given prefix and suffix. */ export function wrapSelection( view: any, prefix: string, suffix: string = prefix ) { if (!view || view.updateInProgress) return; const { state } = view; view.dispatch( state.changeByRange((range: any) => { return { changes: [ { from: range.from, insert: prefix }, { from: range.to, insert: suffix } ], range: range.constructor.range( range.from + prefix.length, range.to + prefix.length ) }; }) ); view.focus(); } /** * Inserts a prefix at the start of each line in the selection (e.g., for lists or blockquotes). */ export function toggleLinePrefix(view: any, prefix: string) { if (!view || view.updateInProgress) return; const { state } = view; view.dispatch( state.changeByRange((range: any) => { const lines = []; for (let pos = range.from; pos <= range.to; ) { const line = state.doc.lineAt(pos); lines.push(line); pos = line.to + 1; } const isAlreadyPrefixed = lines.every((l) => l.text.startsWith(prefix) ); const lineChanges = lines.map((l) => { if (isAlreadyPrefixed) { return { from: l.from, to: l.from + prefix.length, insert: '' }; } else { return { from: l.from, insert: prefix }; } }); const newFrom = range.from + (isAlreadyPrefixed ? -prefix.length : prefix.length); const newTo = range.to + (isAlreadyPrefixed ? -prefix.length * lines.length : prefix.length * lines.length); return { changes: lineChanges, range: range.constructor.range( newFrom, Math.max(newFrom, newTo) ) }; }) ); view.focus(); }