@adecore/editor-react 0.0.1 → 0.17.0-beta.2

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 (264) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +60 -0
  3. package/dist/AnchoredPopup.d.ts +12 -0
  4. package/dist/AnchoredPopup.js +27 -0
  5. package/dist/AttributionCard.d.ts +14 -0
  6. package/dist/AttributionCard.js +5 -0
  7. package/dist/BaselineStatus.d.ts +4 -0
  8. package/dist/BaselineStatus.js +13 -0
  9. package/dist/ChangeReview.d.ts +12 -0
  10. package/dist/ChangeReview.js +27 -0
  11. package/dist/CodeAuthorsCard.d.ts +6 -0
  12. package/dist/CodeAuthorsCard.js +22 -0
  13. package/dist/CompletionPopup.d.ts +8 -0
  14. package/dist/CompletionPopup.js +103 -0
  15. package/dist/EditorContextMenu.d.ts +8 -0
  16. package/dist/EditorContextMenu.js +23 -0
  17. package/dist/EditorView.d.ts +16 -0
  18. package/dist/EditorView.js +27 -0
  19. package/dist/FindReplace.d.ts +6 -0
  20. package/dist/FindReplace.js +44 -0
  21. package/dist/HoverCard.d.ts +11 -0
  22. package/dist/HoverCard.js +38 -0
  23. package/dist/HoverSections.d.ts +21 -0
  24. package/dist/HoverSections.js +82 -0
  25. package/dist/LanguagePopups.d.ts +6 -0
  26. package/dist/LanguagePopups.js +38 -0
  27. package/dist/Markdown.d.ts +3 -0
  28. package/dist/Markdown.js +7 -0
  29. package/dist/PathText.d.ts +4 -0
  30. package/dist/PathText.js +12 -0
  31. package/dist/PeekPanel.d.ts +6 -0
  32. package/dist/PeekPanel.js +111 -0
  33. package/dist/PickPopup.d.ts +8 -0
  34. package/dist/PickPopup.js +33 -0
  35. package/dist/RenameCard.d.ts +9 -0
  36. package/dist/RenameCard.js +108 -0
  37. package/dist/SignatureCard.d.ts +4 -0
  38. package/dist/SignatureCard.js +8 -0
  39. package/dist/SymbolPicker.d.ts +6 -0
  40. package/dist/SymbolPicker.js +108 -0
  41. package/dist/code-actions-model.d.ts +23 -0
  42. package/dist/code-actions-model.js +114 -0
  43. package/dist/code-actions.d.ts +30 -0
  44. package/dist/code-actions.js +326 -0
  45. package/dist/code-authors.d.ts +18 -0
  46. package/dist/code-authors.js +79 -0
  47. package/dist/code-vision-model.d.ts +21 -0
  48. package/dist/code-vision-model.js +183 -0
  49. package/dist/code-vision.d.ts +48 -0
  50. package/dist/code-vision.js +236 -0
  51. package/dist/completion-call.d.ts +24 -0
  52. package/dist/completion-call.js +110 -0
  53. package/dist/completion-model.d.ts +51 -0
  54. package/dist/completion-model.js +353 -0
  55. package/dist/completion.d.ts +43 -0
  56. package/dist/completion.js +463 -0
  57. package/dist/conflict-model.d.ts +15 -0
  58. package/dist/conflict-model.js +36 -0
  59. package/dist/context-menu.d.ts +10 -0
  60. package/dist/context-menu.js +55 -0
  61. package/dist/definition-link.d.ts +14 -0
  62. package/dist/definition-link.js +99 -0
  63. package/dist/diagnostics-model.d.ts +15 -0
  64. package/dist/diagnostics-model.js +83 -0
  65. package/dist/diagnostics.d.ts +23 -0
  66. package/dist/diagnostics.js +95 -0
  67. package/dist/editor-language.d.ts +65 -0
  68. package/dist/editor-language.js +170 -0
  69. package/dist/editor-react.css +43 -0
  70. package/dist/find-query.d.ts +26 -0
  71. package/dist/find-query.js +51 -0
  72. package/dist/folding.d.ts +16 -0
  73. package/dist/folding.js +95 -0
  74. package/dist/highlight-layers.d.ts +10 -0
  75. package/dist/highlight-layers.js +30 -0
  76. package/dist/highlights.d.ts +16 -0
  77. package/dist/highlights.js +102 -0
  78. package/dist/history.d.ts +8 -0
  79. package/dist/history.js +46 -0
  80. package/dist/holder.d.ts +5 -0
  81. package/dist/holder.js +19 -0
  82. package/dist/host-types.d.ts +45 -0
  83. package/dist/host-types.js +1 -0
  84. package/dist/hover-content.d.ts +45 -0
  85. package/dist/hover-content.js +198 -0
  86. package/dist/hover.d.ts +32 -0
  87. package/dist/hover.js +260 -0
  88. package/dist/index.d.ts +44 -0
  89. package/dist/index.js +28 -0
  90. package/dist/inlay-hints.d.ts +13 -0
  91. package/dist/inlay-hints.js +71 -0
  92. package/dist/language-ids.d.ts +3 -0
  93. package/dist/language-ids.js +49 -0
  94. package/dist/line-edits.d.ts +8 -0
  95. package/dist/line-edits.js +39 -0
  96. package/dist/locales/en.json +171 -0
  97. package/dist/locales/nl.json +171 -0
  98. package/dist/models.d.ts +20 -0
  99. package/dist/models.js +20 -0
  100. package/dist/navigation-history.d.ts +16 -0
  101. package/dist/navigation-history.js +53 -0
  102. package/dist/navigation.d.ts +23 -0
  103. package/dist/navigation.js +155 -0
  104. package/dist/paths.d.ts +1 -0
  105. package/dist/paths.js +3 -0
  106. package/dist/peek-model.d.ts +28 -0
  107. package/dist/peek-model.js +104 -0
  108. package/dist/peek.d.ts +30 -0
  109. package/dist/peek.js +215 -0
  110. package/dist/pick.d.ts +34 -0
  111. package/dist/pick.js +166 -0
  112. package/dist/popup-placement.d.ts +23 -0
  113. package/dist/popup-placement.js +34 -0
  114. package/dist/popups.d.ts +133 -0
  115. package/dist/popups.js +14 -0
  116. package/dist/project-language.d.ts +36 -0
  117. package/dist/project-language.js +190 -0
  118. package/dist/project-problems.d.ts +24 -0
  119. package/dist/project-problems.js +63 -0
  120. package/dist/proposal-model.d.ts +36 -0
  121. package/dist/proposal-model.js +197 -0
  122. package/dist/recent-choices.d.ts +10 -0
  123. package/dist/recent-choices.js +39 -0
  124. package/dist/refresher.d.ts +13 -0
  125. package/dist/refresher.js +50 -0
  126. package/dist/relative-time.d.ts +1 -0
  127. package/dist/relative-time.js +9 -0
  128. package/dist/rename-model.d.ts +25 -0
  129. package/dist/rename-model.js +93 -0
  130. package/dist/rename.d.ts +21 -0
  131. package/dist/rename.js +257 -0
  132. package/dist/rendering-context.d.ts +6 -0
  133. package/dist/rendering-context.js +5 -0
  134. package/dist/rendering.d.ts +6 -0
  135. package/dist/rendering.js +5 -0
  136. package/dist/review-group.d.ts +16 -0
  137. package/dist/review-group.js +54 -0
  138. package/dist/row-host.d.ts +42 -0
  139. package/dist/row-host.js +120 -0
  140. package/dist/selection-ranges.d.ts +7 -0
  141. package/dist/selection-ranges.js +26 -0
  142. package/dist/semantic-model.d.ts +4 -0
  143. package/dist/semantic-model.js +76 -0
  144. package/dist/semantic-tokens.d.ts +6 -0
  145. package/dist/semantic-tokens.js +38 -0
  146. package/dist/shortcut-keys.d.ts +91 -0
  147. package/dist/shortcut-keys.js +12 -0
  148. package/dist/signature-model.d.ts +18 -0
  149. package/dist/signature-model.js +33 -0
  150. package/dist/signature.d.ts +22 -0
  151. package/dist/signature.js +150 -0
  152. package/dist/snippet-session.d.ts +17 -0
  153. package/dist/snippet-session.js +110 -0
  154. package/dist/snippet.d.ts +11 -0
  155. package/dist/snippet.js +134 -0
  156. package/dist/symbol-links.d.ts +6 -0
  157. package/dist/symbol-links.js +50 -0
  158. package/dist/symbol-picker-model.d.ts +44 -0
  159. package/dist/symbol-picker-model.js +146 -0
  160. package/dist/symbol-picker.d.ts +12 -0
  161. package/dist/symbol-picker.js +76 -0
  162. package/dist/symbols.d.ts +11 -0
  163. package/dist/symbols.js +95 -0
  164. package/dist/testing.d.ts +57 -0
  165. package/dist/testing.js +156 -0
  166. package/dist/timers.d.ts +14 -0
  167. package/dist/timers.js +34 -0
  168. package/dist/use-problem-counts.d.ts +3 -0
  169. package/dist/use-problem-counts.js +20 -0
  170. package/dist/view-state.d.ts +21 -0
  171. package/dist/view-state.js +63 -0
  172. package/dist/word-diff.d.ts +1 -0
  173. package/dist/word-diff.js +32 -0
  174. package/dist/workspace-edit.d.ts +21 -0
  175. package/dist/workspace-edit.js +147 -0
  176. package/package.json +74 -2
  177. package/src/AnchoredPopup.tsx +51 -0
  178. package/src/AttributionCard.tsx +36 -0
  179. package/src/BaselineStatus.tsx +20 -0
  180. package/src/ChangeReview.tsx +43 -0
  181. package/src/CodeAuthorsCard.tsx +81 -0
  182. package/src/CompletionPopup.tsx +196 -0
  183. package/src/EditorContextMenu.tsx +67 -0
  184. package/src/EditorView.tsx +47 -0
  185. package/src/FindReplace.tsx +89 -0
  186. package/src/HoverCard.tsx +121 -0
  187. package/src/HoverSections.tsx +146 -0
  188. package/src/LanguagePopups.tsx +65 -0
  189. package/src/Markdown.tsx +11 -0
  190. package/src/PathText.tsx +18 -0
  191. package/src/PeekPanel.tsx +222 -0
  192. package/src/PickPopup.tsx +102 -0
  193. package/src/RenameCard.tsx +219 -0
  194. package/src/SignatureCard.tsx +42 -0
  195. package/src/SymbolPicker.tsx +219 -0
  196. package/src/code-actions-model.ts +146 -0
  197. package/src/code-actions.ts +384 -0
  198. package/src/code-authors.ts +104 -0
  199. package/src/code-vision-model.ts +230 -0
  200. package/src/code-vision.ts +269 -0
  201. package/src/completion-call.ts +139 -0
  202. package/src/completion-model.ts +440 -0
  203. package/src/completion.ts +500 -0
  204. package/src/conflict-model.ts +56 -0
  205. package/src/context-menu.ts +63 -0
  206. package/src/definition-link.ts +106 -0
  207. package/src/diagnostics-model.ts +102 -0
  208. package/src/diagnostics.ts +117 -0
  209. package/src/editor-language.ts +189 -0
  210. package/src/editor-react.css +43 -0
  211. package/src/find-query.ts +74 -0
  212. package/src/folding.ts +110 -0
  213. package/src/highlight-layers.ts +37 -0
  214. package/src/highlights.ts +123 -0
  215. package/src/history.ts +56 -0
  216. package/src/holder.ts +19 -0
  217. package/src/host-types.ts +52 -0
  218. package/src/hover-content.ts +264 -0
  219. package/src/hover.ts +280 -0
  220. package/src/index.ts +63 -0
  221. package/src/inlay-hints.ts +85 -0
  222. package/src/language-ids.ts +54 -0
  223. package/src/line-edits.ts +48 -0
  224. package/src/locales/en.json +171 -0
  225. package/src/locales/nl.json +171 -0
  226. package/src/models.ts +157 -0
  227. package/src/navigation-history.ts +69 -0
  228. package/src/navigation.ts +168 -0
  229. package/src/paths.ts +3 -0
  230. package/src/peek-model.ts +147 -0
  231. package/src/peek.ts +247 -0
  232. package/src/pick.ts +197 -0
  233. package/src/popup-placement.ts +64 -0
  234. package/src/popups.ts +204 -0
  235. package/src/project-language.ts +223 -0
  236. package/src/project-problems.ts +87 -0
  237. package/src/proposal-model.ts +259 -0
  238. package/src/recent-choices.ts +48 -0
  239. package/src/refresher.ts +56 -0
  240. package/src/relative-time.ts +10 -0
  241. package/src/rename-model.ts +130 -0
  242. package/src/rename.ts +290 -0
  243. package/src/rendering-context.ts +12 -0
  244. package/src/rendering.tsx +6 -0
  245. package/src/review-group.ts +70 -0
  246. package/src/row-host.ts +158 -0
  247. package/src/selection-ranges.ts +32 -0
  248. package/src/semantic-model.ts +80 -0
  249. package/src/semantic-tokens.ts +46 -0
  250. package/src/shortcut-keys.ts +21 -0
  251. package/src/signature-model.ts +49 -0
  252. package/src/signature.ts +164 -0
  253. package/src/snippet-session.ts +122 -0
  254. package/src/snippet.ts +147 -0
  255. package/src/symbol-links.ts +72 -0
  256. package/src/symbol-picker-model.ts +198 -0
  257. package/src/symbol-picker.ts +85 -0
  258. package/src/symbols.ts +110 -0
  259. package/src/testing.ts +240 -0
  260. package/src/timers.ts +45 -0
  261. package/src/use-problem-counts.ts +25 -0
  262. package/src/view-state.ts +88 -0
  263. package/src/word-diff.ts +35 -0
  264. package/src/workspace-edit.ts +194 -0
@@ -0,0 +1,133 @@
1
+ import { type StoreApi } from 'zustand';
2
+ import type { EditorPosition, EditorRange, EditorRect } from '@adecore/editor';
3
+ import type { Location } from '@adecore/lsp';
4
+ import type { CodeAuthorship } from './code-authors.ts';
5
+ import type { Problem } from './diagnostics-model.ts';
6
+ import type { PeekFile, PeekSnippet } from './peek-model.ts';
7
+ import type { ActionEntry } from './code-actions-model.ts';
8
+ import type { SymbolEntry } from './symbol-picker-model.ts';
9
+ import type { HoverText } from './hover-content.ts';
10
+ import type { SignatureViewModel } from './signature-model.ts';
11
+ export interface HoverView {
12
+ readonly anchor: EditorPosition;
13
+ readonly position: EditorPosition;
14
+ readonly subject: EditorRange;
15
+ readonly problems: readonly Problem[];
16
+ readonly info: HoverInfo | null;
17
+ }
18
+ export interface HoverInfo {
19
+ readonly text: HoverText;
20
+ readonly definition: Location | null;
21
+ readonly word: string;
22
+ readonly references: number | null;
23
+ }
24
+ export interface CompletionRow {
25
+ readonly label: string;
26
+ readonly kind: number | undefined;
27
+ readonly detail: string;
28
+ readonly description: string;
29
+ readonly matches: readonly number[];
30
+ readonly deprecated: boolean;
31
+ }
32
+ export interface CompletionDocs {
33
+ readonly source: string;
34
+ readonly text: HoverText;
35
+ }
36
+ export interface CompletionView {
37
+ readonly anchor: EditorPosition;
38
+ readonly rows: readonly CompletionRow[];
39
+ readonly active: number;
40
+ readonly detailsOpen: boolean;
41
+ readonly docs: CompletionDocs | null;
42
+ readonly server: string;
43
+ readonly highlightLanguage: string;
44
+ }
45
+ export interface SignatureView {
46
+ readonly anchor: EditorPosition;
47
+ readonly model: SignatureViewModel;
48
+ }
49
+ export interface PickRow {
50
+ readonly id: string;
51
+ readonly label: string;
52
+ readonly detail: string;
53
+ readonly path?: boolean;
54
+ }
55
+ export interface PickGroup {
56
+ readonly title: string | null;
57
+ readonly rows: readonly PickRow[];
58
+ }
59
+ export interface PickPreview {
60
+ readonly removed: readonly string[];
61
+ readonly added: readonly string[];
62
+ readonly note: string | null;
63
+ readonly refusal?: string;
64
+ }
65
+ export interface PickView {
66
+ readonly anchor: EditorPosition;
67
+ readonly groups: readonly PickGroup[];
68
+ readonly active: string;
69
+ readonly preview: PickPreview | null;
70
+ readonly title: string | null;
71
+ }
72
+ export interface RenameFileView {
73
+ readonly uri: string;
74
+ readonly rows: readonly {
75
+ readonly line: number;
76
+ readonly before: string;
77
+ readonly after: string;
78
+ }[];
79
+ }
80
+ export interface RenameView {
81
+ readonly phase: 'input' | 'preview';
82
+ readonly range: EditorRange;
83
+ readonly original: string;
84
+ readonly placeholder: string;
85
+ readonly occurrences: {
86
+ readonly count: number;
87
+ readonly files: number;
88
+ } | null;
89
+ readonly busy: boolean;
90
+ readonly error: string | null;
91
+ readonly name: string;
92
+ readonly files: readonly RenameFileView[];
93
+ readonly suggestions: readonly string[];
94
+ }
95
+ export interface PeekView {
96
+ readonly kind: 'references' | 'definitions';
97
+ readonly container: HTMLElement | null;
98
+ readonly files: readonly PeekFile[];
99
+ readonly active: string;
100
+ readonly collapsed: readonly string[];
101
+ readonly count: number;
102
+ readonly preview: (PeekSnippet & {
103
+ readonly uri: string;
104
+ }) | null;
105
+ }
106
+ export interface SymbolsView {
107
+ readonly file: string;
108
+ readonly entries: readonly SymbolEntry[];
109
+ }
110
+ export interface MenuView {
111
+ readonly x: number;
112
+ readonly y: number;
113
+ readonly refactors: readonly ActionEntry[];
114
+ }
115
+ export interface AuthorsView {
116
+ readonly anchor: EditorRect;
117
+ readonly name: string;
118
+ readonly authorship: CodeAuthorship;
119
+ readonly openCommit: (() => void) | null;
120
+ }
121
+ export interface PopupState {
122
+ readonly hover: HoverView | null;
123
+ readonly completion: CompletionView | null;
124
+ readonly signature: SignatureView | null;
125
+ readonly pick: PickView | null;
126
+ readonly rename: RenameView | null;
127
+ readonly peek: PeekView | null;
128
+ readonly symbols: SymbolsView | null;
129
+ readonly menu: MenuView | null;
130
+ readonly authors: AuthorsView | null;
131
+ }
132
+ export type PopupStore = StoreApi<PopupState>;
133
+ export declare function createPopupStore(): PopupStore;
package/dist/popups.js ADDED
@@ -0,0 +1,14 @@
1
+ import { createStore } from 'zustand';
2
+ export function createPopupStore() {
3
+ return createStore(() => ({
4
+ hover: null,
5
+ completion: null,
6
+ signature: null,
7
+ pick: null,
8
+ rename: null,
9
+ peek: null,
10
+ symbols: null,
11
+ menu: null,
12
+ authors: null
13
+ }));
14
+ }
@@ -0,0 +1,36 @@
1
+ import { type i18n } from 'i18next';
2
+ import { type ApplyWorkspaceEditResult, type LanguageService, type WorkspaceEdit } from '@adecore/lsp';
3
+ import type { Editor, EditorPosition } from '@adecore/editor';
4
+ import { NavigationHistory, type Place } from './navigation-history.ts';
5
+ import { ProjectProblems } from './project-problems.ts';
6
+ import type { LanguageHost } from './host-types.ts';
7
+ export interface LanguageDocumentHandle {
8
+ readonly uri: string;
9
+ readonly service: LanguageService;
10
+ readonly ready: Promise<void>;
11
+ release(): void;
12
+ }
13
+ export declare class ProjectLanguage {
14
+ readonly service: LanguageService;
15
+ readonly host: LanguageHost;
16
+ readonly i18n: i18n;
17
+ readonly folder: string;
18
+ readonly problems: ProjectProblems;
19
+ readonly history: NavigationHistory;
20
+ private readonly holders;
21
+ private readonly files;
22
+ private pendingCaret;
23
+ private lastPlace;
24
+ private disposed;
25
+ constructor(service: LanguageService, host?: LanguageHost);
26
+ pathOfLocation(uri: string): string | null;
27
+ applyWorkspaceEdit(edit: WorkspaceEdit): Promise<ApplyWorkspaceEditResult>;
28
+ readText(uri: string): Promise<string | null>;
29
+ openPlace(place: Place): void;
30
+ noteCaret(place: Place): void;
31
+ jumpTo(place: Place): void;
32
+ takeCaret(uri: string, line: number): EditorPosition | null;
33
+ acquire(uri: string, languageId: string, editor: Editor): LanguageDocumentHandle;
34
+ private release;
35
+ dispose(): void;
36
+ }
@@ -0,0 +1,190 @@
1
+ import i18next, {} from 'i18next';
2
+ import { fileUriToPath } from '@adecore/lsp';
3
+ import { NavigationHistory } from './navigation-history.js';
4
+ import { ProjectProblems } from './project-problems.js';
5
+ import { applyWorkspaceEdit } from './workspace-edit.js';
6
+ class DocumentSync {
7
+ ready;
8
+ pending = [];
9
+ opened = false;
10
+ disposed = false;
11
+ stop;
12
+ service;
13
+ uri;
14
+ editor;
15
+ constructor(service, uri, languageId, editor) {
16
+ this.service = service;
17
+ this.uri = uri;
18
+ this.editor = editor;
19
+ this.stop = editor.onTextChange((change) => this.changed(change.changes));
20
+ this.ready = service.openDocument({ uri, languageId, text: editor.getText() }).then(() => {
21
+ this.opened = true;
22
+ if (!this.disposed) {
23
+ this.flush();
24
+ }
25
+ });
26
+ // A failed open is also a document nothing can be asked of; the features' own requests say so.
27
+ this.ready.catch(() => undefined);
28
+ }
29
+ changed(changes) {
30
+ this.pending.push(...changes);
31
+ if (this.opened) {
32
+ this.flush();
33
+ }
34
+ }
35
+ flush() {
36
+ if (this.pending.length === 0) {
37
+ return;
38
+ }
39
+ const changes = this.pending;
40
+ this.pending = [];
41
+ void this.service.changeDocument(this.uri, changes).catch(() => undefined);
42
+ }
43
+ dispose() {
44
+ this.disposed = true;
45
+ this.pending = [];
46
+ this.stop();
47
+ }
48
+ get text() {
49
+ return this.editor.getText();
50
+ }
51
+ }
52
+ /*
53
+ * A shared language service and document ownership for the editors of a project. Two editors on the same
54
+ * file hold one document, and only the first one sends changes, since both would report the same edit.
55
+ */
56
+ export class ProjectLanguage {
57
+ service;
58
+ host;
59
+ i18n;
60
+ folder;
61
+ problems;
62
+ history = new NavigationHistory();
63
+ holders = new Map();
64
+ files;
65
+ pendingCaret = null;
66
+ lastPlace = null;
67
+ disposed = false;
68
+ constructor(service, host = {}) {
69
+ this.service = service;
70
+ this.host = host;
71
+ this.i18n = host.i18n ?? i18next;
72
+ this.folder = host.folder ?? '';
73
+ this.files = host.files ?? null;
74
+ this.problems = new ProjectProblems(service, (uri) => this.pathOfLocation(uri) ?? uri);
75
+ }
76
+ pathOfLocation(uri) {
77
+ if (this.host.pathOfUri !== undefined) {
78
+ return this.host.pathOfUri(uri);
79
+ }
80
+ const path = fileUriToPath(uri);
81
+ return path !== null && this.folder !== '' && path.startsWith(`${this.folder}/`) ? path.slice(this.folder.length + 1) : path;
82
+ }
83
+ /* Makes an edit of a language server: an open document takes it as one undo step and any other file gets an unsaved draft. */
84
+ applyWorkspaceEdit(edit) {
85
+ return applyWorkspaceEdit(edit, { editorOf: (uri) => this.holders.get(uri)?.editors[0], files: this.files });
86
+ }
87
+ /* The text of a file as it stands now: an open document's, else a draft's or the machine's; null when it is no text file. */
88
+ async readText(uri) {
89
+ const open = this.holders.get(uri)?.sync.text;
90
+ if (open !== undefined) {
91
+ return open;
92
+ }
93
+ const path = fileUriToPath(uri);
94
+ return path === null || this.files === null ? null : ((await this.files.read(path))?.text ?? null);
95
+ }
96
+ /*
97
+ * Opens the file of a place on its line. A file opens on a line only, so the column is kept here until the editor
98
+ * that shows the line asks for it with `takeCaret`.
99
+ */
100
+ openPlace(place) {
101
+ this.pendingCaret = place;
102
+ this.host.openPlace?.(place);
103
+ }
104
+ /* Where an editor's caret stands now, so a jump from a surface without an editor, such as the Problems panel, still knows what it left. */
105
+ noteCaret(place) {
106
+ this.lastPlace = place;
107
+ }
108
+ /* Opens a place from outside any editor and remembers the caret that was last seen. */
109
+ jumpTo(place) {
110
+ if (this.lastPlace !== null) {
111
+ this.history.record(this.lastPlace);
112
+ }
113
+ this.openPlace(place);
114
+ }
115
+ /* The column an opened place waits for, once the editor of its file has put its caret on the line; each place is asked for once. */
116
+ takeCaret(uri, line) {
117
+ const pending = this.pendingCaret;
118
+ if (pending === null || pending.uri !== uri || pending.position.line !== line) {
119
+ return null;
120
+ }
121
+ this.pendingCaret = null;
122
+ return pending.position;
123
+ }
124
+ /* Opens `uri` for the editor, or joins the editors that already hold it. */
125
+ acquire(uri, languageId, editor) {
126
+ if (this.disposed) {
127
+ throw new Error('The project language is disposed');
128
+ }
129
+ let holder = this.holders.get(uri);
130
+ if (holder === undefined) {
131
+ holder = { editors: [], sync: new DocumentSync(this.service, uri, languageId, editor), languageId };
132
+ this.holders.set(uri, holder);
133
+ }
134
+ holder.editors.push(editor);
135
+ let released = false;
136
+ return {
137
+ uri,
138
+ service: this.service,
139
+ get ready() {
140
+ return holder.sync.ready;
141
+ },
142
+ release: () => {
143
+ if (!released) {
144
+ released = true;
145
+ this.release(uri, editor);
146
+ }
147
+ }
148
+ };
149
+ }
150
+ release(uri, editor) {
151
+ const holder = this.holders.get(uri);
152
+ if (holder === undefined) {
153
+ return;
154
+ }
155
+ holder.editors.splice(holder.editors.indexOf(editor), 1);
156
+ const next = holder.editors[0];
157
+ if (next === undefined) {
158
+ holder.sync.dispose();
159
+ this.holders.delete(uri);
160
+ void holder.sync.ready
161
+ .catch(() => undefined)
162
+ .then(() => {
163
+ if (!this.holders.has(uri)) {
164
+ return this.service.closeDocument(uri);
165
+ }
166
+ })
167
+ .catch(() => undefined);
168
+ }
169
+ else if (holder.sync.editor === editor) {
170
+ // The editor that sent the changes is gone; the next one takes over and opens the document with its own text.
171
+ holder.sync.dispose();
172
+ holder.sync = new DocumentSync(this.service, uri, holder.languageId, next);
173
+ }
174
+ }
175
+ dispose() {
176
+ if (this.disposed) {
177
+ return;
178
+ }
179
+ this.disposed = true;
180
+ for (const [uri, holder] of this.holders) {
181
+ holder.sync.dispose();
182
+ void holder.sync.ready
183
+ .catch(() => undefined)
184
+ .then(() => this.service.closeDocument(uri))
185
+ .catch(() => undefined);
186
+ }
187
+ this.holders.clear();
188
+ this.problems.dispose();
189
+ }
190
+ }
@@ -0,0 +1,24 @@
1
+ import type { Diagnostic } from '@adecore/lsp';
2
+ import type { LanguageService } from '@adecore/lsp';
3
+ import type { ProblemCounts } from './diagnostics.ts';
4
+ export interface ProblemRow {
5
+ readonly diagnostic: Diagnostic;
6
+ readonly server: string;
7
+ }
8
+ export interface ProblemFile {
9
+ readonly path: string;
10
+ readonly rows: readonly ProblemRow[];
11
+ }
12
+ export declare function compareRows(left: ProblemRow, right: ProblemRow): number;
13
+ export declare class ProjectProblems {
14
+ private readonly reports;
15
+ private readonly listeners;
16
+ private readonly stop;
17
+ private snapshot;
18
+ constructor(service: LanguageService, pathOf?: (uri: string) => string);
19
+ report(path: string, server: string, diagnostics: readonly Diagnostic[]): void;
20
+ getSnapshot: () => readonly ProblemFile[];
21
+ subscribe: (listener: () => void) => (() => void);
22
+ dispose(): void;
23
+ }
24
+ export declare function countsOf(files: readonly ProblemFile[]): ProblemCounts;
@@ -0,0 +1,63 @@
1
+ import { comparePositions, severityOf } from './diagnostics-model.js';
2
+ const SEVERITY_ORDER = { error: 0, warning: 1, info: 2, hint: 3 };
3
+ /* Worst first, then in the order of the file. */
4
+ export function compareRows(left, right) {
5
+ return (SEVERITY_ORDER[severityOf(left.diagnostic)] - SEVERITY_ORDER[severityOf(right.diagnostic)] ||
6
+ comparePositions(left.diagnostic.range.start, right.diagnostic.range.start));
7
+ }
8
+ /*
9
+ * Each report replaces the previous diagnostics from that source for the file. Files with no
10
+ * remaining problems drop out. Hints remain editor annotations rather than listed problems.
11
+ */
12
+ export class ProjectProblems {
13
+ reports = new Map();
14
+ listeners = new Set();
15
+ stop;
16
+ snapshot = [];
17
+ constructor(service, pathOf = (uri) => uri) {
18
+ const subscription = service.onDiagnostics((report) => this.report(pathOf(report.uri), report.source, report.diagnostics));
19
+ this.stop = () => subscription.dispose();
20
+ }
21
+ report(path, server, diagnostics) {
22
+ const kept = diagnostics.filter((diagnostic) => severityOf(diagnostic) !== 'hint');
23
+ const servers = this.reports.get(path) ?? new Map();
24
+ if (kept.length === 0) {
25
+ servers.delete(server);
26
+ }
27
+ else {
28
+ servers.set(server, kept);
29
+ }
30
+ if (servers.size === 0) {
31
+ this.reports.delete(path);
32
+ }
33
+ else {
34
+ this.reports.set(path, servers);
35
+ }
36
+ this.snapshot = [...this.reports]
37
+ .map(([file, byServer]) => ({
38
+ path: file,
39
+ rows: [...byServer].flatMap(([name, list]) => list.map((diagnostic) => ({ diagnostic, server: name }))).sort(compareRows)
40
+ }))
41
+ .sort((left, right) => left.path.localeCompare(right.path));
42
+ for (const listener of [...this.listeners]) {
43
+ listener();
44
+ }
45
+ }
46
+ /* The same array until the next report, which is what a store a component reads must hand out. */
47
+ getSnapshot = () => this.snapshot;
48
+ subscribe = (listener) => {
49
+ this.listeners.add(listener);
50
+ return () => {
51
+ this.listeners.delete(listener);
52
+ };
53
+ };
54
+ dispose() {
55
+ this.stop();
56
+ this.listeners.clear();
57
+ }
58
+ }
59
+ export function countsOf(files) {
60
+ const rows = files.flatMap((file) => file.rows);
61
+ const count = (severity) => rows.filter((row) => (row.diagnostic.severity ?? 1) === severity).length;
62
+ return { error: count(1), warning: count(2), info: count(3) };
63
+ }
@@ -0,0 +1,36 @@
1
+ import type { EditorPosition, EditorRange } from '@adecore/editor';
2
+ export interface LineSpan {
3
+ readonly startLine: number;
4
+ readonly endLine: number;
5
+ }
6
+ export declare function lineSpanOf(range: EditorRange): LineSpan;
7
+ export declare function isEmptyRange(range: EditorRange): boolean;
8
+ export declare function inlineRangeOf(selection: EditorRange, lineLength: (line: number) => number): EditorRange;
9
+ export interface InlineProblem {
10
+ readonly line: number;
11
+ readonly severity: 'error' | 'warning' | 'info' | 'hint';
12
+ readonly message: string;
13
+ readonly code: string;
14
+ }
15
+ export declare function problemsOnLines<T extends {
16
+ range: EditorRange;
17
+ }>(diagnostics: readonly T[], span: LineSpan, describe: (diagnostic: T) => Omit<InlineProblem, 'line'>): InlineProblem[];
18
+ export interface InlineAnswer {
19
+ readonly replacement: string | null;
20
+ readonly rest: string;
21
+ }
22
+ export declare function parseAnswer(text: string): InlineAnswer;
23
+ export declare function fitReplacement(selected: string, replacement: string): string;
24
+ export declare function endOfInsertion(start: EditorPosition, text: string): EditorPosition;
25
+ export interface DiffSegment {
26
+ readonly kind: 'same' | 'added' | 'removed';
27
+ readonly text: string;
28
+ readonly firstLine?: number;
29
+ readonly replaces?: string;
30
+ }
31
+ export declare function diffSegments(selected: string, proposal: string, startLine: number): DiffSegment[];
32
+ export declare function emphasisOf(segment: DiffSegment): Array<Array<[number, number]>> | undefined;
33
+ export declare function offsetOf(text: string, position: EditorPosition): number | null;
34
+ export declare function textInRange(text: string, range: EditorRange): string | null;
35
+ export declare function replaceRange(text: string, range: EditorRange, replacement: string): string | null;
36
+ export declare function locateSelection(text: string, range: EditorRange, selected: string): EditorRange | null;