Skip to content

Commit

Permalink
feat(editor): Introduce proxy completions to expressions (#5075)
Browse files Browse the repository at this point in the history
* ⚡ 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
  • Loading branch information
ivov authored Jan 6, 2023
1 parent 77031a2 commit f4140d0
Show file tree
Hide file tree
Showing 30 changed files with 1,391 additions and 520 deletions.
4 changes: 2 additions & 2 deletions packages/editor-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"test:dev": "vitest"
},
"dependencies": {
"@codemirror/autocomplete": "^6.1.0",
"@codemirror/autocomplete": "^6.4.0",
"@codemirror/commands": "^6.1.0",
"@codemirror/lang-javascript": "^6.0.2",
"@codemirror/lang-javascript": "^6.1.2",
"@codemirror/language": "^6.2.1",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.1.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,16 @@ import {
lineNumbers,
} from '@codemirror/view';
import { bracketMatching, foldGutter, indentOnInput } from '@codemirror/language';
import { acceptCompletion, closeBrackets } from '@codemirror/autocomplete';
import { acceptCompletion } from '@codemirror/autocomplete';
import {
history,
indentWithTab,
insertNewlineAndIndent,
toggleComment,
} from '@codemirror/commands';
import { lintGutter } from '@codemirror/lint';
import type { Extension } from '@codemirror/state';

import { customInputHandler } from './inputHandler';

const [_, bracketState] = closeBrackets() as readonly Extension[];
import { codeInputHandler } from '@/plugins/codemirror/inputHandlers/code.inputHandler';

export const baseExtensions = [
lineNumbers(),
Expand All @@ -29,7 +26,7 @@ export const baseExtensions = [
history(),
foldGutter(),
lintGutter(),
[customInputHandler, bracketState],
codeInputHandler(),
dropCursor(),
indentOnInput(),
bracketMatching(),
Expand Down
4 changes: 2 additions & 2 deletions packages/editor-ui/src/components/CodeNodeEditor/completer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const completerExtension = mixins(
// luxon
this.todayCompletions,
this.nowCompletions,
this.dateTimeCompltions,
this.dateTimeCompletions,

// item index
this.inputCompletions,
Expand Down Expand Up @@ -174,7 +174,7 @@ export const completerExtension = mixins(

if (value === '$now') return this.nowCompletions(context, variable);
if (value === '$today') return this.todayCompletions(context, variable);
if (value === 'DateTime') return this.dateTimeCompltions(context, variable);
if (value === 'DateTime') return this.dateTimeCompletions(context, variable);

// item index

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Vue from 'vue';
import { isAllowedInDotNotation, escape, toVariableOption } from '../utils';
import { escape, toVariableOption } from '../utils';
import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import type { IDataObject, IPinData, IRunData } from 'n8n-workflow';
import type { CodeNodeEditorMixin } from '../types';
import { mapStores } from 'pinia';
import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
import { isAllowedInDotNotation } from '@/plugins/codemirror/completions/utils';

export const jsonFieldCompletions = (Vue as CodeNodeEditorMixin).extend({
computed: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const luxonCompletions = (Vue as CodeNodeEditorMixin).extend({
/**
* Complete `DateTime` with luxon `DateTime` static methods.
*/
dateTimeCompltions(context: CompletionContext, matcher = 'DateTime'): CompletionResult | null {
dateTimeCompletions(context: CompletionContext, matcher = 'DateTime'): CompletionResult | null {
const pattern = new RegExp(`${escape(matcher)}\..*`);

const preCursor = context.matchBefore(pattern);
Expand Down
42 changes: 0 additions & 42 deletions packages/editor-ui/src/components/CodeNodeEditor/inputHandler.ts

This file was deleted.

6 changes: 0 additions & 6 deletions packages/editor-ui/src/components/CodeNodeEditor/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ export function walk<T extends RangeNode>(
return found as T[];
}

export const isAllowedInDotNotation = (str: string) => {
const DOT_NOTATION_BANNED_CHARS = /^(\d)|[\\ `!@#$%^&*()_+\-=[\]{};':"\\|,.<>?~]/g;

return !DOT_NOTATION_BANNED_CHARS.test(str);
};

export const escape = (str: string) =>
str
.replace('$', '\\$')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import { history } from '@codemirror/commands';
import { workflowHelpers } from '@/mixins/workflowHelpers';
import { expressionManager } from '@/mixins/expressionManager';
import { doubleBraceHandler } from '@/plugins/codemirror/doubleBraceHandler';
import { n8nLanguageSupport } from '@/plugins/codemirror/n8nLanguageSupport';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { n8nLang } from '@/plugins/codemirror/n8nLang';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { inputTheme } from './theme';
import type { IVariableItemSelected } from '@/Interface';
import { forceParse } from '@/utils/forceParse';
import { autocompletion } from '@codemirror/autocomplete';
export default mixins(expressionManager, workflowHelpers).extend({
name: 'ExpressionEditorModalInput',
Expand All @@ -36,9 +37,10 @@ export default mixins(expressionManager, workflowHelpers).extend({
mounted() {
const extensions = [
inputTheme(),
n8nLanguageSupport(),
autocompletion(),
n8nLang(),
history(),
doubleBraceHandler(),
expressionInputHandler(),
EditorView.lineWrapping,
EditorState.readOnly.of(this.isReadOnly),
EditorView.domEventHandlers({ scroll: forceParse }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import { useNDVStore } from '@/stores/ndv';
import { workflowHelpers } from '@/mixins/workflowHelpers';
import { expressionManager } from '@/mixins/expressionManager';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { n8nLanguageSupport } from '@/plugins/codemirror/n8nLanguageSupport';
import { doubleBraceHandler } from '@/plugins/codemirror/doubleBraceHandler';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { inputTheme } from './theme';
import { autocompletion, ifIn } from '@codemirror/autocomplete';
import { n8nLang } from '@/plugins/codemirror/n8nLang';
export default mixins(expressionManager, workflowHelpers).extend({
name: 'InlineExpressionEditorInput',
Expand All @@ -39,35 +40,19 @@ export default mixins(expressionManager, workflowHelpers).extend({
},
watch: {
value(newValue) {
const payload: Record<string, unknown> = {
const isInternalChange = newValue === this.editor?.state.doc.toString();
if (isInternalChange) return;
// manual update on external change, e.g. from expression modal or mapping drop
this.editor?.dispatch({
changes: {
from: 0,
to: this.editor?.state.doc.length,
insert: newValue,
},
selection: { anchor: this.cursorPosition, head: this.cursorPosition },
};
/**
* If completion from selection, preserve selection.
*/
if (this.editor) {
const [range] = this.editor.state.selection.ranges;
const isBraceAutoinsertion =
this.editor.state.sliceDoc(range.from - 1, range.from) === '{' &&
this.editor.state.sliceDoc(range.to, range.to + 1) === '}';
if (isBraceAutoinsertion) {
payload.selection = { anchor: range.from, head: range.to };
}
}
try {
this.editor?.dispatch(payload);
} catch (_) {
// ignore out-of-range selection error on drop
}
});
},
ndvInputData() {
this.editor?.dispatch({
Expand All @@ -92,9 +77,10 @@ export default mixins(expressionManager, workflowHelpers).extend({
mounted() {
const extensions = [
inputTheme({ isSingleLine: this.isSingleLine }),
n8nLanguageSupport(),
autocompletion(),
n8nLang(),
history(),
doubleBraceHandler(),
expressionInputHandler(),
EditorView.lineWrapping,
EditorView.editable.of(!this.isReadOnly),
EditorView.domEventHandlers({
Expand Down
Loading

0 comments on commit f4140d0

Please sign in to comment.