mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-14 21:23:40 +01:00
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import type { Extension, TransactionSpec } from '@codemirror/state';
|
|
import { EditorSelection, EditorState, Transaction } from '@codemirror/state';
|
|
|
|
/**
|
|
* A CodeMirror extension that forces single-line input by stripping
|
|
* all newline characters from user input, including pasted content.
|
|
*
|
|
* This extension uses a transaction filter to intercept user input,
|
|
* removes any newline characters, and adjusts the selection to the end
|
|
* of the inserted text.
|
|
*
|
|
* IME composition events are ignored to preserve proper input behavior
|
|
* for non-Latin languages.
|
|
*
|
|
* @returns A CodeMirror extension that enforces single-line editing.
|
|
*/
|
|
export function singleLineExtensions(): Extension {
|
|
return EditorState.transactionFilter.of(
|
|
(tr: Transaction): TransactionSpec | readonly TransactionSpec[] => {
|
|
if (!tr.isUserEvent('input') || tr.isUserEvent('input.type.compose')) return tr;
|
|
|
|
const changes: { from: number; to: number; insert: string }[] = [];
|
|
|
|
tr.changes.iterChanges((_fromA, toA, fromB, _toB, inserted) => {
|
|
let insert = '';
|
|
for (const line of inserted.iterLines()) {
|
|
insert += line.replace(/\n/g, '');
|
|
}
|
|
|
|
if (insert !== inserted.toString()) {
|
|
changes.push({ from: fromB, to: toA, insert });
|
|
}
|
|
});
|
|
|
|
const lastChange = changes[changes.length - 1];
|
|
if (lastChange == null) return tr;
|
|
|
|
const selection = EditorSelection.cursor(lastChange.from + lastChange.insert.length);
|
|
|
|
return {
|
|
changes,
|
|
selection,
|
|
userEvent: tr.annotation(Transaction.userEvent) ?? undefined,
|
|
};
|
|
},
|
|
);
|
|
}
|