@adecore/editor-react 0.42.0 → 0.44.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 (150) hide show
  1. package/dist/CallHierarchyPanel.js +177 -181
  2. package/dist/EditorContextMenu.js +118 -105
  3. package/dist/LanguagePopups.js +7 -0
  4. package/dist/PickPopup.js +245 -104
  5. package/dist/WrapCard.d.ts +8 -0
  6. package/dist/WrapCard.js +172 -0
  7. package/dist/call-hierarchy-model.d.ts +4 -2
  8. package/dist/call-hierarchy-model.js +20 -0
  9. package/dist/call-hierarchy.d.ts +3 -0
  10. package/dist/call-hierarchy.js +54 -22
  11. package/dist/clipboard-history.d.ts +31 -0
  12. package/dist/clipboard-history.js +70 -0
  13. package/dist/code-actions.d.ts +3 -1
  14. package/dist/code-actions.js +50 -10
  15. package/dist/code-vision.js +2 -3
  16. package/dist/completion.d.ts +28 -0
  17. package/dist/completion.js +83 -27
  18. package/dist/context-menu-rows.d.ts +1 -1
  19. package/dist/context-menu-rows.js +4 -0
  20. package/dist/definition-link.js +15 -5
  21. package/dist/document-colors.d.ts +24 -0
  22. package/dist/document-colors.js +194 -0
  23. package/dist/document-links.d.ts +22 -0
  24. package/dist/document-links.js +133 -0
  25. package/dist/document-query.d.ts +15 -0
  26. package/dist/document-query.js +54 -0
  27. package/dist/edit-locations.d.ts +20 -0
  28. package/dist/edit-locations.js +136 -0
  29. package/dist/editor-language.d.ts +23 -1
  30. package/dist/editor-language.js +83 -2
  31. package/dist/emmet.d.ts +13 -0
  32. package/dist/emmet.js +62 -0
  33. package/dist/folding.js +2 -3
  34. package/dist/format-on-type.js +3 -5
  35. package/dist/highlights.js +2 -3
  36. package/dist/history.d.ts +7 -0
  37. package/dist/history.js +79 -1
  38. package/dist/host-types.d.ts +10 -0
  39. package/dist/index.d.ts +13 -2
  40. package/dist/index.js +10 -0
  41. package/dist/inlay-hints.js +2 -2
  42. package/dist/inline-completion.d.ts +39 -0
  43. package/dist/inline-completion.js +221 -0
  44. package/dist/key-priority.d.ts +9 -5
  45. package/dist/key-priority.js +11 -6
  46. package/dist/linked-editing.d.ts +26 -0
  47. package/dist/linked-editing.js +215 -0
  48. package/dist/live-templates.d.ts +16 -0
  49. package/dist/live-templates.js +289 -0
  50. package/dist/locales/en.json +61 -2
  51. package/dist/locales/nl.json +61 -2
  52. package/dist/markup-context.d.ts +55 -0
  53. package/dist/markup-context.js +408 -0
  54. package/dist/markup.d.ts +39 -0
  55. package/dist/markup.js +465 -0
  56. package/dist/navigation.js +4 -6
  57. package/dist/paste-history.d.ts +7 -0
  58. package/dist/paste-history.js +104 -0
  59. package/dist/peek.js +3 -4
  60. package/dist/pick.d.ts +21 -2
  61. package/dist/pick.js +152 -19
  62. package/dist/popups.d.ts +10 -0
  63. package/dist/popups.js +2 -1
  64. package/dist/postfix.d.ts +21 -0
  65. package/dist/postfix.js +212 -0
  66. package/dist/project-language.d.ts +20 -1
  67. package/dist/project-language.js +132 -18
  68. package/dist/rename.js +8 -11
  69. package/dist/rendered-docs.js +1 -2
  70. package/dist/selection-ranges.js +2 -3
  71. package/dist/shortcut-keys.d.ts +24 -0
  72. package/dist/signature.js +3 -6
  73. package/dist/snippet-insert.d.ts +10 -0
  74. package/dist/snippet-insert.js +217 -0
  75. package/dist/snippet-session.d.ts +2 -2
  76. package/dist/snippet-session.js +3 -3
  77. package/dist/snippet.d.ts +7 -1
  78. package/dist/snippet.js +65 -8
  79. package/dist/surround-constructs.d.ts +10 -0
  80. package/dist/surround-constructs.js +100 -0
  81. package/dist/surround.d.ts +18 -0
  82. package/dist/surround.js +399 -0
  83. package/dist/symbol-picker.js +4 -6
  84. package/dist/symbols.js +22 -3
  85. package/dist/template-builtins.d.ts +3 -0
  86. package/dist/template-builtins.js +46 -0
  87. package/dist/template-context.d.ts +12 -0
  88. package/dist/template-context.js +56 -0
  89. package/dist/templates.d.ts +59 -0
  90. package/dist/templates.js +103 -0
  91. package/dist/testing.d.ts +23 -1
  92. package/dist/testing.js +114 -0
  93. package/package.json +7 -6
  94. package/src/CallHierarchyPanel.tsx +26 -11
  95. package/src/EditorContextMenu.tsx +7 -0
  96. package/src/LanguagePopups.tsx +4 -0
  97. package/src/PickPopup.tsx +47 -5
  98. package/src/WrapCard.tsx +64 -0
  99. package/src/call-hierarchy-model.ts +25 -3
  100. package/src/call-hierarchy.ts +62 -20
  101. package/src/clipboard-history.ts +102 -0
  102. package/src/code-actions.ts +48 -11
  103. package/src/code-vision.ts +3 -3
  104. package/src/completion.ts +123 -25
  105. package/src/context-menu-rows.ts +3 -2
  106. package/src/definition-link.ts +17 -5
  107. package/src/document-colors.ts +189 -0
  108. package/src/document-links.ts +129 -0
  109. package/src/document-query.ts +71 -0
  110. package/src/edit-locations.ts +162 -0
  111. package/src/editor-language.ts +86 -3
  112. package/src/emmet-module.d.ts +44 -0
  113. package/src/emmet.ts +73 -0
  114. package/src/folding.ts +3 -3
  115. package/src/format-on-type.ts +5 -5
  116. package/src/highlights.ts +3 -3
  117. package/src/history.ts +81 -1
  118. package/src/host-types.ts +17 -0
  119. package/src/index.ts +28 -3
  120. package/src/inlay-hints.ts +2 -2
  121. package/src/inline-completion.ts +221 -0
  122. package/src/key-priority.ts +11 -6
  123. package/src/linked-editing.ts +199 -0
  124. package/src/live-templates.ts +315 -0
  125. package/src/locales/en.json +61 -2
  126. package/src/locales/nl.json +61 -2
  127. package/src/markup-context.ts +387 -0
  128. package/src/markup.ts +377 -0
  129. package/src/navigation.ts +6 -6
  130. package/src/paste-history.ts +111 -0
  131. package/src/peek.ts +4 -4
  132. package/src/pick.ts +218 -20
  133. package/src/popups.ts +21 -1
  134. package/src/postfix.ts +224 -0
  135. package/src/project-language.ts +139 -19
  136. package/src/rename.ts +11 -11
  137. package/src/rendered-docs.ts +2 -2
  138. package/src/selection-ranges.ts +3 -3
  139. package/src/signature.ts +6 -6
  140. package/src/snippet-insert.ts +258 -0
  141. package/src/snippet-session.ts +9 -4
  142. package/src/snippet.ts +82 -7
  143. package/src/surround-constructs.ts +85 -0
  144. package/src/surround.ts +430 -0
  145. package/src/symbol-picker.ts +6 -6
  146. package/src/symbols.ts +30 -4
  147. package/src/template-builtins.ts +94 -0
  148. package/src/template-context.ts +65 -0
  149. package/src/templates.ts +197 -0
  150. package/src/testing.ts +126 -1
package/dist/history.js CHANGED
@@ -3,6 +3,7 @@ import { isShortcut } from './shortcut-keys.js';
3
3
  /* Back, Forward and the list of recent locations over the history the whole project shares. */
4
4
  export class HistoryFeature {
5
5
  language;
6
+ editing = false;
6
7
  constructor(language) {
7
8
  this.language = language;
8
9
  const off = language.onKey(event => {
@@ -18,9 +19,37 @@ export class HistoryFeature {
18
19
  this.recent();
19
20
  return true;
20
21
  }
22
+ if (isShortcut(this.language.shortcuts.lastEditLocation, event)) {
23
+ this.lastEdit();
24
+ return true;
25
+ }
26
+ if (isShortcut(this.language.shortcuts.nextEditLocation, event)) {
27
+ this.nextEdit();
28
+ return true;
29
+ }
21
30
  return false;
22
31
  }, KEY_PRIORITY.history);
23
- language.onDispose(off);
32
+ // A jump of the editor's own, such as Method Down, is a place Back returns to like any other jump.
33
+ const navigations = language.editor.onNavigate?.(from => language.project.history.record({
34
+ uri: language.uri,
35
+ position: from
36
+ }));
37
+ const changes = language.editor.onTextChange(change => this.edited(change));
38
+ const carets = language.editor.onCaret(position => this.moved(position));
39
+ language.onDispose(() => {
40
+ off();
41
+ navigations?.();
42
+ changes();
43
+ carets();
44
+ });
45
+ }
46
+ /* Goes to where the project was edited before the carets' place; false when there is no such place. */
47
+ lastEdit() {
48
+ return this.visitEdit(this.language.project.edits.previous(this.currentEdit()));
49
+ }
50
+ /* Goes to where the project was edited after the place Last Edit Location came back to. */
51
+ nextEdit() {
52
+ return this.visitEdit(this.language.project.edits.next(this.currentEdit()));
24
53
  }
25
54
  /* Returns to where the caret was before the last jump; false when there is no such place. */
26
55
  back() {
@@ -40,6 +69,55 @@ export class HistoryFeature {
40
69
  }
41
70
  })), this.language.editor.getCaret(), this.language.project.i18n.t('editor:language.history.recent'));
42
71
  }
72
+ currentEdit() {
73
+ return {
74
+ uri: this.language.uri,
75
+ selections: this.language.editor.getSelections()
76
+ };
77
+ }
78
+ /* Every edit moves the places of the file; one a person made counts as an edit location once the caret has settled. */
79
+ edited(change) {
80
+ const {
81
+ editor,
82
+ project,
83
+ uri
84
+ } = this.language;
85
+ project.edits.map(uri, change.changes);
86
+ this.editing = true;
87
+ queueMicrotask(() => {
88
+ this.editing = false;
89
+ if (change.source !== 'external' && editor.hasFocus?.() !== false && !this.language.isDisposed) {
90
+ project.edits.record(this.currentEdit());
91
+ }
92
+ });
93
+ }
94
+ /* A caret that moves on its own ends the walk through the edits, unless an edit moved it. */
95
+ moved(position) {
96
+ if (!this.editing) {
97
+ this.language.project.edits.moved(this.language.uri, position);
98
+ }
99
+ }
100
+ visitEdit(place) {
101
+ if (place === null) {
102
+ return false;
103
+ }
104
+ const {
105
+ editor,
106
+ project,
107
+ uri
108
+ } = this.language;
109
+ if (place.uri === uri) {
110
+ editor.setSelections(place.selections, 'center');
111
+ editor.focus();
112
+ } else {
113
+ // Another file opens on one caret, the primary.
114
+ project.openPlace({
115
+ uri: place.uri,
116
+ position: place.selections.at(-1).end
117
+ });
118
+ }
119
+ return true;
120
+ }
43
121
  visit(place) {
44
122
  if (place === null) {
45
123
  return false;
@@ -2,9 +2,12 @@ import type { WorkerRequestPort } from '@adecore/editor/worker-client';
2
2
  import type { EditorPosition, EditorRange } from '@adecore/editor';
3
3
  import type { i18n } from 'i18next';
4
4
  import type { Keymap } from '@adecore/editor/keymap';
5
+ import type { ClipboardHistory } from './clipboard-history.ts';
5
6
  import type { ProjectFiles } from './workspace-edit.ts';
6
7
  import type { Place } from './navigation-history.ts';
7
8
  import type { ProblemSource } from './project-problems.ts';
9
+ import type { LiveTemplateDraft, TemplateRegistry } from './templates.ts';
10
+ import type { ServerMessage } from '@adecore/lsp';
8
11
  export interface DiskText {
9
12
  text: string;
10
13
  mtime: number;
@@ -55,13 +58,20 @@ export interface LanguageHost {
55
58
  readonly files?: ProjectFiles;
56
59
  readonly apple?: boolean;
57
60
  readonly keymap?: Keymap;
61
+ readonly clipboard?: ClipboardHistory;
62
+ readonly templates?: TemplateRegistry;
63
+ saveAsLiveTemplate?(draft: LiveTemplateDraft): void;
64
+ openTemplateSettings?(): void;
65
+ readonly editHistoryLimit?: number;
58
66
  readonly panelBodyHeight?: number;
59
67
  onPanelResize?(height: number): void;
60
68
  readonly problemSource?: ProblemSource;
61
69
  openPlace?(place: Place): void;
70
+ openExternal?(url: string): void;
62
71
  pathOfUri?(uri: string): string | null;
63
72
  serverNames?(uri: string): readonly string[];
64
73
  notify?(notification: EditorNotification): void;
74
+ onServerMessage?(message: ServerMessage): void;
65
75
  resolveSnippetVariable?(name: string, context: SnippetVariableContext): string | undefined;
66
76
  suggestNames?(request: RenameSuggestionsRequest, signal: AbortSignal): Promise<readonly string[]>;
67
77
  }
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { KEY_PRIORITY } from './key-priority.ts';
3
3
  export { realTimers, type Timers } from './timers.ts';
4
4
  export { type SemanticTokensOptions } from './semantic-tokens.ts';
5
5
  export { ProjectLanguage, type FileOperationTarget } from './project-language.ts';
6
- export type { LanguageDocumentHandle } from './project-language.ts';
6
+ export type { AcquireOptions, LanguageDocumentHandle } from './project-language.ts';
7
7
  export type { SnippetVariableContext, LanguageHost, DiskText, GitBlameCommit, GitBlameResult, EditorNotification, RenameSuggestionsRequest } from './host-types.ts';
8
8
  export { EditorView } from './EditorView.tsx';
9
9
  export { createHolder } from './holder.ts';
@@ -13,6 +13,10 @@ export type { LanguagePopupsProps } from './LanguagePopups.tsx';
13
13
  export { AnchoredPopup } from './AnchoredPopup.tsx';
14
14
  export { SignatureCard } from './SignatureCard.tsx';
15
15
  export { type RenderedDocsFeature } from './rendered-docs.ts';
16
+ export { type DocumentLinksFeature } from './document-links.ts';
17
+ export { type DocumentColorsFeature } from './document-colors.ts';
18
+ export { type LinkedEditingFeature } from './linked-editing.ts';
19
+ export { type InlineCompletionFeature, type InlineSuggestion } from './inline-completion.ts';
16
20
  export type { RenderedDocEntry, RenderedDocsSettings } from './rendered-docs.ts';
17
21
  export type { DocTagEntry, DocTagSection, ParsedDocComment } from './doc-comment-model.ts';
18
22
  export { EditorRenderingProvider } from './rendering.tsx';
@@ -28,12 +32,19 @@ export { useProblemCounts } from './use-problem-counts.ts';
28
32
  export type { ProblemCounts } from './diagnostics.ts';
29
33
  export type { BlameSource, CodeVisionSettings } from './code-vision.ts';
30
34
  export type { HoverSettings } from './hover.ts';
31
- export type { PopupState, PopupStore, HoverInfo, HoverView, CompletionView, CompletionDocs, CompletionRow, SignatureView, RenameView, RenameFileView, PeekView, CallHierarchyView, PickView, PickGroup, PickRow, PickPreview, SymbolsView, MenuView, AuthorsView } from './popups.ts';
35
+ export type { PopupState, PopupStore, HoverInfo, HoverView, CompletionView, CompletionDocs, CompletionRow, SignatureView, RenameView, RenameFileView, PeekView, CallHierarchyView, PickView, PickGroup, PickRow, PickPreview, SymbolsView, MenuView, AuthorsView, WrapView } from './popups.ts';
36
+ export { type MarkupFeature } from './markup.ts';
37
+ export { type SurroundFeature } from './surround.ts';
38
+ export type { MarkupSettings } from './markup.ts';
32
39
  export { RowHost, LineActionHost } from './row-host.ts';
33
40
  export type { HostedRow, HostedAction } from './row-host.ts';
34
41
  export { type HighlightLayers, highlightLayers } from './highlight-layers.ts';
35
42
  export { type NavigationHistory } from './navigation-history.ts';
36
43
  export type { Place } from './navigation-history.ts';
44
+ export { EditLocations, type EditPlace } from './edit-locations.ts';
45
+ export { ClipboardHistory, type ClipboardEntry, type ClipboardHistoryOptions } from './clipboard-history.ts';
46
+ export { type PasteHistoryFeature } from './paste-history.ts';
47
+ export { TemplateRegistry, checkTemplate, BUILT_IN_LIVE_TEMPLATES, BUILT_IN_POSTFIX_TEMPLATES, type TemplatesFeature, type LiveTemplate, type PostfixTemplate, type LiveTemplateDraft, type TemplateLanguage, type TemplatePlace, type TemplateSettings, type TemplateRegistryOptions, type TemplateUpdate } from './templates.ts';
37
48
  export { openingPlace, viewStates, followViewStates, viewStateKey, forgetMovesFrom } from './view-state.ts';
38
49
  export type { ViewState, RevealLineRequest } from './view-state.ts';
39
50
  export { lspLanguageIdOf, shikiLanguageOf, shikiLanguageOfPath } from './language-ids.ts';
package/dist/index.js CHANGED
@@ -9,15 +9,25 @@ export { LanguagePopups } from "./LanguagePopups.js";
9
9
  export { AnchoredPopup } from "./AnchoredPopup.js";
10
10
  export { SignatureCard } from "./SignatureCard.js";
11
11
  export {} from './rendered-docs.js';
12
+ export {} from './document-links.js';
13
+ export {} from './document-colors.js';
14
+ export {} from './linked-editing.js';
15
+ export {} from './inline-completion.js';
12
16
  export { EditorRenderingProvider } from "./rendering.js";
13
17
  export { FindReplace } from "./FindReplace.js";
14
18
  export { ChangeReview } from "./ChangeReview.js";
15
19
  export { ProjectProblems, serviceProblems, countsOf } from './project-problems.js';
16
20
  export { applyWorkspaceEdit, supportedResourceOperations } from './workspace-edit.js';
17
21
  export { useProblemCounts } from './use-problem-counts.js';
22
+ export {} from './markup.js';
23
+ export {} from './surround.js';
18
24
  export { RowHost, LineActionHost } from './row-host.js';
19
25
  export { highlightLayers } from './highlight-layers.js';
20
26
  export {} from './navigation-history.js';
27
+ export { EditLocations } from './edit-locations.js';
28
+ export { ClipboardHistory } from './clipboard-history.js';
29
+ export {} from './paste-history.js';
30
+ export { TemplateRegistry, checkTemplate, BUILT_IN_LIVE_TEMPLATES, BUILT_IN_POSTFIX_TEMPLATES } from './templates.js';
21
31
  export { openingPlace, viewStates, followViewStates, viewStateKey, forgetMovesFrom } from './view-state.js';
22
32
  export { lspLanguageIdOf, shikiLanguageOf, shikiLanguageOfPath } from './language-ids.js';
23
33
  export { AttributionCard } from "./AttributionCard.js";
@@ -321,7 +321,7 @@ export class InlayHintsFeature {
321
321
  }
322
322
  /* Whether asking the server could still change what the hint offers. */
323
323
  resolvable(entry) {
324
- return !entry.answered && entry.epoch === this.epoch && this.language.project.service.supports(RESOLVE_METHOD, this.language.uri);
324
+ return !entry.answered && entry.epoch === this.epoch && this.language.service.supports(RESOLVE_METHOD, this.language.uri);
325
325
  }
326
326
  /* Underlines the part under the pointer when a press would do something with it: a command always, a place while the key is down. */
327
327
  updateLink() {
@@ -398,7 +398,7 @@ export class InlayHintsFeature {
398
398
  this.cancelHover();
399
399
  this.language.goTo(action.location);
400
400
  } else if (action.kind === 'run') {
401
- await project.service.executeCommand(uri, action.command);
401
+ await this.language.service.executeCommand(uri, action.command);
402
402
  } else if (entry.epoch === this.epoch && editsFit(editor, action.edits)) {
403
403
  this.cancelHover();
404
404
  const applied = editor.applyEdits(action.edits.map(edit => ({
@@ -0,0 +1,39 @@
1
+ import type { EditorPosition } from '@adecore/editor';
2
+ import type { InlineCompletionItem, InlineCompletionResult, Range } from '@adecore/lsp';
3
+ import type { EditorLanguage } from './editor-language.ts';
4
+ import { type Timers } from './timers.ts';
5
+ export interface InlineSuggestion {
6
+ readonly item: InlineCompletionItem;
7
+ readonly text: string;
8
+ readonly range: Range;
9
+ readonly rest: string;
10
+ }
11
+ export declare function itemsOf(result: InlineCompletionResult): InlineCompletionItem[];
12
+ export declare function suggestionOf(item: InlineCompletionItem, caret: EditorPosition, textOf: (range: Range) => string): InlineSuggestion | null;
13
+ export declare class InlineCompletionFeature {
14
+ private readonly language;
15
+ private readonly timers;
16
+ private enabled;
17
+ private suggestions;
18
+ private index;
19
+ private timer;
20
+ private controller;
21
+ private revision;
22
+ private accepting;
23
+ constructor(language: EditorLanguage, timers?: Timers);
24
+ get supported(): boolean;
25
+ get isEnabled(): boolean;
26
+ get current(): InlineSuggestion | null;
27
+ configure(settings: {
28
+ readonly enabled?: boolean;
29
+ }): void;
30
+ trigger(): void;
31
+ accept(): boolean;
32
+ cycle(step: 1 | -1): void;
33
+ hide(): void;
34
+ private key;
35
+ private edited;
36
+ private moved;
37
+ private ask;
38
+ private draw;
39
+ }
@@ -0,0 +1,221 @@
1
+ import { comparePositions } from './diagnostics-model.js';
2
+ import { KEY_PRIORITY } from './key-priority.js';
3
+ import { isShortcut } from './shortcut-keys.js';
4
+ import { parseSnippet } from './snippet.js';
5
+ import { realTimers } from './timers.js';
6
+ const METHOD = 'textDocument/inlineCompletion';
7
+ /* How long typing rests before a suggestion is asked. */
8
+ const DELAY_MS = 300;
9
+ export function itemsOf(result) {
10
+ if (result === null) {
11
+ return [];
12
+ }
13
+ return Array.isArray(result) ? result : result.items;
14
+ }
15
+ /*
16
+ * A server's item as a suggestion at the caret, or null when it does not continue what the line holds: the text the
17
+ * item replaces up to the caret must start its insert text, so the rest can stand after the caret.
18
+ */
19
+ export function suggestionOf(item, caret, textOf) {
20
+ const text = typeof item.insertText === 'string' ? item.insertText : parseSnippet(item.insertText.value).text;
21
+ const range = item.range ?? {
22
+ start: caret,
23
+ end: caret
24
+ };
25
+ if (comparePositions(range.start, caret) > 0 || comparePositions(range.end, caret) < 0) {
26
+ return null;
27
+ }
28
+ const typed = textOf({
29
+ start: range.start,
30
+ end: caret
31
+ });
32
+ if (!text.startsWith(typed)) {
33
+ return null;
34
+ }
35
+ const rest = text.slice(typed.length);
36
+ return rest === '' ? null : {
37
+ item,
38
+ text,
39
+ range,
40
+ rest
41
+ };
42
+ }
43
+ /*
44
+ * Suggestions a server writes ahead of the caret, drawn as ghost text: asked a moment after typing stops, or at
45
+ * once with the `suggestInline` key of the host. Tab takes the suggestion, Alt+] and Alt+[ step through the others,
46
+ * Escape and any key that moves away put it away. Off unless the host turns it on, since a host may draw
47
+ * suggestions of its own in the same place.
48
+ */
49
+ export class InlineCompletionFeature {
50
+ language;
51
+ timers;
52
+ enabled = false;
53
+ suggestions = [];
54
+ index = 0;
55
+ timer = null;
56
+ controller = null;
57
+ revision = 0;
58
+ accepting = false;
59
+ constructor(language, timers = realTimers) {
60
+ this.language = language;
61
+ this.timers = timers;
62
+ const {
63
+ editor
64
+ } = language;
65
+ const offs = [language.onKey(event => this.key(event), KEY_PRIORITY.inlineCompletion), editor.onTextChange(change => this.edited(change)), editor.onCaret(() => queueMicrotask(() => this.moved()))];
66
+ language.onDispose(() => {
67
+ this.hide();
68
+ for (const off of offs) {
69
+ off();
70
+ }
71
+ });
72
+ }
73
+ get supported() {
74
+ const {
75
+ service
76
+ } = this.language;
77
+ return service.inlineCompletions !== undefined && service.supports(METHOD, this.language.uri);
78
+ }
79
+ get isEnabled() {
80
+ return this.enabled;
81
+ }
82
+ /* The suggestion drawn now, or null. */
83
+ get current() {
84
+ return this.suggestions[this.index] ?? null;
85
+ }
86
+ configure(settings) {
87
+ this.enabled = settings.enabled === true;
88
+ if (!this.enabled) {
89
+ this.hide();
90
+ }
91
+ }
92
+ /* Asks for suggestions at the caret now, as a person asking for one does. */
93
+ trigger() {
94
+ this.timers.clear(this.timer);
95
+ void this.ask(1);
96
+ }
97
+ /* Takes the drawn suggestion into the text; false when there is none. */
98
+ accept() {
99
+ const suggestion = this.current;
100
+ if (suggestion === null) {
101
+ return false;
102
+ }
103
+ const {
104
+ editor,
105
+ service,
106
+ uri
107
+ } = this.language;
108
+ this.accepting = true;
109
+ try {
110
+ editor.applyEdits([{
111
+ range: suggestion.range,
112
+ text: suggestion.text
113
+ }]);
114
+ } finally {
115
+ this.accepting = false;
116
+ }
117
+ this.hide();
118
+ const {
119
+ command
120
+ } = suggestion.item;
121
+ if (command !== undefined && service.supports('workspace/executeCommand', uri)) {
122
+ void service.executeCommand(uri, command).catch(() => undefined);
123
+ }
124
+ return true;
125
+ }
126
+ /* Steps to the next or the previous suggestion. */
127
+ cycle(step) {
128
+ if (this.suggestions.length > 1) {
129
+ this.index = (this.index + step + this.suggestions.length) % this.suggestions.length;
130
+ this.draw();
131
+ }
132
+ }
133
+ hide() {
134
+ this.revision++;
135
+ this.timers.clear(this.timer);
136
+ this.controller?.abort();
137
+ if (this.suggestions.length > 0) {
138
+ this.suggestions = [];
139
+ this.language.editor.setGhostText(null);
140
+ }
141
+ }
142
+ key(event) {
143
+ if (isShortcut(this.language.shortcuts.suggestInline, event) && this.enabled) {
144
+ this.trigger();
145
+ return true;
146
+ }
147
+ if (this.current === null || event.isComposing) {
148
+ return false;
149
+ }
150
+ if (event.key === 'Tab' && !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {
151
+ return this.accept();
152
+ }
153
+ if (event.key === 'Escape') {
154
+ this.hide();
155
+ return true;
156
+ }
157
+ if (event.altKey && !event.ctrlKey && !event.metaKey && (event.code === 'BracketRight' || event.code === 'BracketLeft')) {
158
+ this.cycle(event.code === 'BracketRight' ? 1 : -1);
159
+ return true;
160
+ }
161
+ return false;
162
+ }
163
+ edited(change) {
164
+ if (this.accepting) {
165
+ return;
166
+ }
167
+ this.hide();
168
+ if (this.enabled && change.source === 'input' && this.supported) {
169
+ this.timer = this.timers.set(() => void this.ask(2), DELAY_MS);
170
+ }
171
+ }
172
+ /* A caret that left the place of the suggestion puts it away. */
173
+ moved() {
174
+ const suggestion = this.current;
175
+ if (suggestion === null) {
176
+ return;
177
+ }
178
+ const caret = this.language.editor.getCaret();
179
+ const selections = this.language.editor.getSelections();
180
+ if (selections.length !== 1 || suggestionOf(suggestion.item, caret, range => this.language.editor.textInRange(range)) === null) {
181
+ this.hide();
182
+ }
183
+ }
184
+ async ask(triggerKind) {
185
+ const {
186
+ editor,
187
+ service,
188
+ uri
189
+ } = this.language;
190
+ if (!this.enabled || !this.supported || editor.getSelections().length !== 1 || editor.isReadOnly?.() === true) {
191
+ return;
192
+ }
193
+ this.controller?.abort();
194
+ const controller = new AbortController();
195
+ this.controller = controller;
196
+ const revision = this.revision;
197
+ const caret = editor.getCaret();
198
+ try {
199
+ const result = await service.inlineCompletions(uri, caret, {
200
+ triggerKind
201
+ }, {
202
+ signal: controller.signal
203
+ });
204
+ if (revision !== this.revision || comparePositions(editor.getCaret(), caret) !== 0) {
205
+ return;
206
+ }
207
+ this.suggestions = itemsOf(result).flatMap(item => suggestionOf(item, caret, range => editor.textInRange(range)) ?? []);
208
+ this.index = 0;
209
+ this.draw();
210
+ } catch {
211
+ // A refusal or a failing server is no suggestion; the next pause asks again.
212
+ }
213
+ }
214
+ draw() {
215
+ const suggestion = this.current;
216
+ this.language.editor.setGhostText(suggestion === null ? null : {
217
+ position: this.language.editor.getCaret(),
218
+ text: suggestion.rest
219
+ });
220
+ }
221
+ }
@@ -1,10 +1,12 @@
1
1
  import type { EditorKeyHandler } from '@adecore/editor';
2
2
  export declare const KEY_PRIORITY: {
3
- readonly pick: 1500;
4
- readonly diagnostics: 1400;
5
- readonly hover: 1300;
6
- readonly completion: 1200;
7
- readonly snippets: 1100;
3
+ readonly pick: 1600;
4
+ readonly diagnostics: 1500;
5
+ readonly hover: 1400;
6
+ readonly completion: 1300;
7
+ readonly snippets: 1200;
8
+ readonly templates: 1150;
9
+ readonly markup: 1100;
8
10
  readonly signature: 1000;
9
11
  readonly highlights: 900;
10
12
  readonly codeActions: 800;
@@ -15,6 +17,8 @@ export declare const KEY_PRIORITY: {
15
17
  readonly symbolPicker: 300;
16
18
  readonly history: 200;
17
19
  readonly renderedDocs: 100;
20
+ readonly pasteHistory: 50;
21
+ readonly inlineCompletion: 25;
18
22
  };
19
23
  export declare class KeyDispatcher {
20
24
  private readonly entries;
@@ -3,11 +3,14 @@
3
3
  * apart, so a handler of the app can stand between two features; 0, the default, comes after all of them.
4
4
  */
5
5
  export const KEY_PRIORITY = {
6
- pick: 1500,
7
- diagnostics: 1400,
8
- hover: 1300,
9
- completion: 1200,
10
- snippets: 1100,
6
+ pick: 1600,
7
+ diagnostics: 1500,
8
+ hover: 1400,
9
+ completion: 1300,
10
+ snippets: 1200,
11
+ // Between snippets and markup, so the spacing of a hundred bends here: Tab has to reach the templates after a running snippet and before Emmet.
12
+ templates: 1150,
13
+ markup: 1100,
11
14
  signature: 1000,
12
15
  highlights: 900,
13
16
  codeActions: 800,
@@ -17,7 +20,9 @@ export const KEY_PRIORITY = {
17
20
  callHierarchy: 400,
18
21
  symbolPicker: 300,
19
22
  history: 200,
20
- renderedDocs: 100
23
+ renderedDocs: 100,
24
+ pasteHistory: 50,
25
+ inlineCompletion: 25
21
26
  };
22
27
  /* Hands a key to its handlers by priority until one takes it; of two of the same priority the one added first. */
23
28
  export class KeyDispatcher {
@@ -0,0 +1,26 @@
1
+ import type { LinkedEditingRanges } from '@adecore/lsp';
2
+ import type { EditorLanguage } from './editor-language.ts';
3
+ import { type Timers } from './timers.ts';
4
+ export declare function wordPatternOf(ranges: LinkedEditingRanges): RegExp | null;
5
+ export declare class LinkedEditingFeature {
6
+ private readonly language;
7
+ private readonly timers;
8
+ private session;
9
+ private timer;
10
+ private controller;
11
+ private revision;
12
+ private mirroring;
13
+ private enabled;
14
+ constructor(language: EditorLanguage, timers?: Timers);
15
+ get supported(): boolean;
16
+ get isActive(): boolean;
17
+ configure(settings: {
18
+ readonly enabled?: boolean;
19
+ }): void;
20
+ private stop;
21
+ private caretOffset;
22
+ private moved;
23
+ private ask;
24
+ private edited;
25
+ private mirror;
26
+ }