@adecore/editor-react 0.31.12 → 0.33.0

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 (137) hide show
  1. package/dist/AnchoredPopup.js +73 -19
  2. package/dist/AttributionCard.js +162 -4
  3. package/dist/BaselineStatus.js +62 -8
  4. package/dist/CallHierarchyPanel.js +977 -60
  5. package/dist/ChangeReview.js +76 -25
  6. package/dist/CodeAuthorsCard.js +314 -14
  7. package/dist/CompletionPopup.js +490 -83
  8. package/dist/DiffView.js +548 -181
  9. package/dist/EditorContextMenu.js +352 -34
  10. package/dist/EditorView.js +276 -99
  11. package/dist/FindReplace.js +525 -67
  12. package/dist/HoverCard.js +378 -38
  13. package/dist/HoverSections.js +367 -56
  14. package/dist/LanguagePopups.js +95 -34
  15. package/dist/Markdown.js +41 -6
  16. package/dist/PanelResizeHandle.js +199 -66
  17. package/dist/PathText.js +49 -7
  18. package/dist/PeekPanel.js +675 -72
  19. package/dist/PickPopup.js +304 -34
  20. package/dist/RenameCard.js +679 -85
  21. package/dist/RenderedDocs.js +329 -58
  22. package/dist/SignatureCard.js +91 -7
  23. package/dist/SplitDiffView.js +344 -254
  24. package/dist/SymbolPicker.js +440 -85
  25. package/dist/call-hierarchy-model.js +102 -68
  26. package/dist/call-hierarchy.js +458 -359
  27. package/dist/code-actions-model.js +88 -76
  28. package/dist/code-actions.js +372 -283
  29. package/dist/code-authors.js +64 -55
  30. package/dist/code-vision-model.js +134 -127
  31. package/dist/code-vision.js +224 -206
  32. package/dist/completion-call.js +94 -67
  33. package/dist/completion-model.js +334 -244
  34. package/dist/completion.js +840 -649
  35. package/dist/conflict-model.js +35 -29
  36. package/dist/context-menu-rows.js +42 -17
  37. package/dist/context-menu.js +64 -46
  38. package/dist/definition-link.js +88 -85
  39. package/dist/diagnostics-model.js +74 -55
  40. package/dist/diagnostics.js +121 -100
  41. package/dist/diff-expansion.js +38 -35
  42. package/dist/diff-overlays.js +144 -22
  43. package/dist/diff-syntax.js +65 -42
  44. package/dist/diff-wordmarks.js +26 -23
  45. package/dist/doc-comment-model.js +265 -216
  46. package/dist/editor-language.js +177 -152
  47. package/dist/error-message.js +2 -2
  48. package/dist/find-query.js +49 -36
  49. package/dist/folding.js +81 -62
  50. package/dist/format-on-type.js +86 -67
  51. package/dist/highlight-layers.js +19 -20
  52. package/dist/highlights.js +105 -83
  53. package/dist/history.js +44 -38
  54. package/dist/holder.js +18 -18
  55. package/dist/host-types.js +1 -1
  56. package/dist/hover-content.js +167 -129
  57. package/dist/hover.js +285 -245
  58. package/dist/index.js +10 -10
  59. package/dist/inlay-hints.js +369 -324
  60. package/dist/key-priority.js +34 -31
  61. package/dist/language-ids.js +45 -42
  62. package/dist/line-edits.js +74 -28
  63. package/dist/line-text.js +18 -3
  64. package/dist/locales/en.json +38 -38
  65. package/dist/locales/nl.json +41 -41
  66. package/dist/models.js +1 -1
  67. package/dist/navigation-history.js +40 -41
  68. package/dist/navigation.js +141 -123
  69. package/dist/panel-size.js +8 -8
  70. package/dist/patch-decorations.js +236 -160
  71. package/dist/patch-layout.js +331 -262
  72. package/dist/paths.js +3 -3
  73. package/dist/peek-model.js +86 -69
  74. package/dist/peek.js +254 -192
  75. package/dist/pick.js +164 -157
  76. package/dist/popup-focus.js +5 -5
  77. package/dist/popup-placement.js +36 -21
  78. package/dist/popups.js +13 -13
  79. package/dist/project-language.js +228 -211
  80. package/dist/project-problems.js +81 -69
  81. package/dist/proposal-model.js +163 -126
  82. package/dist/recent-choices.js +25 -25
  83. package/dist/refresher.js +44 -49
  84. package/dist/rename-model.js +113 -113
  85. package/dist/rename.js +321 -233
  86. package/dist/rendered-docs.d.ts +4 -2
  87. package/dist/rendered-docs.js +384 -318
  88. package/dist/rendering-context.js +5 -3
  89. package/dist/rendering.js +22 -4
  90. package/dist/review-group.js +42 -39
  91. package/dist/row-host.d.ts +4 -2
  92. package/dist/row-host.js +90 -78
  93. package/dist/selection-ranges.js +21 -17
  94. package/dist/semantic-delta.js +22 -19
  95. package/dist/semantic-model.js +86 -73
  96. package/dist/semantic-tokens.js +201 -162
  97. package/dist/shortcut-keys.js +16 -10
  98. package/dist/signature-model.js +34 -28
  99. package/dist/signature.js +177 -129
  100. package/dist/snippet-field-transforms.js +118 -106
  101. package/dist/snippet-indent.js +48 -43
  102. package/dist/snippet-range-order.js +11 -11
  103. package/dist/snippet-session.js +703 -667
  104. package/dist/snippet-transform-client.js +59 -59
  105. package/dist/snippet-transform-format.js +285 -263
  106. package/dist/snippet-transform-protocol.js +1 -1
  107. package/dist/snippet-transform-queue.js +163 -153
  108. package/dist/snippet-transform-worker.js +42 -35
  109. package/dist/snippet-variable-names.js +1 -36
  110. package/dist/snippet-variables.js +53 -63
  111. package/dist/snippet.js +477 -405
  112. package/dist/split-alignment.js +47 -35
  113. package/dist/split-scroll.js +42 -40
  114. package/dist/symbol-links.js +33 -25
  115. package/dist/symbol-picker-model.js +126 -116
  116. package/dist/symbol-picker.js +98 -59
  117. package/dist/symbols.js +117 -88
  118. package/dist/testing.js +248 -165
  119. package/dist/timers.js +35 -30
  120. package/dist/use-panel-body.js +49 -8
  121. package/dist/use-problem-counts.js +29 -15
  122. package/dist/view-state.js +54 -33
  123. package/dist/word-diff.js +18 -18
  124. package/dist/workspace-edit.js +300 -249
  125. package/package.json +6 -6
  126. package/src/CallHierarchyPanel.tsx +2 -2
  127. package/src/DiffView.tsx +3 -3
  128. package/src/FindReplace.tsx +2 -2
  129. package/src/LanguagePopups.tsx +2 -0
  130. package/src/PeekPanel.tsx +3 -3
  131. package/src/RenderedDocs.tsx +9 -10
  132. package/src/SymbolPicker.tsx +2 -2
  133. package/src/diff-overlays.tsx +6 -4
  134. package/src/locales/en.json +38 -38
  135. package/src/locales/nl.json +41 -41
  136. package/src/rendered-docs.ts +14 -3
  137. package/src/row-host.ts +14 -3
package/dist/peek.js CHANGED
@@ -9,11 +9,19 @@ const TOAST_ID = 'language-peek';
9
9
  /* The block as the panel draws it: a hatched band, the header, eight lines of code and a hatched band, until the editor has measured it. */
10
10
  export const PEEK_HEIGHT = 241;
11
11
  const KINDS = {
12
- references: { method: 'textDocument/references', unavailable: 'unavailable', none: 'none' },
13
- definitions: { method: 'textDocument/definition', unavailable: 'unavailableDefinition', none: 'noDefinition' }
12
+ references: {
13
+ method: 'textDocument/references',
14
+ unavailable: 'unavailable',
15
+ none: 'none'
16
+ },
17
+ definitions: {
18
+ method: 'textDocument/definition',
19
+ unavailable: 'unavailableDefinition',
20
+ none: 'noDefinition'
21
+ }
14
22
  };
15
23
  function placeKey(location) {
16
- return `${location.uri}\0${location.range.start.line}\0${location.range.start.character}`;
24
+ return `${location.uri}\0${location.range.start.line}\0${location.range.start.character}`;
17
25
  }
18
26
  /*
19
27
  * The references of the name at the caret, between the lines of the file under the line it is on. The
@@ -21,208 +29,262 @@ function placeKey(location) {
21
29
  * closes it too. A click on a place shows its code and a second one goes there.
22
30
  */
23
31
  export class PeekFeature {
24
- language;
25
- timers;
26
- kind = 'references';
27
- /* The whole declaration of each place of a definition peek, where the server gave it. */
28
- targets = new Map();
29
- texts = new Map();
30
- places = new Map();
31
- order = [];
32
- line = 0;
33
- token = 0;
34
- constructor(language, timers = realTimers) {
35
- this.language = language;
36
- this.timers = timers;
37
- const { editor } = language;
38
- const offs = [
39
- language.onKey((event) => {
40
- if (isShortcut(this.language.shortcuts.peekReferences, event)) {
41
- void this.open();
42
- return true;
43
- }
44
- if (isShortcut(this.language.shortcuts.peekDefinition, event)) {
45
- void this.openDefinition();
46
- return true;
47
- }
48
- return this.key(event);
49
- }, KEY_PRIORITY.peek),
50
- editor.onTextChange(() => this.close())
51
- ];
52
- language.onDispose(() => {
53
- for (const off of offs) {
54
- off();
55
- }
56
- this.close();
57
- });
32
+ language;
33
+ timers;
34
+ kind = 'references';
35
+ /* The whole declaration of each place of a definition peek, where the server gave it. */
36
+ targets = new Map();
37
+ texts = new Map();
38
+ places = new Map();
39
+ order = [];
40
+ line = 0;
41
+ token = 0;
42
+ constructor(language, timers = realTimers) {
43
+ this.language = language;
44
+ this.timers = timers;
45
+ const {
46
+ editor
47
+ } = language;
48
+ const offs = [language.onKey(event => {
49
+ if (isShortcut(this.language.shortcuts.peekReferences, event)) {
50
+ void this.open();
51
+ return true;
52
+ }
53
+ if (isShortcut(this.language.shortcuts.peekDefinition, event)) {
54
+ void this.openDefinition();
55
+ return true;
56
+ }
57
+ return this.key(event);
58
+ }, KEY_PRIORITY.peek), editor.onTextChange(() => this.close())];
59
+ language.onDispose(() => {
60
+ for (const off of offs) {
61
+ off();
62
+ }
63
+ this.close();
64
+ });
65
+ }
66
+ get isOpen() {
67
+ return this.language.popups.getState().peek !== null;
68
+ }
69
+ async open(position = this.language.editor.getCaret(), kind = 'references') {
70
+ const {
71
+ editor,
72
+ project,
73
+ uri
74
+ } = this.language;
75
+ const method = KINDS[kind].method;
76
+ if (!project.service.supports(method, uri)) {
77
+ this.tell(this.say(KINDS[kind].unavailable));
78
+ return;
58
79
  }
59
- get isOpen() {
60
- return this.language.popups.getState().peek !== null;
61
- }
62
- async open(position = this.language.editor.getCaret(), kind = 'references') {
63
- const { editor, project, uri } = this.language;
64
- const method = KINDS[kind].method;
65
- if (!project.service.supports(method, uri)) {
66
- this.tell(this.say(KINDS[kind].unavailable));
67
- return;
68
- }
69
- const token = ++this.token;
70
- let found;
71
- try {
72
- found = await this.fetch(kind, position);
73
- }
74
- catch (error) {
75
- if (!(error instanceof StaleResultError)) {
76
- this.tell(this.say('failed', { message: messageOf(error) }));
77
- }
78
- return;
79
- }
80
- if (token !== this.token) {
81
- return;
82
- }
83
- const { targets } = found;
84
- const seen = new Set();
85
- const unique = found.locations.filter((location) => {
86
- const key = placeKey(location);
87
- if (seen.has(key)) {
88
- return false;
89
- }
90
- seen.add(key);
91
- return true;
92
- });
93
- if (unique.length === 0) {
94
- this.tell(this.say(KINDS[kind].none));
95
- return;
96
- }
97
- const uris = [...new Set(unique.map((location) => location.uri))].slice(0, PEEK_READ_FILES);
98
- const texts = new Map();
99
- await Promise.all(uris.map(async (target) => {
100
- const text = await project.readText(target);
101
- if (text !== null) {
102
- texts.set(target, text);
103
- }
80
+ const token = ++this.token;
81
+ let found;
82
+ try {
83
+ found = await this.fetch(kind, position);
84
+ } catch (error) {
85
+ if (!(error instanceof StaleResultError)) {
86
+ this.tell(this.say('failed', {
87
+ message: messageOf(error)
104
88
  }));
105
- if (token !== this.token) {
106
- return;
107
- }
108
- this.texts = texts;
109
- this.kind = kind;
110
- this.targets = targets;
111
- const files = peekFilesOf(unique, uri, (target) => texts.get(target) ?? null);
112
- this.places = new Map(files.flatMap((file) => file.places.map((place) => [place.id, place.location])));
113
- this.order = files.flatMap((file) => file.places.map((place) => place.id));
114
- // The references open on the first place that is not the one the caret is on, which is what a person came to see.
115
- const first = kind === 'definitions'
116
- ? files[0].places[0]
117
- : (files.flatMap((file) => file.places).find((place) => !(place.location.uri === uri && place.line === position.line)) ?? files[0].places[0]);
118
- this.line = position.line;
119
- this.language.callHierarchy.close();
120
- this.language.popups.setState({ peek: { kind, container: null, files, active: first.id, collapsed: [], count: unique.length, preview: null } });
121
- this.select(first.id);
122
- // The editor draws a row once per id, so a peek opened over another needs an id of its own to get a container.
123
- editor.setWidgets([{ id: `peek-${token}`, line: this.line, height: PEEK_HEIGHT, render: (container) => this.mounted(container) }]);
124
- // The keys come through the editor, which a click on the hover's link or a menu command has taken the focus from.
125
- editor.focus();
89
+ }
90
+ return;
126
91
  }
127
- /* The definition of the name at the caret, as its source between the lines of the file. */
128
- openDefinition(position = this.language.editor.getCaret()) {
129
- return this.open(position, 'definitions');
92
+ if (token !== this.token) {
93
+ return;
130
94
  }
131
- async fetch(kind, position) {
132
- const { project, uri } = this.language;
133
- if (kind === 'references') {
134
- // Without the declaration, so the list holds what the usages count above a declaration counts.
135
- return { locations: (await project.service.references(uri, position, false)) ?? [], targets: new Map() };
136
- }
137
- const places = uniquePlaces(await project.service.definition(uri, position));
138
- const targets = new Map(places.flatMap(({ location, target }) => (target === null ? [] : [[placeKey(location), target]])));
139
- return { locations: places.map(({ location }) => location), targets };
95
+ const {
96
+ targets
97
+ } = found;
98
+ const seen = new Set();
99
+ const unique = found.locations.filter(location => {
100
+ const key = placeKey(location);
101
+ if (seen.has(key)) {
102
+ return false;
103
+ }
104
+ seen.add(key);
105
+ return true;
106
+ });
107
+ if (unique.length === 0) {
108
+ this.tell(this.say(KINDS[kind].none));
109
+ return;
140
110
  }
141
- close() {
142
- this.token++;
143
- if (this.language.popups.getState().peek === null) {
144
- return;
145
- }
146
- this.language.popups.setState({ peek: null });
147
- this.language.editor.setWidgets([]);
148
- this.language.editor.focus();
111
+ const uris = [...new Set(unique.map(location => location.uri))].slice(0, PEEK_READ_FILES);
112
+ const texts = new Map();
113
+ await Promise.all(uris.map(async target => {
114
+ const text = await project.readText(target);
115
+ if (text !== null) {
116
+ texts.set(target, text);
117
+ }
118
+ }));
119
+ if (token !== this.token) {
120
+ return;
149
121
  }
150
- /* Shows the code around a place. */
151
- select(id) {
152
- const view = this.language.popups.getState().peek;
153
- const location = this.places.get(id);
154
- if (view === null || location === undefined) {
155
- return;
156
- }
157
- const text = this.texts.get(location.uri);
158
- const line = location.range.start.line;
159
- const snippet = text === undefined
160
- ? null
161
- : this.kind === 'definitions'
162
- ? definitionSnippetOf(text, line, this.targets.get(placeKey(location)) ?? null, location.range)
163
- : snippetOf(text, line, location.range);
164
- this.language.popups.setState({ peek: { ...view, active: id, preview: snippet === null ? null : { ...snippet, uri: location.uri } } });
165
- }
166
- /* Folds the places of a file away from the list, or brings them back. */
167
- toggleFile(uri) {
168
- const view = this.language.popups.getState().peek;
169
- if (view !== null) {
170
- const collapsed = view.collapsed.includes(uri) ? view.collapsed.filter((other) => other !== uri) : [...view.collapsed, uri];
171
- this.language.popups.setState({ peek: { ...view, collapsed } });
172
- }
122
+ this.texts = texts;
123
+ this.kind = kind;
124
+ this.targets = targets;
125
+ const files = peekFilesOf(unique, uri, target => texts.get(target) ?? null);
126
+ this.places = new Map(files.flatMap(file => file.places.map(place => [place.id, place.location])));
127
+ this.order = files.flatMap(file => file.places.map(place => place.id));
128
+ // The references open on the first place that is not the one the caret is on, which is what a person came to see.
129
+ const first = kind === 'definitions' ? files[0].places[0] : files.flatMap(file => file.places).find(place => !(place.location.uri === uri && place.line === position.line)) ?? files[0].places[0];
130
+ this.line = position.line;
131
+ this.language.callHierarchy.close();
132
+ this.language.popups.setState({
133
+ peek: {
134
+ kind,
135
+ container: null,
136
+ files,
137
+ active: first.id,
138
+ collapsed: [],
139
+ count: unique.length,
140
+ preview: null
141
+ }
142
+ });
143
+ this.select(first.id);
144
+ // The editor draws a row once per id, so a peek opened over another needs an id of its own to get a container.
145
+ editor.setWidgets([{
146
+ id: `peek-${token}`,
147
+ line: this.line,
148
+ height: PEEK_HEIGHT,
149
+ render: container => this.mounted(container)
150
+ }]);
151
+ // The keys come through the editor, which a click on the hover's link or a menu command has taken the focus from.
152
+ editor.focus();
153
+ }
154
+ /* The definition of the name at the caret, as its source between the lines of the file. */
155
+ openDefinition(position = this.language.editor.getCaret()) {
156
+ return this.open(position, 'definitions');
157
+ }
158
+ async fetch(kind, position) {
159
+ const {
160
+ project,
161
+ uri
162
+ } = this.language;
163
+ if (kind === 'references') {
164
+ // Without the declaration, so the list holds what the usages count above a declaration counts.
165
+ return {
166
+ locations: (await project.service.references(uri, position, false)) ?? [],
167
+ targets: new Map()
168
+ };
173
169
  }
174
- /* Goes to a place and closes the peek. */
175
- go(id) {
176
- const location = this.places.get(id);
177
- if (location !== undefined) {
178
- this.close();
179
- this.language.goTo(location);
180
- }
170
+ const places = uniquePlaces(await project.service.definition(uri, position));
171
+ const targets = new Map(places.flatMap(({
172
+ location,
173
+ target
174
+ }) => target === null ? [] : [[placeKey(location), target]]));
175
+ return {
176
+ locations: places.map(({
177
+ location
178
+ }) => location),
179
+ targets
180
+ };
181
+ }
182
+ close() {
183
+ this.token++;
184
+ if (this.language.popups.getState().peek === null) {
185
+ return;
181
186
  }
182
- mounted(container) {
183
- const view = this.language.popups.getState().peek;
184
- if (view !== null && view.container !== container) {
185
- this.language.popups.setState({ peek: { ...view, container } });
186
- revealRow(this.timers, container);
187
- }
187
+ this.language.popups.setState({
188
+ peek: null
189
+ });
190
+ this.language.editor.setWidgets([]);
191
+ this.language.editor.focus();
192
+ }
193
+ /* Shows the code around a place. */
194
+ select(id) {
195
+ const view = this.language.popups.getState().peek;
196
+ const location = this.places.get(id);
197
+ if (view === null || location === undefined) {
198
+ return;
188
199
  }
189
- key(event) {
190
- const view = this.language.popups.getState().peek;
191
- if (view === null || event.metaKey || event.ctrlKey || event.altKey) {
192
- return false;
200
+ const text = this.texts.get(location.uri);
201
+ const line = location.range.start.line;
202
+ const snippet = text === undefined ? null : this.kind === 'definitions' ? definitionSnippetOf(text, line, this.targets.get(placeKey(location)) ?? null, location.range) : snippetOf(text, line, location.range);
203
+ this.language.popups.setState({
204
+ peek: {
205
+ ...view,
206
+ active: id,
207
+ preview: snippet === null ? null : {
208
+ ...snippet,
209
+ uri: location.uri
193
210
  }
194
- switch (event.key) {
195
- case 'ArrowDown':
196
- this.step(view, 1);
197
- return true;
198
- case 'ArrowUp':
199
- this.step(view, -1);
200
- return true;
201
- case 'Enter':
202
- this.go(view.active);
203
- return true;
204
- case 'Escape':
205
- this.close();
206
- return true;
207
- default:
208
- return false;
211
+ }
212
+ });
213
+ }
214
+ /* Folds the places of a file away from the list, or brings them back. */
215
+ toggleFile(uri) {
216
+ const view = this.language.popups.getState().peek;
217
+ if (view !== null) {
218
+ const collapsed = view.collapsed.includes(uri) ? view.collapsed.filter(other => other !== uri) : [...view.collapsed, uri];
219
+ this.language.popups.setState({
220
+ peek: {
221
+ ...view,
222
+ collapsed
209
223
  }
224
+ });
225
+ }
226
+ }
227
+ /* Goes to a place and closes the peek. */
228
+ go(id) {
229
+ const location = this.places.get(id);
230
+ if (location !== undefined) {
231
+ this.close();
232
+ this.language.goTo(location);
210
233
  }
211
- /* The next place in the list a person can see, which a folded file has none of. */
212
- step(view, direction) {
213
- const index = this.order.indexOf(view.active);
214
- for (let next = index + direction; next >= 0 && next < this.order.length; next += direction) {
215
- const id = this.order[next];
216
- if (!view.collapsed.includes(this.places.get(id).uri)) {
217
- this.select(id);
218
- return;
219
- }
234
+ }
235
+ mounted(container) {
236
+ const view = this.language.popups.getState().peek;
237
+ if (view !== null && view.container !== container) {
238
+ this.language.popups.setState({
239
+ peek: {
240
+ ...view,
241
+ container
220
242
  }
243
+ });
244
+ revealRow(this.timers, container);
221
245
  }
222
- tell(title) {
223
- this.language.project.host.notify?.({ id: TOAST_ID, kind: 'error', title });
246
+ }
247
+ key(event) {
248
+ const view = this.language.popups.getState().peek;
249
+ if (view === null || event.metaKey || event.ctrlKey || event.altKey) {
250
+ return false;
224
251
  }
225
- say(key, options) {
226
- return this.language.project.i18n.t(`editor:language.peek.${key}`, options);
252
+ switch (event.key) {
253
+ case 'ArrowDown':
254
+ this.step(view, 1);
255
+ return true;
256
+ case 'ArrowUp':
257
+ this.step(view, -1);
258
+ return true;
259
+ case 'Enter':
260
+ this.go(view.active);
261
+ return true;
262
+ case 'Escape':
263
+ this.close();
264
+ return true;
265
+ default:
266
+ return false;
227
267
  }
228
- }
268
+ }
269
+ /* The next place in the list a person can see, which a folded file has none of. */
270
+ step(view, direction) {
271
+ const index = this.order.indexOf(view.active);
272
+ for (let next = index + direction; next >= 0 && next < this.order.length; next += direction) {
273
+ const id = this.order[next];
274
+ if (!view.collapsed.includes(this.places.get(id).uri)) {
275
+ this.select(id);
276
+ return;
277
+ }
278
+ }
279
+ }
280
+ tell(title) {
281
+ this.language.project.host.notify?.({
282
+ id: TOAST_ID,
283
+ kind: 'error',
284
+ title
285
+ });
286
+ }
287
+ say(key, options) {
288
+ return this.language.project.i18n.t(`editor:language.peek.${key}`, options);
289
+ }
290
+ }