@fresh-editor/fresh-editor 0.2.12 → 0.2.13

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 (51) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +10 -0
  3. package/package.json +1 -1
  4. package/plugins/audit_mode.ts +79 -58
  5. package/plugins/check-types.sh +1 -0
  6. package/plugins/clangd-lsp.ts +9 -6
  7. package/plugins/clangd_support.ts +12 -8
  8. package/plugins/code-tour.ts +15 -10
  9. package/plugins/config-schema.json +40 -3
  10. package/plugins/csharp_support.ts +15 -10
  11. package/plugins/css-lsp.ts +9 -6
  12. package/plugins/diagnostics_panel.ts +25 -18
  13. package/plugins/examples/README.md +1 -2
  14. package/plugins/examples/async_demo.ts +28 -28
  15. package/plugins/examples/bookmarks.ts +34 -32
  16. package/plugins/examples/buffer_query_demo.ts +20 -20
  17. package/plugins/examples/hello_world.ts +46 -10
  18. package/plugins/examples/virtual_buffer_demo.ts +16 -12
  19. package/plugins/find_references.ts +7 -5
  20. package/plugins/git_blame.ts +13 -9
  21. package/plugins/git_explorer.ts +9 -6
  22. package/plugins/git_find_file.ts +7 -5
  23. package/plugins/git_grep.ts +3 -2
  24. package/plugins/git_gutter.ts +15 -10
  25. package/plugins/git_log.ts +27 -18
  26. package/plugins/go-lsp.ts +9 -6
  27. package/plugins/html-lsp.ts +9 -6
  28. package/plugins/java-lsp.ts +9 -6
  29. package/plugins/json-lsp.ts +9 -6
  30. package/plugins/latex-lsp.ts +9 -6
  31. package/plugins/lib/finder.ts +1 -0
  32. package/plugins/lib/fresh.d.ts +139 -14
  33. package/plugins/live_grep.ts +3 -2
  34. package/plugins/markdown_compose.ts +33 -23
  35. package/plugins/markdown_source.ts +15 -10
  36. package/plugins/marksman-lsp.ts +9 -6
  37. package/plugins/merge_conflict.ts +33 -22
  38. package/plugins/odin-lsp.ts +9 -6
  39. package/plugins/path_complete.ts +3 -2
  40. package/plugins/pkg.ts +70 -48
  41. package/plugins/python-lsp.ts +9 -6
  42. package/plugins/rust-lsp.ts +102 -6
  43. package/plugins/search_replace.ts +32 -21
  44. package/plugins/templ-lsp.ts +9 -6
  45. package/plugins/test_i18n.ts +3 -2
  46. package/plugins/theme_editor.i18n.json +28 -14
  47. package/plugins/theme_editor.ts +1230 -495
  48. package/plugins/typescript-lsp.ts +9 -6
  49. package/plugins/vi_mode.ts +487 -297
  50. package/plugins/welcome.ts +9 -6
  51. package/plugins/zig-lsp.ts +9 -6
@@ -48,7 +48,7 @@ let rustLspError: { serverCommand: string; message: string } | null = null;
48
48
  /**
49
49
  * Handle LSP server errors for Rust
50
50
  */
51
- globalThis.on_rust_lsp_server_error = function (
51
+ function on_rust_lsp_server_error(
52
52
  data: LspServerErrorData
53
53
  ): void {
54
54
  // Only handle Rust language errors
@@ -72,7 +72,8 @@ globalThis.on_rust_lsp_server_error = function (
72
72
  } else {
73
73
  editor.setStatus(`Rust LSP error: ${data.message}`);
74
74
  }
75
- };
75
+ }
76
+ registerHandler("on_rust_lsp_server_error", on_rust_lsp_server_error);
76
77
 
77
78
  // Register hook for LSP server errors
78
79
  editor.on("lsp_server_error", "on_rust_lsp_server_error");
@@ -80,7 +81,7 @@ editor.on("lsp_server_error", "on_rust_lsp_server_error");
80
81
  /**
81
82
  * Handle status bar click when there's a Rust LSP error
82
83
  */
83
- globalThis.on_rust_lsp_status_clicked = function (
84
+ function on_rust_lsp_status_clicked(
84
85
  data: LspStatusClickedData
85
86
  ): void {
86
87
  editor.debug(
@@ -110,7 +111,8 @@ globalThis.on_rust_lsp_status_clicked = function (
110
111
  ],
111
112
  });
112
113
  editor.debug(`rust-lsp: showActionPopup returned ${result}`);
113
- };
114
+ }
115
+ registerHandler("on_rust_lsp_status_clicked", on_rust_lsp_status_clicked);
114
116
 
115
117
  // Register hook for status bar clicks
116
118
  editor.on("lsp_status_clicked", "on_rust_lsp_status_clicked");
@@ -118,7 +120,7 @@ editor.on("lsp_status_clicked", "on_rust_lsp_status_clicked");
118
120
  /**
119
121
  * Handle action popup results for Rust LSP help
120
122
  */
121
- globalThis.on_rust_lsp_action_result = function (
123
+ function on_rust_lsp_action_result(
122
124
  data: ActionPopupResultData
123
125
  ): void {
124
126
  editor.debug(
@@ -158,9 +160,103 @@ globalThis.on_rust_lsp_action_result = function (
158
160
  default:
159
161
  editor.debug(`rust-lsp: Unknown action: ${data.action_id}`);
160
162
  }
161
- };
163
+ }
164
+ registerHandler("on_rust_lsp_action_result", on_rust_lsp_action_result);
162
165
 
163
166
  // Register hook for action popup results
164
167
  editor.on("action_popup_result", "on_rust_lsp_action_result");
165
168
 
169
+ // =====================================================================
170
+ // Rust LSP mode switching (Full vs Reduced Memory)
171
+ // =====================================================================
172
+
173
+ // Reduced-memory init options for rust-analyzer:
174
+ // - checkOnSave: false - disables cargo check on every save (#1 cause of slowdowns)
175
+ // - cachePriming.enable: false - no background indexing of entire crate graph
176
+ // - procMacro.enable: false - no proc-macro expansion (saves CPU/RAM)
177
+ // - cargo.buildScripts.enable: false - no build.rs
178
+ // - cargo.autoreload: false - manual reload only
179
+ const REDUCED_MEMORY_INIT_OPTIONS = {
180
+ checkOnSave: false,
181
+ cachePriming: { enable: false },
182
+ procMacro: { enable: false },
183
+ cargo: {
184
+ buildScripts: { enable: false },
185
+ autoreload: false,
186
+ },
187
+ diagnostics: { enable: true },
188
+ files: { watcher: "server" },
189
+ };
190
+
191
+ const REDUCED_MEMORY_PROCESS_LIMITS: ProcessLimitsPackConfig = {
192
+ maxMemoryPercent: 50,
193
+ maxCpuPercent: 90,
194
+ enabled: true,
195
+ };
196
+
197
+ const NO_PROCESS_LIMITS: ProcessLimitsPackConfig = {
198
+ maxMemoryPercent: null,
199
+ maxCpuPercent: null,
200
+ enabled: false,
201
+ };
202
+
203
+ function on_rust_lsp_configure(): void {
204
+ editor.showActionPopup({
205
+ id: "rust-lsp-mode",
206
+ title: "Rust LSP Mode",
207
+ message: "This will override your Rust LSP config and restart the server.",
208
+ actions: [
209
+ { id: "full", label: "Full Mode (all features, no process limits)" },
210
+ { id: "reduced", label: "Reduced Memory (restricted features, 50% RAM / 90% CPU limits)" },
211
+ { id: "dismiss", label: "Cancel (ESC)" },
212
+ ],
213
+ });
214
+ }
215
+ registerHandler("on_rust_lsp_configure", on_rust_lsp_configure);
216
+
217
+ editor.registerCommand(
218
+ "Rust LSP: Configure Mode",
219
+ "Switch rust-analyzer between full and reduced memory modes",
220
+ "on_rust_lsp_configure",
221
+ null
222
+ );
223
+
224
+ function on_rust_lsp_mode_selected(data: ActionPopupResultData): void {
225
+ if (data.popup_id !== "rust-lsp-mode") {
226
+ return;
227
+ }
228
+
229
+ switch (data.action_id) {
230
+ case "full":
231
+ editor.registerLspServer("rust", {
232
+ command: "rust-analyzer",
233
+ args: [],
234
+ autoStart: true,
235
+ initializationOptions: null,
236
+ processLimits: NO_PROCESS_LIMITS,
237
+ });
238
+ editor.restartLspForLanguage("rust");
239
+ editor.setStatus("Rust LSP: Full mode — all features enabled, no process limits");
240
+ break;
241
+
242
+ case "reduced":
243
+ editor.registerLspServer("rust", {
244
+ command: "rust-analyzer",
245
+ args: [],
246
+ autoStart: true,
247
+ initializationOptions: REDUCED_MEMORY_INIT_OPTIONS,
248
+ processLimits: REDUCED_MEMORY_PROCESS_LIMITS,
249
+ });
250
+ editor.restartLspForLanguage("rust");
251
+ editor.setStatus("Rust LSP: Reduced Memory mode — checkOnSave, procMacro, cachePriming disabled");
252
+ break;
253
+
254
+ case "dismiss":
255
+ case "dismissed":
256
+ break;
257
+ }
258
+ }
259
+ registerHandler("on_rust_lsp_mode_selected", on_rust_lsp_mode_selected);
260
+ editor.on("action_popup_result", "on_rust_lsp_mode_selected");
261
+
166
262
  editor.debug("rust-lsp: Plugin loaded");
@@ -274,6 +274,7 @@ async function executeReplacements(): Promise<void> {
274
274
  try {
275
275
  // Read file
276
276
  const content = await editor.readFile(filePath);
277
+ if (!content) continue;
277
278
  const lines = content.split("\n");
278
279
 
279
280
  // Sort results by line (descending) to avoid offset issues
@@ -320,21 +321,22 @@ async function executeReplacements(): Promise<void> {
320
321
  }
321
322
 
322
323
  // Close panel after replacement
323
- globalThis.search_replace_close();
324
+ search_replace_close();
324
325
  }
325
326
 
326
327
  // Start search/replace workflow
327
- globalThis.start_search_replace = function(): void {
328
+ function start_search_replace() : void {
328
329
  searchResults = [];
329
330
  searchPattern = "";
330
331
  replaceText = "";
331
332
 
332
333
  editor.startPrompt(editor.t("prompt.search"), "search-replace-search");
333
334
  editor.setStatus(editor.t("status.enter_pattern"));
334
- };
335
+ }
336
+ registerHandler("start_search_replace", start_search_replace);
335
337
 
336
338
  // Handle search prompt confirmation
337
- globalThis.onSearchReplaceSearchConfirmed = function(args: {
339
+ function onSearchReplaceSearchConfirmed(args: {
338
340
  prompt_type: string;
339
341
  selected_index: number | null;
340
342
  input: string;
@@ -354,10 +356,11 @@ globalThis.onSearchReplaceSearchConfirmed = function(args: {
354
356
  // Ask for replacement text
355
357
  editor.startPrompt(editor.t("prompt.replace"), "search-replace-replace");
356
358
  return true;
357
- };
359
+ }
360
+ registerHandler("onSearchReplaceSearchConfirmed", onSearchReplaceSearchConfirmed);
358
361
 
359
362
  // Handle replace prompt confirmation
360
- globalThis.onSearchReplaceReplaceConfirmed = async function(args: {
363
+ async function onSearchReplaceReplaceConfirmed(args: {
361
364
  prompt_type: string;
362
365
  selected_index: number | null;
363
366
  input: string;
@@ -373,10 +376,11 @@ globalThis.onSearchReplaceReplaceConfirmed = async function(args: {
373
376
  await showResultsPanel();
374
377
 
375
378
  return true;
376
- };
379
+ }
380
+ registerHandler("onSearchReplaceReplaceConfirmed", onSearchReplaceReplaceConfirmed);
377
381
 
378
382
  // Handle prompt cancellation
379
- globalThis.onSearchReplacePromptCancelled = function(args: {
383
+ function onSearchReplacePromptCancelled(args: {
380
384
  prompt_type: string;
381
385
  }): boolean {
382
386
  if (args.prompt_type !== "search-replace-search" &&
@@ -386,10 +390,11 @@ globalThis.onSearchReplacePromptCancelled = function(args: {
386
390
 
387
391
  editor.setStatus(editor.t("status.cancelled"));
388
392
  return true;
389
- };
393
+ }
394
+ registerHandler("onSearchReplacePromptCancelled", onSearchReplacePromptCancelled);
390
395
 
391
396
  // Toggle selection of current item
392
- globalThis.search_replace_toggle_item = function(): void {
397
+ function search_replace_toggle_item() : void {
393
398
  if (resultsBufferId === null || searchResults.length === 0) return;
394
399
 
395
400
  const props = editor.getTextPropertiesAtCursor(resultsBufferId);
@@ -402,28 +407,31 @@ globalThis.search_replace_toggle_item = function(): void {
402
407
  editor.setStatus(editor.t("status.selected_count", { selected: String(selected), total: String(searchResults.length) }));
403
408
  }
404
409
  }
405
- };
410
+ }
411
+ registerHandler("search_replace_toggle_item", search_replace_toggle_item);
406
412
 
407
413
  // Select all items
408
- globalThis.search_replace_select_all = function(): void {
414
+ function search_replace_select_all() : void {
409
415
  for (const result of searchResults) {
410
416
  result.selected = true;
411
417
  }
412
418
  updatePanelContent();
413
419
  editor.setStatus(editor.t("status.selected_count", { selected: String(searchResults.length), total: String(searchResults.length) }));
414
- };
420
+ }
421
+ registerHandler("search_replace_select_all", search_replace_select_all);
415
422
 
416
423
  // Select no items
417
- globalThis.search_replace_select_none = function(): void {
424
+ function search_replace_select_none() : void {
418
425
  for (const result of searchResults) {
419
426
  result.selected = false;
420
427
  }
421
428
  updatePanelContent();
422
429
  editor.setStatus(editor.t("status.selected_count", { selected: "0", total: String(searchResults.length) }));
423
- };
430
+ }
431
+ registerHandler("search_replace_select_none", search_replace_select_none);
424
432
 
425
433
  // Execute replacement
426
- globalThis.search_replace_execute = function(): void {
434
+ function search_replace_execute() : void {
427
435
  const selected = searchResults.filter(r => r.selected).length;
428
436
  if (selected === 0) {
429
437
  editor.setStatus(editor.t("status.no_items_selected"));
@@ -432,10 +440,11 @@ globalThis.search_replace_execute = function(): void {
432
440
 
433
441
  editor.setStatus(editor.t("status.replacing", { count: String(selected) }));
434
442
  executeReplacements();
435
- };
443
+ }
444
+ registerHandler("search_replace_execute", search_replace_execute);
436
445
 
437
446
  // Preview current item (jump to location)
438
- globalThis.search_replace_preview = function(): void {
447
+ function search_replace_preview() : void {
439
448
  if (sourceSplitId === null || resultsBufferId === null) return;
440
449
 
441
450
  const props = editor.getTextPropertiesAtCursor(resultsBufferId);
@@ -446,10 +455,11 @@ globalThis.search_replace_preview = function(): void {
446
455
  editor.setStatus(editor.t("status.preview", { file: getRelativePath(location.file), line: String(location.line) }));
447
456
  }
448
457
  }
449
- };
458
+ }
459
+ registerHandler("search_replace_preview", search_replace_preview);
450
460
 
451
461
  // Close the panel
452
- globalThis.search_replace_close = function(): void {
462
+ function search_replace_close() : void {
453
463
  if (!panelOpen) return;
454
464
 
455
465
  if (resultsBufferId !== null) {
@@ -466,7 +476,8 @@ globalThis.search_replace_close = function(): void {
466
476
  resultsSplitId = null;
467
477
  searchResults = [];
468
478
  editor.setStatus(editor.t("status.closed"));
469
- };
479
+ }
480
+ registerHandler("search_replace_close", search_replace_close);
470
481
 
471
482
  // Register event handlers
472
483
  editor.on("prompt_confirmed", "onSearchReplaceSearchConfirmed");
@@ -22,7 +22,7 @@ interface ActionPopupResultData {
22
22
  const INSTALL_URL = "https://templ.guide/quick-start/installation";
23
23
  let templLspError: { serverCommand: string; message: string } | null = null;
24
24
 
25
- globalThis.on_templ_lsp_server_error = function (data: LspServerErrorData): void {
25
+ function on_templ_lsp_server_error(data: LspServerErrorData) : void {
26
26
  if (data.language !== "templ") return;
27
27
  templLspError = { serverCommand: data.server_command, message: data.message };
28
28
  if (data.error_type === "not_found") {
@@ -30,10 +30,11 @@ globalThis.on_templ_lsp_server_error = function (data: LspServerErrorData): void
30
30
  } else {
31
31
  editor.setStatus(`Templ LSP error: ${data.message}`);
32
32
  }
33
- };
33
+ }
34
+ registerHandler("on_templ_lsp_server_error", on_templ_lsp_server_error);
34
35
  editor.on("lsp_server_error", "on_templ_lsp_server_error");
35
36
 
36
- globalThis.on_templ_lsp_status_clicked = function (data: LspStatusClickedData): void {
37
+ function on_templ_lsp_status_clicked(data: LspStatusClickedData) : void {
37
38
  if (data.language !== "templ" || !templLspError) return;
38
39
  editor.showActionPopup({
39
40
  id: "templ-lsp-help",
@@ -45,10 +46,11 @@ globalThis.on_templ_lsp_status_clicked = function (data: LspStatusClickedData):
45
46
  { id: "dismiss", label: "Dismiss (ESC)" },
46
47
  ],
47
48
  });
48
- };
49
+ }
50
+ registerHandler("on_templ_lsp_status_clicked", on_templ_lsp_status_clicked);
49
51
  editor.on("lsp_status_clicked", "on_templ_lsp_status_clicked");
50
52
 
51
- globalThis.on_templ_lsp_action_result = function (data: ActionPopupResultData): void {
53
+ function on_templ_lsp_action_result(data: ActionPopupResultData) : void {
52
54
  if (data.popup_id !== "templ-lsp-help") return;
53
55
  switch (data.action_id) {
54
56
  case "copy_url":
@@ -61,5 +63,6 @@ globalThis.on_templ_lsp_action_result = function (data: ActionPopupResultData):
61
63
  templLspError = null;
62
64
  break;
63
65
  }
64
- };
66
+ }
67
+ registerHandler("on_templ_lsp_action_result", on_templ_lsp_action_result);
65
68
  editor.on("action_popup_result", "on_templ_lsp_action_result");
@@ -2,11 +2,12 @@
2
2
  const editor = getEditor();
3
3
 
4
4
 
5
- globalThis.test_i18n_action = function() {
5
+ function test_i18n_action() {
6
6
  const locale = editor.getCurrentLocale();
7
7
  const msg = editor.t("msg.hello", { name: "User", locale: locale });
8
8
  editor.setStatus(msg);
9
- };
9
+ }
10
+ registerHandler("test_i18n_action", test_i18n_action);
10
11
 
11
12
  editor.registerCommand(
12
13
  "%cmd.test",