feat(editor): Add sections to autocomplete dropdown (#8720)

Co-authored-by: Giulio Andreini <andreini@netseven.it>
This commit is contained in:
Elias Meire
2024-03-07 17:01:05 +01:00
committed by GitHub
parent ed6dc86d60
commit 9b4618dd5e
35 changed files with 1308 additions and 468 deletions

View File

@@ -6,24 +6,19 @@ import {
highlightSpecialChars,
keymap,
lineNumbers,
type KeyBinding,
} from '@codemirror/view';
import { bracketMatching, foldGutter, indentOnInput } from '@codemirror/language';
import { acceptCompletion, selectedCompletion } from '@codemirror/autocomplete';
import {
history,
indentLess,
indentMore,
insertNewlineAndIndent,
toggleComment,
redo,
deleteCharBackward,
undo,
} from '@codemirror/commands';
import { history, toggleComment, deleteCharBackward } from '@codemirror/commands';
import { lintGutter } from '@codemirror/lint';
import { type Extension, Prec } from '@codemirror/state';
import { codeInputHandler } from '@/plugins/codemirror/inputHandlers/code.inputHandler';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
export const readOnlyEditorExtensions: readonly Extension[] = [
lineNumbers(),
@@ -31,42 +26,6 @@ export const readOnlyEditorExtensions: readonly Extension[] = [
highlightSpecialChars(),
];
export const tabKeyMap: KeyBinding[] = [
{
any(editor, event) {
if (event.key === 'Tab' || (event.key === 'Escape' && selectedCompletion(editor.state))) {
event.stopPropagation();
}
return false;
},
},
{
key: 'Tab',
run: (editor) => {
if (selectedCompletion(editor.state)) {
return acceptCompletion(editor);
}
return indentMore(editor);
},
},
{ key: 'Shift-Tab', run: indentLess },
];
export const enterKeyMap: KeyBinding[] = [
{
key: 'Enter',
run: (editor) => {
if (selectedCompletion(editor.state)) {
return acceptCompletion(editor);
}
return insertNewlineAndIndent(editor);
},
},
];
export const writableEditorExtensions: readonly Extension[] = [
history(),
lintGutter(),
@@ -79,11 +38,11 @@ export const writableEditorExtensions: readonly Extension[] = [
highlightActiveLineGutter(),
Prec.highest(
keymap.of([
...tabKeyMap,
...tabKeyMap(),
...enterKeyMap,
...autocompleteKeyMap,
...historyKeyMap,
{ key: 'Mod-/', run: toggleComment },
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
{ key: 'Backspace', run: deleteCharBackward, shift: deleteCharBackward },
]),
),

View File

@@ -37,6 +37,7 @@ export const completerExtension = defineComponent({
}
return autocompletion({
icons: false,
compareCompletions: (a: Completion, b: Completion) => {
if (/\.json$|id$|id['"]\]$/.test(a.label)) return 0;

View File

@@ -6,18 +6,24 @@
import { defineComponent } from 'vue';
import { EditorView, keymap } from '@codemirror/view';
import { EditorState, Prec } from '@codemirror/state';
import { history, redo, undo } from '@codemirror/commands';
import { history } from '@codemirror/commands';
import { expressionManager } from '@/mixins/expressionManager';
import { completionManager } from '@/mixins/completionManager';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { n8nLang } from '@/plugins/codemirror/n8nLang';
import { n8nAutocompletion, n8nLang } from '@/plugins/codemirror/n8nLang';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { inputTheme } from './theme';
import { forceParse } from '@/utils/forceParse';
import { acceptCompletion, autocompletion } from '@codemirror/autocomplete';
import { completionStatus } from '@codemirror/autocomplete';
import type { IVariableItemSelected } from '@/Interface';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
export default defineComponent({
name: 'ExpressionEditorModalInput',
@@ -44,13 +50,15 @@ export default defineComponent({
mounted() {
const extensions = [
inputTheme(),
autocompletion(),
Prec.highest(
keymap.of([
{ key: 'Tab', run: acceptCompletion },
...tabKeyMap(),
...historyKeyMap,
...enterKeyMap,
...autocompleteKeyMap,
{
any: (_: EditorView, event: KeyboardEvent) => {
if (event.key === 'Escape') {
any: (view, event) => {
if (event.key === 'Escape' && completionStatus(view.state) === null) {
event.stopPropagation();
this.$emit('close');
}
@@ -58,11 +66,10 @@ export default defineComponent({
return false;
},
},
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
]),
),
n8nLang(),
n8nAutocompletion(),
history(),
expressionInputHandler(),
EditorView.lineWrapping,
@@ -71,7 +78,11 @@ export default defineComponent({
EditorView.contentAttributes.of({ 'data-gramm': 'false' }), // disable grammarly
EditorView.domEventHandlers({ scroll: forceParse }),
EditorView.updateListener.of((viewUpdate) => {
if (!this.editor || !viewUpdate.docChanged) return;
if (!this.editor) return;
this.completionStatus = completionStatus(viewUpdate.view.state);
if (!viewUpdate.docChanged) return;
this.editorState = this.editor.state;

View File

@@ -6,8 +6,7 @@
</template>
<script lang="ts">
import { autocompletion } from '@codemirror/autocomplete';
import { history, redo, undo } from '@codemirror/commands';
import { history } from '@codemirror/commands';
import {
LanguageSupport,
bracketMatching,
@@ -39,11 +38,18 @@ import { expressionManager } from '@/mixins/expressionManager';
import { n8nCompletionSources } from '@/plugins/codemirror/completions/addCompletions';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
import type { Range, Section } from './types';
import { nonTakenRanges } from './utils';
import { isEqual } from 'lodash-es';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
import { completionStatus } from '@codemirror/autocomplete';
export default defineComponent({
name: 'HtmlEditor',
@@ -105,17 +111,12 @@ export default defineComponent({
return [
bracketMatching(),
autocompletion(),
n8nAutocompletion(),
this.disableExpressionCompletions ? html() : htmlWithCompletions(),
autoCloseTags,
expressionInputHandler(),
Prec.highest(
keymap.of([
...tabKeyMap,
...enterKeyMap,
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
]),
keymap.of([...tabKeyMap(), ...enterKeyMap, ...historyKeyMap, ...autocompleteKeyMap]),
),
indentOnInput(),
codeNodeEditorTheme({
@@ -135,7 +136,11 @@ export default defineComponent({
EditorView.editable.of(!this.isReadOnly),
EditorState.readOnly.of(this.isReadOnly),
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
if (!this.editor || !viewUpdate.docChanged) return;
if (!this.editor) return;
this.completionStatus = completionStatus(viewUpdate.view.state);
if (!viewUpdate.docChanged) return;
// Force segments value update by keeping track of editor state
this.editorState = this.editor.state;

View File

@@ -3,8 +3,7 @@
</template>
<script lang="ts">
import { acceptCompletion, autocompletion, completionStatus } from '@codemirror/autocomplete';
import { history, redo, undo } from '@codemirror/commands';
import { history } from '@codemirror/commands';
import { Compartment, EditorState, Prec } from '@codemirror/state';
import { EditorView, keymap } from '@codemirror/view';
import type { PropType } from 'vue';
@@ -13,11 +12,18 @@ import { defineComponent } from 'vue';
import { completionManager } from '@/mixins/completionManager';
import { expressionManager } from '@/mixins/expressionManager';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { n8nLang } from '@/plugins/codemirror/n8nLang';
import { n8nAutocompletion, n8nLang } from '@/plugins/codemirror/n8nLang';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { isEqual } from 'lodash-es';
import type { IDataObject } from 'n8n-workflow';
import { inputTheme } from './theme';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
import { completionStatus } from '@codemirror/autocomplete';
const editableConf = new Compartment();
@@ -81,25 +87,12 @@ export default defineComponent({
},
mounted() {
const extensions = [
n8nLang(),
inputTheme({ rows: this.rows }),
Prec.highest(
keymap.of([
{ key: 'Tab', run: acceptCompletion },
{
any(view: EditorView, event: KeyboardEvent) {
if (event.key === 'Escape' && completionStatus(view.state) !== null) {
event.stopPropagation();
}
return false;
},
},
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
]),
keymap.of([...tabKeyMap(true), ...enterKeyMap, ...autocompleteKeyMap, ...historyKeyMap]),
),
autocompletion(),
n8nLang(),
n8nAutocompletion(),
inputTheme({ rows: this.rows }),
history(),
expressionInputHandler(),
EditorView.lineWrapping,
@@ -111,7 +104,11 @@ export default defineComponent({
},
}),
EditorView.updateListener.of((viewUpdate) => {
if (!this.editor || !viewUpdate.docChanged) return;
if (!this.editor) return;
this.completionStatus = completionStatus(viewUpdate.view.state);
if (!viewUpdate.docChanged) return;
// Force segments value update by keeping track of editor state
this.editorState = this.editor.state;

View File

@@ -6,8 +6,7 @@
</template>
<script lang="ts">
import { autocompletion } from '@codemirror/autocomplete';
import { history, redo, toggleComment, undo } from '@codemirror/commands';
import { history, toggleComment } from '@codemirror/commands';
import { javascript } from '@codemirror/lang-javascript';
import { foldGutter, indentOnInput } from '@codemirror/language';
import { lintGutter } from '@codemirror/lint';
@@ -24,8 +23,14 @@ import {
} from '@codemirror/view';
import { defineComponent } from 'vue';
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
export default defineComponent({
name: 'JsEditor',
@@ -77,15 +82,15 @@ export default defineComponent({
history(),
Prec.highest(
keymap.of([
...tabKeyMap,
...tabKeyMap(),
...enterKeyMap,
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
...historyKeyMap,
...autocompleteKeyMap,
{ key: 'Mod-/', run: toggleComment },
]),
),
lintGutter(),
autocompletion(),
n8nAutocompletion(),
indentOnInput(),
highlightActiveLine(),
highlightActiveLineGutter(),

View File

@@ -6,8 +6,7 @@
</template>
<script lang="ts">
import { autocompletion } from '@codemirror/autocomplete';
import { history, redo, undo } from '@codemirror/commands';
import { history } from '@codemirror/commands';
import { json, jsonParseLinter } from '@codemirror/lang-json';
import { bracketMatching, foldGutter, indentOnInput } from '@codemirror/language';
import { linter as createLinter, lintGutter } from '@codemirror/lint';
@@ -24,8 +23,14 @@ import {
} from '@codemirror/view';
import { defineComponent } from 'vue';
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
export default defineComponent({
name: 'JsonEditor',
@@ -76,16 +81,11 @@ export default defineComponent({
extensions.push(
history(),
Prec.highest(
keymap.of([
...tabKeyMap,
...enterKeyMap,
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
]),
keymap.of([...tabKeyMap(), ...enterKeyMap, ...historyKeyMap, ...autocompleteKeyMap]),
),
createLinter(jsonParseLinter()),
lintGutter(),
autocompletion(),
n8nAutocompletion(),
indentOnInput(),
highlightActiveLine(),
highlightActiveLineGutter(),

View File

@@ -20,8 +20,8 @@ import { expressionManager } from '@/mixins/expressionManager';
import { n8nCompletionSources } from '@/plugins/codemirror/completions/addCompletions';
import { expressionInputHandler } from '@/plugins/codemirror/inputHandlers/expression.inputHandler';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { autocompletion, ifNotIn } from '@codemirror/autocomplete';
import { history, redo, toggleComment, undo } from '@codemirror/commands';
import { ifNotIn } from '@codemirror/autocomplete';
import { history, toggleComment } from '@codemirror/commands';
import { LanguageSupport, bracketMatching, foldGutter, indentOnInput } from '@codemirror/language';
import { type Extension, type Line, Prec } from '@codemirror/state';
import { EditorState } from '@codemirror/state';
@@ -47,9 +47,15 @@ import {
keywordCompletionSource,
} from '@n8n/codemirror-lang-sql';
import { defineComponent } from 'vue';
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
import { isEqual } from 'lodash-es';
import {
autocompleteKeyMap,
enterKeyMap,
historyKeyMap,
tabKeyMap,
} from '@/plugins/codemirror/keymap';
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
const SQL_DIALECTS = {
StandardSQL,
@@ -157,14 +163,14 @@ export default defineComponent({
history(),
Prec.highest(
keymap.of([
...tabKeyMap,
...tabKeyMap(),
...enterKeyMap,
{ key: 'Mod-z', run: undo },
{ key: 'Mod-Shift-z', run: redo },
...historyKeyMap,
...autocompleteKeyMap,
{ key: 'Mod-/', run: toggleComment },
]),
),
autocompletion(),
n8nAutocompletion(),
indentOnInput(),
highlightActiveLine(),
highlightActiveLineGutter(),