feat(editor): Introduce proxy completions to expressions (#5075)
* ⚡ Introduce proxy completions to expressions * 🧪 Add tests * ⚡ Replace snippet with alphabetic char completions * ⚡ Tighten `DateTime` check * 🧹 Clean up `n8nLang` * 🔥 Remove duplicate * 👕 Remove non-null assertion * ⚡ Confirm that `overlay` is needed * 🔥 Remove comment * 🔥 Remove more unneeded code * 🔥 Remove unneded Pinia setup * ⚡ Simplify syntax
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { closeBrackets, completionStatus, insertBracket } from '@codemirror/autocomplete';
|
||||
import { codePointAt, codePointSize, Extension } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
|
||||
const handler = EditorView.inputHandler.of((view, from, to, insert) => {
|
||||
if (view.composing || view.state.readOnly) return false;
|
||||
|
||||
// customization: do not autoclose tokens while autocompletion is active
|
||||
if (completionStatus(view.state) !== null) return false;
|
||||
|
||||
const selection = view.state.selection.main;
|
||||
|
||||
// customization: do not autoclose square brackets prior to `.json`
|
||||
if (
|
||||
insert === '[' &&
|
||||
view.state.doc.toString().slice(selection.from - '.json'.length, selection.to) === '.json'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
insert.length > 2 ||
|
||||
(insert.length === 2 && codePointSize(codePointAt(insert, 0)) === 1) ||
|
||||
from !== selection.from ||
|
||||
to !== selection.to
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const transaction = insertBracket(view.state, insert);
|
||||
|
||||
if (!transaction) return false;
|
||||
|
||||
view.dispatch(transaction);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const [_, bracketState] = closeBrackets() as readonly Extension[];
|
||||
|
||||
/**
|
||||
* CodeMirror plugin for code node editor:
|
||||
*
|
||||
* - prevent token autoclosing during autocompletion
|
||||
* - prevent square bracket autoclosing prior to `.json`
|
||||
*
|
||||
* Other than segments marked `customization`, this is a copy of the [original](https://github.com/codemirror/closebrackets/blob/0a56edfaf2c6d97bc5e88f272de0985b4f41e37a/src/closebrackets.ts#L79).
|
||||
*/
|
||||
export const codeInputHandler = () => [handler, bracketState];
|
||||
@@ -0,0 +1,96 @@
|
||||
import { closeBrackets, completionStatus, insertBracket } from '@codemirror/autocomplete';
|
||||
import { codePointAt, codePointSize, Extension } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
|
||||
const handler = EditorView.inputHandler.of((view, from, to, insert) => {
|
||||
if (view.composing || view.state.readOnly) return false;
|
||||
|
||||
// customization: do not autoclose tokens while autocompletion is active
|
||||
if (completionStatus(view.state) !== null) return false;
|
||||
|
||||
const selection = view.state.selection.main;
|
||||
|
||||
// customization: do not autoclose square brackets prior to `.json`
|
||||
if (
|
||||
insert === '[' &&
|
||||
view.state.doc.toString().slice(selection.from - '.json'.length, selection.to) === '.json'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
insert.length > 2 ||
|
||||
(insert.length === 2 && codePointSize(codePointAt(insert, 0)) === 1) ||
|
||||
from !== selection.from ||
|
||||
to !== selection.to
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const transaction = insertBracket(view.state, insert);
|
||||
|
||||
if (!transaction) return false;
|
||||
|
||||
view.dispatch(transaction);
|
||||
|
||||
// customization: inject whitespace and second brace for brace completion: {| } -> {{ | }}
|
||||
|
||||
const cursor = view.state.selection.main.head;
|
||||
|
||||
const isBraceCompletion =
|
||||
view.state.sliceDoc(cursor - 2, cursor) === '{{' &&
|
||||
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
||||
|
||||
if (isBraceCompletion) {
|
||||
view.dispatch({
|
||||
changes: { from: cursor, to: cursor + 2, insert: ' }' },
|
||||
selection: { anchor: cursor + 1 },
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// customization: inject whitespace for brace setup: empty -> {| }
|
||||
|
||||
const isBraceSetup =
|
||||
view.state.sliceDoc(cursor - 1, cursor) === '{' &&
|
||||
view.state.sliceDoc(cursor, cursor + 1) === '}';
|
||||
|
||||
if (isBraceSetup) {
|
||||
view.dispatch({ changes: { from: cursor, insert: ' ' } });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// customization: inject whitespace for brace completion from selection: {{abc|}} -> {{ abc| }}
|
||||
|
||||
const [range] = view.state.selection.ranges;
|
||||
|
||||
const isBraceCompletionFromSelection =
|
||||
view.state.sliceDoc(range.from - 2, range.from) === '{{' &&
|
||||
view.state.sliceDoc(range.to, range.to + 2) === '}}';
|
||||
|
||||
if (isBraceCompletionFromSelection) {
|
||||
view.dispatch(
|
||||
{ changes: { from: range.from, insert: ' ' } },
|
||||
{ changes: { from: range.to, insert: ' ' }, selection: { anchor: range.to, head: range.to } },
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const [_, bracketState] = closeBrackets() as readonly Extension[];
|
||||
|
||||
/**
|
||||
* CodeMirror plugin for (inline and modal) expression editor:
|
||||
*
|
||||
* - prevent token autoclosing during autocompletion (exception: `{`),
|
||||
* - prevent square bracket autoclosing prior to `.json`
|
||||
* - inject whitespace and braces for resolvables
|
||||
*
|
||||
* Other than segments marked `customization`, this is a copy of the [original](https://github.com/codemirror/closebrackets/blob/0a56edfaf2c6d97bc5e88f272de0985b4f41e37a/src/closebrackets.ts#L79).
|
||||
*/
|
||||
export const expressionInputHandler = () => [handler, bracketState];
|
||||
Reference in New Issue
Block a user