@adecore/editor-react 0.17.0-beta.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.
- package/LICENSE +1 -1
- package/README.md +35 -30
- package/dist/EditorView.d.ts +3 -2
- package/dist/EditorView.js +2 -2
- package/dist/LanguagePopups.d.ts +3 -1
- package/dist/LanguagePopups.js +3 -3
- package/dist/code-actions.d.ts +1 -0
- package/dist/code-actions.js +19 -22
- package/dist/code-authors.d.ts +2 -1
- package/dist/code-authors.js +2 -3
- package/dist/code-vision-model.d.ts +2 -1
- package/dist/code-vision-model.js +3 -4
- package/dist/code-vision.js +12 -10
- package/dist/completion.js +1 -2
- package/dist/editor-language.d.ts +1 -0
- package/dist/editor-language.js +22 -0
- package/dist/folding.js +3 -5
- package/dist/history.js +1 -2
- package/dist/host-types.d.ts +2 -0
- package/dist/hover.js +1 -2
- package/dist/inlay-hints.js +3 -5
- package/dist/navigation.d.ts +1 -0
- package/dist/navigation.js +8 -9
- package/dist/peek.d.ts +1 -0
- package/dist/peek.js +6 -7
- package/dist/project-language.d.ts +2 -0
- package/dist/project-language.js +3 -0
- package/dist/rename.d.ts +1 -0
- package/dist/rename.js +10 -11
- package/dist/semantic-tokens.js +3 -5
- package/dist/symbol-picker.js +2 -3
- package/dist/symbols.js +3 -5
- package/package.json +5 -5
- package/src/EditorView.tsx +5 -3
- package/src/LanguagePopups.tsx +8 -4
- package/src/code-actions.ts +20 -23
- package/src/code-authors.ts +3 -3
- package/src/code-vision-model.ts +4 -4
- package/src/code-vision.ts +12 -10
- package/src/completion.ts +1 -2
- package/src/editor-language.ts +26 -0
- package/src/folding.ts +3 -5
- package/src/history.ts +1 -2
- package/src/host-types.ts +3 -0
- package/src/hover.ts +1 -2
- package/src/inlay-hints.ts +3 -5
- package/src/navigation.ts +9 -10
- package/src/peek.ts +7 -8
- package/src/project-language.ts +3 -0
- package/src/rename.ts +11 -12
- package/src/semantic-tokens.ts +3 -5
- package/src/symbol-picker.ts +2 -3
- package/src/symbols.ts +3 -5
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,55 +1,60 @@
|
|
|
1
1
|
# @adecore/editor-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@adecore/editor-react)
|
|
4
|
+
[](https://adecore.dev/editor-react/)
|
|
4
5
|
|
|
5
|
-
Language
|
|
6
|
+
Language features for [`@adecore/editor`](https://adecore.dev/editor/) over a `LanguageService` of [`@adecore/lsp`](https://adecore.dev/lsp/): suggestions and snippets, hover, signature help, problems, navigation, peek, rename, code actions, symbols, semantic colors, inlay hints, folds and code vision, with the React cards that show them. It starts no language server and touches no file; the app hands it a service and the file operations it allows.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
**[Documentation with live demos](https://adecore.dev/editor-react/)**
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
import { createSmartEditorEngine } from '@adecore/editor';
|
|
11
|
-
import { resolveKeymap } from '@adecore/editor/keymap';
|
|
12
|
-
import { EditorView, ProjectLanguage } from '@adecore/editor-react';
|
|
10
|
+
## Install
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const project = new ProjectLanguage(service, { keymap, apple: false, openPlace });
|
|
17
|
-
const options = { text: 'const greeting = "Hello";', language: 'typescript', theme: 'github-light' };
|
|
18
|
-
|
|
19
|
-
// Render inside a parent with a height; dispose the project when its owner closes it.
|
|
20
|
-
<EditorView engine={engine} options={options} project={project} uri="file:///example.ts" languageId="typescript" className="h-72" />;
|
|
12
|
+
```sh
|
|
13
|
+
bun add @adecore/editor-react
|
|
21
14
|
```
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
## CSS and translations
|
|
16
|
+
`@adecore/ui`, React 19, `react-dom`, `i18next` and `react-i18next` are peer dependencies.
|
|
26
17
|
|
|
27
|
-
|
|
18
|
+
## Set up
|
|
28
19
|
|
|
29
20
|
```css
|
|
30
21
|
@import '@adecore/ui/theme.css';
|
|
31
22
|
@import '@adecore/editor/editor.css';
|
|
32
23
|
@import '@adecore/editor-react/editor-react.css';
|
|
33
|
-
@source "../node_modules/@adecore/
|
|
34
|
-
@source "../node_modules/@adecore/editor-react/src";
|
|
24
|
+
@source "../node_modules/@adecore/editor-react/dist";
|
|
35
25
|
```
|
|
36
26
|
|
|
37
|
-
|
|
27
|
+
Add `@adecore/editor-react/locales/en.json` and `nl.json` to i18next as the `editor` namespace, then:
|
|
38
28
|
|
|
39
|
-
|
|
29
|
+
```tsx
|
|
30
|
+
import { EditorView, ProjectLanguage } from '@adecore/editor-react';
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
const project = new ProjectLanguage(service, { folder, keymap, openPlace, files, notify });
|
|
42
33
|
|
|
43
|
-
|
|
34
|
+
<EditorView engine={engine} options={options} project={project} uri={uri} languageId="typescript" className="h-96" />;
|
|
35
|
+
```
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
## Entry points
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
| Import | What it holds |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `@adecore/editor-react` | The components, `ProjectLanguage`, `EditorLanguage` and every model |
|
|
42
|
+
| `@adecore/editor-react/models` | The pure models, without React |
|
|
43
|
+
| `@adecore/editor-react/testing` | `FakeLanguageService` and `ManualTimers` |
|
|
44
|
+
| `@adecore/editor-react/editor-react.css` | The styles of the cards |
|
|
45
|
+
| `@adecore/editor-react/locales/*.json` | The words, in English and Dutch |
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
## Documentation
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
| Page | What it covers |
|
|
50
|
+
|---|---|
|
|
51
|
+
| [Getting started](https://adecore.dev/editor-react/getting-started) | Install, styles, words and a first editor |
|
|
52
|
+
| [Projects and documents](https://adecore.dev/editor-react/project) | `ProjectLanguage`, the host, shared documents and workspace edits |
|
|
53
|
+
| [EditorView](https://adecore.dev/editor-react/editor-view) | The component, `EditorLanguage` and the popups |
|
|
54
|
+
| [Views](https://adecore.dev/editor-react/completion) | A page per feature with a live demo, in the sidebar |
|
|
55
|
+
| [Models](https://adecore.dev/editor-react/models) | The pure functions behind the features |
|
|
56
|
+
| [Testing](https://adecore.dev/editor-react/testing) | `FakeLanguageService` and `ManualTimers` |
|
|
52
57
|
|
|
53
|
-
|
|
58
|
+
## License
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
FSL-1.1-MIT
|
package/dist/EditorView.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Ref } from 'react';
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
2
|
import type { Editor, EditorEngine, EditorOptions } from '@adecore/editor';
|
|
3
3
|
import { EditorLanguage } from './editor-language.ts';
|
|
4
4
|
import type { ProjectLanguage } from './project-language.ts';
|
|
@@ -11,5 +11,6 @@ export interface EditorViewProps {
|
|
|
11
11
|
className?: string;
|
|
12
12
|
ref?: Ref<HTMLDivElement>;
|
|
13
13
|
onMount?(editor: Editor, language: EditorLanguage | null): void | (() => void);
|
|
14
|
+
contextMenuItems?(language: EditorLanguage): ReactNode;
|
|
14
15
|
}
|
|
15
|
-
export declare function EditorView({ engine, options, project, uri, languageId, className, ref, onMount }: EditorViewProps): import("react").JSX.Element;
|
|
16
|
+
export declare function EditorView({ engine, options, project, uri, languageId, className, ref, onMount, contextMenuItems }: EditorViewProps): import("react").JSX.Element;
|
package/dist/EditorView.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createHolder } from './holder.js';
|
|
|
3
3
|
import { useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
4
4
|
import { EditorLanguage } from './editor-language.js';
|
|
5
5
|
import { LanguagePopups } from './LanguagePopups.js';
|
|
6
|
-
export function EditorView({ engine, options, project, uri, languageId, className, ref, onMount }) {
|
|
6
|
+
export function EditorView({ engine, options, project, uri, languageId, className, ref, onMount, contextMenuItems }) {
|
|
7
7
|
const element = useRef(null);
|
|
8
8
|
const holder = useMemo(() => createHolder(), []);
|
|
9
9
|
const language = useSyncExternalStore(holder.subscribe, holder.get, holder.get);
|
|
@@ -23,5 +23,5 @@ export function EditorView({ engine, options, project, uri, languageId, classNam
|
|
|
23
23
|
editor.dispose();
|
|
24
24
|
};
|
|
25
25
|
}, [engine, options, project, uri, languageId, holder, onMount]);
|
|
26
|
-
return (_jsxs("div", { className: className, ref: ref, style: { position: 'relative', minHeight: 0 }, children: [_jsx("div", { ref: element, style: { position: 'absolute', inset: 0 } }), language !== null && _jsx(LanguagePopups, { language: language })] }));
|
|
26
|
+
return (_jsxs("div", { className: className, ref: ref, style: { position: 'relative', minHeight: 0 }, children: [_jsx("div", { ref: element, style: { position: 'absolute', inset: 0 } }), language !== null && _jsx(LanguagePopups, { language: language, contextMenuItems: contextMenuItems })] }));
|
|
27
27
|
}
|
package/dist/LanguagePopups.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
1
2
|
import type { EditorLanguage } from './editor-language.ts';
|
|
2
|
-
export declare function LanguagePopups({ language }: {
|
|
3
|
+
export declare function LanguagePopups({ language, contextMenuItems }: {
|
|
3
4
|
language: EditorLanguage;
|
|
5
|
+
contextMenuItems?: (language: EditorLanguage) => ReactNode;
|
|
4
6
|
}): import("react").JSX.Element;
|
package/dist/LanguagePopups.js
CHANGED
|
@@ -14,9 +14,9 @@ import { SignatureCard } from './SignatureCard.js';
|
|
|
14
14
|
/*
|
|
15
15
|
* Every card a language feature opens over the editor. Each feature keeps its own state and these
|
|
16
16
|
* only draw it, placed by the screen position of the character it belongs to, which is read again
|
|
17
|
-
* whenever the editor scrolls or resizes.
|
|
17
|
+
* whenever the editor scrolls or resizes. `contextMenuItems` adds rows of the app to the context menu.
|
|
18
18
|
*/
|
|
19
|
-
export function LanguagePopups({ language }) {
|
|
19
|
+
export function LanguagePopups({ language, contextMenuItems }) {
|
|
20
20
|
const [, redraw] = useReducer((count) => count + 1, 0);
|
|
21
21
|
const hover = useStore(language.popups, (state) => state.hover);
|
|
22
22
|
const completion = useStore(language.popups, (state) => state.completion);
|
|
@@ -34,5 +34,5 @@ export function LanguagePopups({ language }) {
|
|
|
34
34
|
const pickRect = pick === null ? null : language.editor.rectAt(pick.anchor);
|
|
35
35
|
const renameRect = rename === null ? null : language.editor.rectAt(rename.range.start);
|
|
36
36
|
const renameEnd = rename === null ? null : language.editor.rectAt(rename.range.end);
|
|
37
|
-
return (_jsxs(_Fragment, { children: [hover !== null && hoverRect !== null && (_jsx(AnchoredPopup, { rect: hoverRect, onPointerEnter: () => language.hover.holdCard(true), onPointerLeave: () => language.hover.holdCard(false), children: _jsx(HoverCard, { language: language, problems: hover.problems, info: hover.info, anchor: hover.anchor, position: hover.position }) })), signature !== null && signatureRect !== null && (_jsx(AnchoredPopup, { rect: signatureRect, placement: { prefer: 'above' }, children: _jsx(SignatureCard, { model: signature.model }) })), completion !== null && completionRect !== null && _jsx(CompletionPopup, { language: language, view: completion, rect: completionRect }), pick !== null && pickRect !== null && _jsx(PickPopup, { language: language, view: pick, rect: pickRect }), menu !== null && _jsx(EditorContextMenu, { language: language, view: menu }), symbols !== null && _jsx(SymbolPicker, { language: language, view: symbols }), peek !== null && _jsx(PeekPanel, { language: language, view: peek }), authors !== null && _jsx(CodeAuthorsCard, { language: language, view: authors }), rename !== null && renameRect !== null && _jsx(RenameCard, { language: language, view: rename, rect: renameRect, endRect: renameEnd })] }));
|
|
37
|
+
return (_jsxs(_Fragment, { children: [hover !== null && hoverRect !== null && (_jsx(AnchoredPopup, { rect: hoverRect, onPointerEnter: () => language.hover.holdCard(true), onPointerLeave: () => language.hover.holdCard(false), children: _jsx(HoverCard, { language: language, problems: hover.problems, info: hover.info, anchor: hover.anchor, position: hover.position }) })), signature !== null && signatureRect !== null && (_jsx(AnchoredPopup, { rect: signatureRect, placement: { prefer: 'above' }, children: _jsx(SignatureCard, { model: signature.model }) })), completion !== null && completionRect !== null && _jsx(CompletionPopup, { language: language, view: completion, rect: completionRect }), pick !== null && pickRect !== null && _jsx(PickPopup, { language: language, view: pick, rect: pickRect }), menu !== null && (_jsx(EditorContextMenu, { language: language, view: menu, children: contextMenuItems?.(language) })), symbols !== null && _jsx(SymbolPicker, { language: language, view: symbols }), peek !== null && _jsx(PeekPanel, { language: language, view: peek }), authors !== null && _jsx(CodeAuthorsCard, { language: language, view: authors }), rename !== null && renameRect !== null && _jsx(RenameCard, { language: language, view: rename, rect: renameRect, endRect: renameEnd })] }));
|
|
38
38
|
}
|
package/dist/code-actions.d.ts
CHANGED
package/dist/code-actions.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18next from 'i18next';
|
|
2
1
|
import { ErrorCodes, LspError, StaleResultError } from '@adecore/lsp';
|
|
3
2
|
import { ACTION_GROUPS, REFACTOR_GROUPS, actionsOf, diagnosticsAt, fixableOnLine, isHint, mergeEntries, previewOf } from './code-actions-model.js';
|
|
4
3
|
import { Refresher } from './refresher.js';
|
|
@@ -19,9 +18,6 @@ class ActionRefused extends Error {
|
|
|
19
18
|
function isRefusal(error) {
|
|
20
19
|
return error instanceof LspError && error.code === ErrorCodes.InternalError;
|
|
21
20
|
}
|
|
22
|
-
function say(key, options) {
|
|
23
|
-
return i18next.t(`editor:language.actions.${key}`, options);
|
|
24
|
-
}
|
|
25
21
|
/*
|
|
26
22
|
* What the language servers offer to do at the caret or the selection: a lightbulb in the gutter on the line
|
|
27
23
|
* that has something, a list under the caret (Mod+.) grouped by kind with the change an action would make
|
|
@@ -39,12 +35,10 @@ export class CodeActionsFeature {
|
|
|
39
35
|
resolved = new Map();
|
|
40
36
|
constructor(language, timers = realTimers) {
|
|
41
37
|
this.language = language;
|
|
42
|
-
const { editor
|
|
38
|
+
const { editor } = language;
|
|
43
39
|
this.refresher = new Refresher((signal) => this.hint(signal), PAUSE_MS, timers);
|
|
44
|
-
const providers =
|
|
45
|
-
|
|
46
|
-
this.refresher.later();
|
|
47
|
-
}
|
|
40
|
+
const providers = language.onProvidersChanged(() => {
|
|
41
|
+
this.refresher.later();
|
|
48
42
|
});
|
|
49
43
|
const offs = [
|
|
50
44
|
editor.onCaret(() => {
|
|
@@ -65,7 +59,7 @@ export class CodeActionsFeature {
|
|
|
65
59
|
return false;
|
|
66
60
|
}),
|
|
67
61
|
language.diagnostics.onChange(() => this.refresher.later()),
|
|
68
|
-
|
|
62
|
+
providers
|
|
69
63
|
];
|
|
70
64
|
language.onDispose(() => {
|
|
71
65
|
for (const off of offs) {
|
|
@@ -99,7 +93,7 @@ export class CodeActionsFeature {
|
|
|
99
93
|
const entries = await this.request(everything, ['source.organizeImports'], INVOKED);
|
|
100
94
|
const entry = entries?.find((candidate) => candidate.action.kind?.startsWith('source.organizeImports') === true);
|
|
101
95
|
if (entry === undefined) {
|
|
102
|
-
this.tell('success', say(entries === null ? 'unavailable' : 'organized'));
|
|
96
|
+
this.tell('success', this.say(entries === null ? 'unavailable' : 'organized'));
|
|
103
97
|
return;
|
|
104
98
|
}
|
|
105
99
|
await this.apply(entry);
|
|
@@ -107,13 +101,13 @@ export class CodeActionsFeature {
|
|
|
107
101
|
async formatDocument() {
|
|
108
102
|
const { editor, project, uri } = this.language;
|
|
109
103
|
if (!project.service.supports('textDocument/formatting', uri)) {
|
|
110
|
-
this.tell('error', say('noFormatter'));
|
|
104
|
+
this.tell('error', this.say('noFormatter'));
|
|
111
105
|
return;
|
|
112
106
|
}
|
|
113
107
|
try {
|
|
114
108
|
const edits = await project.service.formatting(uri, { ...editor.getIndentation() });
|
|
115
109
|
if (edits !== null && edits.length > 0 && !editor.applyEdits(edits.map((edit) => ({ range: edit.range, text: edit.newText })))) {
|
|
116
|
-
this.tell('error', say('readOnly'));
|
|
110
|
+
this.tell('error', this.say('readOnly'));
|
|
117
111
|
}
|
|
118
112
|
}
|
|
119
113
|
catch (error) {
|
|
@@ -128,7 +122,7 @@ export class CodeActionsFeature {
|
|
|
128
122
|
}
|
|
129
123
|
async ask(options) {
|
|
130
124
|
if (!this.supported) {
|
|
131
|
-
this.tell('error', say('unavailable'));
|
|
125
|
+
this.tell('error', this.say('unavailable'));
|
|
132
126
|
return;
|
|
133
127
|
}
|
|
134
128
|
// The press on a card or the gutter may have taken the focus, and the list answers to the editor's keys.
|
|
@@ -147,13 +141,13 @@ export class CodeActionsFeature {
|
|
|
147
141
|
return;
|
|
148
142
|
}
|
|
149
143
|
if (entries.length === 0) {
|
|
150
|
-
this.tell('success', say('none'));
|
|
144
|
+
this.tell('success', this.say('none'));
|
|
151
145
|
return;
|
|
152
146
|
}
|
|
153
147
|
const byId = new Map(entries.map((entry) => [entry.id, entry]));
|
|
154
148
|
const groups = (options.groups ?? ACTION_GROUPS).flatMap((group) => {
|
|
155
149
|
const rows = entries.filter((entry) => entry.group === group).map((entry) => ({ id: entry.id, label: entry.action.title, detail: '' }));
|
|
156
|
-
return rows.length === 0 ? [] : [{ title: say(`groups.${group}`), rows }];
|
|
150
|
+
return rows.length === 0 ? [] : [{ title: this.say(`groups.${group}`), rows }];
|
|
157
151
|
});
|
|
158
152
|
this.language.completion.close();
|
|
159
153
|
this.language.pick.open({
|
|
@@ -220,7 +214,7 @@ export class CodeActionsFeature {
|
|
|
220
214
|
if (signal.aborted || this.asking) {
|
|
221
215
|
return;
|
|
222
216
|
}
|
|
223
|
-
editor.setGutterAction(entries?.some(isHint) === true ? { line: editor.getCaret().line, label: say('show') } : null);
|
|
217
|
+
editor.setGutterAction(entries?.some(isHint) === true ? { line: editor.getCaret().line, label: this.say('show') } : null);
|
|
224
218
|
}
|
|
225
219
|
async resolve(entry, signal) {
|
|
226
220
|
const known = this.resolved.get(entry);
|
|
@@ -267,9 +261,9 @@ export class CodeActionsFeature {
|
|
|
267
261
|
return null;
|
|
268
262
|
}
|
|
269
263
|
const notes = [
|
|
270
|
-
...(found.hiddenLines > 0 ? [say('moreLines', { count: found.hiddenLines })] : []),
|
|
271
|
-
...(found.otherFiles > 0 ? [say('otherFiles', { count: found.otherFiles })] : []),
|
|
272
|
-
...(found.moves > 0 ? [say('moves', { count: found.moves })] : [])
|
|
264
|
+
...(found.hiddenLines > 0 ? [this.say('moreLines', { count: found.hiddenLines })] : []),
|
|
265
|
+
...(found.otherFiles > 0 ? [this.say('otherFiles', { count: found.otherFiles })] : []),
|
|
266
|
+
...(found.moves > 0 ? [this.say('moves', { count: found.moves })] : [])
|
|
273
267
|
];
|
|
274
268
|
return { removed: found.removed, added: found.added, note: notes.length === 0 ? null : notes.join(' · ') };
|
|
275
269
|
}
|
|
@@ -294,7 +288,7 @@ export class CodeActionsFeature {
|
|
|
294
288
|
if (action.edit !== undefined) {
|
|
295
289
|
const result = await project.applyWorkspaceEdit(action.edit);
|
|
296
290
|
if (!result.applied) {
|
|
297
|
-
this.tell('error', say('failed', { message: result.failureReason ?? say('refused') }));
|
|
291
|
+
this.tell('error', this.say('failed', { message: result.failureReason ?? this.say('refused') }));
|
|
298
292
|
return;
|
|
299
293
|
}
|
|
300
294
|
}
|
|
@@ -323,7 +317,10 @@ export class CodeActionsFeature {
|
|
|
323
317
|
}
|
|
324
318
|
fail(error) {
|
|
325
319
|
if (!(error instanceof StaleResultError)) {
|
|
326
|
-
this.tell('error', say('failed', { message: error instanceof Error ? error.message : String(error) }));
|
|
320
|
+
this.tell('error', this.say('failed', { message: error instanceof Error ? error.message : String(error) }));
|
|
327
321
|
}
|
|
328
322
|
}
|
|
323
|
+
say(key, options) {
|
|
324
|
+
return this.language.project.i18n.t(`editor:language.actions.${key}`, options);
|
|
325
|
+
}
|
|
329
326
|
}
|
package/dist/code-authors.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { i18n } from 'i18next';
|
|
1
2
|
import type { GitBlameCommit, GitBlameResult } from './host-types.ts';
|
|
2
3
|
export declare const UNCOMMITTED = -1;
|
|
3
4
|
export declare function mapBlame(blame: GitBlameResult, base: string, current: readonly string[]): Int32Array | null;
|
|
@@ -14,4 +15,4 @@ export interface CodeAuthorship {
|
|
|
14
15
|
}
|
|
15
16
|
export declare function shortName(name: string): string;
|
|
16
17
|
export declare function authorshipOf(commits: readonly GitBlameCommit[], mapped: Int32Array, lines: readonly string[], from: number, to: number): CodeAuthorship;
|
|
17
|
-
export declare function authorsText(authorship: CodeAuthorship): string;
|
|
18
|
+
export declare function authorsText(authorship: CodeAuthorship, i18n: i18n): string;
|
package/dist/code-authors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18next from 'i18next';
|
|
2
1
|
import { diffLines, splitLines } from '@adecore/merge';
|
|
3
2
|
import { formatNumber } from '@adecore/ui/format';
|
|
4
3
|
/* What a line of the text in the editor is: the index of the commit that wrote it, or this for a line no commit holds yet. */
|
|
@@ -70,10 +69,10 @@ export function authorshipOf(commits, mapped, lines, from, to) {
|
|
|
70
69
|
return { authors, uncommittedLines, modified, latest };
|
|
71
70
|
}
|
|
72
71
|
/* The row's words: the author with most lines, how many others wrote some, and a star when the range is edited since the commit. */
|
|
73
|
-
export function authorsText(authorship) {
|
|
72
|
+
export function authorsText(authorship, i18n) {
|
|
74
73
|
const main = authorship.authors[0];
|
|
75
74
|
if (main === undefined) {
|
|
76
|
-
return
|
|
75
|
+
return i18n.t('editor:language.codeVision.newCode');
|
|
77
76
|
}
|
|
78
77
|
const others = authorship.authors.length - 1;
|
|
79
78
|
return `${main.name}${others > 0 ? ` +${formatNumber(others)}` : ''}${authorship.modified ? ' *' : ''}`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DocumentSymbolResult, Position } from '@adecore/lsp';
|
|
2
|
+
import type { i18n } from 'i18next';
|
|
2
3
|
export declare const MAX_DECLARATIONS = 3000;
|
|
3
4
|
export interface CodeVisionDeclaration {
|
|
4
5
|
readonly id: string;
|
|
@@ -17,4 +18,4 @@ export interface DeclarationSource {
|
|
|
17
18
|
}
|
|
18
19
|
export declare function startAfterComments(source: DeclarationSource, from: Position, to: Position): Position | null;
|
|
19
20
|
export declare function declarationsOf(result: DocumentSymbolResult, source: DeclarationSource): CodeVisionDeclaration[];
|
|
20
|
-
export declare function usagesText(count: number): string;
|
|
21
|
+
export declare function usagesText(count: number, i18n: i18n): string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { formatNumber } from '@adecore/ui/format';
|
|
2
|
-
import i18next from 'i18next';
|
|
3
2
|
/* More declarations than this in one file and the rows are left out, which is the file that is too big for them to be quiet. */
|
|
4
3
|
export const MAX_DECLARATIONS = 3000;
|
|
5
4
|
/* LSP's SymbolKind: the kinds a row is drawn for and the ones whose children can be declarations too. */
|
|
@@ -177,8 +176,8 @@ export function declarationsOf(result, source) {
|
|
|
177
176
|
return declarations;
|
|
178
177
|
}
|
|
179
178
|
/* "No usages", "1 usage" and "N usages". */
|
|
180
|
-
export function usagesText(count) {
|
|
179
|
+
export function usagesText(count, i18n) {
|
|
181
180
|
return count === 0
|
|
182
|
-
?
|
|
183
|
-
:
|
|
181
|
+
? i18n.t('editor:language.codeVision.usagesNone')
|
|
182
|
+
: i18n.t('editor:language.codeVision.usages', { count, formatted: formatNumber(count) });
|
|
184
183
|
}
|
package/dist/code-vision.js
CHANGED
|
@@ -42,7 +42,7 @@ export class CodeVisionFeature {
|
|
|
42
42
|
constructor(language, onSymbols, timers = realTimers) {
|
|
43
43
|
this.language = language;
|
|
44
44
|
this.timers = timers;
|
|
45
|
-
const { editor
|
|
45
|
+
const { editor } = language;
|
|
46
46
|
const offs = [
|
|
47
47
|
onSymbols((result) => this.read(result)),
|
|
48
48
|
editor.onTextChange(() => {
|
|
@@ -54,19 +54,17 @@ export class CodeVisionFeature {
|
|
|
54
54
|
this.scrollTimer = this.timers.set(() => this.plan(), SCROLL_PAUSE_MS);
|
|
55
55
|
})
|
|
56
56
|
];
|
|
57
|
-
const providers =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.plan();
|
|
62
|
-
}
|
|
57
|
+
const providers = language.onProvidersChanged(() => {
|
|
58
|
+
this.failed.clear();
|
|
59
|
+
this.publish();
|
|
60
|
+
this.plan();
|
|
63
61
|
});
|
|
64
62
|
language.onDispose(() => {
|
|
65
63
|
this.disposed = true;
|
|
66
64
|
for (const off of offs) {
|
|
67
65
|
off();
|
|
68
66
|
}
|
|
69
|
-
providers
|
|
67
|
+
providers();
|
|
70
68
|
this.timers.clear(this.scrollTimer);
|
|
71
69
|
for (const controller of this.running.values()) {
|
|
72
70
|
controller.abort();
|
|
@@ -180,7 +178,11 @@ export class CodeVisionFeature {
|
|
|
180
178
|
const entries = [];
|
|
181
179
|
const known = this.counts.get(declaration.id);
|
|
182
180
|
if (counted && declaration.usages && known !== undefined) {
|
|
183
|
-
entries.push({
|
|
181
|
+
entries.push({
|
|
182
|
+
id: 'usages',
|
|
183
|
+
text: usagesText(known.count, this.language.project.i18n),
|
|
184
|
+
activate: () => void this.language.peek.open(declaration.position)
|
|
185
|
+
});
|
|
184
186
|
}
|
|
185
187
|
if (mapped !== null && declaration.authors) {
|
|
186
188
|
let authorship = this.authorships.get(declaration.id);
|
|
@@ -191,7 +193,7 @@ export class CodeVisionFeature {
|
|
|
191
193
|
const shown = authorship;
|
|
192
194
|
entries.push({
|
|
193
195
|
id: 'authors',
|
|
194
|
-
text: authorsText(shown),
|
|
196
|
+
text: authorsText(shown, this.language.project.i18n),
|
|
195
197
|
...(shown.authors.length > 0 ? { icon: shown.authors.length > 1 ? 'users' : 'user' } : {}),
|
|
196
198
|
activate: (anchor) => this.showAuthors(declaration, shown, anchor)
|
|
197
199
|
});
|
package/dist/completion.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18next from 'i18next';
|
|
2
1
|
import { StaleResultError } from '@adecore/lsp';
|
|
3
2
|
import { comparePositions, shiftPosition } from './diagnostics-model.js';
|
|
4
3
|
import { completionDocsOf, identifierPrefix, insertionOf, isIdentifierCharacter, itemsOf, matchedCharacters, mirroredInsertions, prefixFor, qualifiersOf, rankCompletions } from './completion-model.js';
|
|
@@ -368,7 +367,7 @@ export class CompletionFeature {
|
|
|
368
367
|
const asked = this.explicit && !refresh;
|
|
369
368
|
this.refilter();
|
|
370
369
|
if (asked && !this.isOpen && !this.incomplete) {
|
|
371
|
-
this.language.project.host.notify?.({ id: TOAST_ID, kind: 'error', title:
|
|
370
|
+
this.language.project.host.notify?.({ id: TOAST_ID, kind: 'error', title: this.language.project.i18n.t('editor:language.completion.none') });
|
|
372
371
|
}
|
|
373
372
|
else if (asked && this.ranked.length === 1 && !this.incomplete) {
|
|
374
373
|
// One answer to a list that was asked for is the one wanted.
|
|
@@ -59,6 +59,7 @@ export declare class EditorLanguage {
|
|
|
59
59
|
jump(position: EditorPosition): void;
|
|
60
60
|
visit(place: Place): void;
|
|
61
61
|
locations(places: readonly Location[], anchor: EditorPosition, title: string): void;
|
|
62
|
+
onProvidersChanged(listener: () => void): () => void;
|
|
62
63
|
onDispose(dispose: () => void): void;
|
|
63
64
|
dispose(): void;
|
|
64
65
|
}
|
package/dist/editor-language.js
CHANGED
|
@@ -131,6 +131,28 @@ export class EditorLanguage {
|
|
|
131
131
|
const rows = places.map((place, index) => ({ id: String(index), ...locationRow(place, this.project.pathOfLocation(place.uri)) }));
|
|
132
132
|
this.pick.open({ anchor, title, groups: [{ title: null, rows }], accept: (id) => this.goTo(places[Number(id)]) });
|
|
133
133
|
}
|
|
134
|
+
/*
|
|
135
|
+
* Runs `listener` once the document is open and again whenever the service says what it can ask for
|
|
136
|
+
* this document changed. A service that is ready before the document opens never says so, so the
|
|
137
|
+
* opening counts as the first change.
|
|
138
|
+
*/
|
|
139
|
+
onProvidersChanged(listener) {
|
|
140
|
+
let listening = true;
|
|
141
|
+
void this.document.ready.then(() => {
|
|
142
|
+
if (listening && !this.disposed) {
|
|
143
|
+
listener();
|
|
144
|
+
}
|
|
145
|
+
}, () => undefined);
|
|
146
|
+
const providers = this.project.service.onProvidersChanged((uri) => {
|
|
147
|
+
if (uri === this.uri) {
|
|
148
|
+
listener();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return () => {
|
|
152
|
+
listening = false;
|
|
153
|
+
providers.dispose();
|
|
154
|
+
};
|
|
155
|
+
}
|
|
134
156
|
/* Runs `dispose` when the editor lets go of its document. */
|
|
135
157
|
onDispose(dispose) {
|
|
136
158
|
this.disposers.push(dispose);
|
package/dist/folding.js
CHANGED
|
@@ -77,15 +77,13 @@ export class FoldingFeature {
|
|
|
77
77
|
this.publish();
|
|
78
78
|
});
|
|
79
79
|
const edits = editor.onTextChange(() => this.refresher.later());
|
|
80
|
-
const providers =
|
|
81
|
-
|
|
82
|
-
this.refresher.now();
|
|
83
|
-
}
|
|
80
|
+
const providers = language.onProvidersChanged(() => {
|
|
81
|
+
this.refresher.now();
|
|
84
82
|
});
|
|
85
83
|
language.onDispose(() => {
|
|
86
84
|
symbols();
|
|
87
85
|
edits();
|
|
88
|
-
providers
|
|
86
|
+
providers();
|
|
89
87
|
this.refresher.dispose();
|
|
90
88
|
editor.setFoldHints(null);
|
|
91
89
|
});
|
package/dist/history.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18next from 'i18next';
|
|
2
1
|
import { isShortcut } from './shortcut-keys.js';
|
|
3
2
|
/* Back, Forward and the list of recent locations over the history the whole project shares. */
|
|
4
3
|
export class HistoryFeature {
|
|
@@ -42,6 +41,6 @@ export class HistoryFeature {
|
|
|
42
41
|
/* Lists the places of the history under the caret; choosing one jumps there like any other jump. */
|
|
43
42
|
recent() {
|
|
44
43
|
const places = this.language.project.history.recent(this.language.place);
|
|
45
|
-
this.language.locations(places.map((place) => ({ uri: place.uri, range: { start: place.position, end: place.position } })), this.language.editor.getCaret(),
|
|
44
|
+
this.language.locations(places.map((place) => ({ uri: place.uri, range: { start: place.position, end: place.position } })), this.language.editor.getCaret(), this.language.project.i18n.t('editor:language.history.recent'));
|
|
46
45
|
}
|
|
47
46
|
}
|
package/dist/host-types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { i18n } from 'i18next';
|
|
1
2
|
import type { Keymap } from '@adecore/editor/keymap';
|
|
2
3
|
import type { ProjectFiles } from './workspace-edit.ts';
|
|
3
4
|
import type { Place } from './navigation-history.ts';
|
|
@@ -31,6 +32,7 @@ export interface RenameSuggestionsRequest {
|
|
|
31
32
|
uses: readonly string[];
|
|
32
33
|
}
|
|
33
34
|
export interface LanguageHost {
|
|
35
|
+
readonly i18n?: i18n;
|
|
34
36
|
readonly folder?: string;
|
|
35
37
|
readonly files?: ProjectFiles;
|
|
36
38
|
readonly apple?: boolean;
|
package/dist/hover.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18next from 'i18next';
|
|
2
1
|
import { rangeHolds } from './diagnostics-model.js';
|
|
3
2
|
import { hoverTextOf, isEmptyHover, locationsOf } from './hover-content.js';
|
|
4
3
|
import { wordRangeAt } from './rename-model.js';
|
|
@@ -197,7 +196,7 @@ export class HoverFeature {
|
|
|
197
196
|
if (problems.length === 0 && info === null) {
|
|
198
197
|
this.hide();
|
|
199
198
|
if (pinned) {
|
|
200
|
-
this.language.project.host.notify?.({ id: TOAST_ID, kind: 'error', title:
|
|
199
|
+
this.language.project.host.notify?.({ id: TOAST_ID, kind: 'error', title: this.language.project.i18n.t('editor:language.hover.none') });
|
|
201
200
|
}
|
|
202
201
|
return;
|
|
203
202
|
}
|
package/dist/inlay-hints.js
CHANGED
|
@@ -57,15 +57,13 @@ export class InlayHintsFeature {
|
|
|
57
57
|
this.refresher.later();
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
-
const providers =
|
|
61
|
-
|
|
62
|
-
this.refresher.now();
|
|
63
|
-
}
|
|
60
|
+
const providers = language.onProvidersChanged(() => {
|
|
61
|
+
this.refresher.now();
|
|
64
62
|
});
|
|
65
63
|
language.onDispose(() => {
|
|
66
64
|
edits();
|
|
67
65
|
scrolls();
|
|
68
|
-
providers
|
|
66
|
+
providers();
|
|
69
67
|
this.refresher.dispose();
|
|
70
68
|
editor.setInlayHints([]);
|
|
71
69
|
});
|
package/dist/navigation.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class NavigationFeature {
|
|
|
14
14
|
go(kind: NavigationKind, position?: EditorPosition): Promise<void>;
|
|
15
15
|
goToName(name: string, anchor: EditorPosition, own: Location | null): Promise<void>;
|
|
16
16
|
private tell;
|
|
17
|
+
private say;
|
|
17
18
|
}
|
|
18
19
|
export declare function locationRow(location: Location, stored: string | null): {
|
|
19
20
|
label: string;
|