@fresh-editor/fresh-editor 0.1.76 → 0.1.83

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.
@@ -11,7 +11,15 @@
11
11
  */
12
12
 
13
13
  // Types
14
- export type { RGB, Location, PanelOptions, PanelState, NavigationOptions, HighlightPattern } from "./types.ts";
14
+ export type {
15
+ RGB,
16
+ Location,
17
+ PanelOptions,
18
+ PanelState,
19
+ NavigationOptions,
20
+ HighlightPattern,
21
+ FileExplorerDecoration,
22
+ } from "./types.ts";
15
23
 
16
24
  // Panel Management
17
25
  export { PanelManager } from "./panel-manager.ts";
@@ -11,6 +11,20 @@
11
11
  */
12
12
  export type RGB = [number, number, number];
13
13
 
14
+ /**
15
+ * File explorer decoration metadata provided by plugins
16
+ */
17
+ export interface FileExplorerDecoration {
18
+ /** Absolute or workspace-relative path to decorate */
19
+ path: string;
20
+ /** Symbol to display (single character recommended) */
21
+ symbol?: string;
22
+ /** RGB color for the symbol */
23
+ color?: RGB;
24
+ /** Priority for resolving conflicts (higher wins) */
25
+ priority?: number;
26
+ }
27
+
14
28
  /**
15
29
  * File location with line and column
16
30
  */
@@ -92,7 +92,7 @@ editor.registerCommand(
92
92
  "%cmd.live_grep",
93
93
  "%cmd.live_grep_desc",
94
94
  "start_live_grep",
95
- "normal"
95
+ null
96
96
  );
97
97
 
98
98
  editor.debug("Live Grep plugin loaded (using Finder abstraction)");
@@ -0,0 +1,135 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+
5
+ /**
6
+ * Odin LSP Helper Plugin
7
+ *
8
+ * Provides user-friendly error handling for Odin LSP server issues.
9
+ * When ols (Odin Language Server) fails to start, this plugin shows an actionable
10
+ * popup with installation instructions.
11
+ *
12
+ * Features:
13
+ * - Detects Odin LSP server errors (ols)
14
+ * - Shows popup with build instructions
15
+ * - Allows copying build commands to clipboard
16
+ * - Provides option to disable Odin LSP
17
+ *
18
+ * OLS: https://github.com/DanielGavin/ols
19
+ */
20
+
21
+ interface LspServerErrorData {
22
+ language: string;
23
+ server_command: string;
24
+ error_type: string;
25
+ message: string;
26
+ }
27
+
28
+ interface LspStatusClickedData {
29
+ language: string;
30
+ has_error: boolean;
31
+ }
32
+
33
+ interface ActionPopupResultData {
34
+ popup_id: string;
35
+ action_id: string;
36
+ }
37
+
38
+ // OLS GitHub repository
39
+ const OLS_URL = "https://github.com/DanielGavin/ols";
40
+
41
+ // Track error state for Odin LSP
42
+ let odinLspError: { serverCommand: string; message: string } | null = null;
43
+
44
+ /**
45
+ * Handle LSP server errors for Odin
46
+ */
47
+ globalThis.on_odin_lsp_server_error = function (data: LspServerErrorData): void {
48
+ // Only handle Odin language errors
49
+ if (data.language !== "odin") {
50
+ return;
51
+ }
52
+
53
+ editor.debug(`odin-lsp: Server error - ${data.error_type}: ${data.message}`);
54
+
55
+ // Store error state for later reference
56
+ odinLspError = {
57
+ serverCommand: data.server_command,
58
+ message: data.message,
59
+ };
60
+
61
+ // Show a status message for immediate feedback
62
+ if (data.error_type === "not_found") {
63
+ editor.setStatus(
64
+ `Odin LSP server '${data.server_command}' not found. Click status bar for help.`
65
+ );
66
+ } else {
67
+ editor.setStatus(`Odin LSP error: ${data.message}`);
68
+ }
69
+ };
70
+
71
+ // Register hook for LSP server errors
72
+ editor.on("lsp_server_error", "on_odin_lsp_server_error");
73
+
74
+ /**
75
+ * Handle status bar click when there's an Odin LSP error
76
+ */
77
+ globalThis.on_odin_lsp_status_clicked = function (
78
+ data: LspStatusClickedData
79
+ ): void {
80
+ // Only handle Odin language clicks when there's an error
81
+ if (data.language !== "odin" || !odinLspError) {
82
+ return;
83
+ }
84
+
85
+ editor.debug("odin-lsp: Status clicked, showing help popup");
86
+
87
+ // Show action popup with install options
88
+ editor.showActionPopup({
89
+ id: "odin-lsp-help",
90
+ title: "Odin Language Server Not Found",
91
+ message: `"${odinLspError.serverCommand}" (OLS) provides code completion, diagnostics, and navigation for Odin files.\n\nInstallation: ${OLS_URL}`,
92
+ actions: [
93
+ { id: "disable", label: "Disable Odin LSP" },
94
+ { id: "dismiss", label: "Dismiss (ESC)" },
95
+ ],
96
+ });
97
+ };
98
+
99
+ // Register hook for status bar clicks
100
+ editor.on("lsp_status_clicked", "on_odin_lsp_status_clicked");
101
+
102
+ /**
103
+ * Handle action popup results for Odin LSP help
104
+ */
105
+ globalThis.on_odin_lsp_action_result = function (
106
+ data: ActionPopupResultData
107
+ ): void {
108
+ // Only handle our popup
109
+ if (data.popup_id !== "odin-lsp-help") {
110
+ return;
111
+ }
112
+
113
+ editor.debug(`odin-lsp: Action selected - ${data.action_id}`);
114
+
115
+ switch (data.action_id) {
116
+ case "disable":
117
+ editor.disableLspForLanguage("odin");
118
+ editor.setStatus("Odin LSP disabled");
119
+ odinLspError = null;
120
+ break;
121
+
122
+ case "dismiss":
123
+ case "dismissed":
124
+ // Just close the popup without action
125
+ break;
126
+
127
+ default:
128
+ editor.debug(`odin-lsp: Unknown action: ${data.action_id}`);
129
+ }
130
+ };
131
+
132
+ // Register hook for action popup results
133
+ editor.on("action_popup_result", "on_odin_lsp_action_result");
134
+
135
+ editor.debug("odin-lsp: Plugin loaded");
@@ -478,7 +478,7 @@ editor.registerCommand(
478
478
  "%cmd.search_replace",
479
479
  "%cmd.search_replace_desc",
480
480
  "start_search_replace",
481
- "normal"
481
+ null
482
482
  );
483
483
 
484
484
  // Plugin initialization
@@ -484,10 +484,17 @@ function findThemesDir(): string {
484
484
  */
485
485
  async function loadBuiltinThemes(): Promise<string[]> {
486
486
  try {
487
- const builtinThemes = editor.getBuiltinThemes() as Record<string, string>;
487
+ editor.debug("[theme_editor] loadBuiltinThemes: calling editor.getBuiltinThemes()");
488
+ const rawThemes = editor.getBuiltinThemes();
489
+ editor.debug(`[theme_editor] loadBuiltinThemes: got rawThemes type=${typeof rawThemes}`);
490
+ // getBuiltinThemes returns a JSON string, need to parse it
491
+ const builtinThemes = typeof rawThemes === "string"
492
+ ? JSON.parse(rawThemes) as Record<string, string>
493
+ : rawThemes as Record<string, string>;
494
+ editor.debug(`[theme_editor] loadBuiltinThemes: parsed ${Object.keys(builtinThemes).length} themes`);
488
495
  return Object.keys(builtinThemes);
489
496
  } catch (e) {
490
- editor.debug(`Failed to load built-in themes list: ${e}`);
497
+ editor.debug(`[theme_editor] Failed to load built-in themes list: ${e}`);
491
498
  throw e;
492
499
  }
493
500
  }
@@ -497,13 +504,17 @@ async function loadBuiltinThemes(): Promise<string[]> {
497
504
  */
498
505
  async function loadThemeFile(name: string): Promise<Record<string, unknown> | null> {
499
506
  try {
500
- const builtinThemes = editor.getBuiltinThemes() as Record<string, string>;
507
+ const rawThemes = editor.getBuiltinThemes();
508
+ // getBuiltinThemes returns a JSON string, need to parse it
509
+ const builtinThemes = typeof rawThemes === "string"
510
+ ? JSON.parse(rawThemes) as Record<string, string>
511
+ : rawThemes as Record<string, string>;
501
512
  if (name in builtinThemes) {
502
513
  return JSON.parse(builtinThemes[name]);
503
514
  }
504
515
  return null;
505
516
  } catch (e) {
506
- editor.debug(`Failed to load theme data for '${name}': ${e}`);
517
+ editor.debug(`[theme_editor] Failed to load theme data for '${name}': ${e}`);
507
518
  return null;
508
519
  }
509
520
  }
@@ -1190,7 +1201,12 @@ globalThis.onThemeSelectInitialPromptConfirmed = async function(args: {
1190
1201
  selected_index: number | null;
1191
1202
  input: string;
1192
1203
  }): Promise<boolean> {
1193
- if (args.prompt_type !== "theme-select-initial") return true;
1204
+ editor.debug(`[theme_editor] onThemeSelectInitialPromptConfirmed called with: ${JSON.stringify(args)}`);
1205
+ if (args.prompt_type !== "theme-select-initial") {
1206
+ editor.debug(`[theme_editor] prompt_type mismatch, expected 'theme-select-initial', got '${args.prompt_type}'`);
1207
+ return true;
1208
+ }
1209
+ editor.debug(`[theme_editor] prompt_type matched, processing selection...`);
1194
1210
 
1195
1211
  const value = args.input.trim();
1196
1212
 
@@ -1252,7 +1268,9 @@ globalThis.onThemeSelectInitialPromptConfirmed = async function(args: {
1252
1268
  }
1253
1269
 
1254
1270
  // Now open the editor with loaded theme
1271
+ editor.debug(`[theme_editor] About to call doOpenThemeEditor()`);
1255
1272
  await doOpenThemeEditor();
1273
+ editor.debug(`[theme_editor] doOpenThemeEditor() completed`);
1256
1274
 
1257
1275
  return true;
1258
1276
  };
@@ -1642,7 +1660,9 @@ globalThis.theme_editor_nav_prev_section = function(): void {
1642
1660
  * Open the theme editor - prompts user to select theme first
1643
1661
  */
1644
1662
  globalThis.open_theme_editor = async function(): Promise<void> {
1663
+ editor.debug("[theme_editor] open_theme_editor called");
1645
1664
  if (isThemeEditorOpen()) {
1665
+ editor.debug("[theme_editor] already open, focusing");
1646
1666
  // Focus the existing theme editor split
1647
1667
  if (state.splitId !== null) {
1648
1668
  editor.focusSplit(state.splitId);
@@ -1651,12 +1671,15 @@ globalThis.open_theme_editor = async function(): Promise<void> {
1651
1671
  return;
1652
1672
  }
1653
1673
 
1674
+ editor.debug("[theme_editor] saving context");
1654
1675
  // Save context
1655
1676
  state.sourceSplitId = editor.getActiveSplitId();
1656
1677
  state.sourceBufferId = editor.getActiveBufferId();
1657
1678
 
1679
+ editor.debug("[theme_editor] loading builtin themes...");
1658
1680
  // Load available themes
1659
1681
  state.builtinThemes = await loadBuiltinThemes();
1682
+ editor.debug(`[theme_editor] loaded ${state.builtinThemes.length} builtin themes`);
1660
1683
 
1661
1684
  // Get current theme name from config
1662
1685
  const config = editor.getConfig() as Record<string, unknown>;
@@ -1704,10 +1727,13 @@ globalThis.open_theme_editor = async function(): Promise<void> {
1704
1727
  * Actually open the theme editor with loaded theme data
1705
1728
  */
1706
1729
  async function doOpenThemeEditor(): Promise<void> {
1730
+ editor.debug("[theme_editor] doOpenThemeEditor: building display entries");
1707
1731
  // Build initial entries
1708
1732
  const entries = buildDisplayEntries();
1733
+ editor.debug(`[theme_editor] doOpenThemeEditor: built ${entries.length} entries`);
1709
1734
 
1710
1735
  // Create virtual buffer in current split (no new split)
1736
+ editor.debug("[theme_editor] doOpenThemeEditor: calling createVirtualBuffer...");
1711
1737
  const bufferId = await editor.createVirtualBuffer({
1712
1738
  name: "*Theme Editor*",
1713
1739
  mode: "theme-editor",
@@ -1717,13 +1743,20 @@ async function doOpenThemeEditor(): Promise<void> {
1717
1743
  show_cursors: true,
1718
1744
  editing_disabled: true,
1719
1745
  });
1746
+ editor.debug(`[theme_editor] doOpenThemeEditor: createVirtualBuffer returned bufferId=${bufferId}`);
1747
+ editor.debug(`[theme_editor] doOpenThemeEditor: checking if bufferId !== null...`);
1720
1748
 
1721
1749
  if (bufferId !== null) {
1750
+ editor.debug(`[theme_editor] doOpenThemeEditor: bufferId is not null, setting state...`);
1722
1751
  state.bufferId = bufferId;
1723
1752
  state.splitId = null;
1724
1753
 
1754
+ editor.debug(`[theme_editor] doOpenThemeEditor: calling applyHighlighting...`);
1725
1755
  applyHighlighting();
1756
+ editor.debug(`[theme_editor] doOpenThemeEditor: applyHighlighting completed`);
1757
+ editor.debug(`[theme_editor] doOpenThemeEditor: calling setStatus...`);
1726
1758
  editor.setStatus(editor.t("status.ready"));
1759
+ editor.debug(`[theme_editor] doOpenThemeEditor: completed successfully`);
1727
1760
  } else {
1728
1761
  editor.setStatus(editor.t("status.open_failed"));
1729
1762
  }
@@ -2037,12 +2070,11 @@ globalThis.onThemeDeletePromptConfirmed = async function(args: {
2037
2070
  // Command Registration
2038
2071
  // =============================================================================
2039
2072
 
2040
- // Main command to open theme editor (always available)
2073
+ // Main command to open theme editor (always available - no context restriction)
2041
2074
  editor.registerCommand(
2042
2075
  "%cmd.edit_theme",
2043
2076
  "%cmd.edit_theme_desc",
2044
- "open_theme_editor",
2045
- "normal"
2077
+ "open_theme_editor"
2046
2078
  );
2047
2079
 
2048
2080
  // Buffer-scoped commands - only visible when a buffer with mode "theme-editor" is focused
@@ -2724,17 +2724,23 @@ editor.on("prompt_confirmed", "vi_command_handler");
2724
2724
  let viModeEnabled = false;
2725
2725
 
2726
2726
  globalThis.vi_mode_toggle = function (): void {
2727
+ editor.debug("[vi_mode_toggle] called, viModeEnabled was: " + viModeEnabled);
2727
2728
  viModeEnabled = !viModeEnabled;
2729
+ editor.debug("[vi_mode_toggle] viModeEnabled now: " + viModeEnabled);
2728
2730
 
2729
2731
  if (viModeEnabled) {
2732
+ editor.debug("[vi_mode_toggle] enabling vi mode, calling switchMode('normal')");
2730
2733
  switchMode("normal");
2734
+ editor.debug("[vi_mode_toggle] switchMode done, setting status");
2731
2735
  editor.setStatus(editor.t("status.enabled"));
2732
2736
  } else {
2737
+ editor.debug("[vi_mode_toggle] disabling vi mode");
2733
2738
  editor.setEditorMode(null);
2734
2739
  state.mode = "normal";
2735
2740
  state.pendingOperator = null;
2736
2741
  editor.setStatus(editor.t("status.disabled"));
2737
2742
  }
2743
+ editor.debug("[vi_mode_toggle] done");
2738
2744
  };
2739
2745
 
2740
2746
  editor.registerCommand(
@@ -15,14 +15,14 @@ editor.registerCommand(
15
15
  "%cmd.open_help",
16
16
  "%cmd.open_help_desc",
17
17
  "show_help",
18
- "normal"
18
+ null
19
19
  );
20
20
 
21
21
  editor.registerCommand(
22
22
  "%cmd.save_file",
23
23
  "%cmd.save_file_desc",
24
24
  "save",
25
- "normal"
25
+ null
26
26
  );
27
27
 
28
28
  // Register commands with custom TypeScript callbacks
@@ -36,7 +36,7 @@ editor.registerCommand(
36
36
  "%cmd.say_hello",
37
37
  "%cmd.say_hello_desc",
38
38
  "plugin_say_hello",
39
- "normal"
39
+ null
40
40
  );
41
41
 
42
42
  globalThis.plugin_insert_time = function(): void {
@@ -50,7 +50,7 @@ editor.registerCommand(
50
50
  "%cmd.insert_time",
51
51
  "%cmd.insert_time_desc",
52
52
  "plugin_insert_time",
53
- "normal"
53
+ null
54
54
  );
55
55
 
56
56
  globalThis.plugin_insert_comment = function(): void {
@@ -63,7 +63,7 @@ editor.registerCommand(
63
63
  "%cmd.insert_comment",
64
64
  "%cmd.insert_comment_desc",
65
65
  "plugin_insert_comment",
66
- "normal"
66
+ null
67
67
  );
68
68
 
69
69
  // Debug output