@fresh-editor/fresh-editor 0.2.17 → 0.2.20

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 (48) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/package.json +1 -1
  3. package/plugins/astro-lsp.ts +118 -0
  4. package/plugins/bash-lsp.ts +161 -0
  5. package/plugins/clojure-lsp.ts +125 -0
  6. package/plugins/cmake-lsp.ts +138 -0
  7. package/plugins/config-schema.json +275 -29
  8. package/plugins/dart-lsp.ts +144 -0
  9. package/plugins/diagnostics_panel.ts +4 -12
  10. package/plugins/diff_nav.i18n.json +128 -0
  11. package/plugins/diff_nav.ts +196 -0
  12. package/plugins/elixir-lsp.ts +120 -0
  13. package/plugins/erlang-lsp.ts +121 -0
  14. package/plugins/fsharp-lsp.ts +125 -0
  15. package/plugins/git_gutter.ts +5 -0
  16. package/plugins/gleam-lsp.ts +124 -0
  17. package/plugins/graphql-lsp.ts +139 -0
  18. package/plugins/haskell-lsp.ts +125 -0
  19. package/plugins/julia-lsp.ts +111 -0
  20. package/plugins/kotlin-lsp.ts +162 -0
  21. package/plugins/lib/finder.ts +19 -12
  22. package/plugins/lib/fresh.d.ts +30 -1
  23. package/plugins/lua-lsp.ts +161 -0
  24. package/plugins/nim-lsp.ts +118 -0
  25. package/plugins/nix-lsp.ts +125 -0
  26. package/plugins/nushell-lsp.ts +144 -0
  27. package/plugins/ocaml-lsp.ts +119 -0
  28. package/plugins/perl-lsp.ts +118 -0
  29. package/plugins/php-lsp.ts +165 -0
  30. package/plugins/pkg.ts +37 -76
  31. package/plugins/protobuf-lsp.ts +144 -0
  32. package/plugins/r-lsp.ts +118 -0
  33. package/plugins/ruby-lsp.ts +165 -0
  34. package/plugins/scala-lsp.ts +119 -0
  35. package/plugins/schemas/package.schema.json +437 -272
  36. package/plugins/schemas/theme.schema.json +18 -0
  37. package/plugins/solidity-lsp.ts +130 -0
  38. package/plugins/sql-lsp.ts +129 -0
  39. package/plugins/svelte-lsp.ts +119 -0
  40. package/plugins/swift-lsp.ts +120 -0
  41. package/plugins/tailwindcss-lsp.ts +119 -0
  42. package/plugins/terraform-lsp.ts +144 -0
  43. package/plugins/theme_editor.i18n.json +70 -14
  44. package/plugins/theme_editor.ts +71 -39
  45. package/plugins/toml-lsp.ts +162 -0
  46. package/plugins/typst-lsp.ts +165 -0
  47. package/plugins/vue-lsp.ts +118 -0
  48. package/plugins/yaml-lsp.ts +163 -0
@@ -0,0 +1,111 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * Julia LSP Helper Plugin
6
+ *
7
+ * Server: LanguageServer.jl (Julia package)
8
+ * VS Code: "Julia" extension (bundles LanguageServer.jl)
9
+ * Neovim: nvim-lspconfig julials
10
+ * Install via: Julia's Pkg.add() - runs as a Julia script
11
+ * Note: First startup can be slow due to Julia compilation
12
+ */
13
+
14
+ interface LspServerErrorData {
15
+ language: string;
16
+ server_command: string;
17
+ error_type: string;
18
+ message: string;
19
+ }
20
+
21
+ interface LspStatusClickedData {
22
+ language: string;
23
+ has_error: boolean;
24
+ }
25
+
26
+ interface ActionPopupResultData {
27
+ popup_id: string;
28
+ action_id: string;
29
+ }
30
+
31
+ const INSTALL_COMMANDS = {
32
+ julia: 'julia -e \'using Pkg; Pkg.add("LanguageServer")\'',
33
+ };
34
+
35
+ let juliaLspError: { serverCommand: string; message: string } | null = null;
36
+
37
+ function on_julia_lsp_server_error(data: LspServerErrorData): void {
38
+ if (data.language !== "julia") {
39
+ return;
40
+ }
41
+
42
+ editor.debug(`julia-lsp: Server error - ${data.error_type}: ${data.message}`);
43
+
44
+ juliaLspError = {
45
+ serverCommand: data.server_command,
46
+ message: data.message,
47
+ };
48
+
49
+ if (data.error_type === "not_found") {
50
+ editor.setStatus(
51
+ `Julia LSP server '${data.server_command}' not found. Click status bar for help.`
52
+ );
53
+ } else {
54
+ editor.setStatus(`Julia LSP error: ${data.message}`);
55
+ }
56
+ }
57
+ registerHandler("on_julia_lsp_server_error", on_julia_lsp_server_error);
58
+ editor.on("lsp_server_error", "on_julia_lsp_server_error");
59
+
60
+ function on_julia_lsp_status_clicked(data: LspStatusClickedData): void {
61
+ if (data.language !== "julia" || !juliaLspError) {
62
+ return;
63
+ }
64
+
65
+ editor.debug("julia-lsp: Status clicked, showing help popup");
66
+
67
+ editor.showActionPopup({
68
+ id: "julia-lsp-help",
69
+ title: "Julia Language Server Not Found",
70
+ message: `The Julia language server (LanguageServer.jl) provides completion, diagnostics, formatting, and navigation for Julia. Julia must be installed.\n\nNote: First startup is slow due to Julia's compilation. Consider using PackageCompiler.jl for faster restarts.\nVS Code users: Install the "Julia" extension (auto-installs LanguageServer.jl).\nSee: https://github.com/julia-vscode/LanguageServer.jl`,
71
+ actions: [
72
+ { id: "copy_julia", label: `Copy: ${INSTALL_COMMANDS.julia}` },
73
+ { id: "disable", label: "Disable Julia LSP" },
74
+ { id: "dismiss", label: "Dismiss (ESC)" },
75
+ ],
76
+ });
77
+ }
78
+ registerHandler("on_julia_lsp_status_clicked", on_julia_lsp_status_clicked);
79
+ editor.on("lsp_status_clicked", "on_julia_lsp_status_clicked");
80
+
81
+ function on_julia_lsp_action_result(data: ActionPopupResultData): void {
82
+ if (data.popup_id !== "julia-lsp-help") {
83
+ return;
84
+ }
85
+
86
+ editor.debug(`julia-lsp: Action selected - ${data.action_id}`);
87
+
88
+ switch (data.action_id) {
89
+ case "copy_julia":
90
+ editor.setClipboard(INSTALL_COMMANDS.julia);
91
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.julia);
92
+ break;
93
+
94
+ case "disable":
95
+ editor.disableLspForLanguage("julia");
96
+ editor.setStatus("Julia LSP disabled");
97
+ juliaLspError = null;
98
+ break;
99
+
100
+ case "dismiss":
101
+ case "dismissed":
102
+ break;
103
+
104
+ default:
105
+ editor.debug(`julia-lsp: Unknown action: ${data.action_id}`);
106
+ }
107
+ }
108
+ registerHandler("on_julia_lsp_action_result", on_julia_lsp_action_result);
109
+ editor.on("action_popup_result", "on_julia_lsp_action_result");
110
+
111
+ editor.debug("julia-lsp: Plugin loaded");
@@ -0,0 +1,162 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * Kotlin LSP Helper Plugin
6
+ *
7
+ * Provides user-friendly error handling for Kotlin LSP server issues.
8
+ * When kotlin-language-server fails to start, this plugin shows an actionable
9
+ * popup with installation instructions.
10
+ *
11
+ * Features:
12
+ * - Detects Kotlin LSP server errors (kotlin-language-server)
13
+ * - Shows popup with install commands (brew, SDKMAN, snap)
14
+ * - Allows copying install commands to clipboard
15
+ * - Provides option to disable Kotlin LSP
16
+ *
17
+ * VS Code: "Kotlin" extension (fwcd.kotlin)
18
+ * Neovim: nvim-lspconfig kotlin_language_server
19
+ * Note: Requires JDK 11+. For full IDE support, consider IntelliJ IDEA
20
+ */
21
+
22
+ interface LspServerErrorData {
23
+ language: string;
24
+ server_command: string;
25
+ error_type: string;
26
+ message: string;
27
+ }
28
+
29
+ interface LspStatusClickedData {
30
+ language: string;
31
+ has_error: boolean;
32
+ }
33
+
34
+ interface ActionPopupResultData {
35
+ popup_id: string;
36
+ action_id: string;
37
+ }
38
+
39
+ // Install commands for Kotlin LSP server (kotlin-language-server)
40
+ // See: https://github.com/fwcd/kotlin-language-server
41
+ const INSTALL_COMMANDS = {
42
+ brew: "brew install kotlin-language-server",
43
+ snap: "sudo snap install kotlin-language-server --classic",
44
+ nix: "nix-env -i kotlin-language-server",
45
+ };
46
+
47
+ // Track error state for Kotlin LSP
48
+ let kotlinLspError: { serverCommand: string; message: string } | null = null;
49
+
50
+ /**
51
+ * Handle LSP server errors for Kotlin
52
+ */
53
+ function on_kotlin_lsp_server_error(data: LspServerErrorData): void {
54
+ // Only handle Kotlin language errors
55
+ if (data.language !== "kotlin") {
56
+ return;
57
+ }
58
+
59
+ editor.debug(`kotlin-lsp: Server error - ${data.error_type}: ${data.message}`);
60
+
61
+ // Store error state for later reference
62
+ kotlinLspError = {
63
+ serverCommand: data.server_command,
64
+ message: data.message,
65
+ };
66
+
67
+ // Show a status message for immediate feedback
68
+ if (data.error_type === "not_found") {
69
+ editor.setStatus(
70
+ `Kotlin LSP server '${data.server_command}' not found. Click status bar for help.`
71
+ );
72
+ } else {
73
+ editor.setStatus(`Kotlin LSP error: ${data.message}`);
74
+ }
75
+ }
76
+ registerHandler("on_kotlin_lsp_server_error", on_kotlin_lsp_server_error);
77
+
78
+ // Register hook for LSP server errors
79
+ editor.on("lsp_server_error", "on_kotlin_lsp_server_error");
80
+
81
+ /**
82
+ * Handle status bar click when there's a Kotlin LSP error
83
+ */
84
+ function on_kotlin_lsp_status_clicked(
85
+ data: LspStatusClickedData
86
+ ): void {
87
+ // Only handle Kotlin language clicks when there's an error
88
+ if (data.language !== "kotlin" || !kotlinLspError) {
89
+ return;
90
+ }
91
+
92
+ editor.debug("kotlin-lsp: Status clicked, showing help popup");
93
+
94
+ // Show action popup with install options
95
+ editor.showActionPopup({
96
+ id: "kotlin-lsp-help",
97
+ title: "Kotlin Language Server Not Found",
98
+ message: `"${kotlinLspError.serverCommand}" provides code completion, diagnostics, and navigation for Kotlin files. Requires a JDK (Java 11+). Copy a command below to install it, or visit https://github.com/fwcd/kotlin-language-server for build instructions and releases. For full Kotlin IDE support, consider IntelliJ IDEA or Android Studio.`,
99
+ actions: [
100
+ { id: "copy_brew", label: `Copy: ${INSTALL_COMMANDS.brew}` },
101
+ { id: "copy_snap", label: `Copy: ${INSTALL_COMMANDS.snap}` },
102
+ { id: "copy_nix", label: `Copy: ${INSTALL_COMMANDS.nix}` },
103
+ { id: "disable", label: "Disable Kotlin LSP" },
104
+ { id: "dismiss", label: "Dismiss (ESC)" },
105
+ ],
106
+ });
107
+ }
108
+ registerHandler("on_kotlin_lsp_status_clicked", on_kotlin_lsp_status_clicked);
109
+
110
+ // Register hook for status bar clicks
111
+ editor.on("lsp_status_clicked", "on_kotlin_lsp_status_clicked");
112
+
113
+ /**
114
+ * Handle action popup results for Kotlin LSP help
115
+ */
116
+ function on_kotlin_lsp_action_result(
117
+ data: ActionPopupResultData
118
+ ): void {
119
+ // Only handle our popup
120
+ if (data.popup_id !== "kotlin-lsp-help") {
121
+ return;
122
+ }
123
+
124
+ editor.debug(`kotlin-lsp: Action selected - ${data.action_id}`);
125
+
126
+ switch (data.action_id) {
127
+ case "copy_brew":
128
+ editor.setClipboard(INSTALL_COMMANDS.brew);
129
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.brew);
130
+ break;
131
+
132
+ case "copy_snap":
133
+ editor.setClipboard(INSTALL_COMMANDS.snap);
134
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.snap);
135
+ break;
136
+
137
+ case "copy_nix":
138
+ editor.setClipboard(INSTALL_COMMANDS.nix);
139
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.nix);
140
+ break;
141
+
142
+ case "disable":
143
+ editor.disableLspForLanguage("kotlin");
144
+ editor.setStatus("Kotlin LSP disabled");
145
+ kotlinLspError = null;
146
+ break;
147
+
148
+ case "dismiss":
149
+ case "dismissed":
150
+ // Just close the popup without action
151
+ break;
152
+
153
+ default:
154
+ editor.debug(`kotlin-lsp: Unknown action: ${data.action_id}`);
155
+ }
156
+ }
157
+ registerHandler("on_kotlin_lsp_action_result", on_kotlin_lsp_action_result);
158
+
159
+ // Register hook for action popup results
160
+ editor.on("action_popup_result", "on_kotlin_lsp_action_result");
161
+
162
+ editor.debug("kotlin-lsp: Plugin loaded");
@@ -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
- // Default: open file at location
1258
- if (this.panelState.sourceSplitId !== null) {
1259
- this.editor.focusSplit(this.panelState.sourceSplitId);
1260
- }
1261
- this.editor.openFile(
1262
- entry.location.file,
1263
- entry.location.line,
1264
- entry.location.column
1265
- );
1266
- this.editor.setStatus(
1267
- `Jumped to ${entry.location.file}:${entry.location.line}`
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 {
@@ -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
  /**
@@ -1031,6 +1030,31 @@ interface EditorAPI {
1031
1030
  */
1032
1031
  readDir(path: string): DirEntry[];
1033
1032
  /**
1033
+ * Create a directory (and all parent directories) recursively.
1034
+ * Returns true if the directory was created or already exists.
1035
+ */
1036
+ createDir(path: string): boolean;
1037
+ /**
1038
+ * Remove a file or directory by moving it to the OS trash/recycle bin.
1039
+ * For safety, the path must be under the OS temp directory or the Fresh
1040
+ * config directory. Returns true on success.
1041
+ */
1042
+ removePath(path: string): boolean;
1043
+ /**
1044
+ * Rename/move a file or directory. Returns true on success.
1045
+ * Falls back to copy then trash for cross-filesystem moves.
1046
+ */
1047
+ renamePath(from: string, to: string): boolean;
1048
+ /**
1049
+ * Copy a file or directory recursively to a new location.
1050
+ * Returns true on success.
1051
+ */
1052
+ copyPath(from: string, to: string): boolean;
1053
+ /**
1054
+ * Get the OS temporary directory path.
1055
+ */
1056
+ getTempDir(): string;
1057
+ /**
1034
1058
  * Get current config as JS object
1035
1059
  */
1036
1060
  getConfig(): unknown;
@@ -1071,6 +1095,11 @@ interface EditorAPI {
1071
1095
  */
1072
1096
  reloadGrammars(): Promise<void>;
1073
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
+ /**
1074
1103
  * Get config directory path
1075
1104
  */
1076
1105
  getConfigDir(): string;
@@ -0,0 +1,161 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * Lua LSP Helper Plugin
6
+ *
7
+ * Provides user-friendly error handling for Lua LSP server issues.
8
+ * When lua-language-server fails to start, this plugin shows an actionable
9
+ * popup with installation instructions.
10
+ *
11
+ * Features:
12
+ * - Detects Lua LSP server errors (lua-language-server / LuaLS)
13
+ * - Shows popup with install commands (brew, pacman, etc.)
14
+ * - Allows copying install commands to clipboard
15
+ * - Provides option to disable Lua LSP
16
+ *
17
+ * Alternatives:
18
+ * - EmmyLua: IntelliJ-based Lua IDE support
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
+ // Install commands for Lua LSP server (lua-language-server / LuaLS)
39
+ // See: https://luals.github.io/#install
40
+ const INSTALL_COMMANDS = {
41
+ brew: "brew install lua-language-server",
42
+ pacman: "sudo pacman -S lua-language-server",
43
+ nix: "nix-env -i lua-language-server",
44
+ };
45
+
46
+ // Track error state for Lua LSP
47
+ let luaLspError: { serverCommand: string; message: string } | null = null;
48
+
49
+ /**
50
+ * Handle LSP server errors for Lua
51
+ */
52
+ function on_lua_lsp_server_error(data: LspServerErrorData): void {
53
+ // Only handle Lua language errors
54
+ if (data.language !== "lua") {
55
+ return;
56
+ }
57
+
58
+ editor.debug(`lua-lsp: Server error - ${data.error_type}: ${data.message}`);
59
+
60
+ // Store error state for later reference
61
+ luaLspError = {
62
+ serverCommand: data.server_command,
63
+ message: data.message,
64
+ };
65
+
66
+ // Show a status message for immediate feedback
67
+ if (data.error_type === "not_found") {
68
+ editor.setStatus(
69
+ `Lua LSP server '${data.server_command}' not found. Click status bar for help.`
70
+ );
71
+ } else {
72
+ editor.setStatus(`Lua LSP error: ${data.message}`);
73
+ }
74
+ }
75
+ registerHandler("on_lua_lsp_server_error", on_lua_lsp_server_error);
76
+
77
+ // Register hook for LSP server errors
78
+ editor.on("lsp_server_error", "on_lua_lsp_server_error");
79
+
80
+ /**
81
+ * Handle status bar click when there's a Lua LSP error
82
+ */
83
+ function on_lua_lsp_status_clicked(
84
+ data: LspStatusClickedData
85
+ ): void {
86
+ // Only handle Lua language clicks when there's an error
87
+ if (data.language !== "lua" || !luaLspError) {
88
+ return;
89
+ }
90
+
91
+ editor.debug("lua-lsp: Status clicked, showing help popup");
92
+
93
+ // Show action popup with install options
94
+ editor.showActionPopup({
95
+ id: "lua-lsp-help",
96
+ title: "Lua Language Server Not Found",
97
+ message: `"${luaLspError.serverCommand}" (LuaLS) provides code completion, diagnostics, and navigation for Lua files. Copy a command below to install it, or visit https://luals.github.io/#install for platform-specific instructions. Pre-built binaries are also available from https://github.com/LuaLS/lua-language-server/releases.`,
98
+ actions: [
99
+ { id: "copy_brew", label: `Copy: ${INSTALL_COMMANDS.brew}` },
100
+ { id: "copy_pacman", label: `Copy: ${INSTALL_COMMANDS.pacman}` },
101
+ { id: "copy_nix", label: `Copy: ${INSTALL_COMMANDS.nix}` },
102
+ { id: "disable", label: "Disable Lua LSP" },
103
+ { id: "dismiss", label: "Dismiss (ESC)" },
104
+ ],
105
+ });
106
+ }
107
+ registerHandler("on_lua_lsp_status_clicked", on_lua_lsp_status_clicked);
108
+
109
+ // Register hook for status bar clicks
110
+ editor.on("lsp_status_clicked", "on_lua_lsp_status_clicked");
111
+
112
+ /**
113
+ * Handle action popup results for Lua LSP help
114
+ */
115
+ function on_lua_lsp_action_result(
116
+ data: ActionPopupResultData
117
+ ): void {
118
+ // Only handle our popup
119
+ if (data.popup_id !== "lua-lsp-help") {
120
+ return;
121
+ }
122
+
123
+ editor.debug(`lua-lsp: Action selected - ${data.action_id}`);
124
+
125
+ switch (data.action_id) {
126
+ case "copy_brew":
127
+ editor.setClipboard(INSTALL_COMMANDS.brew);
128
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.brew);
129
+ break;
130
+
131
+ case "copy_pacman":
132
+ editor.setClipboard(INSTALL_COMMANDS.pacman);
133
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.pacman);
134
+ break;
135
+
136
+ case "copy_nix":
137
+ editor.setClipboard(INSTALL_COMMANDS.nix);
138
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.nix);
139
+ break;
140
+
141
+ case "disable":
142
+ editor.disableLspForLanguage("lua");
143
+ editor.setStatus("Lua LSP disabled");
144
+ luaLspError = null;
145
+ break;
146
+
147
+ case "dismiss":
148
+ case "dismissed":
149
+ // Just close the popup without action
150
+ break;
151
+
152
+ default:
153
+ editor.debug(`lua-lsp: Unknown action: ${data.action_id}`);
154
+ }
155
+ }
156
+ registerHandler("on_lua_lsp_action_result", on_lua_lsp_action_result);
157
+
158
+ // Register hook for action popup results
159
+ editor.on("action_popup_result", "on_lua_lsp_action_result");
160
+
161
+ editor.debug("lua-lsp: Plugin loaded");
@@ -0,0 +1,118 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * Nim LSP Helper Plugin
6
+ *
7
+ * Server: nimlangserver (github.com/nim-lang/langserver)
8
+ * VS Code: "Nim" extension (nimsaem.nimvscode)
9
+ * Neovim: nvim-lspconfig nim_langserver
10
+ * Install via: nimble (Nim package manager)
11
+ * Alternative: nimlsp (older, less maintained)
12
+ */
13
+
14
+ interface LspServerErrorData {
15
+ language: string;
16
+ server_command: string;
17
+ error_type: string;
18
+ message: string;
19
+ }
20
+
21
+ interface LspStatusClickedData {
22
+ language: string;
23
+ has_error: boolean;
24
+ }
25
+
26
+ interface ActionPopupResultData {
27
+ popup_id: string;
28
+ action_id: string;
29
+ }
30
+
31
+ const INSTALL_COMMANDS = {
32
+ nimble: "nimble install nimlangserver",
33
+ choosenim: "choosenim stable && nimble install nimlangserver",
34
+ };
35
+
36
+ let nimLspError: { serverCommand: string; message: string } | null = null;
37
+
38
+ function on_nim_lsp_server_error(data: LspServerErrorData): void {
39
+ if (data.language !== "nim") {
40
+ return;
41
+ }
42
+
43
+ editor.debug(`nim-lsp: Server error - ${data.error_type}: ${data.message}`);
44
+
45
+ nimLspError = {
46
+ serverCommand: data.server_command,
47
+ message: data.message,
48
+ };
49
+
50
+ if (data.error_type === "not_found") {
51
+ editor.setStatus(
52
+ `Nim LSP server '${data.server_command}' not found. Click status bar for help.`
53
+ );
54
+ } else {
55
+ editor.setStatus(`Nim LSP error: ${data.message}`);
56
+ }
57
+ }
58
+ registerHandler("on_nim_lsp_server_error", on_nim_lsp_server_error);
59
+ editor.on("lsp_server_error", "on_nim_lsp_server_error");
60
+
61
+ function on_nim_lsp_status_clicked(data: LspStatusClickedData): void {
62
+ if (data.language !== "nim" || !nimLspError) {
63
+ return;
64
+ }
65
+
66
+ editor.debug("nim-lsp: Status clicked, showing help popup");
67
+
68
+ editor.showActionPopup({
69
+ id: "nim-lsp-help",
70
+ title: "Nim Language Server Not Found",
71
+ message: `"${nimLspError.serverCommand}" provides completion, diagnostics, hover, and go-to-definition for Nim. Requires Nim and nimble.\n\nInstall Nim via choosenim: curl https://nim-lang.org/choosenim/init.sh -sSf | sh\nVS Code users: Install the "Nim" extension.\nSee: https://github.com/nim-lang/langserver`,
72
+ actions: [
73
+ { id: "copy_nimble", label: `Copy: ${INSTALL_COMMANDS.nimble}` },
74
+ { id: "copy_choosenim", label: `Copy: ${INSTALL_COMMANDS.choosenim}` },
75
+ { id: "disable", label: "Disable Nim LSP" },
76
+ { id: "dismiss", label: "Dismiss (ESC)" },
77
+ ],
78
+ });
79
+ }
80
+ registerHandler("on_nim_lsp_status_clicked", on_nim_lsp_status_clicked);
81
+ editor.on("lsp_status_clicked", "on_nim_lsp_status_clicked");
82
+
83
+ function on_nim_lsp_action_result(data: ActionPopupResultData): void {
84
+ if (data.popup_id !== "nim-lsp-help") {
85
+ return;
86
+ }
87
+
88
+ editor.debug(`nim-lsp: Action selected - ${data.action_id}`);
89
+
90
+ switch (data.action_id) {
91
+ case "copy_nimble":
92
+ editor.setClipboard(INSTALL_COMMANDS.nimble);
93
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.nimble);
94
+ break;
95
+
96
+ case "copy_choosenim":
97
+ editor.setClipboard(INSTALL_COMMANDS.choosenim);
98
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.choosenim);
99
+ break;
100
+
101
+ case "disable":
102
+ editor.disableLspForLanguage("nim");
103
+ editor.setStatus("Nim LSP disabled");
104
+ nimLspError = null;
105
+ break;
106
+
107
+ case "dismiss":
108
+ case "dismissed":
109
+ break;
110
+
111
+ default:
112
+ editor.debug(`nim-lsp: Unknown action: ${data.action_id}`);
113
+ }
114
+ }
115
+ registerHandler("on_nim_lsp_action_result", on_nim_lsp_action_result);
116
+ editor.on("action_popup_result", "on_nim_lsp_action_result");
117
+
118
+ editor.debug("nim-lsp: Plugin loaded");