@fresh-editor/fresh-editor 0.2.18 → 0.2.21
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/CHANGELOG.md +100 -0
- package/package.json +1 -1
- package/plugins/config-schema.json +264 -42
- package/plugins/diagnostics_panel.ts +4 -12
- package/plugins/diff_nav.i18n.json +128 -0
- package/plugins/diff_nav.ts +196 -0
- package/plugins/git_explorer.ts +6 -0
- package/plugins/git_gutter.ts +5 -0
- package/plugins/lib/finder.ts +19 -12
- package/plugins/lib/fresh.d.ts +5 -1
- package/plugins/pkg.ts +4 -29
- package/plugins/schemas/package.schema.json +437 -272
- package/plugins/schemas/theme.schema.json +18 -0
- package/plugins/theme_editor.i18n.json +42 -14
- package/plugins/theme_editor.ts +30 -3
- package/plugins/vi_mode.ts +189 -51
- package/themes/high-contrast.json +66 -66
- package/themes/light.json +18 -18
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"en": {
|
|
3
|
+
"cmd.next_change": "Next Change",
|
|
4
|
+
"cmd.next_change_desc": "Jump to the next changed region",
|
|
5
|
+
"cmd.prev_change": "Previous Change",
|
|
6
|
+
"cmd.prev_change_desc": "Jump to the previous changed region",
|
|
7
|
+
"status.no_changes": "No changes",
|
|
8
|
+
"status.change": "Change %{n}/%{total}",
|
|
9
|
+
"status.change_wrapped": "Change %{n}/%{total} [wrapped]"
|
|
10
|
+
},
|
|
11
|
+
"cs": {
|
|
12
|
+
"cmd.next_change": "Další změna",
|
|
13
|
+
"cmd.next_change_desc": "Přejít na další změněnou oblast",
|
|
14
|
+
"cmd.prev_change": "Předchozí změna",
|
|
15
|
+
"cmd.prev_change_desc": "Přejít na předchozí změněnou oblast",
|
|
16
|
+
"status.no_changes": "Žádné změny",
|
|
17
|
+
"status.change": "Změna %{n}/%{total}",
|
|
18
|
+
"status.change_wrapped": "Změna %{n}/%{total} [zabaleno]"
|
|
19
|
+
},
|
|
20
|
+
"de": {
|
|
21
|
+
"cmd.next_change": "Nächste Änderung",
|
|
22
|
+
"cmd.next_change_desc": "Zur nächsten geänderten Region springen",
|
|
23
|
+
"cmd.prev_change": "Vorherige Änderung",
|
|
24
|
+
"cmd.prev_change_desc": "Zur vorherigen geänderten Region springen",
|
|
25
|
+
"status.no_changes": "Keine Änderungen",
|
|
26
|
+
"status.change": "Änderung %{n}/%{total}",
|
|
27
|
+
"status.change_wrapped": "Änderung %{n}/%{total} [umgebrochen]"
|
|
28
|
+
},
|
|
29
|
+
"es": {
|
|
30
|
+
"cmd.next_change": "Siguiente cambio",
|
|
31
|
+
"cmd.next_change_desc": "Saltar a la siguiente región modificada",
|
|
32
|
+
"cmd.prev_change": "Cambio anterior",
|
|
33
|
+
"cmd.prev_change_desc": "Saltar a la región modificada anterior",
|
|
34
|
+
"status.no_changes": "Sin cambios",
|
|
35
|
+
"status.change": "Cambio %{n}/%{total}",
|
|
36
|
+
"status.change_wrapped": "Cambio %{n}/%{total} [envuelto]"
|
|
37
|
+
},
|
|
38
|
+
"fr": {
|
|
39
|
+
"cmd.next_change": "Modification suivante",
|
|
40
|
+
"cmd.next_change_desc": "Aller à la prochaine région modifiée",
|
|
41
|
+
"cmd.prev_change": "Modification précédente",
|
|
42
|
+
"cmd.prev_change_desc": "Aller à la région modifiée précédente",
|
|
43
|
+
"status.no_changes": "Aucune modification",
|
|
44
|
+
"status.change": "Modification %{n}/%{total}",
|
|
45
|
+
"status.change_wrapped": "Modification %{n}/%{total} [bouclé]"
|
|
46
|
+
},
|
|
47
|
+
"it": {
|
|
48
|
+
"cmd.next_change": "Modifica successiva",
|
|
49
|
+
"cmd.next_change_desc": "Vai alla prossima regione modificata",
|
|
50
|
+
"cmd.prev_change": "Modifica precedente",
|
|
51
|
+
"cmd.prev_change_desc": "Vai alla regione modificata precedente",
|
|
52
|
+
"status.no_changes": "Nessuna modifica",
|
|
53
|
+
"status.change": "Modifica %{n}/%{total}",
|
|
54
|
+
"status.change_wrapped": "Modifica %{n}/%{total} [avvolto]"
|
|
55
|
+
},
|
|
56
|
+
"ja": {
|
|
57
|
+
"cmd.next_change": "次の変更",
|
|
58
|
+
"cmd.next_change_desc": "次の変更箇所にジャンプ",
|
|
59
|
+
"cmd.prev_change": "前の変更",
|
|
60
|
+
"cmd.prev_change_desc": "前の変更箇所にジャンプ",
|
|
61
|
+
"status.no_changes": "変更なし",
|
|
62
|
+
"status.change": "変更 %{n}/%{total}",
|
|
63
|
+
"status.change_wrapped": "変更 %{n}/%{total} [折り返し]"
|
|
64
|
+
},
|
|
65
|
+
"ko": {
|
|
66
|
+
"cmd.next_change": "다음 변경",
|
|
67
|
+
"cmd.next_change_desc": "다음 변경된 영역으로 이동",
|
|
68
|
+
"cmd.prev_change": "이전 변경",
|
|
69
|
+
"cmd.prev_change_desc": "이전 변경된 영역으로 이동",
|
|
70
|
+
"status.no_changes": "변경 없음",
|
|
71
|
+
"status.change": "변경 %{n}/%{total}",
|
|
72
|
+
"status.change_wrapped": "변경 %{n}/%{total} [순환]"
|
|
73
|
+
},
|
|
74
|
+
"pt-BR": {
|
|
75
|
+
"cmd.next_change": "Próxima alteração",
|
|
76
|
+
"cmd.next_change_desc": "Ir para a próxima região alterada",
|
|
77
|
+
"cmd.prev_change": "Alteração anterior",
|
|
78
|
+
"cmd.prev_change_desc": "Ir para a região alterada anterior",
|
|
79
|
+
"status.no_changes": "Sem alterações",
|
|
80
|
+
"status.change": "Alteração %{n}/%{total}",
|
|
81
|
+
"status.change_wrapped": "Alteração %{n}/%{total} [retornou]"
|
|
82
|
+
},
|
|
83
|
+
"ru": {
|
|
84
|
+
"cmd.next_change": "Следующее изменение",
|
|
85
|
+
"cmd.next_change_desc": "Перейти к следующей изменённой области",
|
|
86
|
+
"cmd.prev_change": "Предыдущее изменение",
|
|
87
|
+
"cmd.prev_change_desc": "Перейти к предыдущей изменённой области",
|
|
88
|
+
"status.no_changes": "Нет изменений",
|
|
89
|
+
"status.change": "Изменение %{n}/%{total}",
|
|
90
|
+
"status.change_wrapped": "Изменение %{n}/%{total} [цикл]"
|
|
91
|
+
},
|
|
92
|
+
"th": {
|
|
93
|
+
"cmd.next_change": "การเปลี่ยนแปลงถัดไป",
|
|
94
|
+
"cmd.next_change_desc": "ข้ามไปยังพื้นที่ที่เปลี่ยนแปลงถัดไป",
|
|
95
|
+
"cmd.prev_change": "การเปลี่ยนแปลงก่อนหน้า",
|
|
96
|
+
"cmd.prev_change_desc": "ข้ามไปยังพื้นที่ที่เปลี่ยนแปลงก่อนหน้า",
|
|
97
|
+
"status.no_changes": "ไม่มีการเปลี่ยนแปลง",
|
|
98
|
+
"status.change": "การเปลี่ยนแปลง %{n}/%{total}",
|
|
99
|
+
"status.change_wrapped": "การเปลี่ยนแปลง %{n}/%{total} [วนรอบ]"
|
|
100
|
+
},
|
|
101
|
+
"uk": {
|
|
102
|
+
"cmd.next_change": "Наступна зміна",
|
|
103
|
+
"cmd.next_change_desc": "Перейти до наступної зміненої області",
|
|
104
|
+
"cmd.prev_change": "Попередня зміна",
|
|
105
|
+
"cmd.prev_change_desc": "Перейти до попередньої зміненої області",
|
|
106
|
+
"status.no_changes": "Немає змін",
|
|
107
|
+
"status.change": "Зміна %{n}/%{total}",
|
|
108
|
+
"status.change_wrapped": "Зміна %{n}/%{total} [цикл]"
|
|
109
|
+
},
|
|
110
|
+
"vi": {
|
|
111
|
+
"cmd.next_change": "Thay đổi tiếp theo",
|
|
112
|
+
"cmd.next_change_desc": "Nhảy đến vùng thay đổi tiếp theo",
|
|
113
|
+
"cmd.prev_change": "Thay đổi trước đó",
|
|
114
|
+
"cmd.prev_change_desc": "Nhảy đến vùng thay đổi trước đó",
|
|
115
|
+
"status.no_changes": "Không có thay đổi",
|
|
116
|
+
"status.change": "Thay đổi %{n}/%{total}",
|
|
117
|
+
"status.change_wrapped": "Thay đổi %{n}/%{total} [quay vòng]"
|
|
118
|
+
},
|
|
119
|
+
"zh-CN": {
|
|
120
|
+
"cmd.next_change": "下一个更改",
|
|
121
|
+
"cmd.next_change_desc": "跳转到下一个已更改的区域",
|
|
122
|
+
"cmd.prev_change": "上一个更改",
|
|
123
|
+
"cmd.prev_change_desc": "跳转到上一个已更改的区域",
|
|
124
|
+
"status.no_changes": "没有更改",
|
|
125
|
+
"status.change": "更改 %{n}/%{total}",
|
|
126
|
+
"status.change_wrapped": "更改 %{n}/%{total} [已循环]"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
2
|
+
const editor = getEditor();
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Diff Navigation Plugin
|
|
6
|
+
*
|
|
7
|
+
* Provides unified next/previous change commands that merge changes from all
|
|
8
|
+
* available diff sources: git diff AND piece-tree saved-diff. This means a
|
|
9
|
+
* single keybinding pair navigates both committed and unsaved changes.
|
|
10
|
+
*
|
|
11
|
+
* When only one source is available (e.g. file not tracked by git), it still
|
|
12
|
+
* works using that source alone.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
interface DiffHunk {
|
|
20
|
+
type: "added" | "modified" | "deleted";
|
|
21
|
+
startLine: number; // 1-indexed
|
|
22
|
+
lineCount: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A jump target with a byte position for sorting/deduplication */
|
|
26
|
+
interface JumpTarget {
|
|
27
|
+
bytePos: number;
|
|
28
|
+
line: number; // 0-indexed, for scrollToLineCenter
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Collecting jump targets from all sources
|
|
33
|
+
// =============================================================================
|
|
34
|
+
|
|
35
|
+
async function collectTargets(bid: number): Promise<JumpTarget[]> {
|
|
36
|
+
const targets: JumpTarget[] = [];
|
|
37
|
+
|
|
38
|
+
// Source 1: git gutter hunks
|
|
39
|
+
const hunks = editor.getViewState(bid, "git_gutter_hunks") as DiffHunk[] | null;
|
|
40
|
+
if (hunks && hunks.length > 0) {
|
|
41
|
+
for (const hunk of hunks) {
|
|
42
|
+
const line = Math.max(0, hunk.startLine - 1); // 0-indexed
|
|
43
|
+
const pos = await editor.getLineStartPosition(line);
|
|
44
|
+
if (pos !== null) {
|
|
45
|
+
targets.push({ bytePos: pos, line });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Source 2: saved-diff (unsaved changes)
|
|
51
|
+
const diff = editor.getBufferSavedDiff(bid);
|
|
52
|
+
if (diff && !diff.equal) {
|
|
53
|
+
for (const [start, _end] of diff.byte_ranges) {
|
|
54
|
+
// We don't know the line yet; resolve it lazily after dedup
|
|
55
|
+
targets.push({ bytePos: start, line: -1 });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (targets.length === 0) return targets;
|
|
60
|
+
|
|
61
|
+
// Sort by byte position
|
|
62
|
+
targets.sort((a, b) => a.bytePos - b.bytePos);
|
|
63
|
+
|
|
64
|
+
// Deduplicate: if two targets are on the same line, keep the first.
|
|
65
|
+
// Resolve line numbers for saved-diff targets that still have line = -1.
|
|
66
|
+
const deduped: JumpTarget[] = [];
|
|
67
|
+
const seenLines = new Set<number>();
|
|
68
|
+
|
|
69
|
+
for (const t of targets) {
|
|
70
|
+
// Resolve line if unknown
|
|
71
|
+
if (t.line === -1) {
|
|
72
|
+
// Jump cursor temporarily to find the line, then restore.
|
|
73
|
+
// Instead, use a simpler heuristic: find the line by checking
|
|
74
|
+
// existing targets or using getLineStartPosition in reverse.
|
|
75
|
+
// Actually, we can set cursor, read line, but that's side-effectful.
|
|
76
|
+
// Simpler: just check if any existing target has a bytePos close enough.
|
|
77
|
+
// For dedup, we check if any already-added target has same bytePos.
|
|
78
|
+
let isDup = false;
|
|
79
|
+
for (const existing of deduped) {
|
|
80
|
+
if (Math.abs(existing.bytePos - t.bytePos) < 2) {
|
|
81
|
+
isDup = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (isDup) continue;
|
|
86
|
+
deduped.push(t);
|
|
87
|
+
} else {
|
|
88
|
+
if (seenLines.has(t.line)) continue;
|
|
89
|
+
seenLines.add(t.line);
|
|
90
|
+
// Also check if a saved-diff target at similar byte pos was already added
|
|
91
|
+
let isDup = false;
|
|
92
|
+
for (const existing of deduped) {
|
|
93
|
+
if (existing.line === -1 && Math.abs(existing.bytePos - t.bytePos) < 2) {
|
|
94
|
+
// Replace the unresolved one with this one (which has a known line)
|
|
95
|
+
existing.line = t.line;
|
|
96
|
+
isDup = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (isDup) continue;
|
|
101
|
+
deduped.push(t);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return deduped;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// =============================================================================
|
|
109
|
+
// Navigation
|
|
110
|
+
// =============================================================================
|
|
111
|
+
|
|
112
|
+
function goToTarget(bid: number, target: JumpTarget): void {
|
|
113
|
+
if (target.line >= 0) {
|
|
114
|
+
const splitId = editor.getActiveSplitId();
|
|
115
|
+
editor.scrollToLineCenter(splitId, bid, target.line);
|
|
116
|
+
}
|
|
117
|
+
editor.setBufferCursor(bid, target.bytePos);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function diff_nav_next(): Promise<void> {
|
|
121
|
+
const bid = editor.getActiveBufferId();
|
|
122
|
+
const targets = await collectTargets(bid);
|
|
123
|
+
|
|
124
|
+
if (targets.length === 0) {
|
|
125
|
+
editor.setStatus(editor.t("status.no_changes"));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const cursor = editor.getCursorPosition();
|
|
130
|
+
let idx = targets.findIndex((t) => t.bytePos > cursor);
|
|
131
|
+
let wrapped = false;
|
|
132
|
+
if (idx === -1) {
|
|
133
|
+
idx = 0;
|
|
134
|
+
wrapped = true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
goToTarget(bid, targets[idx]);
|
|
138
|
+
|
|
139
|
+
const msg = wrapped
|
|
140
|
+
? editor.t("status.change_wrapped", { n: String(idx + 1), total: String(targets.length) })
|
|
141
|
+
: editor.t("status.change", { n: String(idx + 1), total: String(targets.length) });
|
|
142
|
+
editor.setStatus(msg);
|
|
143
|
+
}
|
|
144
|
+
registerHandler("diff_nav_next", diff_nav_next);
|
|
145
|
+
|
|
146
|
+
async function diff_nav_prev(): Promise<void> {
|
|
147
|
+
const bid = editor.getActiveBufferId();
|
|
148
|
+
const targets = await collectTargets(bid);
|
|
149
|
+
|
|
150
|
+
if (targets.length === 0) {
|
|
151
|
+
editor.setStatus(editor.t("status.no_changes"));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const cursor = editor.getCursorPosition();
|
|
156
|
+
let idx = -1;
|
|
157
|
+
for (let i = targets.length - 1; i >= 0; i--) {
|
|
158
|
+
if (targets[i].bytePos < cursor) {
|
|
159
|
+
idx = i;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
let wrapped = false;
|
|
164
|
+
if (idx === -1) {
|
|
165
|
+
idx = targets.length - 1;
|
|
166
|
+
wrapped = true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
goToTarget(bid, targets[idx]);
|
|
170
|
+
|
|
171
|
+
const msg = wrapped
|
|
172
|
+
? editor.t("status.change_wrapped", { n: String(idx + 1), total: String(targets.length) })
|
|
173
|
+
: editor.t("status.change", { n: String(idx + 1), total: String(targets.length) });
|
|
174
|
+
editor.setStatus(msg);
|
|
175
|
+
}
|
|
176
|
+
registerHandler("diff_nav_prev", diff_nav_prev);
|
|
177
|
+
|
|
178
|
+
// =============================================================================
|
|
179
|
+
// Registration
|
|
180
|
+
// =============================================================================
|
|
181
|
+
|
|
182
|
+
editor.registerCommand(
|
|
183
|
+
"%cmd.next_change",
|
|
184
|
+
"%cmd.next_change_desc",
|
|
185
|
+
"diff_nav_next",
|
|
186
|
+
null
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
editor.registerCommand(
|
|
190
|
+
"%cmd.prev_change",
|
|
191
|
+
"%cmd.prev_change_desc",
|
|
192
|
+
"diff_nav_prev",
|
|
193
|
+
null
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
editor.debug("Diff Nav plugin loaded");
|
package/plugins/git_explorer.ts
CHANGED
|
@@ -156,8 +156,14 @@ function onGitExplorerEditorInitialized() {
|
|
|
156
156
|
}
|
|
157
157
|
registerHandler("onGitExplorerEditorInitialized", onGitExplorerEditorInitialized);
|
|
158
158
|
|
|
159
|
+
function onGitExplorerFocusGained() {
|
|
160
|
+
refreshGitExplorerDecorations();
|
|
161
|
+
}
|
|
162
|
+
registerHandler("onGitExplorerFocusGained", onGitExplorerFocusGained);
|
|
163
|
+
|
|
159
164
|
editor.on("after_file_open", "onGitExplorerAfterFileOpen");
|
|
160
165
|
editor.on("after_file_save", "onGitExplorerAfterFileSave");
|
|
161
166
|
editor.on("editor_initialized", "onGitExplorerEditorInitialized");
|
|
167
|
+
editor.on("focus_gained", "onGitExplorerFocusGained");
|
|
162
168
|
|
|
163
169
|
refreshGitExplorerDecorations();
|
package/plugins/git_gutter.ts
CHANGED
|
@@ -248,6 +248,8 @@ async function updateGitGutter(bufferId: number): Promise<void> {
|
|
|
248
248
|
editor.debug("Git Gutter: file not tracked by git");
|
|
249
249
|
editor.clearLineIndicators(bufferId, NAMESPACE);
|
|
250
250
|
state.hunks = [];
|
|
251
|
+
// Signal to other plugins that git is not available for this buffer
|
|
252
|
+
editor.setViewState(bufferId, "git_gutter_hunks", null);
|
|
251
253
|
return;
|
|
252
254
|
}
|
|
253
255
|
|
|
@@ -304,6 +306,9 @@ async function updateGitGutter(bufferId: number): Promise<void> {
|
|
|
304
306
|
}
|
|
305
307
|
|
|
306
308
|
state.hunks = hunks;
|
|
309
|
+
|
|
310
|
+
// Export hunks for other plugins (e.g. diff_nav) via shared view state
|
|
311
|
+
editor.setViewState(bufferId, "git_gutter_hunks", hunks);
|
|
307
312
|
} finally {
|
|
308
313
|
state.updating = false;
|
|
309
314
|
}
|
package/plugins/lib/finder.ts
CHANGED
|
@@ -115,6 +115,9 @@ export interface FinderConfig<T> {
|
|
|
115
115
|
|
|
116
116
|
/** Panel-specific: navigate source split when cursor moves (preview without focus change) */
|
|
117
117
|
navigateOnCursorMove?: boolean;
|
|
118
|
+
|
|
119
|
+
/** Called when the panel or prompt is closed (e.g. via Escape) */
|
|
120
|
+
onClose?: () => void;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
/**
|
|
@@ -1254,18 +1257,17 @@ export class Finder<T> {
|
|
|
1254
1257
|
if (this.config.onSelect) {
|
|
1255
1258
|
this.config.onSelect(item, entry);
|
|
1256
1259
|
} else if (entry.location) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
this.editor.
|
|
1267
|
-
|
|
1268
|
-
);
|
|
1260
|
+
const loc = entry.location;
|
|
1261
|
+
|
|
1262
|
+
// Close the panel first. This is necessary because
|
|
1263
|
+
// navigateOnCursorMove's focusSplit(panelSplitId) can interfere with
|
|
1264
|
+
// the jump — it queues a FocusSplit that runs after OpenFileInSplit
|
|
1265
|
+
// and restores the panel as the active split.
|
|
1266
|
+
this.closePanel();
|
|
1267
|
+
|
|
1268
|
+
// Now navigate with the panel gone — only one split remains
|
|
1269
|
+
this.editor.openFile(loc.file, loc.line, loc.column);
|
|
1270
|
+
this.editor.setStatus(`Jumped to ${loc.file}:${loc.line}`);
|
|
1269
1271
|
}
|
|
1270
1272
|
}
|
|
1271
1273
|
|
|
@@ -1306,6 +1308,11 @@ export class Finder<T> {
|
|
|
1306
1308
|
}
|
|
1307
1309
|
|
|
1308
1310
|
this.editor.setStatus("Closed");
|
|
1311
|
+
|
|
1312
|
+
// Notify the caller that the panel was closed
|
|
1313
|
+
if (this.config.onClose) {
|
|
1314
|
+
this.config.onClose();
|
|
1315
|
+
}
|
|
1309
1316
|
}
|
|
1310
1317
|
|
|
1311
1318
|
private revealItem(index: number): void {
|
package/plugins/lib/fresh.d.ts
CHANGED
|
@@ -539,7 +539,6 @@ type BackgroundProcessResult = {
|
|
|
539
539
|
type BufferSavedDiff = {
|
|
540
540
|
equal: boolean;
|
|
541
541
|
byte_ranges: Array<[number, number]>;
|
|
542
|
-
line_ranges: Array<[number, number]> | null;
|
|
543
542
|
};
|
|
544
543
|
type CreateVirtualBufferInExistingSplitOptions = {
|
|
545
544
|
/**
|
|
@@ -1096,6 +1095,11 @@ interface EditorAPI {
|
|
|
1096
1095
|
*/
|
|
1097
1096
|
reloadGrammars(): Promise<void>;
|
|
1098
1097
|
/**
|
|
1098
|
+
* Get the directory where this plugin's files are stored.
|
|
1099
|
+
* For package plugins this is `<plugins_dir>/packages/<plugin_name>/`.
|
|
1100
|
+
*/
|
|
1101
|
+
getPluginDir(): string;
|
|
1102
|
+
/**
|
|
1099
1103
|
* Get config directory path
|
|
1100
1104
|
*/
|
|
1101
1105
|
getConfigDir(): string;
|
package/plugins/pkg.ts
CHANGED
|
@@ -3035,34 +3035,9 @@ editor.registerCommand("%cmd.install_url", "%cmd.install_url_desc", "pkg_install
|
|
|
3035
3035
|
// Note: Other commands (install_plugin, install_theme, update, remove, sync, etc.)
|
|
3036
3036
|
// are available via the package manager UI and don't need global command palette entries.
|
|
3037
3037
|
|
|
3038
|
-
//
|
|
3039
|
-
//
|
|
3040
|
-
//
|
|
3041
|
-
|
|
3042
|
-
(async function loadInstalledPackages() {
|
|
3043
|
-
// Load language packs
|
|
3044
|
-
const languages = getInstalledPackages("language");
|
|
3045
|
-
for (const pkg of languages) {
|
|
3046
|
-
if (pkg.manifest) {
|
|
3047
|
-
editor.debug(`[pkg] Loading language pack: ${pkg.name}`);
|
|
3048
|
-
await loadLanguagePack(pkg.path, pkg.manifest);
|
|
3049
|
-
}
|
|
3050
|
-
}
|
|
3051
|
-
if (languages.length > 0) {
|
|
3052
|
-
editor.debug(`[pkg] Loaded ${languages.length} language pack(s)`);
|
|
3053
|
-
}
|
|
3054
|
-
|
|
3055
|
-
// Load bundles
|
|
3056
|
-
const bundles = getInstalledPackages("bundle");
|
|
3057
|
-
for (const pkg of bundles) {
|
|
3058
|
-
if (pkg.manifest) {
|
|
3059
|
-
editor.debug(`[pkg] Loading bundle: ${pkg.name}`);
|
|
3060
|
-
await loadBundle(pkg.path, pkg.manifest);
|
|
3061
|
-
}
|
|
3062
|
-
}
|
|
3063
|
-
if (bundles.length > 0) {
|
|
3064
|
-
editor.debug(`[pkg] Loaded ${bundles.length} bundle(s)`);
|
|
3065
|
-
}
|
|
3066
|
-
})();
|
|
3038
|
+
// Note: Startup loading of installed language packs and bundles is now handled
|
|
3039
|
+
// by Rust (services::packages::scan_installed_packages) during editor init.
|
|
3040
|
+
// The loadLanguagePack() and loadBundle() functions above are still used for
|
|
3041
|
+
// runtime installs via the package manager UI.
|
|
3067
3042
|
|
|
3068
3043
|
editor.debug("Package Manager plugin loaded");
|