@fresh-editor/fresh-editor 0.3.1 → 0.3.4

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.
@@ -224,6 +224,30 @@ interface ThemeField {
224
224
  */
225
225
  let cachedThemeSections: ThemeSection[] | null = null;
226
226
 
227
+ /**
228
+ * Whether a property schema entry refers to `ColorDef` — directly via
229
+ * `$ref` or wrapped inside an `anyOf` (the schema generator wraps
230
+ * `Option<ColorDef>` as `anyOf: [{$ref: ColorDef}, {type: null}]`).
231
+ * Returns false for unrelated $refs such as `ModifierDef`.
232
+ */
233
+ function fieldRefersToColorDef(fieldObj: Record<string, unknown>): boolean {
234
+ const refStr = fieldObj["$ref"];
235
+ if (typeof refStr === "string" && refStr.endsWith("/ColorDef")) {
236
+ return true;
237
+ }
238
+ const anyOf = fieldObj["anyOf"];
239
+ if (Array.isArray(anyOf)) {
240
+ for (const variant of anyOf) {
241
+ if (variant && typeof variant === "object") {
242
+ const v = variant as Record<string, unknown>;
243
+ const r = v["$ref"];
244
+ if (typeof r === "string" && r.endsWith("/ColorDef")) return true;
245
+ }
246
+ }
247
+ }
248
+ return false;
249
+ }
250
+
227
251
  /**
228
252
  * Load theme sections from the Rust API.
229
253
  * Parses the raw JSON Schema and resolves $ref references.
@@ -258,8 +282,12 @@ function loadThemeSections(): ThemeSection[] {
258
282
  const sectionOrder = ["editor", "ui", "search", "diagnostic", "syntax"];
259
283
 
260
284
  for (const [sectionName, sectionSchema] of Object.entries(properties)) {
261
- // Skip "name" field - it's not a color section
262
- if (sectionName === "name") continue;
285
+ // Skip top-level fields that aren't color sections: `name` is the
286
+ // theme's identity and `extends` is the inheritance pointer (a string,
287
+ // not a section). Without this check, the plugin would emit
288
+ // `"extends": {}` when serializing back out, which fails to round-trip
289
+ // as a `ThemeFile`.
290
+ if (sectionName === "name" || sectionName === "extends") continue;
263
291
 
264
292
  const sectionObj = sectionSchema as Record<string, unknown>;
265
293
  const sectionDesc = (sectionObj.description as string) || "";
@@ -276,6 +304,14 @@ function loadThemeSections(): ThemeSection[] {
276
304
  const fieldObj = fieldSchema as Record<string, unknown>;
277
305
  const fieldDesc = (fieldObj.description as string) || "";
278
306
 
307
+ // Skip non-color fields (e.g. `selection_modifier`, which is a
308
+ // string array of SGR text-attribute names). The theme editor only
309
+ // knows how to format and edit `ColorDef` values; if it tried to
310
+ // hand a modifier-array to `formatColorValue` it would treat the
311
+ // array as an RGB tuple and crash inside `rgbToHex` when the second
312
+ // element turns out to be undefined.
313
+ if (!fieldRefersToColorDef(fieldObj)) continue;
314
+
279
315
  // Generate i18n keys from field names
280
316
  const i18nName = `field.${fieldName}`;
281
317
  const i18nDesc = `field.${fieldName}_desc`;
@@ -685,59 +721,31 @@ function setNestedValue(obj: Record<string, unknown>, path: string, value: unkno
685
721
  }
686
722
 
687
723
  /**
688
- * Find themes directory
724
+ * Load theme registry and populate state.themeRegistry + state.builtinKeys.
725
+ *
726
+ * Themes come pre-merged from the Rust registry (builtins + user dir +
727
+ * packages + bundles), keyed by canonical registry key with `_key`/`_pack`
728
+ * metadata baked in — same data the native `select_theme` prompt sees.
689
729
  */
690
- function findThemesDir(): string {
691
- const cwd = editor.getCwd();
692
- const candidates = [
693
- editor.pathJoin(cwd, "themes"),
694
- ];
730
+ async function loadThemeRegistry(): Promise<void> {
731
+ const themes = editor.getAllThemes() as Record<string, Record<string, unknown>>;
695
732
 
696
- for (const path of candidates) {
697
- if (editor.fileExists(path)) {
698
- return path;
699
- }
700
- }
733
+ state.themeRegistry = new Map();
734
+ state.builtinKeys = new Set();
701
735
 
702
- return candidates[0];
703
- }
736
+ for (const [key, data] of Object.entries(themes)) {
737
+ const name = (data?.name as string) || key;
738
+ const pack = (data?._pack as string) || "";
704
739
 
705
- /**
706
- * Load list of available built-in themes
707
- */
708
- /**
709
- * Load all themes from the registry, returning a map of key → display name.
710
- *
711
- * The registry is keyed by unique keys (repo URLs, file:// paths, or bare
712
- * names for builtins). Each value contains a `name` field (display name)
713
- * and `_key`/`_pack` metadata.
714
- */
715
- /**
716
- * Load theme registry and populate state.themeRegistry + state.builtinKeys.
717
- */
718
- async function loadThemeRegistry(): Promise<void> {
719
- try {
720
- editor.debug("[theme_editor] loadThemeRegistry: calling editor.getBuiltinThemes()");
721
- const rawThemes = editor.getBuiltinThemes();
722
- const themes = typeof rawThemes === "string"
723
- ? JSON.parse(rawThemes) as Record<string, Record<string, unknown>>
724
- : rawThemes as Record<string, Record<string, unknown>>;
725
- state.themeRegistry = new Map();
726
- state.builtinKeys = new Set();
727
- for (const [key, data] of Object.entries(themes)) {
728
- const name = (data?.name as string) || key;
729
- const pack = (data?._pack as string) || "";
730
- state.themeRegistry.set(key, {name, pack});
731
- // Builtin themes have an empty pack; user themes start with "user"
732
- if (!pack || (!pack.startsWith("user") && !pack.startsWith("pkg"))) {
733
- state.builtinKeys.add(key);
734
- }
740
+ state.themeRegistry.set(key, { name, pack });
741
+
742
+ // Builtin themes have an empty pack; user themes start with "user"
743
+ if (!pack || (!pack.startsWith("user") && !pack.startsWith("pkg"))) {
744
+ state.builtinKeys.add(key);
735
745
  }
736
- editor.debug(`[theme_editor] loadThemeRegistry: loaded ${state.themeRegistry.size} themes (${state.builtinKeys.size} builtin)`);
737
- } catch (e) {
738
- editor.debug(`[theme_editor] Failed to load theme registry: ${e}`);
739
- throw e;
740
746
  }
747
+
748
+ editor.debug(`[theme_editor] loadThemeRegistry: loaded ${state.themeRegistry.size} themes (${state.builtinKeys.size} builtin)`);
741
749
  }
742
750
 
743
751
  /**
@@ -2592,7 +2600,7 @@ async function open_theme_editor() : Promise<void> {
2592
2600
  state.sourceSplitId = editor.getActiveSplitId();
2593
2601
  state.sourceBufferId = editor.getActiveBufferId();
2594
2602
 
2595
- editor.debug("[theme_editor] loading builtin themes...");
2603
+ editor.debug("[theme_editor] loading themes...");
2596
2604
  // Load available themes
2597
2605
  await loadThemeRegistry();
2598
2606
  editor.debug(`[theme_editor] loaded ${state.themeRegistry.size} themes (${state.builtinKeys.size} builtin)`);
@@ -57,6 +57,7 @@
57
57
  "julia-lsp.ts",
58
58
  "kotlin-lsp.ts",
59
59
  "latex-lsp.ts",
60
+ "live_diff.ts",
60
61
  "live_grep.ts",
61
62
  "lua-lsp.ts",
62
63
  "markdown_compose.ts",
package/themes/dark.json CHANGED
@@ -40,6 +40,8 @@
40
40
  "menu_disabled_bg": [50, 50, 50],
41
41
  "status_bar_fg": "White",
42
42
  "status_bar_bg": [30, 30, 30],
43
+ "status_palette_fg": [255, 255, 255],
44
+ "status_palette_bg": [70, 130, 180],
43
45
  "prompt_fg": "White",
44
46
  "prompt_bg": [20, 20, 20],
45
47
  "prompt_selection_fg": "White",
@@ -48,6 +50,8 @@
48
50
  "popup_bg": [30, 30, 30],
49
51
  "popup_selection_bg": [58, 79, 120],
50
52
  "popup_text_fg": "White",
53
+ "settings_selected_bg": [58, 79, 120],
54
+ "settings_selected_fg": [255, 255, 255],
51
55
  "suggestion_bg": [30, 30, 30],
52
56
  "suggestion_selected_bg": [58, 79, 120],
53
57
  "help_bg": "Black",
@@ -23,6 +23,8 @@
23
23
  "tab_hover_bg": [80, 83, 100],
24
24
  "status_bar_fg": [40, 42, 54],
25
25
  "status_bar_bg": [189, 147, 249],
26
+ "status_palette_fg": [40, 42, 54],
27
+ "status_palette_bg": [139, 233, 253],
26
28
  "prompt_fg": [40, 42, 54],
27
29
  "prompt_bg": [80, 250, 123],
28
30
  "prompt_selection_fg": [248, 248, 242],
@@ -40,6 +40,8 @@
40
40
  "menu_disabled_bg": [20, 20, 20],
41
41
  "status_bar_fg": [255, 255, 255],
42
42
  "status_bar_bg": [20, 20, 20],
43
+ "status_palette_fg": [0, 0, 0],
44
+ "status_palette_bg": [0, 255, 255],
43
45
  "prompt_fg": [255, 255, 255],
44
46
  "prompt_bg": [10, 10, 10],
45
47
  "prompt_selection_fg": [255, 255, 255],
@@ -48,6 +50,8 @@
48
50
  "popup_bg": [0, 0, 0],
49
51
  "popup_selection_bg": [0, 100, 200],
50
52
  "popup_text_fg": [255, 255, 255],
53
+ "settings_selected_bg": [0, 100, 200],
54
+ "settings_selected_fg": [255, 255, 255],
51
55
  "suggestion_bg": [0, 0, 0],
52
56
  "suggestion_selected_bg": [0, 100, 200],
53
57
  "help_bg": [0, 0, 0],
package/themes/light.json CHANGED
@@ -40,6 +40,8 @@
40
40
  "menu_disabled_bg": [248, 248, 248],
41
41
  "status_bar_fg": [0, 0, 0],
42
42
  "status_bar_bg": [220, 220, 220],
43
+ "status_palette_fg": [255, 255, 255],
44
+ "status_palette_bg": [70, 130, 180],
43
45
  "prompt_fg": [0, 0, 0],
44
46
  "prompt_bg": [230, 240, 250],
45
47
  "prompt_selection_fg": [0, 0, 0],
@@ -48,6 +50,8 @@
48
50
  "popup_bg": [232, 238, 245],
49
51
  "popup_selection_bg": [209, 226, 243],
50
52
  "popup_text_fg": [30, 30, 30],
53
+ "settings_selected_bg": [173, 214, 255],
54
+ "settings_selected_fg": [0, 0, 0],
51
55
  "suggestion_bg": [232, 238, 245],
52
56
  "popup_selection_fg": [0, 0, 0],
53
57
  "suggestion_selected_bg": [209, 226, 243],
package/themes/nord.json CHANGED
@@ -18,6 +18,8 @@
18
18
  "tab_separator_bg": [46, 52, 64],
19
19
  "status_bar_fg": [46, 52, 64],
20
20
  "status_bar_bg": [136, 192, 208],
21
+ "status_palette_fg": [236, 239, 244],
22
+ "status_palette_bg": [94, 129, 172],
21
23
  "prompt_fg": [46, 52, 64],
22
24
  "prompt_bg": [163, 190, 140],
23
25
  "prompt_selection_fg": [236, 239, 244],
@@ -27,6 +29,11 @@
27
29
  "popup_selection_bg": [94, 129, 172],
28
30
  "popup_selection_fg": [236, 239, 244],
29
31
  "popup_text_fg": [216, 222, 233],
32
+ "menu_fg": [216, 222, 233],
33
+ "menu_highlight_bg": [94, 129, 172],
34
+ "menu_highlight_fg": [236, 239, 244],
35
+ "menu_hover_bg": [67, 76, 94],
36
+ "menu_hover_fg": [216, 222, 233],
30
37
  "suggestion_bg": [59, 66, 82],
31
38
  "suggestion_selected_bg": [94, 129, 172],
32
39
  "help_bg": [46, 52, 64],
@@ -38,6 +38,8 @@
38
38
  "menu_disabled_bg": [170, 170, 170],
39
39
  "status_bar_fg": [0, 0, 0],
40
40
  "status_bar_bg": [0, 170, 170],
41
+ "status_palette_fg": [255, 255, 255],
42
+ "status_palette_bg": [0, 170, 0],
41
43
  "prompt_fg": [255, 255, 85],
42
44
  "prompt_bg": [0, 0, 170],
43
45
  "prompt_selection_fg": [0, 0, 0],
@@ -46,6 +48,8 @@
46
48
  "popup_bg": [0, 0, 170],
47
49
  "popup_selection_bg": [0, 170, 0],
48
50
  "popup_text_fg": [255, 255, 85],
51
+ "settings_selected_bg": [170, 0, 170],
52
+ "settings_selected_fg": [255, 255, 255],
49
53
  "suggestion_bg": [0, 0, 170],
50
54
  "suggestion_selected_bg": [0, 170, 0],
51
55
  "help_bg": [0, 0, 170],
@@ -18,6 +18,8 @@
18
18
  "tab_separator_bg": [0, 43, 54],
19
19
  "status_bar_fg": [0, 43, 54],
20
20
  "status_bar_bg": [147, 161, 161],
21
+ "status_palette_fg": [253, 246, 227],
22
+ "status_palette_bg": [38, 139, 210],
21
23
  "prompt_fg": [0, 43, 54],
22
24
  "prompt_bg": [181, 137, 0],
23
25
  "prompt_selection_fg": [253, 246, 227],
@@ -27,6 +29,11 @@
27
29
  "popup_selection_bg": [38, 139, 210],
28
30
  "popup_selection_fg": [253, 246, 227],
29
31
  "popup_text_fg": [147, 161, 161],
32
+ "menu_fg": [147, 161, 161],
33
+ "menu_highlight_bg": [38, 139, 210],
34
+ "menu_highlight_fg": [253, 246, 227],
35
+ "menu_hover_bg": [88, 110, 117],
36
+ "menu_hover_fg": [253, 246, 227],
30
37
  "suggestion_bg": [7, 54, 66],
31
38
  "suggestion_selected_bg": [38, 139, 210],
32
39
  "help_bg": [0, 43, 54],
@@ -0,0 +1,128 @@
1
+ {
2
+ "name": "terminal",
3
+ "editor": {
4
+ "bg": "Default",
5
+ "fg": "Default",
6
+ "cursor": "Default",
7
+ "inactive_cursor": "DarkGray",
8
+ "selection_bg": "Default",
9
+ "selection_modifier": ["reversed"],
10
+ "current_line_bg": "Default",
11
+ "line_number_fg": "DarkGray",
12
+ "line_number_bg": "Default",
13
+ "diff_add_bg": "Green",
14
+ "diff_remove_bg": "Red",
15
+ "diff_add_highlight_bg": "LightGreen",
16
+ "diff_remove_highlight_bg": "LightRed",
17
+ "diff_modify_bg": "Yellow",
18
+ "ruler_bg": "DarkGray",
19
+ "whitespace_indicator_fg": "DarkGray",
20
+ "after_eof_bg": "Default"
21
+ },
22
+ "ui": {
23
+ "tab_active_fg": "Yellow",
24
+ "tab_active_bg": "Default",
25
+ "tab_inactive_fg": "Gray",
26
+ "tab_inactive_bg": "Default",
27
+ "tab_separator_bg": "Default",
28
+ "tab_close_hover_fg": "Red",
29
+ "tab_hover_bg": "DarkGray",
30
+ "menu_bg": "Default",
31
+ "menu_fg": "Default",
32
+ "menu_active_bg": "Blue",
33
+ "menu_active_fg": "White",
34
+ "menu_dropdown_bg": "Default",
35
+ "menu_dropdown_fg": "Default",
36
+ "menu_highlight_bg": "Blue",
37
+ "menu_highlight_fg": "White",
38
+ "menu_border_fg": "DarkGray",
39
+ "menu_separator_fg": "DarkGray",
40
+ "menu_hover_bg": "DarkGray",
41
+ "menu_hover_fg": "White",
42
+ "menu_disabled_fg": "DarkGray",
43
+ "menu_disabled_bg": "Default",
44
+ "status_bar_fg": "Default",
45
+ "status_bar_bg": "Default",
46
+ "status_palette_fg": "White",
47
+ "status_palette_bg": "Magenta",
48
+ "status_lsp_on_fg": "Default",
49
+ "status_lsp_on_bg": "Default",
50
+ "status_lsp_actionable_fg": "Black",
51
+ "status_lsp_actionable_bg": "Yellow",
52
+ "prompt_fg": "Default",
53
+ "prompt_bg": "Default",
54
+ "prompt_selection_fg": "White",
55
+ "prompt_selection_bg": "Blue",
56
+ "popup_border_fg": "Gray",
57
+ "popup_bg": "Default",
58
+ "popup_selection_bg": "Blue",
59
+ "popup_selection_fg": "White",
60
+ "popup_text_fg": "Default",
61
+ "suggestion_bg": "Default",
62
+ "suggestion_selected_bg": "Blue",
63
+ "help_bg": "Default",
64
+ "help_fg": "Default",
65
+ "help_key_fg": "Cyan",
66
+ "help_separator_fg": "DarkGray",
67
+ "help_indicator_fg": "Red",
68
+ "help_indicator_bg": "Default",
69
+ "inline_code_bg": "DarkGray",
70
+ "split_separator_fg": "DarkGray",
71
+ "split_separator_hover_fg": "Cyan",
72
+ "scrollbar_track_fg": "DarkGray",
73
+ "scrollbar_thumb_fg": "Gray",
74
+ "scrollbar_track_hover_fg": "Gray",
75
+ "scrollbar_thumb_hover_fg": "White",
76
+ "compose_margin_bg": "Default",
77
+ "semantic_highlight_bg": "Default",
78
+ "semantic_highlight_modifier": ["bold", "underlined"],
79
+ "terminal_bg": "Default",
80
+ "terminal_fg": "Default",
81
+ "status_warning_indicator_bg": "Yellow",
82
+ "status_warning_indicator_fg": "Black",
83
+ "status_error_indicator_bg": "Red",
84
+ "status_error_indicator_fg": "White",
85
+ "status_warning_indicator_hover_bg": "LightYellow",
86
+ "status_warning_indicator_hover_fg": "Black",
87
+ "status_error_indicator_hover_bg": "LightRed",
88
+ "status_error_indicator_hover_fg": "White",
89
+ "tab_drop_zone_bg": "Blue",
90
+ "tab_drop_zone_border": "Cyan",
91
+ "settings_selected_bg": "Blue",
92
+ "settings_selected_fg": "White",
93
+ "file_status_added_fg": "Green",
94
+ "file_status_modified_fg": "Yellow",
95
+ "file_status_deleted_fg": "Red",
96
+ "file_status_renamed_fg": "Cyan",
97
+ "file_status_untracked_fg": "Gray",
98
+ "file_status_conflicted_fg": "Magenta"
99
+ },
100
+ "search": {
101
+ "match_bg": "Yellow",
102
+ "match_fg": "Black",
103
+ "label_bg": "Magenta",
104
+ "label_fg": "White"
105
+ },
106
+ "diagnostic": {
107
+ "error_fg": "Red",
108
+ "error_bg": "Default",
109
+ "warning_fg": "Yellow",
110
+ "warning_bg": "Default",
111
+ "info_fg": "Blue",
112
+ "info_bg": "Default",
113
+ "hint_fg": "Gray",
114
+ "hint_bg": "Default"
115
+ },
116
+ "syntax": {
117
+ "keyword": "Red",
118
+ "string": "Green",
119
+ "comment": "DarkGray",
120
+ "function": "Blue",
121
+ "type": "Yellow",
122
+ "variable": "Default",
123
+ "constant": "Magenta",
124
+ "operator": "Default",
125
+ "punctuation_bracket": "Default",
126
+ "punctuation_delimiter": "Default"
127
+ }
128
+ }