@neo4j-cypher/react-codemirror 2.0.0-alpha.0 → 2.0.0-canary-e8a1279
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/LICENSE.md +201 -0
- package/README.md +27 -4
- package/dist/CypherEditor.d.ts +153 -0
- package/dist/CypherEditor.js +242 -0
- package/dist/CypherEditor.js.map +1 -0
- package/dist/e2e_tests/autoCompletion.spec.d.ts +1 -0
- package/dist/e2e_tests/autoCompletion.spec.js +133 -0
- package/dist/e2e_tests/autoCompletion.spec.js.map +1 -0
- package/dist/e2e_tests/configuration.spec.d.ts +1 -0
- package/dist/e2e_tests/configuration.spec.js +73 -0
- package/dist/e2e_tests/configuration.spec.js.map +1 -0
- package/dist/e2e_tests/e2eUtils.d.ts +12 -0
- package/dist/e2e_tests/e2eUtils.js +60 -0
- package/dist/e2e_tests/e2eUtils.js.map +1 -0
- package/dist/e2e_tests/extraKeybindings.spec.d.ts +1 -0
- package/dist/e2e_tests/extraKeybindings.spec.js +44 -0
- package/dist/e2e_tests/extraKeybindings.spec.js.map +1 -0
- package/dist/e2e_tests/historyNavigation.spec.d.ts +1 -0
- package/dist/e2e_tests/historyNavigation.spec.js +136 -0
- package/dist/e2e_tests/historyNavigation.spec.js.map +1 -0
- package/dist/e2e_tests/performanceTest.spec.d.ts +6 -0
- package/dist/e2e_tests/performanceTest.spec.js +96 -0
- package/dist/e2e_tests/performanceTest.spec.js.map +1 -0
- package/dist/e2e_tests/sanityChecks.spec.d.ts +1 -0
- package/dist/e2e_tests/sanityChecks.spec.js +56 -0
- package/dist/e2e_tests/sanityChecks.spec.js.map +1 -0
- package/dist/e2e_tests/signatureHelp.spec.d.ts +1 -0
- package/dist/e2e_tests/signatureHelp.spec.js +152 -0
- package/dist/e2e_tests/signatureHelp.spec.js.map +1 -0
- package/dist/e2e_tests/snippets.spec.d.ts +1 -0
- package/dist/e2e_tests/snippets.spec.js +63 -0
- package/dist/e2e_tests/snippets.spec.js.map +1 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.d.ts +1 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.js +91 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.js.map +1 -0
- package/dist/e2e_tests/syntaxValidation.spec.d.ts +1 -0
- package/dist/e2e_tests/syntaxValidation.spec.js +79 -0
- package/dist/e2e_tests/syntaxValidation.spec.js.map +1 -0
- package/dist/historyNavigation.d.ts +7 -0
- package/dist/historyNavigation.js +163 -0
- package/dist/historyNavigation.js.map +1 -0
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +62 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lang-cypher/autocomplete.d.ts +3 -0
- package/dist/lang-cypher/autocomplete.js +62 -0
- package/dist/lang-cypher/autocomplete.js.map +1 -0
- package/dist/lang-cypher/constants.d.ts +40 -0
- package/dist/lang-cypher/constants.js +65 -0
- package/dist/lang-cypher/constants.js.map +1 -0
- package/dist/lang-cypher/contants.test.d.ts +1 -0
- package/dist/lang-cypher/contants.test.js +102 -0
- package/dist/lang-cypher/contants.test.js.map +1 -0
- package/dist/lang-cypher/createCypherTheme.d.ts +26 -0
- package/dist/lang-cypher/createCypherTheme.js +172 -0
- package/dist/lang-cypher/createCypherTheme.js.map +1 -0
- package/dist/lang-cypher/langCypher.d.ts +9 -0
- package/dist/lang-cypher/langCypher.js +24 -0
- package/dist/lang-cypher/langCypher.js.map +1 -0
- package/dist/lang-cypher/lintWorker.d.ts +8 -0
- package/dist/lang-cypher/lintWorker.js +4 -0
- package/dist/lang-cypher/lintWorker.js.map +1 -0
- package/dist/lang-cypher/parser-adapter.d.ts +19 -0
- package/dist/lang-cypher/parser-adapter.js +113 -0
- package/dist/lang-cypher/parser-adapter.js.map +1 -0
- package/dist/lang-cypher/signatureHelp.d.ts +4 -0
- package/dist/lang-cypher/signatureHelp.js +93 -0
- package/dist/lang-cypher/signatureHelp.js.map +1 -0
- package/dist/lang-cypher/syntaxValidation.d.ts +5 -0
- package/dist/lang-cypher/syntaxValidation.js +71 -0
- package/dist/lang-cypher/syntaxValidation.js.map +1 -0
- package/dist/lang-cypher/themeIcons.d.ts +7 -0
- package/dist/lang-cypher/themeIcons.js +22 -0
- package/dist/lang-cypher/themeIcons.js.map +1 -0
- package/dist/ndlTokensCopy.d.ts +379 -0
- package/dist/ndlTokensCopy.js +380 -0
- package/dist/ndlTokensCopy.js.map +1 -0
- package/dist/ndlTokensCopy.test.d.ts +1 -0
- package/dist/ndlTokensCopy.test.js +11 -0
- package/dist/ndlTokensCopy.test.js.map +1 -0
- package/dist/neo4jSetup.d.ts +2 -0
- package/dist/neo4jSetup.js +120 -0
- package/dist/neo4jSetup.js.map +1 -0
- package/dist/themes.d.ts +11 -0
- package/dist/themes.js +114 -0
- package/dist/themes.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +46 -16
- package/src/CypherEditor.tsx +461 -0
- package/src/e2e_tests/autoCompletion.spec.tsx +236 -0
- package/src/e2e_tests/configuration.spec.tsx +97 -0
- package/src/e2e_tests/e2eUtils.ts +85 -0
- package/src/e2e_tests/extraKeybindings.spec.tsx +57 -0
- package/src/e2e_tests/historyNavigation.spec.tsx +196 -0
- package/src/e2e_tests/performanceTest.spec.tsx +158 -0
- package/src/e2e_tests/sanityChecks.spec.tsx +78 -0
- package/src/e2e_tests/signatureHelp.spec.tsx +309 -0
- package/src/e2e_tests/snippets.spec.tsx +94 -0
- package/src/e2e_tests/syntaxHighlighting.spec.tsx +198 -0
- package/src/e2e_tests/syntaxValidation.spec.tsx +156 -0
- package/src/historyNavigation.ts +191 -0
- package/{esm/index.mjs → src/icons.ts} +37 -1283
- package/src/index.ts +4 -0
- package/src/lang-cypher/autocomplete.ts +81 -0
- package/src/lang-cypher/constants.ts +84 -0
- package/src/lang-cypher/contants.test.ts +104 -0
- package/src/lang-cypher/createCypherTheme.ts +240 -0
- package/src/lang-cypher/langCypher.ts +41 -0
- package/src/lang-cypher/lintWorker.ts +14 -0
- package/src/lang-cypher/parser-adapter.ts +145 -0
- package/src/lang-cypher/signatureHelp.ts +131 -0
- package/src/lang-cypher/syntaxValidation.ts +99 -0
- package/src/lang-cypher/themeIcons.ts +27 -0
- package/src/ndlTokensCopy.test.ts +11 -0
- package/src/ndlTokensCopy.ts +379 -0
- package/src/neo4jSetup.tsx +179 -0
- package/src/themes.ts +132 -0
- package/dist/index.cjs +0 -1330
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
2
|
+
import { CypherEditor } from '../CypherEditor';
|
|
3
|
+
import { CypherEditorPage } from './e2eUtils';
|
|
4
|
+
|
|
5
|
+
test.use({ viewport: { width: 1000, height: 500 } });
|
|
6
|
+
test('Prop lint set to false disables syntax validation', async ({
|
|
7
|
+
page,
|
|
8
|
+
mount,
|
|
9
|
+
}) => {
|
|
10
|
+
const query = 'METCH (n) RETURN n';
|
|
11
|
+
|
|
12
|
+
await mount(<CypherEditor value={query} lint={false} />);
|
|
13
|
+
|
|
14
|
+
await expect(page.locator('.cm-lintRange-error').last()).not.toBeVisible({
|
|
15
|
+
timeout: 2000,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('Can turn linting back on', async ({ page, mount }) => {
|
|
20
|
+
const editorPage = new CypherEditorPage(page);
|
|
21
|
+
const query = 'METCH (n) RETURN n';
|
|
22
|
+
|
|
23
|
+
const component = await mount(<CypherEditor value={query} lint={false} />);
|
|
24
|
+
|
|
25
|
+
await expect(page.locator('.cm-lintRange-error').last()).not.toBeVisible({
|
|
26
|
+
timeout: 2000,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await component.update(<CypherEditor value={query} lint={true} />);
|
|
30
|
+
|
|
31
|
+
await editorPage.getEditor().fill('METCH (n) RETURN n');
|
|
32
|
+
|
|
33
|
+
await editorPage.checkErrorMessage(
|
|
34
|
+
'METCH',
|
|
35
|
+
'Unrecognized keyword. Did you mean MATCH?',
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Syntactic errors are surfaced', async ({ page, mount }) => {
|
|
40
|
+
const editorPage = new CypherEditorPage(page);
|
|
41
|
+
const query = 'METCH (n) RETURN n';
|
|
42
|
+
|
|
43
|
+
await mount(<CypherEditor value={query} />);
|
|
44
|
+
|
|
45
|
+
await editorPage.checkErrorMessage(
|
|
46
|
+
'METCH',
|
|
47
|
+
'Unrecognized keyword. Did you mean MATCH?',
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('Errors for undefined labels are surfaced', async ({ page, mount }) => {
|
|
52
|
+
const editorPage = new CypherEditorPage(page);
|
|
53
|
+
const query = 'MATCH (n: Person) RETURN n';
|
|
54
|
+
|
|
55
|
+
await mount(
|
|
56
|
+
<CypherEditor
|
|
57
|
+
value={query}
|
|
58
|
+
schema={{ labels: ['Movie'], relationshipTypes: [] }}
|
|
59
|
+
/>,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await editorPage.checkWarningMessage(
|
|
63
|
+
'Person',
|
|
64
|
+
"Label Person is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application",
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('Errors for multiline undefined labels are highlighted correctly', async ({
|
|
69
|
+
page,
|
|
70
|
+
mount,
|
|
71
|
+
}) => {
|
|
72
|
+
const editorPage = new CypherEditorPage(page);
|
|
73
|
+
const query = `MATCH (n:\`Foo
|
|
74
|
+
Bar\`) RETURN n`;
|
|
75
|
+
const expectedMsg = `Label \`Foo
|
|
76
|
+
Bar\` is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application`;
|
|
77
|
+
|
|
78
|
+
await mount(
|
|
79
|
+
<CypherEditor
|
|
80
|
+
value={query}
|
|
81
|
+
schema={{ labels: ['Movie'], relationshipTypes: [] }}
|
|
82
|
+
/>,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
await editorPage.checkWarningMessage('`Foo', expectedMsg);
|
|
86
|
+
await editorPage.checkWarningMessage('Bar`', expectedMsg);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('Semantic errors are surfaced when there are no syntactic errors', async ({
|
|
90
|
+
page,
|
|
91
|
+
mount,
|
|
92
|
+
}) => {
|
|
93
|
+
const editorPage = new CypherEditorPage(page);
|
|
94
|
+
const query = 'MATCH (n) RETURN m';
|
|
95
|
+
|
|
96
|
+
await mount(<CypherEditor value={query} />);
|
|
97
|
+
|
|
98
|
+
await editorPage.checkErrorMessage('m', 'Variable `m` not defined');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('Semantic errors are correctly accumulated', async ({ page, mount }) => {
|
|
102
|
+
const editorPage = new CypherEditorPage(page);
|
|
103
|
+
const query = 'CALL { MATCH (n) } IN TRANSACTIONS OF -1 ROWS';
|
|
104
|
+
|
|
105
|
+
await mount(<CypherEditor value={query} />);
|
|
106
|
+
|
|
107
|
+
await editorPage.checkErrorMessage(
|
|
108
|
+
'MATCH (n)',
|
|
109
|
+
'Query cannot conclude with MATCH (must be a RETURN clause, a FINISH clause, an update clause, a unit subquery call, or a procedure call with no YIELD).',
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
await editorPage.checkErrorMessage(
|
|
113
|
+
'-1',
|
|
114
|
+
"Invalid input. '-1' is not a valid value. Must be a positive integer",
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('Multiline errors are correctly placed', async ({ page, mount }) => {
|
|
119
|
+
const editorPage = new CypherEditorPage(page);
|
|
120
|
+
const query = `CALL {
|
|
121
|
+
MATCH (n)
|
|
122
|
+
} IN TRANSACTIONS
|
|
123
|
+
OF -1 ROWS`;
|
|
124
|
+
|
|
125
|
+
await mount(<CypherEditor value={query} />);
|
|
126
|
+
|
|
127
|
+
await editorPage.checkErrorMessage(
|
|
128
|
+
'MATCH (n)',
|
|
129
|
+
'Query cannot conclude with MATCH (must be a RETURN clause, a FINISH clause, an update clause, a unit subquery call, or a procedure call with no YIELD)',
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
await editorPage.checkErrorMessage(
|
|
133
|
+
'-1',
|
|
134
|
+
"Invalid input. '-1' is not a valid value. Must be a positive integer",
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('Validation errors are correctly overlapped', async ({ page, mount }) => {
|
|
139
|
+
const editorPage = new CypherEditorPage(page);
|
|
140
|
+
const query = `CALL { MATCH (n)
|
|
141
|
+
RETURN n
|
|
142
|
+
} IN TRANSACTIONS
|
|
143
|
+
OF -1 ROWS`;
|
|
144
|
+
|
|
145
|
+
await mount(<CypherEditor value={query} />);
|
|
146
|
+
|
|
147
|
+
await editorPage.checkErrorMessage(
|
|
148
|
+
'-1',
|
|
149
|
+
'Query cannot conclude with CALL (must be a RETURN clause, a FINISH clause, an update clause, a unit subquery call, or a procedure call with no YIELD).',
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await editorPage.checkErrorMessage(
|
|
153
|
+
'-1',
|
|
154
|
+
"Invalid input. '-1' is not a valid value. Must be a positive integer",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Extension, StateEffect } from '@codemirror/state';
|
|
2
|
+
import { EditorView, keymap } from '@codemirror/view';
|
|
3
|
+
|
|
4
|
+
import { StateField } from '@codemirror/state';
|
|
5
|
+
|
|
6
|
+
type HistoryState = {
|
|
7
|
+
history: string[];
|
|
8
|
+
index: number;
|
|
9
|
+
draft: string;
|
|
10
|
+
documentUpdate: string | null;
|
|
11
|
+
};
|
|
12
|
+
const DRAFT_ENTRY_INDEX = -1;
|
|
13
|
+
const historyInitialState = {
|
|
14
|
+
history: [],
|
|
15
|
+
index: DRAFT_ENTRY_INDEX,
|
|
16
|
+
documentUpdate: null,
|
|
17
|
+
draft: '',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const historyState = StateField.define<HistoryState>({
|
|
21
|
+
create() {
|
|
22
|
+
return historyInitialState;
|
|
23
|
+
},
|
|
24
|
+
toJSON(value) {
|
|
25
|
+
return JSON.stringify(value);
|
|
26
|
+
},
|
|
27
|
+
update(value, transaction) {
|
|
28
|
+
for (const effect of transaction.effects) {
|
|
29
|
+
if (effect.is(moveInHistory)) {
|
|
30
|
+
if (value.history.length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
...value,
|
|
33
|
+
documentUpdate: null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const currentHistoryIndex = value.index;
|
|
38
|
+
if (effect.value === 'BACK') {
|
|
39
|
+
const newHistoryIndex = currentHistoryIndex + 1;
|
|
40
|
+
|
|
41
|
+
if (newHistoryIndex === value.history.length) {
|
|
42
|
+
return {
|
|
43
|
+
...value,
|
|
44
|
+
documentUpdate: null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let draft = value.draft;
|
|
49
|
+
if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
|
|
50
|
+
draft = transaction.state.doc.toString();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...value,
|
|
55
|
+
draft,
|
|
56
|
+
index: newHistoryIndex,
|
|
57
|
+
documentUpdate: value.history[newHistoryIndex],
|
|
58
|
+
};
|
|
59
|
+
} else if (effect.value === 'FORWARDS') {
|
|
60
|
+
const newHistoryIndex = currentHistoryIndex - 1;
|
|
61
|
+
|
|
62
|
+
if (currentHistoryIndex === DRAFT_ENTRY_INDEX) {
|
|
63
|
+
return { ...value, documentUpdate: null };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (newHistoryIndex === DRAFT_ENTRY_INDEX) {
|
|
67
|
+
return {
|
|
68
|
+
...value,
|
|
69
|
+
index: newHistoryIndex,
|
|
70
|
+
documentUpdate: value.draft,
|
|
71
|
+
};
|
|
72
|
+
} else {
|
|
73
|
+
return {
|
|
74
|
+
...value,
|
|
75
|
+
index: newHistoryIndex,
|
|
76
|
+
documentUpdate: value.history[newHistoryIndex],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else if (effect.is(replaceHistory)) {
|
|
81
|
+
return {
|
|
82
|
+
...value,
|
|
83
|
+
index: DRAFT_ENTRY_INDEX,
|
|
84
|
+
history: effect.value,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
type HistoryNavigation = 'BACK' | 'FORWARDS';
|
|
93
|
+
const moveInHistory = StateEffect.define<HistoryNavigation>();
|
|
94
|
+
export const replaceHistory = StateEffect.define<string[]>();
|
|
95
|
+
|
|
96
|
+
function navigateHistory(view: EditorView, direction: HistoryNavigation) {
|
|
97
|
+
view.dispatch(
|
|
98
|
+
view.state.update({
|
|
99
|
+
effects: moveInHistory.of(direction),
|
|
100
|
+
selection: { anchor: view.state.doc.length },
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const updatedHistory = view.state.field<HistoryState>(historyState, false);
|
|
105
|
+
if (updatedHistory.documentUpdate !== null) {
|
|
106
|
+
view.dispatch(
|
|
107
|
+
view.state.update({
|
|
108
|
+
changes: {
|
|
109
|
+
from: 0,
|
|
110
|
+
to: view.state.doc.length,
|
|
111
|
+
insert: updatedHistory.documentUpdate,
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type ReplProps = {
|
|
119
|
+
history?: string[];
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const replMode = ({ history }: ReplProps): Extension[] => {
|
|
123
|
+
return [
|
|
124
|
+
historyState.init(() => ({
|
|
125
|
+
...historyInitialState,
|
|
126
|
+
history,
|
|
127
|
+
})),
|
|
128
|
+
keymap.of([
|
|
129
|
+
{
|
|
130
|
+
key: 'ArrowUp',
|
|
131
|
+
preventDefault: true,
|
|
132
|
+
run: (view) => {
|
|
133
|
+
// If text is selected or cursor is not at top of document, do nothing
|
|
134
|
+
const { empty, head } = view.state.selection.main;
|
|
135
|
+
if (!empty || head !== 0) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
navigateHistory(view, 'BACK');
|
|
140
|
+
return true;
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
mac: 'Cmd-ArrowUp',
|
|
145
|
+
win: 'Ctrl-ArrowUp',
|
|
146
|
+
linux: 'Ctrl-ArrowUp',
|
|
147
|
+
preventDefault: true,
|
|
148
|
+
run: (view) => {
|
|
149
|
+
// If text is selected or cursor is not at top of document, do nothing
|
|
150
|
+
const { empty, head } = view.state.selection.main;
|
|
151
|
+
if (!empty || head !== 0) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
navigateHistory(view, 'BACK');
|
|
156
|
+
return true;
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
key: 'ArrowDown',
|
|
161
|
+
preventDefault: true,
|
|
162
|
+
run: (view) => {
|
|
163
|
+
const { empty, head } = view.state.selection.main;
|
|
164
|
+
// If text is selected or cursor is not at end of document, do nothing
|
|
165
|
+
if (!empty || head !== view.state.doc.length) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
navigateHistory(view, 'FORWARDS');
|
|
169
|
+
|
|
170
|
+
return true;
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
mac: 'Cmd-ArrowDown',
|
|
175
|
+
win: 'Ctrl-ArrowDown',
|
|
176
|
+
linux: 'Ctrl-ArrowDown',
|
|
177
|
+
preventDefault: true,
|
|
178
|
+
run: (view) => {
|
|
179
|
+
const { empty, head } = view.state.selection.main;
|
|
180
|
+
// If text is selected or cursor is not at end of document, do nothing
|
|
181
|
+
if (!empty || head !== view.state.doc.length) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
navigateHistory(view, 'FORWARDS');
|
|
185
|
+
|
|
186
|
+
return true;
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
]),
|
|
190
|
+
];
|
|
191
|
+
};
|