@neo4j-cypher/react-codemirror 2.0.0-next.7 → 2.0.0-next.8

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/CypherEditor.d.ts +32 -1
  3. package/dist/CypherEditor.js +45 -9
  4. package/dist/CypherEditor.js.map +1 -1
  5. package/dist/e2e_tests/autoCompletion.spec.js +0 -21
  6. package/dist/e2e_tests/autoCompletion.spec.js.map +1 -1
  7. package/dist/e2e_tests/configuration.spec.d.ts +1 -0
  8. package/dist/e2e_tests/configuration.spec.js +73 -0
  9. package/dist/e2e_tests/configuration.spec.js.map +1 -0
  10. package/dist/e2e_tests/e2eUtils.js +9 -1
  11. package/dist/e2e_tests/e2eUtils.js.map +1 -1
  12. package/dist/e2e_tests/sanityChecks.spec.js +0 -9
  13. package/dist/e2e_tests/sanityChecks.spec.js.map +1 -1
  14. package/dist/e2e_tests/signatureHelp.spec.js +16 -15
  15. package/dist/e2e_tests/signatureHelp.spec.js.map +1 -1
  16. package/dist/e2e_tests/snippets.spec.d.ts +1 -0
  17. package/dist/e2e_tests/snippets.spec.js +63 -0
  18. package/dist/e2e_tests/snippets.spec.js.map +1 -0
  19. package/dist/e2e_tests/syntaxValidation.spec.js +3 -3
  20. package/dist/e2e_tests/syntaxValidation.spec.js.map +1 -1
  21. package/dist/lang-cypher/createCypherTheme.js +26 -1
  22. package/dist/lang-cypher/createCypherTheme.js.map +1 -1
  23. package/dist/lang-cypher/signatureHelp.js +36 -20
  24. package/dist/lang-cypher/signatureHelp.js.map +1 -1
  25. package/dist/neo4jSetup.js +35 -1
  26. package/dist/neo4jSetup.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +2 -2
  29. package/src/CypherEditor.tsx +102 -10
  30. package/src/e2e_tests/autoCompletion.spec.tsx +0 -33
  31. package/src/e2e_tests/configuration.spec.tsx +97 -0
  32. package/src/e2e_tests/e2eUtils.ts +11 -1
  33. package/src/e2e_tests/sanityChecks.spec.tsx +0 -14
  34. package/src/e2e_tests/signatureHelp.spec.tsx +16 -19
  35. package/src/e2e_tests/snippets.spec.tsx +94 -0
  36. package/src/e2e_tests/syntaxValidation.spec.tsx +3 -3
  37. package/src/lang-cypher/createCypherTheme.ts +27 -1
  38. package/src/lang-cypher/signatureHelp.ts +57 -28
  39. package/src/neo4jSetup.tsx +51 -1
@@ -1,6 +1,7 @@
1
1
  import { EditorState, StateField } from '@codemirror/state';
2
2
  import { showTooltip, Tooltip } from '@codemirror/view';
3
3
  import { signatureHelp } from '@neo4j-cypher/language-support';
4
+ import { SignatureInformation } from 'vscode-languageserver-types';
4
5
  import { CypherConfig } from './langCypher';
5
6
 
6
7
  function getTriggerCharacter(query: string, caretPosition: number) {
@@ -16,6 +17,61 @@ function getTriggerCharacter(query: string, caretPosition: number) {
16
17
  return triggerCharacter;
17
18
  }
18
19
 
20
+ const createSignatureHelpElement =
21
+ ({
22
+ signature,
23
+ activeParameter,
24
+ }: {
25
+ signature: SignatureInformation;
26
+ activeParameter: number;
27
+ }) =>
28
+ () => {
29
+ const parameters = signature.parameters;
30
+ const doc = signature.documentation.toString();
31
+ const dom = document.createElement('div');
32
+ dom.className = 'cm-signature-help-panel';
33
+
34
+ const contents = document.createElement('div');
35
+ contents.className = 'cm-signature-help-panel-contents';
36
+ dom.appendChild(contents);
37
+
38
+ const signatureLabel = document.createElement('div');
39
+ signatureLabel.className = 'cm-signature-help-panel-name';
40
+ signatureLabel.appendChild(document.createTextNode(`${signature.label}(`));
41
+
42
+ parameters.forEach((param, index) => {
43
+ if (typeof param.documentation === 'string') {
44
+ const span = document.createElement('span');
45
+ span.appendChild(document.createTextNode(param.documentation));
46
+ if (index !== parameters.length - 1) {
47
+ span.appendChild(document.createTextNode(', '));
48
+ }
49
+
50
+ if (index === activeParameter) {
51
+ span.className = 'cm-signature-help-panel-current-argument';
52
+ }
53
+ signatureLabel.appendChild(span);
54
+ }
55
+ });
56
+
57
+ signatureLabel.appendChild(document.createTextNode(')'));
58
+
59
+ contents.appendChild(signatureLabel);
60
+
61
+ const separator = document.createElement('div');
62
+ separator.className = 'cm-signature-help-panel-separator';
63
+
64
+ contents.appendChild(separator);
65
+
66
+ const description = document.createElement('div');
67
+ description.className = 'cm-signature-help-panel-description';
68
+ description.appendChild(document.createTextNode(doc));
69
+
70
+ contents.appendChild(description);
71
+
72
+ return { dom };
73
+ };
74
+
19
75
  function getSignatureHelpTooltip(
20
76
  state: EditorState,
21
77
  config: CypherConfig,
@@ -44,17 +100,6 @@ function getSignatureHelpTooltip(
44
100
  signatures[activeSignature].documentation !== undefined
45
101
  ) {
46
102
  const signature = signatures[activeSignature];
47
- const parameters = signature.parameters;
48
- let doc = signature.documentation.toString();
49
-
50
- if (
51
- activeParameter >= 0 &&
52
- activeParameter <
53
- (signatures[activeSignature].parameters?.length ?? 0)
54
- ) {
55
- doc =
56
- parameters[activeParameter].documentation.toString() + '\n\n' + doc;
57
- }
58
103
 
59
104
  result = [
60
105
  {
@@ -62,23 +107,7 @@ function getSignatureHelpTooltip(
62
107
  above: true,
63
108
  strictSide: true,
64
109
  arrow: true,
65
- create: () => {
66
- const div = document.createElement('div');
67
- const methodName = document.createElement('div');
68
- const argPlusDescription = document.createElement('div');
69
- const separator = document.createElement('hr');
70
- const lineBreak = document.createElement('br');
71
-
72
- div.append(
73
- ...[methodName, separator, lineBreak, argPlusDescription],
74
- );
75
- div.className = 'cm-tooltip-signature-help';
76
-
77
- methodName.innerText = signature.label;
78
- argPlusDescription.innerText = doc;
79
-
80
- return { dom: div };
81
- },
110
+ create: createSignatureHelpElement({ signature, activeParameter }),
82
111
  },
83
112
  ];
84
113
  }
@@ -1,9 +1,14 @@
1
1
  import {
2
2
  acceptCompletion,
3
3
  autocompletion,
4
+ clearSnippet,
4
5
  closeBrackets,
5
6
  closeBracketsKeymap,
7
+ closeCompletion,
6
8
  completionKeymap,
9
+ nextSnippetField,
10
+ prevSnippetField,
11
+ snippetKeymap,
7
12
  } from '@codemirror/autocomplete';
8
13
  import {
9
14
  defaultKeymap,
@@ -22,11 +27,13 @@ import {
22
27
  import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
23
28
  import { EditorState, Extension, StateCommand } from '@codemirror/state';
24
29
  import {
30
+ Command,
25
31
  crosshairCursor,
26
32
  drawSelection,
27
33
  dropCursor,
28
34
  EditorView,
29
35
  highlightSpecialChars,
36
+ KeyBinding,
30
37
  keymap,
31
38
  rectangularSelection,
32
39
  } from '@codemirror/view';
@@ -55,7 +62,7 @@ const insertTab: StateCommand = (cmd) => {
55
62
  };
56
63
 
57
64
  export const basicNeo4jSetup = (): Extension[] => {
58
- const keymaps = [
65
+ const keymaps: KeyBinding[] = [
59
66
  closeBracketsKeymap,
60
67
  defaultKeymap,
61
68
  searchKeymap,
@@ -125,5 +132,48 @@ export const basicNeo4jSetup = (): Extension[] => {
125
132
 
126
133
  extensions.push(keymap.of(keymaps));
127
134
 
135
+ extensions.push(
136
+ snippetKeymap.of([
137
+ {
138
+ key: 'Tab',
139
+ run: acceptCompletionOrGotoNextSnippet,
140
+ shift: acceptCompletionOrGotoPrevSnippet,
141
+ },
142
+ { key: 'Escape', run: closeCompletionsOrClearSnippets },
143
+ ]),
144
+ );
145
+
128
146
  return extensions;
129
147
  };
148
+
149
+ // The logic to check if there's a completion open is surprisingly complex
150
+ // https://github.com/codemirror/autocomplete/blob/5ad2ebc861f2f61cdc943fc087a5bfb756a7d0fa/src/view.ts#L31
151
+ // For example it respects an interaction delay, so we can't just check if the completion is open
152
+ // instead we just run the acceptCompletion command which returns true if a completion was accepted
153
+ // in that case we know that we shouldn't move to the next snippet field
154
+ const acceptCompletionOrGotoNextSnippet: Command = (view: EditorView) => {
155
+ const didCompletion = acceptCompletion(view);
156
+ if (didCompletion) {
157
+ return true;
158
+ }
159
+
160
+ return nextSnippetField(view);
161
+ };
162
+
163
+ const acceptCompletionOrGotoPrevSnippet: Command = (view: EditorView) => {
164
+ const didCompletion = acceptCompletion(view);
165
+ if (didCompletion) {
166
+ return true;
167
+ }
168
+
169
+ return prevSnippetField(view);
170
+ };
171
+
172
+ const closeCompletionsOrClearSnippets: Command = (view: EditorView) => {
173
+ const closedCompletions = closeCompletion(view);
174
+ if (closedCompletions) {
175
+ return true;
176
+ }
177
+
178
+ return clearSnippet(view);
179
+ };