@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,144 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * Terraform LSP Helper Plugin
6
+ *
7
+ * Provides user-friendly error handling for Terraform LSP server issues.
8
+ * When terraform-ls fails to start, this plugin shows an actionable
9
+ * popup with installation instructions.
10
+ *
11
+ * Features:
12
+ * - Detects Terraform LSP server errors (terraform-ls)
13
+ * - Shows popup with install commands (brew, choco, etc.)
14
+ * - Provides option to disable Terraform LSP
15
+ *
16
+ * VS Code: "HashiCorp Terraform" extension (uses terraform-ls)
17
+ * Neovim: nvim-lspconfig terraformls
18
+ * Also supports: Terraform, Terraform variables, and tfvars files
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 Terraform LSP server (terraform-ls by HashiCorp)
39
+ // See: https://github.com/hashicorp/terraform-ls
40
+ const INSTALL_COMMANDS = {
41
+ brew: "brew install hashicorp/tap/terraform-ls",
42
+ choco: "choco install terraform-ls",
43
+ nix: "nix-env -i terraform-ls",
44
+ };
45
+
46
+ // Track error state for Terraform LSP
47
+ let terraformLspError: { serverCommand: string; message: string } | null = null;
48
+
49
+ /**
50
+ * Handle LSP server errors for Terraform
51
+ */
52
+ function on_terraform_lsp_server_error(data: LspServerErrorData): void {
53
+ if (data.language !== "terraform") {
54
+ return;
55
+ }
56
+
57
+ editor.debug(`terraform-lsp: Server error - ${data.error_type}: ${data.message}`);
58
+
59
+ terraformLspError = {
60
+ serverCommand: data.server_command,
61
+ message: data.message,
62
+ };
63
+
64
+ if (data.error_type === "not_found") {
65
+ editor.setStatus(
66
+ `Terraform LSP server '${data.server_command}' not found. Click status bar for help.`
67
+ );
68
+ } else {
69
+ editor.setStatus(`Terraform LSP error: ${data.message}`);
70
+ }
71
+ }
72
+ registerHandler("on_terraform_lsp_server_error", on_terraform_lsp_server_error);
73
+ editor.on("lsp_server_error", "on_terraform_lsp_server_error");
74
+
75
+ /**
76
+ * Handle status bar click when there's a Terraform LSP error
77
+ */
78
+ function on_terraform_lsp_status_clicked(data: LspStatusClickedData): void {
79
+ if (data.language !== "terraform" || !terraformLspError) {
80
+ return;
81
+ }
82
+
83
+ editor.debug("terraform-lsp: Status clicked, showing help popup");
84
+
85
+ editor.showActionPopup({
86
+ id: "terraform-lsp-help",
87
+ title: "Terraform Language Server Not Found",
88
+ message: `"${terraformLspError.serverCommand}" (by HashiCorp) provides code completion, diagnostics, and navigation for Terraform files. Copy a command below to install it, or visit https://github.com/hashicorp/terraform-ls for details and pre-built binaries.`,
89
+ actions: [
90
+ { id: "copy_brew", label: `Copy: ${INSTALL_COMMANDS.brew}` },
91
+ { id: "copy_choco", label: `Copy: ${INSTALL_COMMANDS.choco} (Windows)` },
92
+ { id: "copy_nix", label: `Copy: ${INSTALL_COMMANDS.nix}` },
93
+ { id: "disable", label: "Disable Terraform LSP" },
94
+ { id: "dismiss", label: "Dismiss (ESC)" },
95
+ ],
96
+ });
97
+ }
98
+ registerHandler("on_terraform_lsp_status_clicked", on_terraform_lsp_status_clicked);
99
+ editor.on("lsp_status_clicked", "on_terraform_lsp_status_clicked");
100
+
101
+ /**
102
+ * Handle action popup results for Terraform LSP help
103
+ */
104
+ function on_terraform_lsp_action_result(data: ActionPopupResultData): void {
105
+ if (data.popup_id !== "terraform-lsp-help") {
106
+ return;
107
+ }
108
+
109
+ editor.debug(`terraform-lsp: Action selected - ${data.action_id}`);
110
+
111
+ switch (data.action_id) {
112
+ case "copy_brew":
113
+ editor.setClipboard(INSTALL_COMMANDS.brew);
114
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.brew);
115
+ break;
116
+
117
+ case "copy_choco":
118
+ editor.setClipboard(INSTALL_COMMANDS.choco);
119
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.choco);
120
+ break;
121
+
122
+ case "copy_nix":
123
+ editor.setClipboard(INSTALL_COMMANDS.nix);
124
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.nix);
125
+ break;
126
+
127
+ case "disable":
128
+ editor.disableLspForLanguage("terraform");
129
+ editor.setStatus("Terraform LSP disabled");
130
+ terraformLspError = null;
131
+ break;
132
+
133
+ case "dismiss":
134
+ case "dismissed":
135
+ break;
136
+
137
+ default:
138
+ editor.debug(`terraform-lsp: Unknown action: ${data.action_id}`);
139
+ }
140
+ }
141
+ registerHandler("on_terraform_lsp_action_result", on_terraform_lsp_action_result);
142
+ editor.on("action_popup_result", "on_terraform_lsp_action_result");
143
+
144
+ editor.debug("terraform-lsp: Plugin loaded");
@@ -296,7 +296,11 @@
296
296
  "field.popup_selection_fg": "vyskakovací okno výběr popředí",
297
297
  "field.popup_selection_fg_desc": "vyskakovací okno selected item text barva",
298
298
  "field.whitespace_indicator_fg": "Bílé znaky Indikátor popředí",
299
- "field.whitespace_indicator_fg_desc": "Barva popředí indikátorů bílých znaků (šipky tabulátorů a tečky mezer)"
299
+ "field.whitespace_indicator_fg_desc": "Barva popředí indikátorů bílých znaků (šipky tabulátorů a tečky mezer)",
300
+ "field.punctuation_bracket": "závorka",
301
+ "field.punctuation_bracket_desc": "závorkas ({, }, (, ), [, ])",
302
+ "field.punctuation_delimiter": "oddělovač",
303
+ "field.punctuation_delimiter_desc": "oddělovačs (;, ,, .)"
300
304
  },
301
305
  "de": {
302
306
  "cmd.edit_theme": "Theme bearbeiten",
@@ -595,7 +599,11 @@
595
599
  "field.popup_selection_fg": "Popup Auswahl Vordergrund",
596
600
  "field.popup_selection_fg_desc": "Textfarbe des ausgewaehlten Popup-Elements",
597
601
  "field.whitespace_indicator_fg": "Leerzeichen-Indikator Vordergrund",
598
- "field.whitespace_indicator_fg_desc": "Vordergrundfarbe für Leerzeichen-Indikatoren (Tab-Pfeile und Leerzeichen-Punkte)"
602
+ "field.whitespace_indicator_fg_desc": "Vordergrundfarbe für Leerzeichen-Indikatoren (Tab-Pfeile und Leerzeichen-Punkte)",
603
+ "field.punctuation_bracket": "Klammer",
604
+ "field.punctuation_bracket_desc": "Klammern ({, }, (, ), [, ])",
605
+ "field.punctuation_delimiter": "Trennzeichen",
606
+ "field.punctuation_delimiter_desc": "Trennzeichen (;, ,, .)"
599
607
  },
600
608
  "en": {
601
609
  "cmd.edit_theme": "Edit Theme",
@@ -894,7 +902,11 @@
894
902
  "field.popup_selection_fg": "Popup Selection Foreground",
895
903
  "field.popup_selection_fg_desc": "Popup selected item text color",
896
904
  "field.whitespace_indicator_fg": "Whitespace Indicator Foreground",
897
- "field.whitespace_indicator_fg_desc": "Foreground color for whitespace indicators (tab arrows and space dots)"
905
+ "field.whitespace_indicator_fg_desc": "Foreground color for whitespace indicators (tab arrows and space dots)",
906
+ "field.punctuation_bracket": "Punctuation Bracket",
907
+ "field.punctuation_bracket_desc": "Brackets and parentheses ({, }, (, ), [, ])",
908
+ "field.punctuation_delimiter": "Punctuation Delimiter",
909
+ "field.punctuation_delimiter_desc": "Delimiters and separators (;, ,, .)"
898
910
  },
899
911
  "es": {
900
912
  "cmd.edit_theme": "Editar tema",
@@ -1193,7 +1205,11 @@
1193
1205
  "field.popup_selection_fg": "Fondo de seleccion de ventana emergente",
1194
1206
  "field.popup_selection_fg_desc": "Fondo de elemento seleccionado en ventana emergente",
1195
1207
  "field.whitespace_indicator_fg": "Indicador de espacios en blanco primer plano",
1196
- "field.whitespace_indicator_fg_desc": "Color de primer plano para indicadores de espacios en blanco (flechas de tabulación y puntos de espacio)"
1208
+ "field.whitespace_indicator_fg_desc": "Color de primer plano para indicadores de espacios en blanco (flechas de tabulación y puntos de espacio)",
1209
+ "field.punctuation_bracket": "Paréntesis",
1210
+ "field.punctuation_bracket_desc": "Paréntesis y corchetes ({, }, (, ), [, ])",
1211
+ "field.punctuation_delimiter": "Delimitador",
1212
+ "field.punctuation_delimiter_desc": "Delimitadores y separadores (;, ,, .)"
1197
1213
  },
1198
1214
  "fr": {
1199
1215
  "cmd.edit_theme": "Modifier le theme",
@@ -1492,7 +1508,11 @@
1492
1508
  "field.popup_selection_fg": "Premier plan selection popup",
1493
1509
  "field.popup_selection_fg_desc": "Couleur du texte de l'element selectionne du popup",
1494
1510
  "field.whitespace_indicator_fg": "Indicateur d'espaces premier plan",
1495
- "field.whitespace_indicator_fg_desc": "Couleur de premier plan pour les indicateurs d'espaces (flèches de tabulation et points d'espace)"
1511
+ "field.whitespace_indicator_fg_desc": "Couleur de premier plan pour les indicateurs d'espaces (flèches de tabulation et points d'espace)",
1512
+ "field.punctuation_bracket": "Parenthese",
1513
+ "field.punctuation_bracket_desc": "Parentheses et crochets ({, }, (, ), [, ])",
1514
+ "field.punctuation_delimiter": "Delimiteur",
1515
+ "field.punctuation_delimiter_desc": "Delimiteurs et separateurs (;, ,, .)"
1496
1516
  },
1497
1517
  "ja": {
1498
1518
  "cmd.edit_theme": "テーマを編集",
@@ -1791,7 +1811,11 @@
1791
1811
  "field.popup_selection_fg": "ポップアップ選択前景",
1792
1812
  "field.popup_selection_fg_desc": "ポップアップの選択項目の文字颜色",
1793
1813
  "field.whitespace_indicator_fg": "空白インジケーター前景",
1794
- "field.whitespace_indicator_fg_desc": "空白インジケーターの前景色(タブ矢印とスペースドット)"
1814
+ "field.whitespace_indicator_fg_desc": "空白インジケーターの前景色(タブ矢印とスペースドット)",
1815
+ "field.punctuation_bracket": "括弧",
1816
+ "field.punctuation_bracket_desc": "括弧 ({、}、(、)、[、])",
1817
+ "field.punctuation_delimiter": "区切り文字",
1818
+ "field.punctuation_delimiter_desc": "区切り文字 (;、,、.)"
1795
1819
  },
1796
1820
  "ko": {
1797
1821
  "cmd.edit_theme": "편집 Theme",
@@ -2090,7 +2114,11 @@
2090
2114
  "field.popup_selection_fg": "팝업 선택 전경",
2091
2115
  "field.popup_selection_fg_desc": "팝업 selected item 텍스트 색상",
2092
2116
  "field.whitespace_indicator_fg": "공백 표시기 전경",
2093
- "field.whitespace_indicator_fg_desc": "공백 표시기의 전경색 (탭 화살표 및 공백 점)"
2117
+ "field.whitespace_indicator_fg_desc": "공백 표시기의 전경색 (탭 화살표 및 공백 점)",
2118
+ "field.punctuation_bracket": "괄호",
2119
+ "field.punctuation_bracket_desc": "괄호s ({, }, (, ), [, ])",
2120
+ "field.punctuation_delimiter": "구분자",
2121
+ "field.punctuation_delimiter_desc": "구분자s (;, ,, .)"
2094
2122
  },
2095
2123
  "pt-BR": {
2096
2124
  "cmd.edit_theme": "editar Theme",
@@ -2389,7 +2417,11 @@
2389
2417
  "field.popup_selection_fg": "popup seleção primeiro plano",
2390
2418
  "field.popup_selection_fg_desc": "popup selected item texto cor",
2391
2419
  "field.whitespace_indicator_fg": "Indicador de espaço em branco primeiro plano",
2392
- "field.whitespace_indicator_fg_desc": "Cor de primeiro plano para indicadores de espaço em branco (setas de tabulação e pontos de espaço)"
2420
+ "field.whitespace_indicator_fg_desc": "Cor de primeiro plano para indicadores de espaço em branco (setas de tabulação e pontos de espaço)",
2421
+ "field.punctuation_bracket": "parêntese",
2422
+ "field.punctuation_bracket_desc": "parênteses ({, }, (, ), [, ])",
2423
+ "field.punctuation_delimiter": "delimitador",
2424
+ "field.punctuation_delimiter_desc": "delimitadors (;, ,, .)"
2393
2425
  },
2394
2426
  "ru": {
2395
2427
  "cmd.edit_theme": "редактировать Theme",
@@ -2688,7 +2720,11 @@
2688
2720
  "field.popup_selection_fg": "всплывающее окно выделение передний план",
2689
2721
  "field.popup_selection_fg_desc": "всплывающее окно selected item текст цвет",
2690
2722
  "field.whitespace_indicator_fg": "Индикатор пробелов передний план",
2691
- "field.whitespace_indicator_fg_desc": "Цвет переднего плана для индикаторов пробелов (стрелки табуляции и точки пробелов)"
2723
+ "field.whitespace_indicator_fg_desc": "Цвет переднего плана для индикаторов пробелов (стрелки табуляции и точки пробелов)",
2724
+ "field.punctuation_bracket": "скобка",
2725
+ "field.punctuation_bracket_desc": "скобкаs ({, }, (, ), [, ])",
2726
+ "field.punctuation_delimiter": "разделитель",
2727
+ "field.punctuation_delimiter_desc": "разделительs (;, ,, .)"
2692
2728
  },
2693
2729
  "th": {
2694
2730
  "cmd.edit_theme": "แก้ไข Theme",
@@ -2987,7 +3023,11 @@
2987
3023
  "field.popup_selection_fg": "ป๊อปอัป การเลือก พื้นหน้า",
2988
3024
  "field.popup_selection_fg_desc": "ป๊อปอัป selected item ข้อความ สี",
2989
3025
  "field.whitespace_indicator_fg": "ตัวบ่งชี้ช่องว่างพื้นหน้า",
2990
- "field.whitespace_indicator_fg_desc": "สีพื้นหน้าสำหรับตัวบ่งชี้ช่องว่าง (ลูกศรแท็บและจุดเว้นวรรค)"
3026
+ "field.whitespace_indicator_fg_desc": "สีพื้นหน้าสำหรับตัวบ่งชี้ช่องว่าง (ลูกศรแท็บและจุดเว้นวรรค)",
3027
+ "field.punctuation_bracket": "วงเล็บ",
3028
+ "field.punctuation_bracket_desc": "วงเล็บs ({, }, (, ), [, ])",
3029
+ "field.punctuation_delimiter": "ตัวคั่น",
3030
+ "field.punctuation_delimiter_desc": "ตัวคั่นs (;, ,, .)"
2991
3031
  },
2992
3032
  "uk": {
2993
3033
  "cmd.edit_theme": "редагувати Theme",
@@ -3286,7 +3326,11 @@
3286
3326
  "field.popup_selection_fg": "спливаюче вікно виділення передний план",
3287
3327
  "field.popup_selection_fg_desc": "спливаюче вікно selected item текст цвет",
3288
3328
  "field.whitespace_indicator_fg": "Індикатор пробілів передній план",
3289
- "field.whitespace_indicator_fg_desc": "Колір переднього плану для індикаторів пробілів (стрілки табуляції та крапки пробілів)"
3329
+ "field.whitespace_indicator_fg_desc": "Колір переднього плану для індикаторів пробілів (стрілки табуляції та крапки пробілів)",
3330
+ "field.punctuation_bracket": "дужка",
3331
+ "field.punctuation_bracket_desc": "дужкаs ({, }, (, ), [, ])",
3332
+ "field.punctuation_delimiter": "роздільник",
3333
+ "field.punctuation_delimiter_desc": "роздільникs (;, ,, .)"
3290
3334
  },
3291
3335
  "vi": {
3292
3336
  "cmd.edit_theme": "Chỉnh sửa giao diện",
@@ -3585,7 +3629,11 @@
3585
3629
  "field.popup_selection_fg": "Tiền cảnh lựa chọn cửa sổ bật lên",
3586
3630
  "field.popup_selection_fg_desc": "Màu văn bản mục đã chọn trong cửa sổ bật lên",
3587
3631
  "field.whitespace_indicator_fg": "Chỉ báo khoảng trắng tiền cảnh",
3588
- "field.whitespace_indicator_fg_desc": "Màu tiền cảnh cho chỉ báo khoảng trắng (mũi tên tab và dấu chấm khoảng trắng)"
3632
+ "field.whitespace_indicator_fg_desc": "Màu tiền cảnh cho chỉ báo khoảng trắng (mũi tên tab và dấu chấm khoảng trắng)",
3633
+ "field.punctuation_bracket": "Dấu ngoặc",
3634
+ "field.punctuation_bracket_desc": "Dấu ngoặc ({, }, (, ), [, ])",
3635
+ "field.punctuation_delimiter": "Dấu phân cách",
3636
+ "field.punctuation_delimiter_desc": "Dấu phân cách (;, ,, .)"
3589
3637
  },
3590
3638
  "zh-CN": {
3591
3639
  "cmd.edit_theme": "编辑主题",
@@ -3884,7 +3932,11 @@
3884
3932
  "field.popup_selection_fg": "弹出窗口选择前景",
3885
3933
  "field.popup_selection_fg_desc": "弹出窗口选中项文字颜色",
3886
3934
  "field.whitespace_indicator_fg": "空白指示器前景",
3887
- "field.whitespace_indicator_fg_desc": "空白指示器的前景颜色(制表符箭头和空格点)"
3935
+ "field.whitespace_indicator_fg_desc": "空白指示器的前景颜色(制表符箭头和空格点)",
3936
+ "field.punctuation_bracket": "括号",
3937
+ "field.punctuation_bracket_desc": "括号 ({、}、(、)、[、])",
3938
+ "field.punctuation_delimiter": "分隔符",
3939
+ "field.punctuation_delimiter_desc": "分隔符 (;、,、.)"
3888
3940
  },
3889
3941
  "it": {
3890
3942
  "cmd.edit_theme": "Modifica tema",
@@ -4183,6 +4235,10 @@
4183
4235
  "field.popup_selection_fg": "Primo piano selezione popup",
4184
4236
  "field.popup_selection_fg_desc": "Colore del testo dell elemento selezionato nel popup",
4185
4237
  "field.whitespace_indicator_fg": "Indicatore spazi bianchi primo piano",
4186
- "field.whitespace_indicator_fg_desc": "Colore primo piano per gli indicatori di spazi bianchi (frecce di tabulazione e punti di spazio)"
4238
+ "field.whitespace_indicator_fg_desc": "Colore primo piano per gli indicatori di spazi bianchi (frecce di tabulazione e punti di spazio)",
4239
+ "field.punctuation_bracket": "Parentesi",
4240
+ "field.punctuation_bracket_desc": "Parentesi e parentesi quadre ({, }, (, ), [, ])",
4241
+ "field.punctuation_delimiter": "Delimitatore",
4242
+ "field.punctuation_delimiter_desc": "Delimitatori e separatori (;, ,, .)"
4187
4243
  }
4188
4244
  }
@@ -74,28 +74,28 @@ type PickerFocusTarget =
74
74
  // =============================================================================
75
75
 
76
76
  const NAMED_COLORS_PER_ROW = 6;
77
- const NAMED_COLOR_GRID: Array<Array<{ display: string; value: string; rgb: RGB | null }>> = [
77
+ const NAMED_COLOR_GRID: Array<Array<{ display: string; value: string; rgb: OverlayColorSpec | null }>> = [
78
78
  [
79
- { display: "Black", value: "Black", rgb: [0, 0, 0] },
80
- { display: "Red", value: "Red", rgb: [255, 0, 0] },
81
- { display: "Green", value: "Green", rgb: [0, 128, 0] },
82
- { display: "Yellow", value: "Yellow", rgb: [255, 255, 0] },
83
- { display: "Blue", value: "Blue", rgb: [0, 0, 255] },
84
- { display: "Magenta", value: "Magenta", rgb: [255, 0, 255] },
79
+ { display: "Black", value: "Black", rgb: "Black" },
80
+ { display: "Red", value: "Red", rgb: "Red" },
81
+ { display: "Green", value: "Green", rgb: "Green" },
82
+ { display: "Yellow", value: "Yellow", rgb: "Yellow" },
83
+ { display: "Blue", value: "Blue", rgb: "Blue" },
84
+ { display: "Magenta", value: "Magenta", rgb: "Magenta" },
85
85
  ],
86
86
  [
87
- { display: "Cyan", value: "Cyan", rgb: [0, 255, 255] },
88
- { display: "Gray", value: "Gray", rgb: [128, 128, 128] },
89
- { display: "DkGray", value: "DarkGray", rgb: [169, 169, 169] },
90
- { display: "LtRed", value: "LightRed", rgb: [255, 128, 128] },
91
- { display: "LtGreen", value: "LightGreen", rgb: [144, 238, 144] },
92
- { display: "LtYellw", value: "LightYellow", rgb: [255, 255, 224] },
87
+ { display: "Cyan", value: "Cyan", rgb: "Cyan" },
88
+ { display: "Gray", value: "Gray", rgb: "Gray" },
89
+ { display: "DkGray", value: "DarkGray", rgb: "DarkGray" },
90
+ { display: "LtRed", value: "LightRed", rgb: "LightRed" },
91
+ { display: "LtGreen", value: "LightGreen", rgb: "LightGreen" },
92
+ { display: "LtYellw", value: "LightYellow", rgb: "LightYellow" },
93
93
  ],
94
94
  [
95
- { display: "LtBlue", value: "LightBlue", rgb: [173, 216, 230] },
96
- { display: "LtMag", value: "LightMagenta", rgb: [255, 128, 255] },
97
- { display: "LtCyan", value: "LightCyan", rgb: [224, 255, 255] },
98
- { display: "White", value: "White", rgb: [255, 255, 255] },
95
+ { display: "LtBlue", value: "LightBlue", rgb: "LightBlue" },
96
+ { display: "LtMag", value: "LightMagenta", rgb: "LightMagenta" },
97
+ { display: "LtCyan", value: "LightCyan", rgb: "LightCyan" },
98
+ { display: "White", value: "White", rgb: "White" },
99
99
  { display: "Default", value: "Default", rgb: null },
100
100
  { display: "Reset", value: "Reset", rgb: null },
101
101
  ],
@@ -555,6 +555,27 @@ function parseColorToRgb(value: ColorValue): RGB | null {
555
555
  return null;
556
556
  }
557
557
 
558
+ /**
559
+ * Convert a color value to an OverlayColorSpec for rendering.
560
+ * Named colors (e.g. "Yellow") are sent as strings so the editor renders them
561
+ * using native ANSI color codes, matching the actual theme rendering.
562
+ * RGB arrays are passed through directly.
563
+ */
564
+ function colorValueToOverlaySpec(value: ColorValue): OverlayColorSpec | null {
565
+ if (Array.isArray(value) && value.length === 3) {
566
+ return value as RGB;
567
+ }
568
+ if (typeof value === "string") {
569
+ // For recognized named colors, send the name directly so the editor
570
+ // uses native ANSI rendering (matching actual theme output)
571
+ if (NAMED_COLORS[value] !== undefined) {
572
+ return value;
573
+ }
574
+ return null;
575
+ }
576
+ return null;
577
+ }
578
+
558
579
  /**
559
580
  * Convert RGB to hex string
560
581
  */
@@ -856,14 +877,19 @@ function buildPickerLines(): PickerLine[] {
856
877
  lines.push({ text: `"${field.def.description}"`, type: "picker-desc" });
857
878
  lines.push({ text: "─".repeat(RIGHT_WIDTH - 2), type: "picker-separator" });
858
879
 
859
- // Hex / RGB value
860
- const colorStr = formatColorValue(field.value);
861
- const rgb = parseColorToRgb(field.value);
862
- let valueLine = `Hex: ${colorStr}`;
863
- if (rgb) {
864
- valueLine += ` RGB: ${rgb[0]}, ${rgb[1]}, ${rgb[2]}`;
880
+ // Color value display
881
+ const isNamed = typeof field.value === "string" && NAMED_COLORS[field.value] !== undefined;
882
+ if (isNamed) {
883
+ lines.push({ text: `Color: ${field.value} (terminal native)`, type: "picker-hex" });
884
+ } else {
885
+ const colorStr = formatColorValue(field.value);
886
+ const rgb = parseColorToRgb(field.value);
887
+ let valueLine = `Hex: ${colorStr}`;
888
+ if (rgb) {
889
+ valueLine += ` RGB: ${rgb[0]}, ${rgb[1]}, ${rgb[2]}`;
890
+ }
891
+ lines.push({ text: valueLine, type: "picker-hex" });
865
892
  }
866
- lines.push({ text: valueLine, type: "picker-hex" });
867
893
 
868
894
  lines.push({ text: "", type: "picker-blank" });
869
895
 
@@ -929,14 +955,22 @@ function styleForLeftEntry(item: TreeLine | undefined): { style?: Partial<Overla
929
955
  const paddedLen = getUtf8ByteLength(text.padEnd(LEFT_WIDTH));
930
956
  const colorValue = item.colorValue;
931
957
  const swatchIdx = colorValue !== undefined ? text.indexOf("██") : -1;
932
- const rgb = colorValue !== undefined ? parseColorToRgb(colorValue) : null;
933
958
 
934
- if (rgb && swatchIdx >= 0) {
959
+ // For the swatch, use the native color representation to ensure it matches
960
+ // how the theme actually renders: named colors (e.g. "Yellow") should use
961
+ // the terminal's native ANSI color, not an RGB approximation.
962
+ const swatchColor: OverlayColorSpec | null = colorValue !== undefined
963
+ ? (typeof colorValue === "string" && NAMED_COLORS[colorValue] !== undefined
964
+ ? colorValue as OverlayColorSpec // Send named color string directly
965
+ : parseColorToRgb(colorValue)) // Send RGB for array values
966
+ : null;
967
+
968
+ if (swatchColor && swatchIdx >= 0) {
935
969
  const swatchStart = getUtf8ByteLength(text.substring(0, swatchIdx));
936
970
  const swatchEnd = swatchStart + getUtf8ByteLength("██");
937
971
  // Non-overlapping segments: fieldName | swatch | value
938
972
  inlines.push({ start: 0, end: swatchStart, style: { fg: colors.fieldName } });
939
- inlines.push({ start: swatchStart, end: swatchEnd, style: { fg: rgb, bg: rgb } });
973
+ inlines.push({ start: swatchStart, end: swatchEnd, style: { fg: swatchColor, bg: swatchColor } });
940
974
  const valueStart = swatchEnd + getUtf8ByteLength(" ");
941
975
  if (valueStart < paddedLen) {
942
976
  inlines.push({ start: valueStart, end: paddedLen, style: { fg: colors.customValue } });
@@ -1015,10 +1049,10 @@ function styleForRightEntry(item: PickerLine | undefined): { style?: Partial<Ove
1015
1049
  // entry text = " " + item.text
1016
1050
  // item.text = " " + token texts concatenated
1017
1051
  const editorBg = getNestedValue(state.themeData, "editor.bg") as ColorValue;
1018
- const bgRgb = parseColorToRgb(editorBg);
1052
+ const bgSpec = colorValueToOverlaySpec(editorBg);
1019
1053
  const entryText = " " + item.text;
1020
1054
  const entryLen = getUtf8ByteLength(entryText);
1021
- const baseStyle: Partial<OverlayOptions> | undefined = bgRgb ? { bg: bgRgb } : undefined;
1055
+ const baseStyle: Partial<OverlayOptions> | undefined = bgSpec ? { bg: bgSpec } : undefined;
1022
1056
 
1023
1057
  // Skip the leading " " + " " (from entry " " prefix + item.text leading " ")
1024
1058
  let charPos = 2; // " " prefix + " " in item.text
@@ -1028,15 +1062,15 @@ function styleForRightEntry(item: PickerLine | undefined): { style?: Partial<Ove
1028
1062
  if (token.syntaxType) {
1029
1063
  const syntaxPath = `syntax.${token.syntaxType}`;
1030
1064
  const syntaxColor = getNestedValue(state.themeData, syntaxPath) as ColorValue;
1031
- const syntaxRgb = parseColorToRgb(syntaxColor);
1032
- if (syntaxRgb) {
1033
- inlines.push({ start: bytePos, end: bytePos + tokenLen, style: { fg: syntaxRgb } });
1065
+ const fgSpec = colorValueToOverlaySpec(syntaxColor);
1066
+ if (fgSpec) {
1067
+ inlines.push({ start: bytePos, end: bytePos + tokenLen, style: { fg: fgSpec } });
1034
1068
  }
1035
1069
  } else {
1036
1070
  const fgColor = getNestedValue(state.themeData, "editor.fg") as ColorValue;
1037
- const fgRgb = parseColorToRgb(fgColor);
1038
- if (fgRgb) {
1039
- inlines.push({ start: bytePos, end: bytePos + tokenLen, style: { fg: fgRgb } });
1071
+ const fgSpec = colorValueToOverlaySpec(fgColor);
1072
+ if (fgSpec) {
1073
+ inlines.push({ start: bytePos, end: bytePos + tokenLen, style: { fg: fgSpec } });
1040
1074
  }
1041
1075
  }
1042
1076
  bytePos += tokenLen;
@@ -1344,11 +1378,9 @@ function buildColorSuggestions(field: ThemeField): PromptSuggestion[] {
1344
1378
  suggestions.push({ text: name, description: editor.t("suggestion.terminal_native"), value: name });
1345
1379
  }
1346
1380
 
1347
- // Add named colors with hex format
1381
+ // Add named colors (terminal native - no hex shown since actual color depends on terminal)
1348
1382
  for (const name of NAMED_COLOR_LIST) {
1349
- const rgb = NAMED_COLORS[name];
1350
- const hexValue = rgbToHex(rgb[0], rgb[1], rgb[2]);
1351
- suggestions.push({ text: name, description: hexValue, value: name });
1383
+ suggestions.push({ text: name, description: editor.t("suggestion.terminal_native"), value: name });
1352
1384
  }
1353
1385
 
1354
1386
  return suggestions;
@@ -0,0 +1,162 @@
1
+ /// <reference path="./lib/fresh.d.ts" />
2
+ const editor = getEditor();
3
+
4
+ /**
5
+ * TOML LSP Helper Plugin
6
+ *
7
+ * Provides user-friendly error handling for TOML LSP server issues.
8
+ * When taplo fails to start, this plugin shows an actionable
9
+ * popup with installation instructions.
10
+ *
11
+ * Features:
12
+ * - Detects TOML LSP server errors (taplo)
13
+ * - Shows popup with install commands (cargo, npm, brew)
14
+ * - Allows copying install commands to clipboard
15
+ * - Provides option to disable TOML LSP
16
+ *
17
+ * Notes:
18
+ * - Taplo supports schema validation for Cargo.toml, pyproject.toml, etc.
19
+ * - Also available as a VS Code extension and CLI formatter
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 TOML LSP server (taplo)
40
+ // See: https://taplo.tamasfe.dev/cli/installation.html
41
+ const INSTALL_COMMANDS = {
42
+ cargo: "cargo install taplo-cli --locked",
43
+ npm: "npm i -g @taplo/cli",
44
+ brew: "brew install taplo",
45
+ };
46
+
47
+ // Track error state for TOML LSP
48
+ let tomlLspError: { serverCommand: string; message: string } | null = null;
49
+
50
+ /**
51
+ * Handle LSP server errors for TOML
52
+ */
53
+ function on_toml_lsp_server_error(data: LspServerErrorData): void {
54
+ // Only handle TOML language errors
55
+ if (data.language !== "toml") {
56
+ return;
57
+ }
58
+
59
+ editor.debug(`toml-lsp: Server error - ${data.error_type}: ${data.message}`);
60
+
61
+ // Store error state for later reference
62
+ tomlLspError = {
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
+ `TOML LSP server '${data.server_command}' not found. Click status bar for help.`
71
+ );
72
+ } else {
73
+ editor.setStatus(`TOML LSP error: ${data.message}`);
74
+ }
75
+ }
76
+ registerHandler("on_toml_lsp_server_error", on_toml_lsp_server_error);
77
+
78
+ // Register hook for LSP server errors
79
+ editor.on("lsp_server_error", "on_toml_lsp_server_error");
80
+
81
+ /**
82
+ * Handle status bar click when there's a TOML LSP error
83
+ */
84
+ function on_toml_lsp_status_clicked(
85
+ data: LspStatusClickedData
86
+ ): void {
87
+ // Only handle TOML language clicks when there's an error
88
+ if (data.language !== "toml" || !tomlLspError) {
89
+ return;
90
+ }
91
+
92
+ editor.debug("toml-lsp: Status clicked, showing help popup");
93
+
94
+ // Show action popup with install options
95
+ editor.showActionPopup({
96
+ id: "toml-lsp-help",
97
+ title: "TOML Language Server Not Found",
98
+ message: `"${tomlLspError.serverCommand}" provides code completion, validation, formatting, and schema support for TOML files (Cargo.toml, pyproject.toml, etc.). Copy a command below to install it, or visit https://taplo.tamasfe.dev/cli/installation.html for details.`,
99
+ actions: [
100
+ { id: "copy_cargo", label: `Copy: ${INSTALL_COMMANDS.cargo}` },
101
+ { id: "copy_npm", label: `Copy: ${INSTALL_COMMANDS.npm}` },
102
+ { id: "copy_brew", label: `Copy: ${INSTALL_COMMANDS.brew}` },
103
+ { id: "disable", label: "Disable TOML LSP" },
104
+ { id: "dismiss", label: "Dismiss (ESC)" },
105
+ ],
106
+ });
107
+ }
108
+ registerHandler("on_toml_lsp_status_clicked", on_toml_lsp_status_clicked);
109
+
110
+ // Register hook for status bar clicks
111
+ editor.on("lsp_status_clicked", "on_toml_lsp_status_clicked");
112
+
113
+ /**
114
+ * Handle action popup results for TOML LSP help
115
+ */
116
+ function on_toml_lsp_action_result(
117
+ data: ActionPopupResultData
118
+ ): void {
119
+ // Only handle our popup
120
+ if (data.popup_id !== "toml-lsp-help") {
121
+ return;
122
+ }
123
+
124
+ editor.debug(`toml-lsp: Action selected - ${data.action_id}`);
125
+
126
+ switch (data.action_id) {
127
+ case "copy_cargo":
128
+ editor.setClipboard(INSTALL_COMMANDS.cargo);
129
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.cargo);
130
+ break;
131
+
132
+ case "copy_npm":
133
+ editor.setClipboard(INSTALL_COMMANDS.npm);
134
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.npm);
135
+ break;
136
+
137
+ case "copy_brew":
138
+ editor.setClipboard(INSTALL_COMMANDS.brew);
139
+ editor.setStatus("Copied: " + INSTALL_COMMANDS.brew);
140
+ break;
141
+
142
+ case "disable":
143
+ editor.disableLspForLanguage("toml");
144
+ editor.setStatus("TOML LSP disabled");
145
+ tomlLspError = 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(`toml-lsp: Unknown action: ${data.action_id}`);
155
+ }
156
+ }
157
+ registerHandler("on_toml_lsp_action_result", on_toml_lsp_action_result);
158
+
159
+ // Register hook for action popup results
160
+ editor.on("action_popup_result", "on_toml_lsp_action_result");
161
+
162
+ editor.debug("toml-lsp: Plugin loaded");