@fresh-editor/fresh-editor 0.1.65 → 0.1.69

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 (64) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +4 -2
  3. package/package.json +1 -1
  4. package/plugins/audit_mode.i18n.json +380 -0
  5. package/plugins/audit_mode.ts +1813 -0
  6. package/plugins/buffer_modified.i18n.json +32 -0
  7. package/plugins/buffer_modified.ts +5 -3
  8. package/plugins/calculator.i18n.json +44 -0
  9. package/plugins/calculator.ts +6 -4
  10. package/plugins/clangd-lsp.ts +168 -0
  11. package/plugins/clangd_support.i18n.json +104 -0
  12. package/plugins/clangd_support.ts +18 -16
  13. package/plugins/color_highlighter.i18n.json +68 -0
  14. package/plugins/color_highlighter.ts +12 -10
  15. package/plugins/config-schema.json +79 -141
  16. package/plugins/csharp-lsp.ts +147 -0
  17. package/plugins/csharp_support.i18n.json +38 -0
  18. package/plugins/csharp_support.ts +6 -4
  19. package/plugins/css-lsp.ts +143 -0
  20. package/plugins/diagnostics_panel.i18n.json +110 -0
  21. package/plugins/diagnostics_panel.ts +19 -17
  22. package/plugins/find_references.i18n.json +128 -0
  23. package/plugins/find_references.ts +22 -20
  24. package/plugins/git_blame.i18n.json +230 -0
  25. package/plugins/git_blame.ts +39 -37
  26. package/plugins/git_find_file.i18n.json +146 -0
  27. package/plugins/git_find_file.ts +24 -22
  28. package/plugins/git_grep.i18n.json +80 -0
  29. package/plugins/git_grep.ts +15 -13
  30. package/plugins/git_gutter.i18n.json +44 -0
  31. package/plugins/git_gutter.ts +7 -5
  32. package/plugins/git_log.i18n.json +224 -0
  33. package/plugins/git_log.ts +41 -39
  34. package/plugins/go-lsp.ts +143 -0
  35. package/plugins/html-lsp.ts +145 -0
  36. package/plugins/json-lsp.ts +145 -0
  37. package/plugins/lib/fresh.d.ts +150 -14
  38. package/plugins/lib/index.ts +1 -1
  39. package/plugins/lib/navigation-controller.ts +3 -3
  40. package/plugins/lib/panel-manager.ts +15 -13
  41. package/plugins/lib/virtual-buffer-factory.ts +84 -112
  42. package/plugins/live_grep.i18n.json +80 -0
  43. package/plugins/live_grep.ts +15 -13
  44. package/plugins/markdown_compose.i18n.json +104 -0
  45. package/plugins/markdown_compose.ts +17 -15
  46. package/plugins/merge_conflict.i18n.json +380 -0
  47. package/plugins/merge_conflict.ts +72 -73
  48. package/plugins/path_complete.i18n.json +38 -0
  49. package/plugins/path_complete.ts +6 -4
  50. package/plugins/python-lsp.ts +162 -0
  51. package/plugins/rust-lsp.ts +166 -0
  52. package/plugins/search_replace.i18n.json +188 -0
  53. package/plugins/search_replace.ts +31 -29
  54. package/plugins/test_i18n.i18n.json +12 -0
  55. package/plugins/test_i18n.ts +18 -0
  56. package/plugins/theme_editor.i18n.json +1417 -0
  57. package/plugins/theme_editor.ts +73 -69
  58. package/plugins/todo_highlighter.i18n.json +86 -0
  59. package/plugins/todo_highlighter.ts +15 -13
  60. package/plugins/typescript-lsp.ts +167 -0
  61. package/plugins/vi_mode.i18n.json +716 -0
  62. package/plugins/vi_mode.ts +2747 -0
  63. package/plugins/welcome.i18n.json +110 -0
  64. package/plugins/welcome.ts +18 -16
@@ -1,4 +1,6 @@
1
1
  /// <reference path="../types/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
2
4
 
3
5
  /**
4
6
  * Git Log Plugin - Magit-style Git Log Interface
@@ -185,7 +187,7 @@ async function fetchGitLog(): Promise<GitCommit[]> {
185
187
  const result = await editor.spawnProcess("git", args, cwd);
186
188
 
187
189
  if (result.exit_code !== 0) {
188
- editor.setStatus(`Git log error: ${result.stderr}`);
190
+ editor.setStatus(editor.t("status.git_error", { error: result.stderr }));
189
191
  return [];
190
192
  }
191
193
 
@@ -226,7 +228,7 @@ async function fetchCommitDiff(hash: string): Promise<string> {
226
228
  ], cwd);
227
229
 
228
230
  if (result.exit_code !== 0) {
229
- return `Error fetching diff: ${result.stderr}`;
231
+ return editor.t("status.error_fetching_diff", { error: result.stderr });
230
232
  }
231
233
 
232
234
  return result.stdout;
@@ -265,13 +267,13 @@ function buildGitLogEntries(): TextPropertyEntry[] {
265
267
 
266
268
  // Magit-style header
267
269
  entries.push({
268
- text: "Commits:\n",
270
+ text: editor.t("panel.commits_header") + "\n",
269
271
  properties: { type: "section-header" },
270
272
  });
271
273
 
272
274
  if (gitLogState.commits.length === 0) {
273
275
  entries.push({
274
- text: " No commits found\n",
276
+ text: editor.t("panel.no_commits") + "\n",
275
277
  properties: { type: "empty" },
276
278
  });
277
279
  } else {
@@ -301,7 +303,7 @@ function buildGitLogEntries(): TextPropertyEntry[] {
301
303
  properties: { type: "blank" },
302
304
  });
303
305
  entries.push({
304
- text: `${gitLogState.commits.length} commits | ↑/↓/j/k: navigate | RET: show | y: yank hash | r: refresh | q: quit\n`,
306
+ text: editor.t("panel.log_footer", { count: String(gitLogState.commits.length) }) + "\n",
305
307
  properties: { type: "footer" },
306
308
  });
307
309
 
@@ -333,7 +335,7 @@ function applyGitLogHighlighting(): void {
333
335
  const lineEnd = byteOffset + line.length;
334
336
 
335
337
  // Highlight section header
336
- if (line === "Commits:") {
338
+ if (line === editor.t("panel.commits_header")) {
337
339
  editor.addOverlay(
338
340
  bufferId,
339
341
  "gitlog",
@@ -590,7 +592,7 @@ function buildCommitDetailEntries(commit: GitCommit, showOutput: string): TextPr
590
592
  properties: { type: "blank" },
591
593
  });
592
594
  entries.push({
593
- text: `↑/↓/j/k: navigate | RET: open file at line | q: back to log\n`,
595
+ text: editor.t("panel.detail_footer") + "\n",
594
596
  properties: { type: "footer" },
595
597
  });
596
598
 
@@ -737,11 +739,11 @@ function applyCommitDetailHighlighting(): void {
737
739
 
738
740
  globalThis.show_git_log = async function(): Promise<void> {
739
741
  if (gitLogState.isOpen) {
740
- editor.setStatus("Git log already open");
742
+ editor.setStatus(editor.t("status.already_open"));
741
743
  return;
742
744
  }
743
745
 
744
- editor.setStatus("Loading git log...");
746
+ editor.setStatus(editor.t("status.loading"));
745
747
 
746
748
  // Store the current split ID and buffer ID before opening git log
747
749
  gitLogState.splitId = editor.getActiveSplitId();
@@ -751,7 +753,7 @@ globalThis.show_git_log = async function(): Promise<void> {
751
753
  gitLogState.commits = await fetchGitLog();
752
754
 
753
755
  if (gitLogState.commits.length === 0) {
754
- editor.setStatus("No commits found or not a git repository");
756
+ editor.setStatus(editor.t("status.no_commits"));
755
757
  gitLogState.splitId = null;
756
758
  return;
757
759
  }
@@ -779,11 +781,11 @@ globalThis.show_git_log = async function(): Promise<void> {
779
781
  // Apply syntax highlighting
780
782
  applyGitLogHighlighting();
781
783
 
782
- editor.setStatus(`Git log: ${gitLogState.commits.length} commits | ↑/↓: navigate | RET: show | q: quit`);
784
+ editor.setStatus(editor.t("status.log_ready", { count: String(gitLogState.commits.length) }));
783
785
  editor.debug("Git log panel opened");
784
786
  } else {
785
787
  gitLogState.splitId = null;
786
- editor.setStatus("Failed to open git log panel");
788
+ editor.setStatus(editor.t("status.failed_open"));
787
789
  }
788
790
  };
789
791
 
@@ -807,7 +809,7 @@ globalThis.git_log_close = function(): void {
807
809
  gitLogState.splitId = null;
808
810
  gitLogState.sourceBufferId = null;
809
811
  gitLogState.commits = [];
810
- editor.setStatus("Git log closed");
812
+ editor.setStatus(editor.t("status.closed"));
811
813
  };
812
814
 
813
815
  // Cursor moved handler for git log - update highlighting and status
@@ -831,7 +833,7 @@ globalThis.on_git_log_cursor_moved = function(data: {
831
833
  const commitIndex = cursorLine - headerLines;
832
834
 
833
835
  if (commitIndex >= 0 && commitIndex < gitLogState.commits.length) {
834
- editor.setStatus(`Commit ${commitIndex + 1}/${gitLogState.commits.length}`);
836
+ editor.setStatus(editor.t("status.commit_position", { current: String(commitIndex + 1), total: String(gitLogState.commits.length) }));
835
837
  }
836
838
  };
837
839
 
@@ -841,10 +843,10 @@ editor.on("cursor_moved", "on_git_log_cursor_moved");
841
843
  globalThis.git_log_refresh = async function(): Promise<void> {
842
844
  if (!gitLogState.isOpen) return;
843
845
 
844
- editor.setStatus("Refreshing git log...");
846
+ editor.setStatus(editor.t("status.refreshing"));
845
847
  gitLogState.commits = await fetchGitLog();
846
848
  updateGitLogView();
847
- editor.setStatus(`Git log refreshed: ${gitLogState.commits.length} commits`);
849
+ editor.setStatus(editor.t("status.refreshed", { count: String(gitLogState.commits.length) }));
848
850
  };
849
851
 
850
852
  // Helper function to get commit at current cursor position
@@ -879,11 +881,11 @@ globalThis.git_log_show_commit = async function(): Promise<void> {
879
881
 
880
882
  const commit = getCommitAtCursor();
881
883
  if (!commit) {
882
- editor.setStatus("Move cursor to a commit line");
884
+ editor.setStatus(editor.t("status.move_to_commit"));
883
885
  return;
884
886
  }
885
887
 
886
- editor.setStatus(`Loading commit ${commit.shortHash}...`);
888
+ editor.setStatus(editor.t("status.loading_commit", { hash: commit.shortHash }));
887
889
 
888
890
  // Fetch full commit info using git show (includes header and diff)
889
891
  const showOutput = await fetchCommitDiff(commit.hash);
@@ -915,9 +917,9 @@ globalThis.git_log_show_commit = async function(): Promise<void> {
915
917
  // Apply syntax highlighting
916
918
  applyCommitDetailHighlighting();
917
919
 
918
- editor.setStatus(`Commit ${commit.shortHash} | ↑/↓: navigate | RET: open file | q: back`);
920
+ editor.setStatus(editor.t("status.commit_ready", { hash: commit.shortHash }));
919
921
  } else {
920
- editor.setStatus("Failed to open commit details");
922
+ editor.setStatus(editor.t("status.failed_open_details"));
921
923
  }
922
924
  };
923
925
 
@@ -926,7 +928,7 @@ globalThis.git_log_copy_hash = function(): void {
926
928
 
927
929
  const commit = getCommitAtCursor();
928
930
  if (!commit) {
929
- editor.setStatus("Move cursor to a commit line");
931
+ editor.setStatus(editor.t("status.move_to_commit"));
930
932
  return;
931
933
  }
932
934
 
@@ -934,11 +936,11 @@ globalThis.git_log_copy_hash = function(): void {
934
936
  // Try xclip first (Linux), then pbcopy (macOS), then xsel
935
937
  editor.spawnProcess("sh", ["-c", `echo -n "${commit.hash}" | xclip -selection clipboard 2>/dev/null || echo -n "${commit.hash}" | pbcopy 2>/dev/null || echo -n "${commit.hash}" | xsel --clipboard 2>/dev/null`])
936
938
  .then(() => {
937
- editor.setStatus(`Copied: ${commit.shortHash} (${commit.hash})`);
939
+ editor.setStatus(editor.t("status.hash_copied", { short: commit.shortHash, full: commit.hash }));
938
940
  })
939
941
  .catch(() => {
940
942
  // If all clipboard commands fail, just show the hash
941
- editor.setStatus(`Hash: ${commit.hash}`);
943
+ editor.setStatus(editor.t("status.hash_display", { hash: commit.hash }));
942
944
  });
943
945
  };
944
946
 
@@ -968,7 +970,7 @@ globalThis.git_commit_detail_close = function(): void {
968
970
  commitDetailState.splitId = null;
969
971
  commitDetailState.commit = null;
970
972
 
971
- editor.setStatus(`Git log: ${gitLogState.commits.length} commits | ↑/↓: navigate | RET: show | q: quit`);
973
+ editor.setStatus(editor.t("status.log_ready", { count: String(gitLogState.commits.length) }));
972
974
  };
973
975
 
974
976
  // Close file view and go back to commit detail
@@ -996,7 +998,7 @@ globalThis.git_file_view_close = function(): void {
996
998
  fileViewState.commitHash = null;
997
999
 
998
1000
  if (commitDetailState.commit) {
999
- editor.setStatus(`Commit ${commitDetailState.commit.shortHash} | ↑/↓: navigate | RET: open file | q: back`);
1001
+ editor.setStatus(editor.t("status.commit_ready", { hash: commitDetailState.commit.shortHash }));
1000
1002
  }
1001
1003
  };
1002
1004
 
@@ -1181,7 +1183,7 @@ globalThis.git_commit_detail_open_file = async function(): Promise<void> {
1181
1183
 
1182
1184
  const commit = commitDetailState.commit;
1183
1185
  if (!commit) {
1184
- editor.setStatus("No commit context available");
1186
+ editor.setStatus(editor.t("status.move_to_commit"));
1185
1187
  return;
1186
1188
  }
1187
1189
 
@@ -1193,13 +1195,13 @@ globalThis.git_commit_detail_open_file = async function(): Promise<void> {
1193
1195
  const line = props[0].line as number | undefined;
1194
1196
 
1195
1197
  if (file) {
1196
- editor.setStatus(`Loading ${file} at ${commit.shortHash}...`);
1198
+ editor.setStatus(editor.t("status.file_loading", { file, hash: commit.shortHash }));
1197
1199
 
1198
1200
  // Fetch file content at this commit
1199
1201
  const content = await fetchFileAtCommit(commit.hash, file);
1200
1202
 
1201
1203
  if (content === null) {
1202
- editor.setStatus(`File ${file} not found at commit ${commit.shortHash}`);
1204
+ editor.setStatus(editor.t("status.file_not_found", { file, hash: commit.shortHash }));
1203
1205
  return;
1204
1206
  }
1205
1207
 
@@ -1238,15 +1240,15 @@ globalThis.git_commit_detail_open_file = async function(): Promise<void> {
1238
1240
  applyFileViewHighlighting(bufferId, content, file);
1239
1241
 
1240
1242
  const targetLine = line || 1;
1241
- editor.setStatus(`${file} @ ${commit.shortHash} (read-only) | Target: line ${targetLine} | q: back`);
1243
+ editor.setStatus(editor.t("status.file_view_ready", { file, hash: commit.shortHash, line: String(targetLine) }));
1242
1244
  } else {
1243
- editor.setStatus(`Failed to open ${file}`);
1245
+ editor.setStatus(editor.t("status.failed_open_file", { file }));
1244
1246
  }
1245
1247
  } else {
1246
- editor.setStatus("Move cursor to a diff line with file context");
1248
+ editor.setStatus(editor.t("status.move_to_diff_with_context"));
1247
1249
  }
1248
1250
  } else {
1249
- editor.setStatus("Move cursor to a diff line");
1251
+ editor.setStatus(editor.t("status.move_to_diff"));
1250
1252
  }
1251
1253
  };
1252
1254
 
@@ -1255,22 +1257,22 @@ globalThis.git_commit_detail_open_file = async function(): Promise<void> {
1255
1257
  // =============================================================================
1256
1258
 
1257
1259
  editor.registerCommand(
1258
- "Git Log",
1259
- "Show git log in magit-style interface",
1260
+ "%cmd.git_log",
1261
+ "%cmd.git_log_desc",
1260
1262
  "show_git_log",
1261
1263
  "normal"
1262
1264
  );
1263
1265
 
1264
1266
  editor.registerCommand(
1265
- "Git Log: Close",
1266
- "Close the git log panel",
1267
+ "%cmd.git_log_close",
1268
+ "%cmd.git_log_close_desc",
1267
1269
  "git_log_close",
1268
1270
  "normal"
1269
1271
  );
1270
1272
 
1271
1273
  editor.registerCommand(
1272
- "Git Log: Refresh",
1273
- "Refresh the git log",
1274
+ "%cmd.git_log_refresh",
1275
+ "%cmd.git_log_refresh_desc",
1274
1276
  "git_log_refresh",
1275
1277
  "normal"
1276
1278
  );
@@ -1279,5 +1281,5 @@ editor.registerCommand(
1279
1281
  // Plugin Initialization
1280
1282
  // =============================================================================
1281
1283
 
1282
- editor.setStatus("Git Log plugin loaded (magit-style)");
1284
+ editor.setStatus(editor.t("status.ready", { count: "0" }));
1283
1285
  editor.debug("Git Log plugin initialized - Use 'Git Log' command to open");
@@ -0,0 +1,143 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+
5
+ /**
6
+ * Go LSP Helper Plugin
7
+ *
8
+ * Provides user-friendly error handling for Go LSP server issues.
9
+ * When gopls fails to start, this plugin shows an actionable
10
+ * popup with installation instructions.
11
+ *
12
+ * Features:
13
+ * - Detects Go LSP server errors (gopls)
14
+ * - Shows popup with install commands
15
+ * - Allows copying install commands to clipboard
16
+ * - Provides option to disable Go LSP
17
+ */
18
+
19
+ interface LspServerErrorData {
20
+ language: string;
21
+ server_command: string;
22
+ error_type: string;
23
+ message: string;
24
+ }
25
+
26
+ interface LspStatusClickedData {
27
+ language: string;
28
+ has_error: boolean;
29
+ }
30
+
31
+ interface ActionPopupResultData {
32
+ popup_id: string;
33
+ action_id: string;
34
+ }
35
+
36
+ // Install commands for Go LSP server (gopls)
37
+ // go install is the official recommended method
38
+ // See: https://pkg.go.dev/golang.org/x/tools/gopls
39
+ const INSTALL_COMMANDS = {
40
+ go: "go install golang.org/x/tools/gopls@latest",
41
+ };
42
+
43
+ // Track error state for Go LSP
44
+ let goLspError: { serverCommand: string; message: string } | null = null;
45
+
46
+ /**
47
+ * Handle LSP server errors for Go
48
+ */
49
+ globalThis.on_go_lsp_server_error = function (data: LspServerErrorData): void {
50
+ // Only handle Go language errors
51
+ if (data.language !== "go") {
52
+ return;
53
+ }
54
+
55
+ editor.debug(`go-lsp: Server error - ${data.error_type}: ${data.message}`);
56
+
57
+ // Store error state for later reference
58
+ goLspError = {
59
+ serverCommand: data.server_command,
60
+ message: data.message,
61
+ };
62
+
63
+ // Show a status message for immediate feedback
64
+ if (data.error_type === "not_found") {
65
+ editor.setStatus(
66
+ `Go LSP server '${data.server_command}' not found. Click status bar for help.`
67
+ );
68
+ } else {
69
+ editor.setStatus(`Go LSP error: ${data.message}`);
70
+ }
71
+ };
72
+
73
+ // Register hook for LSP server errors
74
+ editor.on("lsp_server_error", "on_go_lsp_server_error");
75
+
76
+ /**
77
+ * Handle status bar click when there's a Go LSP error
78
+ */
79
+ globalThis.on_go_lsp_status_clicked = function (
80
+ data: LspStatusClickedData
81
+ ): void {
82
+ // Only handle Go language clicks when there's an error
83
+ if (data.language !== "go" || !goLspError) {
84
+ return;
85
+ }
86
+
87
+ editor.debug("go-lsp: Status clicked, showing help popup");
88
+
89
+ // Show action popup with install options
90
+ editor.showActionPopup({
91
+ id: "go-lsp-help",
92
+ title: "Go Language Server Not Found",
93
+ message: `"${goLspError.serverCommand}" provides code completion, diagnostics, and navigation for Go files. Copy the command below to install it.`,
94
+ actions: [
95
+ { id: "copy_go", label: `Copy: ${INSTALL_COMMANDS.go}` },
96
+ { id: "disable", label: "Disable Go LSP" },
97
+ { id: "dismiss", label: "Dismiss (ESC)" },
98
+ ],
99
+ });
100
+ };
101
+
102
+ // Register hook for status bar clicks
103
+ editor.on("lsp_status_clicked", "on_go_lsp_status_clicked");
104
+
105
+ /**
106
+ * Handle action popup results for Go LSP help
107
+ */
108
+ globalThis.on_go_lsp_action_result = function (
109
+ data: ActionPopupResultData
110
+ ): void {
111
+ // Only handle our popup
112
+ if (data.popup_id !== "go-lsp-help") {
113
+ return;
114
+ }
115
+
116
+ editor.debug(`go-lsp: Action selected - ${data.action_id}`);
117
+
118
+ switch (data.action_id) {
119
+ case "copy_go":
120
+ editor.setClipboard(INSTALL_COMMANDS.go);
121
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.go);
122
+ break;
123
+
124
+ case "disable":
125
+ editor.disableLspForLanguage("go");
126
+ editor.setStatus("Go LSP disabled");
127
+ goLspError = null;
128
+ break;
129
+
130
+ case "dismiss":
131
+ case "dismissed":
132
+ // Just close the popup without action
133
+ break;
134
+
135
+ default:
136
+ editor.debug(`go-lsp: Unknown action: ${data.action_id}`);
137
+ }
138
+ };
139
+
140
+ // Register hook for action popup results
141
+ editor.on("action_popup_result", "on_go_lsp_action_result");
142
+
143
+ editor.debug("go-lsp: Plugin loaded");
@@ -0,0 +1,145 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+
5
+ /**
6
+ * HTML LSP Helper Plugin
7
+ *
8
+ * Provides user-friendly error handling for HTML LSP server issues.
9
+ * When the HTML language server fails to start, this plugin shows an
10
+ * actionable popup with installation instructions.
11
+ *
12
+ * Features:
13
+ * - Detects HTML LSP server errors
14
+ * - Shows popup with install commands (npm)
15
+ * - Allows copying install commands to clipboard
16
+ * - Provides option to disable HTML LSP
17
+ */
18
+
19
+ interface LspServerErrorData {
20
+ language: string;
21
+ server_command: string;
22
+ error_type: string;
23
+ message: string;
24
+ }
25
+
26
+ interface LspStatusClickedData {
27
+ language: string;
28
+ has_error: boolean;
29
+ }
30
+
31
+ interface ActionPopupResultData {
32
+ popup_id: string;
33
+ action_id: string;
34
+ }
35
+
36
+ // Install commands for HTML LSP server
37
+ // vscode-langservers-extracted provides HTML, CSS, and JSON language servers
38
+ // See: https://www.npmjs.com/package/vscode-langservers-extracted
39
+ const INSTALL_COMMANDS = {
40
+ npm: "npm install -g vscode-langservers-extracted",
41
+ };
42
+
43
+ // Track error state for HTML LSP
44
+ let htmlLspError: { serverCommand: string; message: string } | null = null;
45
+
46
+ /**
47
+ * Handle LSP server errors for HTML
48
+ */
49
+ globalThis.on_html_lsp_server_error = function (
50
+ data: LspServerErrorData
51
+ ): void {
52
+ // Only handle HTML language errors
53
+ if (data.language !== "html") {
54
+ return;
55
+ }
56
+
57
+ editor.debug(`html-lsp: Server error - ${data.error_type}: ${data.message}`);
58
+
59
+ // Store error state for later reference
60
+ htmlLspError = {
61
+ serverCommand: data.server_command,
62
+ message: data.message,
63
+ };
64
+
65
+ // Show a status message for immediate feedback
66
+ if (data.error_type === "not_found") {
67
+ editor.setStatus(
68
+ `HTML LSP server '${data.server_command}' not found. Click status bar for help.`
69
+ );
70
+ } else {
71
+ editor.setStatus(`HTML LSP error: ${data.message}`);
72
+ }
73
+ };
74
+
75
+ // Register hook for LSP server errors
76
+ editor.on("lsp_server_error", "on_html_lsp_server_error");
77
+
78
+ /**
79
+ * Handle status bar click when there's an HTML LSP error
80
+ */
81
+ globalThis.on_html_lsp_status_clicked = function (
82
+ data: LspStatusClickedData
83
+ ): void {
84
+ // Only handle HTML language clicks when there's an error
85
+ if (data.language !== "html" || !htmlLspError) {
86
+ return;
87
+ }
88
+
89
+ editor.debug("html-lsp: Status clicked, showing help popup");
90
+
91
+ // Show action popup with install options
92
+ editor.showActionPopup({
93
+ id: "html-lsp-help",
94
+ title: "HTML Language Server Not Found",
95
+ message: `"${htmlLspError.serverCommand}" provides code completion, diagnostics, and formatting for HTML files. Copy the command below to install it.`,
96
+ actions: [
97
+ { id: "copy_npm", label: `Copy: ${INSTALL_COMMANDS.npm}` },
98
+ { id: "disable", label: "Disable HTML LSP" },
99
+ { id: "dismiss", label: "Dismiss (ESC)" },
100
+ ],
101
+ });
102
+ };
103
+
104
+ // Register hook for status bar clicks
105
+ editor.on("lsp_status_clicked", "on_html_lsp_status_clicked");
106
+
107
+ /**
108
+ * Handle action popup results for HTML LSP help
109
+ */
110
+ globalThis.on_html_lsp_action_result = function (
111
+ data: ActionPopupResultData
112
+ ): void {
113
+ // Only handle our popup
114
+ if (data.popup_id !== "html-lsp-help") {
115
+ return;
116
+ }
117
+
118
+ editor.debug(`html-lsp: Action selected - ${data.action_id}`);
119
+
120
+ switch (data.action_id) {
121
+ case "copy_npm":
122
+ editor.setClipboard(INSTALL_COMMANDS.npm);
123
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.npm);
124
+ break;
125
+
126
+ case "disable":
127
+ editor.disableLspForLanguage("html");
128
+ editor.setStatus("HTML LSP disabled");
129
+ htmlLspError = null;
130
+ break;
131
+
132
+ case "dismiss":
133
+ case "dismissed":
134
+ // Just close the popup without action
135
+ break;
136
+
137
+ default:
138
+ editor.debug(`html-lsp: Unknown action: ${data.action_id}`);
139
+ }
140
+ };
141
+
142
+ // Register hook for action popup results
143
+ editor.on("action_popup_result", "on_html_lsp_action_result");
144
+
145
+ editor.debug("html-lsp: Plugin loaded");