@fresh-editor/fresh-editor 0.2.21 → 0.2.23

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.
@@ -42,6 +42,24 @@
42
42
  "menu_bar_mnemonics": true,
43
43
  "show_tab_bar": true,
44
44
  "show_status_bar": true,
45
+ "status_bar": {
46
+ "left": [
47
+ "{filename}",
48
+ "{cursor}",
49
+ "{diagnostics}",
50
+ "{cursor_count}",
51
+ "{messages}"
52
+ ],
53
+ "right": [
54
+ "{line_ending}",
55
+ "{encoding}",
56
+ "{language}",
57
+ "{lsp}",
58
+ "{warnings}",
59
+ "{update}",
60
+ "{palette}"
61
+ ]
62
+ },
45
63
  "show_prompt_line": true,
46
64
  "show_vertical_scrollbar": true,
47
65
  "show_horizontal_scrollbar": false,
@@ -158,17 +176,14 @@
158
176
  },
159
177
  "default": {}
160
178
  },
161
- "fallback": {
162
- "description": "Fallback configuration for files whose type cannot be detected.\nApplied when no extension, filename, glob, or built-in detection matches.\nUseful for setting a default grammar (e.g., \"bash\") and comment_prefix\nfor unrecognized .conf, .rc, .rules, etc. files.",
163
- "anyOf": [
164
- {
165
- "$ref": "#/$defs/LanguageConfig"
166
- },
167
- {
168
- "type": "null"
169
- }
179
+ "default_language": {
180
+ "description": "Default language for files whose type cannot be detected.\nMust reference a key in the `languages` map (e.g., \"bash\").\nApplied when no extension, filename, glob, or built-in detection matches.\nThe referenced language's full configuration (grammar, comment_prefix,\ntab_size, etc.) is used for unrecognized files.",
181
+ "type": [
182
+ "string",
183
+ "null"
170
184
  ],
171
- "default": null
185
+ "default": null,
186
+ "x-enum-from": "/languages"
172
187
  },
173
188
  "lsp": {
174
189
  "description": "LSP server configurations by language.\nEach language maps to one or more server configs (multi-LSP support).\nAccepts both single-object and array forms for backwards compatibility.",
@@ -178,6 +193,14 @@
178
193
  },
179
194
  "default": {}
180
195
  },
196
+ "universal_lsp": {
197
+ "description": "Universal LSP servers that apply to all languages.\nThese servers run alongside language-specific LSP servers defined in `lsp`.\nKeyed by a unique server name (e.g. \"quicklsp\").",
198
+ "type": "object",
199
+ "additionalProperties": {
200
+ "$ref": "#/$defs/LspLanguageConfig"
201
+ },
202
+ "default": {}
203
+ },
181
204
  "warnings": {
182
205
  "description": "Warning notification settings",
183
206
  "$ref": "#/$defs/WarningsConfig",
@@ -322,6 +345,29 @@
322
345
  "default": true,
323
346
  "x-section": "Display"
324
347
  },
348
+ "status_bar": {
349
+ "description": "Status bar layout and element configuration.\nControls which elements appear in the status bar and how they are arranged.",
350
+ "$ref": "#/$defs/StatusBarConfig",
351
+ "default": {
352
+ "left": [
353
+ "{filename}",
354
+ "{cursor}",
355
+ "{diagnostics}",
356
+ "{cursor_count}",
357
+ "{messages}"
358
+ ],
359
+ "right": [
360
+ "{line_ending}",
361
+ "{encoding}",
362
+ "{language}",
363
+ "{lsp}",
364
+ "{warnings}",
365
+ "{update}",
366
+ "{palette}"
367
+ ]
368
+ },
369
+ "x-section": "Status Bar"
370
+ },
325
371
  "show_prompt_line": {
326
372
  "description": "Whether the prompt line is visible by default.\nThe prompt line is the bottom-most line used for command input, search, file open, etc.\nWhen hidden, the prompt line only appears when a prompt is active.\nCan be toggled at runtime via command palette or keybinding.\nDefault: true",
327
373
  "type": "boolean",
@@ -671,6 +717,111 @@
671
717
  }
672
718
  }
673
719
  },
720
+ "StatusBarConfig": {
721
+ "description": "Status bar layout and element configuration.\n\nControls which elements appear in the status bar and how they are arranged.\nElements are placed in left and right containers and can be freely reordered.\n\nExample config:\n```json\n{\n \"status_bar\": {\n \"left\": [\"{filename}\", \"{cursor:compact}\"],\n \"right\": [\"{language}\", \"{encoding}\", \"{line_ending}\"]\n }\n}\n```",
722
+ "type": "object",
723
+ "properties": {
724
+ "left": {
725
+ "description": "Elements shown on the left side of the status bar.\nDefault: [\"{filename}\", \"{cursor}\", \"{diagnostics}\", \"{cursor_count}\", \"{messages}\"]",
726
+ "type": "array",
727
+ "items": {
728
+ "$ref": "#/$defs/StatusBarElement"
729
+ },
730
+ "default": [
731
+ "{filename}",
732
+ "{cursor}",
733
+ "{diagnostics}",
734
+ "{cursor_count}",
735
+ "{messages}"
736
+ ],
737
+ "x-section": "Status Bar",
738
+ "x-dual-list-sibling": "/editor/status_bar/right"
739
+ },
740
+ "right": {
741
+ "description": "Elements shown on the right side of the status bar.\nDefault: [\"{line_ending}\", \"{encoding}\", \"{language}\", \"{lsp}\", \"{warnings}\", \"{update}\", \"{palette}\"]",
742
+ "type": "array",
743
+ "items": {
744
+ "$ref": "#/$defs/StatusBarElement"
745
+ },
746
+ "default": [
747
+ "{line_ending}",
748
+ "{encoding}",
749
+ "{language}",
750
+ "{lsp}",
751
+ "{warnings}",
752
+ "{update}",
753
+ "{palette}"
754
+ ],
755
+ "x-section": "Status Bar",
756
+ "x-dual-list-sibling": "/editor/status_bar/left"
757
+ }
758
+ }
759
+ },
760
+ "StatusBarElement": {
761
+ "type": "string",
762
+ "x-dual-list-options": [
763
+ {
764
+ "value": "{filename}",
765
+ "name": "Filename"
766
+ },
767
+ {
768
+ "value": "{cursor}",
769
+ "name": "Cursor"
770
+ },
771
+ {
772
+ "value": "{cursor:compact}",
773
+ "name": "Cursor (compact)"
774
+ },
775
+ {
776
+ "value": "{diagnostics}",
777
+ "name": "Diagnostics"
778
+ },
779
+ {
780
+ "value": "{cursor_count}",
781
+ "name": "Cursor Count"
782
+ },
783
+ {
784
+ "value": "{messages}",
785
+ "name": "Messages"
786
+ },
787
+ {
788
+ "value": "{chord}",
789
+ "name": "Chord"
790
+ },
791
+ {
792
+ "value": "{line_ending}",
793
+ "name": "Line Ending"
794
+ },
795
+ {
796
+ "value": "{encoding}",
797
+ "name": "Encoding"
798
+ },
799
+ {
800
+ "value": "{language}",
801
+ "name": "Language"
802
+ },
803
+ {
804
+ "value": "{lsp}",
805
+ "name": "LSP"
806
+ },
807
+ {
808
+ "value": "{warnings}",
809
+ "name": "Warnings"
810
+ },
811
+ {
812
+ "value": "{update}",
813
+ "name": "Update"
814
+ },
815
+ {
816
+ "value": "{palette}",
817
+ "name": "Palette"
818
+ },
819
+ {
820
+ "value": "{clock}",
821
+ "name": "Clock"
822
+ }
823
+ ]
824
+ },
674
825
  "CursorStyle": {
675
826
  "description": "Terminal cursor style",
676
827
  "type": "string",
@@ -921,11 +1072,6 @@
921
1072
  ],
922
1073
  "default": null
923
1074
  },
924
- "highlighter": {
925
- "description": "Preferred highlighter backend (auto, tree-sitter, or textmate)",
926
- "$ref": "#/$defs/HighlighterPreference",
927
- "default": "auto"
928
- },
929
1075
  "textmate_grammar": {
930
1076
  "description": "Path to custom TextMate grammar file (optional)\nIf specified, this grammar will be used when highlighter is \"textmate\"",
931
1077
  "type": [
@@ -1029,26 +1175,6 @@
1029
1175
  },
1030
1176
  "x-display-field": "/grammar"
1031
1177
  },
1032
- "HighlighterPreference": {
1033
- "description": "Preference for which syntax highlighting backend to use",
1034
- "oneOf": [
1035
- {
1036
- "description": "Use tree-sitter if available, fall back to TextMate",
1037
- "type": "string",
1038
- "const": "auto"
1039
- },
1040
- {
1041
- "description": "Force tree-sitter only (no highlighting if unavailable)",
1042
- "type": "string",
1043
- "const": "tree-sitter"
1044
- },
1045
- {
1046
- "description": "Force TextMate grammar (skip tree-sitter even if available)",
1047
- "type": "string",
1048
- "const": "textmate"
1049
- }
1050
- ]
1051
- },
1052
1178
  "FormatterConfig": {
1053
1179
  "description": "Formatter configuration for a language",
1054
1180
  "type": "object",
@@ -10,12 +10,12 @@ const editor = getEditor();
10
10
  const NAMESPACE = "git-explorer";
11
11
 
12
12
  const COLORS = {
13
- added: [80, 250, 123] as [number, number, number],
14
- modified: [255, 184, 108] as [number, number, number],
15
- deleted: [255, 85, 85] as [number, number, number],
16
- renamed: [139, 233, 253] as [number, number, number],
17
- untracked: [241, 250, 140] as [number, number, number],
18
- conflicted: [255, 121, 198] as [number, number, number],
13
+ added: "ui.file_status_added_fg",
14
+ modified: "ui.file_status_modified_fg",
15
+ deleted: "ui.file_status_deleted_fg",
16
+ renamed: "ui.file_status_renamed_fg",
17
+ untracked: "ui.file_status_untracked_fg",
18
+ conflicted: "ui.file_status_conflicted_fg",
19
19
  };
20
20
 
21
21
  const PRIORITY = {
@@ -58,7 +58,7 @@ function parseStatusOutput(output: string, repoRoot: string) {
58
58
  .split(separator)
59
59
  .map((entry) => entry.replace(/\r$/, ""))
60
60
  .filter((entry) => entry.length > 0);
61
- const byPath = new Map<string, { path: string; symbol: string; color: [number, number, number]; priority: number }>();
61
+ const byPath = new Map<string, { path: string; symbol: string; color: string; priority: number }>();
62
62
 
63
63
  for (let i = 0; i < entries.length; i++) {
64
64
  const entry = entries[i];
@@ -156,6 +156,12 @@ type TsCreateCompositeBufferOptions = {
156
156
  * Diff hunks for alignment (optional)
157
157
  */
158
158
  hunks: Array<TsCompositeHunk> | null;
159
+ /**
160
+ * When set, the first render will scroll to center the Nth hunk (0-indexed).
161
+ * This avoids timing issues with imperative scroll commands that depend on
162
+ * render-created state (viewport dimensions, view state).
163
+ */
164
+ initialFocusHunk?: number;
159
165
  };
160
166
  type ViewportInfo = {
161
167
  /**
@@ -393,9 +399,9 @@ type FileExplorerDecoration = {
393
399
  */
394
400
  symbol: string;
395
401
  /**
396
- * Color as RGB array (rquickjs_serde requires array, not tuple)
402
+ * Color as RGB array or theme key string (e.g., "ui.file_status_added_fg")
397
403
  */
398
- color: [number, number, number];
404
+ color: OverlayColorSpec;
399
405
  /**
400
406
  * Priority for display when multiple decorations exist (higher wins)
401
407
  */
@@ -525,6 +531,24 @@ type InlineOverlay = {
525
531
  */
526
532
  properties?: Record<string, any>;
527
533
  };
534
+ type GrammarInfoSnapshot = {
535
+ /**
536
+ * The grammar name as used in config files (case-insensitive matching)
537
+ */
538
+ name: string;
539
+ /**
540
+ * Where this grammar was loaded from (e.g. "built-in", "plugin (myplugin)")
541
+ */
542
+ source: string;
543
+ /**
544
+ * File extensions associated with this grammar
545
+ */
546
+ file_extensions: Array<string>;
547
+ /**
548
+ * Optional short name alias (e.g., "bash" for "Bourne Again Shell (bash)")
549
+ */
550
+ short_name: string | null;
551
+ };
528
552
  type BackgroundProcessResult = {
529
553
  /**
530
554
  * Unique process ID for later reference
@@ -812,6 +836,10 @@ interface EditorAPI {
812
836
  * List all open buffers - returns array of BufferInfo objects
813
837
  */
814
838
  listBuffers(): BufferInfo[];
839
+ /**
840
+ * List all available grammars with source info - returns array of GrammarInfo objects
841
+ */
842
+ listGrammars(): GrammarInfoSnapshot[];
815
843
  debug(msg: string): void;
816
844
  info(msg: string): void;
817
845
  warn(msg: string): void;
@@ -919,6 +947,17 @@ interface EditorAPI {
919
947
  */
920
948
  scrollToLineCenter(splitId: number, bufferId: number, line: number): boolean;
921
949
  /**
950
+ * Scroll any split/panel showing `buffer_id` so `line` is visible.
951
+ * Unlike `scrollToLineCenter`, this does not require a split id — it
952
+ * updates every split's viewport whose active buffer is the given
953
+ * buffer, including inner leaves of a buffer group. Use this from
954
+ * a panel plugin to keep the user's "selected" row in view after
955
+ * arrow-key navigation (the plugin's own selection state isn't
956
+ * automatically reflected in the buffer cursor, so the core-driven
957
+ * viewport would otherwise stay put).
958
+ */
959
+ scrollBufferToLine(bufferId: number, line: number): boolean;
960
+ /**
922
961
  * Find buffer by file path, returns buffer ID or 0 if not found
923
962
  */
924
963
  findBufferByPath(path: string): number;
@@ -1169,6 +1208,20 @@ interface EditorAPI {
1169
1208
  */
1170
1209
  closeCompositeBuffer(bufferId: number): boolean;
1171
1210
  /**
1211
+ * Force-materialize render-dependent state (like `layoutIfNeeded` in UIKit).
1212
+ * After calling this, commands that depend on view state created during
1213
+ * rendering (e.g., `compositeNextHunk`) will work correctly.
1214
+ */
1215
+ flushLayout(): boolean;
1216
+ /**
1217
+ * Navigate to the next hunk in a composite buffer
1218
+ */
1219
+ compositeNextHunk(bufferId: number): boolean;
1220
+ /**
1221
+ * Navigate to the previous hunk in a composite buffer
1222
+ */
1223
+ compositePrevHunk(bufferId: number): boolean;
1224
+ /**
1172
1225
  * Request syntax highlights for a buffer range (async)
1173
1226
  */
1174
1227
  getHighlights(bufferId: number, start: number, end: number): Promise<TsHighlightSpan[]>;
@@ -1459,6 +1512,18 @@ interface EditorAPI {
1459
1512
  */
1460
1513
  createVirtualBufferInExistingSplit(opts: CreateVirtualBufferInExistingSplitOptions): Promise<VirtualBufferResult>;
1461
1514
  /**
1515
+ * Set the content of a panel within a buffer group
1516
+ */
1517
+ setPanelContent(groupId: number, panelName: string, entriesArr: Record<string, unknown>[]): boolean;
1518
+ /**
1519
+ * Close a buffer group
1520
+ */
1521
+ closeBufferGroup(groupId: number): boolean;
1522
+ /**
1523
+ * Focus a specific panel within a buffer group
1524
+ */
1525
+ focusBufferGroupPanel(groupId: number, panelName: string): boolean;
1526
+ /**
1462
1527
  * Set virtual buffer content (takes array of entry objects)
1463
1528
  *
1464
1529
  * Note: entries should be TextPropertyEntry[] - uses manual parsing for HashMap support
@@ -12,6 +12,8 @@ export interface VirtualBufferOptions {
12
12
  entries: TextPropertyEntry[];
13
13
  /** Whether to show line numbers (default false) */
14
14
  showLineNumbers?: boolean;
15
+ /** Whether to show cursors (default true) */
16
+ showCursors?: boolean;
15
17
  /** Whether editing is disabled (default true) */
16
18
  editingDisabled?: boolean;
17
19
  /** Whether buffer is read-only (default true) */
@@ -55,6 +57,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
55
57
  mode,
56
58
  entries,
57
59
  showLineNumbers = false,
60
+ showCursors,
58
61
  editingDisabled = true,
59
62
  readOnly = true,
60
63
  } = options;
@@ -65,6 +68,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
65
68
  readOnly,
66
69
  entries,
67
70
  showLineNumbers,
71
+ showCursors,
68
72
  editingDisabled,
69
73
  });
70
74
  return result.bufferId;
@@ -79,6 +83,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
79
83
  mode,
80
84
  entries,
81
85
  showLineNumbers = false,
86
+ showCursors,
82
87
  editingDisabled = true,
83
88
  readOnly = true,
84
89
  } = options;
@@ -90,6 +95,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
90
95
  entries,
91
96
  splitId,
92
97
  showLineNumbers,
98
+ showCursors,
93
99
  editingDisabled,
94
100
  });
95
101
  return result.bufferId;
@@ -106,6 +112,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
106
112
  ratio = 0.3,
107
113
  panelId,
108
114
  showLineNumbers = false,
115
+ showCursors,
109
116
  editingDisabled = true,
110
117
  readOnly = true,
111
118
  } = options;
@@ -118,6 +125,7 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
118
125
  ratio,
119
126
  panelId,
120
127
  showLineNumbers,
128
+ showCursors,
121
129
  editingDisabled,
122
130
  });
123
131
  return result.bufferId;