@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
@@ -17,223 +17,241 @@ export const MAX_LINES = 20_000;
17
17
  * stays on its row until the new one is in.
18
18
  */
19
19
  export class CodeVisionFeature {
20
- language;
21
- timers;
22
- settings = { usages: false, authors: false };
23
- declarations = [];
24
- /* What the declarations were read from, so a count never outlives the text it was asked for. */
25
- epoch = 0;
26
- edited = false;
27
- counts = new Map();
28
- queue = [];
29
- /* Scrolling changes the pending queue but keeps requests already in flight. */
30
- running = new Map();
31
- /* Declarations a server could not count for this text, which are not asked again until it says it can. */
32
- failed = new Set();
33
- blame = null;
34
- /* The text the declarations were read from, which the lines of their authors are counted in. */
35
- lines = [];
36
- mapped = null;
37
- authorships = new Map();
38
- scrollTimer;
39
- publishing = false;
40
- disposed = false;
41
- constructor(language, onSymbols, timers = realTimers) {
42
- this.language = language;
43
- this.timers = timers;
44
- const { editor } = language;
45
- const offs = [
46
- onSymbols((result) => this.read(result)),
47
- editor.onTextChange(() => {
48
- this.edited = true;
49
- this.closeAuthors();
50
- }),
51
- editor.onViewChange(() => {
52
- this.timers.clear(this.scrollTimer);
53
- this.scrollTimer = this.timers.set(() => this.plan(), SCROLL_PAUSE_MS);
54
- })
55
- ];
56
- const providers = language.onProvidersChanged(() => {
57
- this.failed.clear();
58
- this.publish();
59
- this.plan();
60
- });
61
- language.onDispose(() => {
62
- this.disposed = true;
63
- for (const off of offs) {
64
- off();
65
- }
66
- providers();
67
- this.timers.clear(this.scrollTimer);
68
- for (const controller of this.running.values()) {
69
- controller.abort();
70
- }
71
- this.closeAuthors();
72
- editor.setCodeVision([]);
73
- });
20
+ language;
21
+ timers;
22
+ settings = {
23
+ usages: false,
24
+ authors: false
25
+ };
26
+ declarations = [];
27
+ /* What the declarations were read from, so a count never outlives the text it was asked for. */
28
+ epoch = 0;
29
+ edited = false;
30
+ counts = new Map();
31
+ queue = [];
32
+ /* Scrolling changes the pending queue but keeps requests already in flight. */
33
+ running = new Map();
34
+ /* Declarations a server could not count for this text, which are not asked again until it says it can. */
35
+ failed = new Set();
36
+ blame = null;
37
+ /* The text the declarations were read from, which the lines of their authors are counted in. */
38
+ lines = [];
39
+ mapped = null;
40
+ authorships = new Map();
41
+ scrollTimer;
42
+ publishing = false;
43
+ disposed = false;
44
+ constructor(language, onSymbols, timers = realTimers) {
45
+ this.language = language;
46
+ this.timers = timers;
47
+ const {
48
+ editor
49
+ } = language;
50
+ const offs = [onSymbols(result => this.read(result)), editor.onTextChange(() => {
51
+ this.edited = true;
52
+ this.closeAuthors();
53
+ }), editor.onViewChange(() => {
54
+ this.timers.clear(this.scrollTimer);
55
+ this.scrollTimer = this.timers.set(() => this.plan(), SCROLL_PAUSE_MS);
56
+ })];
57
+ const providers = language.onProvidersChanged(() => {
58
+ this.failed.clear();
59
+ this.publish();
60
+ this.plan();
61
+ });
62
+ language.onDispose(() => {
63
+ this.disposed = true;
64
+ for (const off of offs) {
65
+ off();
66
+ }
67
+ providers();
68
+ this.timers.clear(this.scrollTimer);
69
+ for (const controller of this.running.values()) {
70
+ controller.abort();
71
+ }
72
+ this.closeAuthors();
73
+ editor.setCodeVision([]);
74
+ });
75
+ }
76
+ /* Which rows to draw, from the settings of the client. */
77
+ configure(settings) {
78
+ if (settings.usages === this.settings.usages && settings.authors === this.settings.authors) {
79
+ return;
74
80
  }
75
- /* Which rows to draw, from the settings of the client. */
76
- configure(settings) {
77
- if (settings.usages === this.settings.usages && settings.authors === this.settings.authors) {
78
- return;
79
- }
80
- this.settings = settings;
81
- this.publish();
82
- this.plan();
81
+ this.settings = settings;
82
+ this.publish();
83
+ this.plan();
84
+ }
85
+ /* What git says about the file, from the client that asked it. */
86
+ setBlame(blame) {
87
+ this.blame = blame;
88
+ this.mapped = null;
89
+ this.authorships.clear();
90
+ this.publish();
91
+ }
92
+ read(result) {
93
+ const {
94
+ editor,
95
+ languageId
96
+ } = this.language;
97
+ const lines = splitLines(editor.getText());
98
+ this.lines = lines;
99
+ this.mapped = null;
100
+ this.authorships.clear();
101
+ this.edited = false;
102
+ this.declarations = lines.length > MAX_LINES ? [] : declarationsOf(result, {
103
+ lineCount: lines.length,
104
+ lineAt: line => lines[line] ?? '',
105
+ languageId
106
+ });
107
+ this.epoch++;
108
+ this.failed.clear();
109
+ this.publish();
110
+ this.plan();
111
+ }
112
+ get canCount() {
113
+ return this.settings.usages && this.language.project.service.supports(REFERENCES, this.language.uri);
114
+ }
115
+ /* Queues the declarations in view whose count is not from the current text, nearest the top of the view first. */
116
+ plan() {
117
+ if (this.disposed || this.edited || !this.canCount) {
118
+ return;
83
119
  }
84
- /* What git says about the file, from the client that asked it. */
85
- setBlame(blame) {
86
- this.blame = blame;
87
- this.mapped = null;
88
- this.authorships.clear();
89
- this.publish();
120
+ const view = this.language.editor.getVisibleRange();
121
+ const first = view.start.line - MARGIN_LINES;
122
+ const last = view.end.line + MARGIN_LINES;
123
+ this.queue = this.declarations.filter(declaration => declaration.usages && declaration.line >= first && declaration.line <= last && this.counts.get(declaration.id)?.epoch !== this.epoch && !this.running.has(declaration.id) && !this.failed.has(declaration.id)).sort((left, right) => Math.abs(left.line - view.start.line) - Math.abs(right.line - view.start.line));
124
+ while (this.running.size < MAX_PARALLEL && this.queue.length > 0) {
125
+ void this.count(this.queue.shift());
90
126
  }
91
- read(result) {
92
- const { editor, languageId } = this.language;
93
- const lines = splitLines(editor.getText());
94
- this.lines = lines;
95
- this.mapped = null;
96
- this.authorships.clear();
97
- this.edited = false;
98
- this.declarations =
99
- lines.length > MAX_LINES ? [] : declarationsOf(result, { lineCount: lines.length, lineAt: (line) => lines[line] ?? '', languageId });
100
- this.epoch++;
101
- this.failed.clear();
127
+ }
128
+ async count(declaration) {
129
+ const {
130
+ project,
131
+ uri
132
+ } = this.language;
133
+ const controller = new AbortController();
134
+ this.running.set(declaration.id, controller);
135
+ const epoch = this.epoch;
136
+ try {
137
+ const locations = await project.service.references(uri, declaration.position, false, {
138
+ signal: controller.signal,
139
+ parallel: true
140
+ });
141
+ if (!this.disposed && epoch === this.epoch) {
142
+ this.counts.set(declaration.id, {
143
+ count: distinctPlaces(locations ?? []),
144
+ epoch
145
+ });
102
146
  this.publish();
103
- this.plan();
104
- }
105
- get canCount() {
106
- return this.settings.usages && this.language.project.service.supports(REFERENCES, this.language.uri);
147
+ }
148
+ } catch {
149
+ // A text that moved on is counted again from its own symbols; for a server that is not up the declaration waits for it to say so.
150
+ if (epoch === this.epoch) {
151
+ this.failed.add(declaration.id);
152
+ }
153
+ } finally {
154
+ this.running.delete(declaration.id);
155
+ this.plan();
107
156
  }
108
- /* Queues the declarations in view whose count is not from the current text, nearest the top of the view first. */
109
- plan() {
110
- if (this.disposed || this.edited || !this.canCount) {
111
- return;
112
- }
113
- const view = this.language.editor.getVisibleRange();
114
- const first = view.start.line - MARGIN_LINES;
115
- const last = view.end.line + MARGIN_LINES;
116
- this.queue = this.declarations
117
- .filter((declaration) => declaration.usages &&
118
- declaration.line >= first &&
119
- declaration.line <= last &&
120
- this.counts.get(declaration.id)?.epoch !== this.epoch &&
121
- !this.running.has(declaration.id) &&
122
- !this.failed.has(declaration.id))
123
- .sort((left, right) => Math.abs(left.line - view.start.line) - Math.abs(right.line - view.start.line));
124
- while (this.running.size < MAX_PARALLEL && this.queue.length > 0) {
125
- void this.count(this.queue.shift());
126
- }
157
+ }
158
+ /* Said once for every change that lands in the same turn, since each is a pass over the rows of the layout. */
159
+ publish() {
160
+ if (this.publishing) {
161
+ return;
127
162
  }
128
- async count(declaration) {
129
- const { project, uri } = this.language;
130
- const controller = new AbortController();
131
- this.running.set(declaration.id, controller);
132
- const epoch = this.epoch;
133
- try {
134
- const locations = await project.service.references(uri, declaration.position, false, { signal: controller.signal, parallel: true });
135
- if (!this.disposed && epoch === this.epoch) {
136
- this.counts.set(declaration.id, { count: distinctPlaces(locations ?? []), epoch });
137
- this.publish();
138
- }
139
- }
140
- catch {
141
- // A text that moved on is counted again from its own symbols; for a server that is not up the declaration waits for it to say so.
142
- if (epoch === this.epoch) {
143
- this.failed.add(declaration.id);
144
- }
145
- }
146
- finally {
147
- this.running.delete(declaration.id);
148
- this.plan();
149
- }
150
- }
151
- /* Said once for every change that lands in the same turn, since each is a pass over the rows of the layout. */
152
- publish() {
153
- if (this.publishing) {
154
- return;
155
- }
156
- this.publishing = true;
157
- queueMicrotask(() => {
158
- this.publishing = false;
159
- if (!this.disposed) {
160
- this.language.editor.setCodeVision(this.rows());
161
- }
163
+ this.publishing = true;
164
+ queueMicrotask(() => {
165
+ this.publishing = false;
166
+ if (!this.disposed) {
167
+ this.language.editor.setCodeVision(this.rows());
168
+ }
169
+ });
170
+ }
171
+ rows() {
172
+ const rows = [];
173
+ const taken = new Set();
174
+ const counted = this.canCount;
175
+ const withAuthors = this.settings.authors && this.blame !== null;
176
+ const commits = this.blame?.kind === 'ready' ? this.blame.blame.commits : [];
177
+ const mapped = this.blame?.kind === 'ready' && this.settings.authors ? this.mapOfBlame(this.blame) : null;
178
+ for (const declaration of this.declarations) {
179
+ const reserved = counted && declaration.usages || withAuthors && declaration.authors;
180
+ if (!reserved || taken.has(declaration.line)) {
181
+ continue;
182
+ }
183
+ taken.add(declaration.line);
184
+ const entries = [];
185
+ const known = this.counts.get(declaration.id);
186
+ if (counted && declaration.usages && known !== undefined) {
187
+ entries.push({
188
+ id: 'usages',
189
+ text: usagesText(known.count, this.language.project.i18n),
190
+ activate: () => void this.language.peek.open(declaration.position)
162
191
  });
192
+ }
193
+ if (mapped !== null && declaration.authors) {
194
+ const authorship = this.authorshipOf(declaration, commits, mapped);
195
+ entries.push({
196
+ id: 'authors',
197
+ text: authorsText(authorship, this.language.project.i18n),
198
+ ...(authorship.authors.length > 0 ? {
199
+ icon: authorship.authors.length > 1 ? 'users' : 'user'
200
+ } : {}),
201
+ activate: anchor => this.showAuthors(declaration, authorship, anchor)
202
+ });
203
+ }
204
+ rows.push({
205
+ id: declaration.id,
206
+ line: declaration.line,
207
+ entries
208
+ });
163
209
  }
164
- rows() {
165
- const rows = [];
166
- const taken = new Set();
167
- const counted = this.canCount;
168
- const withAuthors = this.settings.authors && this.blame !== null;
169
- const commits = this.blame?.kind === 'ready' ? this.blame.blame.commits : [];
170
- const mapped = this.blame?.kind === 'ready' && this.settings.authors ? this.mapOfBlame(this.blame) : null;
171
- for (const declaration of this.declarations) {
172
- const reserved = (counted && declaration.usages) || (withAuthors && declaration.authors);
173
- if (!reserved || taken.has(declaration.line)) {
174
- continue;
175
- }
176
- taken.add(declaration.line);
177
- const entries = [];
178
- const known = this.counts.get(declaration.id);
179
- if (counted && declaration.usages && known !== undefined) {
180
- entries.push({
181
- id: 'usages',
182
- text: usagesText(known.count, this.language.project.i18n),
183
- activate: () => void this.language.peek.open(declaration.position)
184
- });
185
- }
186
- if (mapped !== null && declaration.authors) {
187
- const authorship = this.authorshipOf(declaration, commits, mapped);
188
- entries.push({
189
- id: 'authors',
190
- text: authorsText(authorship, this.language.project.i18n),
191
- ...(authorship.authors.length > 0 ? { icon: authorship.authors.length > 1 ? 'users' : 'user' } : {}),
192
- activate: (anchor) => this.showAuthors(declaration, authorship, anchor)
193
- });
194
- }
195
- rows.push({ id: declaration.id, line: declaration.line, entries });
196
- }
197
- return rows;
198
- }
199
- authorshipOf(declaration, commits, mapped) {
200
- const known = this.authorships.get(declaration.id);
201
- if (known !== undefined) {
202
- return known;
203
- }
204
- const authorship = authorshipOf(commits, mapped, this.lines, declaration.authorFrom, declaration.authorTo);
205
- this.authorships.set(declaration.id, authorship);
206
- return authorship;
207
- }
208
- mapOfBlame(source) {
209
- if (this.mapped?.blame !== source.blame) {
210
- this.mapped = { blame: source.blame, lines: mapBlame(source.blame, source.base, this.lines) };
211
- }
212
- return this.mapped.lines;
210
+ return rows;
211
+ }
212
+ authorshipOf(declaration, commits, mapped) {
213
+ const known = this.authorships.get(declaration.id);
214
+ if (known !== undefined) {
215
+ return known;
213
216
  }
214
- showAuthors(declaration, authorship, anchor) {
215
- const source = this.blame;
216
- const openCommit = source?.kind === 'ready' ? source.openCommit : undefined;
217
- this.language.popups.setState({
218
- authors: {
219
- anchor,
220
- name: declaration.name,
221
- authorship,
222
- openCommit: openCommit === undefined || authorship.latest === null ? null : () => openCommit(authorship.latest.hash)
223
- }
224
- });
217
+ const authorship = authorshipOf(commits, mapped, this.lines, declaration.authorFrom, declaration.authorTo);
218
+ this.authorships.set(declaration.id, authorship);
219
+ return authorship;
220
+ }
221
+ mapOfBlame(source) {
222
+ if (this.mapped?.blame !== source.blame) {
223
+ this.mapped = {
224
+ blame: source.blame,
225
+ lines: mapBlame(source.blame, source.base, this.lines)
226
+ };
225
227
  }
226
- /* Closes the card of the authors; `restoreFocus` is for a close that came from the keyboard, which gives the editor its keys back. */
227
- closeAuthors(restoreFocus = false) {
228
- if (this.language.popups.getState().authors !== null) {
229
- this.language.popups.setState({ authors: null });
230
- if (restoreFocus) {
231
- this.language.editor.focus();
232
- }
233
- }
228
+ return this.mapped.lines;
229
+ }
230
+ showAuthors(declaration, authorship, anchor) {
231
+ const source = this.blame;
232
+ const openCommit = source?.kind === 'ready' ? source.openCommit : undefined;
233
+ this.language.popups.setState({
234
+ authors: {
235
+ anchor,
236
+ name: declaration.name,
237
+ authorship,
238
+ openCommit: openCommit === undefined || authorship.latest === null ? null : () => openCommit(authorship.latest.hash)
239
+ }
240
+ });
241
+ }
242
+ /* Closes the card of the authors; `restoreFocus` is for a close that came from the keyboard, which gives the editor its keys back. */
243
+ closeAuthors(restoreFocus = false) {
244
+ if (this.language.popups.getState().authors !== null) {
245
+ this.language.popups.setState({
246
+ authors: null
247
+ });
248
+ if (restoreFocus) {
249
+ this.language.editor.focus();
250
+ }
234
251
  }
252
+ }
235
253
  }
236
254
  /* The places a server named, each counted once however many ways it was reached. */
237
255
  function distinctPlaces(locations) {
238
- return new Set(locations.map((location) => `${location.uri}\0${location.range.start.line}\0${location.range.start.character}`)).size;
239
- }
256
+ return new Set(locations.map(location => `${location.uri}\0${location.range.start.line}\0${location.range.start.character}`)).size;
257
+ }
@@ -11,68 +11,66 @@ const EXISTING_CALL = /^\s*\(/;
11
11
  const SIGNATURE_KIND_PREFIX = /^\([a-z]+(?: [a-z]+)*\)\s+(?!=>)/;
12
12
  /* Whether the item is something that is called where it stands: a function, a method, a constructor, or a class after `new`. */
13
13
  export function isCallItem(item, lineBefore) {
14
- return isCallableKind(item.kind) || (item.kind === CLASS_KIND && AFTER_NEW.test(lineBefore));
14
+ return isCallableKind(item.kind) || item.kind === CLASS_KIND && AFTER_NEW.test(lineBefore);
15
15
  }
16
16
  /* Whether the parameter list in a signature has anything in it; null when the text names no list. */
17
17
  function listedParameters(signature) {
18
- const text = signature.replace(SIGNATURE_KIND_PREFIX, '');
19
- const open = text.indexOf('(');
20
- if (open < 0) {
21
- return null;
22
- }
23
- let depth = 0;
24
- for (let i = open; i < text.length; i++) {
25
- if (text[i] === '(') {
26
- depth++;
27
- }
28
- else if (text[i] === ')' && --depth === 0) {
29
- return text.slice(open + 1, i).trim() !== '';
30
- }
31
- }
18
+ const text = signature.replace(SIGNATURE_KIND_PREFIX, '');
19
+ const open = text.indexOf('(');
20
+ if (open < 0) {
32
21
  return null;
22
+ }
23
+ let depth = 0;
24
+ for (let i = open; i < text.length; i++) {
25
+ if (text[i] === '(') {
26
+ depth++;
27
+ } else if (text[i] === ')' && --depth === 0) {
28
+ return text.slice(open + 1, i).trim() !== '';
29
+ }
30
+ }
31
+ return null;
33
32
  }
34
33
  /* From what the server says of the item: `(method) Box.open(flag: boolean): void` has parameters and `(): void` has none. Null when it says nothing about them. */
35
34
  export function hasParameters(item) {
36
- const lines = (item.detail ?? '').split('\n').filter((line) => !SOURCE_LINE.test(line.trim()));
37
- for (const signature of [item.labelDetails?.detail ?? '', ...lines]) {
38
- const listed = listedParameters(signature);
39
- if (listed !== null) {
40
- return listed;
41
- }
35
+ const lines = (item.detail ?? '').split('\n').filter(line => !SOURCE_LINE.test(line.trim()));
36
+ for (const signature of [item.labelDetails?.detail ?? '', ...lines]) {
37
+ const listed = listedParameters(signature);
38
+ if (listed !== null) {
39
+ return listed;
42
40
  }
43
- return null;
41
+ }
42
+ return null;
44
43
  }
45
44
  /* The text before the innermost brace that is still open, which says whether the caret is in an import or export list. */
46
45
  function beforeOpenBrace(before) {
47
- let depth = 0;
48
- for (let i = before.length - 1; i >= 0; i--) {
49
- if (before[i] === '}') {
50
- depth++;
51
- }
52
- else if (before[i] === '{' && depth-- === 0) {
53
- return before.slice(0, i);
54
- }
46
+ let depth = 0;
47
+ for (let i = before.length - 1; i >= 0; i--) {
48
+ if (before[i] === '}') {
49
+ depth++;
50
+ } else if (before[i] === '{' && depth-- === 0) {
51
+ return before.slice(0, i);
55
52
  }
56
- return null;
53
+ }
54
+ return null;
57
55
  }
58
56
  /* Where a name is not called: in an import or export list, a `use`, a type operator's operand, an attribute or a tag. */
59
57
  function isNameOnly(languageId, before) {
60
- const lineBefore = before.slice(before.lastIndexOf('\n') + 1);
61
- const brace = beforeOpenBrace(before);
62
- if (brace !== null && (IMPORT_BRACE.test(brace) || (languageId === 'php' && PHP_USE_BRACE.test(brace)))) {
63
- return true;
64
- }
65
- if (TYPE_OPERATOR.test(lineBefore) || /^\s*export\s+default\s+[\w$]*$/.test(lineBefore)) {
66
- return true;
67
- }
68
- switch (languageId) {
69
- case 'php':
70
- return /^\s*use\s/.test(lineBefore) || /#\[[^\]]*$/.test(lineBefore);
71
- case 'python':
72
- return /^\s*(?:from\s+\S+\s+)?import\b/.test(lineBefore);
73
- default:
74
- return /^\s*import\b/.test(lineBefore) || (MARKUP_LANGUAGES.has(languageId) && /<\/?[\w$.:-]*$/.test(lineBefore));
75
- }
58
+ const lineBefore = before.slice(before.lastIndexOf('\n') + 1);
59
+ const brace = beforeOpenBrace(before);
60
+ if (brace !== null && (IMPORT_BRACE.test(brace) || languageId === 'php' && PHP_USE_BRACE.test(brace))) {
61
+ return true;
62
+ }
63
+ if (TYPE_OPERATOR.test(lineBefore) || /^\s*export\s+default\s+[\w$]*$/.test(lineBefore)) {
64
+ return true;
65
+ }
66
+ switch (languageId) {
67
+ case 'php':
68
+ return /^\s*use\s/.test(lineBefore) || /#\[[^\]]*$/.test(lineBefore);
69
+ case 'python':
70
+ return /^\s*(?:from\s+\S+\s+)?import\b/.test(lineBefore);
71
+ default:
72
+ return /^\s*import\b/.test(lineBefore) || MARKUP_LANGUAGES.has(languageId) && /<\/?[\w$.:-]*$/.test(lineBefore);
73
+ }
76
74
  }
77
75
  /*
78
76
  * Decides what accepting `item` does about a call, as the platform's parentheses handler does: a callable
@@ -81,26 +79,55 @@ function isNameOnly(languageId, before) {
81
79
  * parenthesis, carries its own call and wins.
82
80
  */
83
81
  export function planCall(site) {
84
- const { item, languageId, insertion, before, rest, replace } = site;
85
- const lineBefore = before.slice(before.lastIndexOf('\n') + 1);
86
- if (!CALL_LANGUAGES.has(languageId) || !isCallItem(item, lineBefore) || item.insertTextFormat === SNIPPET_FORMAT || insertion.text.includes('(')) {
87
- return { action: 'none' };
88
- }
89
- if (isNameOnly(languageId, before)) {
90
- return { action: 'none' };
91
- }
92
- const existing = EXISTING_CALL.exec(rest);
93
- if (existing !== null) {
94
- return replace ? { action: 'enter', shift: existing[0].length } : { action: 'none' };
95
- }
96
- if (rest.startsWith('<')) {
97
- return { action: 'none' };
98
- }
99
- return { action: 'add', inside: hasParameters(item) !== false };
82
+ const {
83
+ item,
84
+ languageId,
85
+ insertion,
86
+ before,
87
+ rest,
88
+ replace
89
+ } = site;
90
+ const lineBefore = before.slice(before.lastIndexOf('\n') + 1);
91
+ if (!CALL_LANGUAGES.has(languageId) || !isCallItem(item, lineBefore) || item.insertTextFormat === SNIPPET_FORMAT || insertion.text.includes('(')) {
92
+ return {
93
+ action: 'none'
94
+ };
95
+ }
96
+ if (isNameOnly(languageId, before)) {
97
+ return {
98
+ action: 'none'
99
+ };
100
+ }
101
+ const existing = EXISTING_CALL.exec(rest);
102
+ if (existing !== null) {
103
+ return replace ? {
104
+ action: 'enter',
105
+ shift: existing[0].length
106
+ } : {
107
+ action: 'none'
108
+ };
109
+ }
110
+ if (rest.startsWith('<')) {
111
+ return {
112
+ action: 'none'
113
+ };
114
+ }
115
+ return {
116
+ action: 'add',
117
+ inside: hasParameters(item) !== false
118
+ };
100
119
  }
101
120
  /* The insertion with its parentheses, and the one tab stop that puts the caret where the plan says. */
102
121
  export function withParentheses(insertion, inside) {
103
- const text = `${insertion.text}()`;
104
- const caret = inside ? text.length - 1 : text.length;
105
- return { range: insertion.range, text, stops: [{ index: 0, start: caret, end: caret }] };
106
- }
122
+ const text = `${insertion.text}()`;
123
+ const caret = inside ? text.length - 1 : text.length;
124
+ return {
125
+ range: insertion.range,
126
+ text,
127
+ stops: [{
128
+ index: 0,
129
+ start: caret,
130
+ end: caret
131
+ }]
132
+ };
133
+ }