@fresh-editor/fresh-editor 0.2.3 → 0.2.5

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # Release Notes
2
2
 
3
+ ## 0.2.5
4
+
5
+ ### Features
6
+
7
+ * **Persistent Auto-Save**: New `auto_save_enabled` config option (default: false) to automatically save modified buffers to their original file at a configurable interval (`auto_save_interval_secs`, default: 30s) (#542)
8
+
9
+ * **Smart Home**: Home key now uses smart home behavior by default, toggling between the first non-whitespace character and column 0. On soft-wrapped lines, smart home respects visual line boundaries instead of jumping to the physical line start (#1064).
10
+
11
+ ### Bug Fixes
12
+
13
+ * **Diff View Scrollbar**: Fixed scrollbar click-to-jump and thumb drag not working in side-by-side diff views. Composite buffer views now use row-based scrolling via CompositeViewState.
14
+
15
+ * **Terminal Bracket Paste**: Fixed pasted text going into the editor buffer instead of the terminal PTY when in terminal mode (#1056).
16
+
17
+ * **LSP did_open Reliability**: Fixed buffer being incorrectly marked as LSP-opened when the did_open send fails, which prevented retry and could corrupt server document state.
18
+
19
+ * **Remote Editing Data Loss**: Fixed intermittent data loss when loading large files via SSH remote editing on macOS. The bounded channel now uses backpressure instead of silently dropping data when the buffer overflows (#1059).
20
+
21
+ ### Configuration
22
+
23
+ * Renamed `auto_save_interval_secs` (recovery) to `auto_recovery_save_interval_secs` to distinguish it from the new persistent auto-save feature. Added `auto_recovery_save_interval_secs` config option (default: 2s).
24
+
25
+ ### Internal
26
+
27
+ * Introduced typed `LeafId` and `ContainerId` wrappers around `SplitId` to enforce leaf-vs-container constraints at compile time.
28
+ * Enabled `#![deny(clippy::let_underscore_must_use)]` crate-wide; all ignored `Result` values now have explicit annotations or proper error handling.
29
+ * Made `request_completion` and `request_signature_help` infallible, removing dead `Result` return types.
30
+ * Added CONTRIBUTING.md with development guidelines.
31
+
32
+ ---
33
+
34
+ ## 0.2.4
35
+
36
+ ### Features
37
+
38
+ * **Markdown Compose Mode**: Distraction-free writing mode with concealed markup, soft breaks, table rendering, and mouse support. Split-view allows editing source and rendered markdown side-by-side with synchronized scrolling.
39
+
40
+ * **Vertical Rulers**: Configurable column rulers with add/remove commands via command palette. Per-buffer state and Settings UI JSON editor support (#1028).
41
+
42
+ * **Horizontal Scrollbar**: New horizontal scrollbar with drag support and toggle commands (#972).
43
+
44
+ * **Smooth Scrolling**: Cursor movement now scrolls one line at a time instead of jumping/recentering the viewport (#1040).
45
+
46
+ ### Improvements
47
+
48
+ * **Macro Keybinding**: F4 shortcut for Play Last Macro. Removed Ctrl+0-9 and Alt+Shift+0-9 macro keybindings (#700).
49
+
50
+ * **Configurable Clipboard**: New `clipboard` config with `use_osc52` and `use_system_clipboard` toggles to prevent hangs in certain terminals (#964). Useful for Putty and other terminals that sometimes cause Fresh to hang on OSC 52.
51
+
52
+ * **Scrollbar Visibility**: New `show_vertical_scrollbar` and `show_horizontal_scrollbar` config options (#974).
53
+
54
+ * **Package Manager**: Reinstall support for local-path packages.
55
+
56
+ * **File Explorer Persistence**: Show hidden and show gitignored toggles now persist to config immediately (#569).
57
+
58
+ ### Bug Fixes
59
+
60
+ * **Macro correctness**: Replaying a macro now respects the exact same effect as interactive flow.
61
+
62
+ * **Cursor Navigation**: Cursor up/down now lands at end-of-line when goal column is past content (#514).
63
+
64
+ * **Line Numbers**: Fixed line numbers leaking between splits due to shared margins state. Line numbers now live exclusively in per-split BufferViewState.
65
+
66
+ ### Plugin API
67
+
68
+ * **Plugin API v2**: Versioned plugin API with `createTerminal`, `sendTerminalInput`, `closeTerminal`, `getAllCursors`, and plugin state API. Improved type declarations in `fresh.d.ts` (#1045).
69
+
70
+ * **Split Labels**: Splits can be labeled to prevent files opening in managed splits. Labels persist across save/restore. New `before` option to place buffers left/top.
71
+
72
+ ### Internal
73
+
74
+ * Refactored per-buffer view state: cursors owned by SplitViewState, ComposeState extracted from EditorState.
75
+ * Conceal ranges, soft breaks, and overlay filtering by view_mode at render time.
76
+ * Plugin state snapshot reports active split's view_mode and compose flag.
77
+ * i18n updates for vertical rulers and macro shortcuts across all locales.
78
+ * PieceTree Performance: Use binary search instead of linear scan in line lookup.
79
+
80
+ ---
81
+
3
82
  ## 0.2.3
4
83
 
5
84
  ### Bug Fixes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A modern, full-featured terminal text editor, **with zero configuration**. Familiar keybindings, mouse support, and IDE-level features — no learning curve required.
4
4
 
5
- [Official Website](https://sinelaw.github.io/fresh/)  ·  [Documentation](https://getfresh.dev/docs)  ·  [Discord](https://discord.gg/qUutBj9t)  ·  [Contributing](#contributing)
5
+ [Official Website](https://sinelaw.github.io/fresh/)  ·  [Documentation](https://getfresh.dev/docs)  ·  [Discord](https://discord.gg/GpNWqMUH)  ·  [Contributing](#contributing)
6
6
 
7
7
  **[Quick Install](#installation):**   `curl https://raw.githubusercontent.com/sinelaw/fresh/refs/heads/master/scripts/install.sh | sh`
8
8
 
@@ -240,30 +240,7 @@ cargo build --release
240
240
 
241
241
  ## Contributing
242
242
 
243
- Thanks for contributing!
244
-
245
- 1. **Reproduce Before Fixing**: Always include a test case that reproduces the bug (fails) without the fix, and passes with the fix. This ensures the issue is verified and prevents future regressions.
246
-
247
- 2. **E2E Tests for New Flows**: Any new user flow or feature must include an end-to-end (e2e) test. E2E tests send keyboard/mouse events and examines the final rendered output, do not examine internal state.
248
-
249
- 3. **No timeouts or time-sensitive tests**: Use "semantic waiting" (waiting for specific state changes/events) instead of fixed timers to ensure test stability. Wait indefinitely, don't put timeouts inside tests (cargo nextest will timeout externally).
250
-
251
- 4. **Test isolation**: Tests should run in parallel. Use the internal clipboard mode in tests to isolate them from the host system and prevent flakiness in CI. Same for other external resources (temp files, etc. should all be isolated between tests, under a per-test temporary workdir).
252
-
253
- 5. **Required Formatting**: All code must be formatted with `cargo fmt` before submission. PRs that fail formatting checks will not be merged.
254
-
255
- 6. **Cross-Platform Consistency**: Avoid hard-coding newline or CRLF related logic, consider the buffer mode.
256
-
257
- 7. **LSP**: Ensure LSP interactions follow the correct lifecycle (e.g., `didOpen` must always precede other requests to avoid server-side errors). Use the appropriate existing helpers for this pattern.
258
-
259
- 8. **Regenerate plugin types and schemas**: After modifying the plugin API or config types:
260
- - **TypeScript definitions** (`plugins/lib/fresh.d.ts`): Auto-generated from Rust types with `#[derive(TS)]`. Run: `cargo test -p fresh-plugin-runtime write_fresh_dts_file -- --ignored`
261
- - **JSON schemas** (`plugins/config-schema.json`, `plugins/schemas/theme.schema.json`): Auto-generated from Rust types with `#[derive(JsonSchema)]`. Run: `./scripts/gen_schema.sh`
262
- - **Package schema** (`plugins/schemas/package.schema.json`): Manually maintained - edit directly when adding new language pack fields
263
-
264
- 9. **Type check plugins**: Run `crates/fresh-editor/plugins/check-types.sh` (requires `tsc`)
265
-
266
- **Tip**: You can use tmux + send-keys + render-pane to script ad-hoc tests on the UI, for example when trying to reproduce an issue.
243
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
267
244
 
268
245
  ## Privacy
269
246
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fresh-editor/fresh-editor",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "A modern terminal-based text editor with plugin support",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,8 +36,11 @@
36
36
  "syntax_highlighting": true,
37
37
  "show_menu_bar": true,
38
38
  "show_tab_bar": true,
39
+ "show_vertical_scrollbar": true,
40
+ "show_horizontal_scrollbar": false,
39
41
  "use_terminal_bg": false,
40
42
  "cursor_style": "default",
43
+ "rulers": [],
41
44
  "tab_size": 4,
42
45
  "auto_indent": true,
43
46
  "scroll_offset": 3,
@@ -55,8 +58,10 @@
55
58
  "mouse_hover_enabled": true,
56
59
  "mouse_hover_delay_ms": 500,
57
60
  "double_click_time_ms": 500,
61
+ "auto_save_enabled": false,
62
+ "auto_save_interval_secs": 30,
58
63
  "recovery_enabled": true,
59
- "auto_save_interval_secs": 2,
64
+ "auto_recovery_save_interval_secs": 2,
60
65
  "auto_revert_poll_interval_ms": 2000,
61
66
  "keyboard_disambiguate_escape_codes": true,
62
67
  "keyboard_report_event_types": false,
@@ -88,6 +93,14 @@
88
93
  "show_hidden": false
89
94
  }
90
95
  },
96
+ "clipboard": {
97
+ "description": "Clipboard settings (which clipboard methods to use)",
98
+ "$ref": "#/$defs/ClipboardConfig",
99
+ "default": {
100
+ "use_osc52": true,
101
+ "use_system_clipboard": true
102
+ }
103
+ },
91
104
  "terminal": {
92
105
  "description": "Terminal settings",
93
106
  "$ref": "#/$defs/TerminalConfig",
@@ -230,6 +243,18 @@
230
243
  "default": true,
231
244
  "x-section": "Display"
232
245
  },
246
+ "show_vertical_scrollbar": {
247
+ "description": "Whether the vertical scrollbar is visible in each split pane.\nCan be toggled at runtime via command palette or keybinding.\nDefault: true",
248
+ "type": "boolean",
249
+ "default": true,
250
+ "x-section": "Display"
251
+ },
252
+ "show_horizontal_scrollbar": {
253
+ "description": "Whether the horizontal scrollbar is visible in each split pane.\nThe horizontal scrollbar appears when line wrap is disabled and content extends beyond the viewport.\nCan be toggled at runtime via command palette or keybinding.\nDefault: false",
254
+ "type": "boolean",
255
+ "default": false,
256
+ "x-section": "Display"
257
+ },
233
258
  "use_terminal_bg": {
234
259
  "description": "Use the terminal's default background color instead of the theme's editor background.\nWhen enabled, the editor background inherits from the terminal emulator,\nallowing transparency or custom terminal backgrounds to show through.\nDefault: false",
235
260
  "type": "boolean",
@@ -242,6 +267,17 @@
242
267
  "default": "default",
243
268
  "x-section": "Display"
244
269
  },
270
+ "rulers": {
271
+ "description": "Vertical ruler lines at specific column positions.\nDraws subtle vertical lines to help with line length conventions.\nExample: [80, 120] draws rulers at columns 80 and 120.\nDefault: [] (no rulers)",
272
+ "type": "array",
273
+ "items": {
274
+ "type": "integer",
275
+ "format": "uint",
276
+ "minimum": 0
277
+ },
278
+ "default": [],
279
+ "x-section": "Display"
280
+ },
245
281
  "tab_size": {
246
282
  "description": "Number of spaces per tab character",
247
283
  "type": "integer",
@@ -354,14 +390,28 @@
354
390
  "default": 500,
355
391
  "x-section": "Mouse"
356
392
  },
393
+ "auto_save_enabled": {
394
+ "description": "Whether to enable persistent auto-save (save to original file on disk).\nWhen enabled, modified buffers are saved to their original file path\nat a configurable interval.\nDefault: false",
395
+ "type": "boolean",
396
+ "default": false,
397
+ "x-section": "Recovery"
398
+ },
399
+ "auto_save_interval_secs": {
400
+ "description": "Interval in seconds for persistent auto-save.\nModified buffers are saved to their original file at this interval.\nOnly effective when auto_save_enabled is true.\nDefault: 30 seconds",
401
+ "type": "integer",
402
+ "format": "uint32",
403
+ "minimum": 0,
404
+ "default": 30,
405
+ "x-section": "Recovery"
406
+ },
357
407
  "recovery_enabled": {
358
408
  "description": "Whether to enable file recovery (Emacs-style auto-save)\nWhen enabled, buffers are periodically saved to recovery files\nso they can be recovered if the editor crashes.",
359
409
  "type": "boolean",
360
410
  "default": true,
361
411
  "x-section": "Recovery"
362
412
  },
363
- "auto_save_interval_secs": {
364
- "description": "Auto-save interval in seconds for file recovery\nModified buffers are saved to recovery files at this interval.\nDefault: 2 seconds for fast recovery with minimal data loss.\nSet to 0 to disable periodic auto-save (manual recovery only).",
413
+ "auto_recovery_save_interval_secs": {
414
+ "description": "Interval in seconds for auto-recovery-save.\nModified buffers are saved to recovery files at this interval.\nOnly effective when recovery_enabled is true.\nDefault: 2 seconds",
365
415
  "type": "integer",
366
416
  "format": "uint32",
367
417
  "minimum": 0,
@@ -529,6 +579,22 @@
529
579
  }
530
580
  }
531
581
  },
582
+ "ClipboardConfig": {
583
+ "description": "Clipboard configuration\n\nControls which clipboard methods are used for copy/paste operations.\nBy default, all methods are enabled and the editor tries them in order:\n1. OSC 52 escape sequences (works in modern terminals like Kitty, Alacritty, Wezterm)\n2. System clipboard via X11/Wayland APIs (works in Gnome Console, XFCE Terminal, etc.)\n3. Internal clipboard (always available as fallback)\n\nIf you experience hangs or issues (e.g., when using PuTTY or certain SSH setups),\nyou can disable specific methods.",
584
+ "type": "object",
585
+ "properties": {
586
+ "use_osc52": {
587
+ "description": "Enable OSC 52 escape sequences for clipboard access (default: true)\nDisable this if your terminal doesn't support OSC 52 or if it causes hangs",
588
+ "type": "boolean",
589
+ "default": true
590
+ },
591
+ "use_system_clipboard": {
592
+ "description": "Enable system clipboard access via X11/Wayland APIs (default: true)\nDisable this if you don't have a display server or it causes issues",
593
+ "type": "boolean",
594
+ "default": true
595
+ }
596
+ }
597
+ },
532
598
  "TerminalConfig": {
533
599
  "description": "Terminal configuration",
534
600
  "type": "object",
@@ -250,6 +250,25 @@ type BufferInfo = {
250
250
  * Length of buffer in bytes
251
251
  */
252
252
  length: number;
253
+ /**
254
+ * Whether this is a virtual buffer (not backed by a file)
255
+ */
256
+ is_virtual: boolean;
257
+ /**
258
+ * Current view mode of the active split: "source" or "compose"
259
+ */
260
+ view_mode: string;
261
+ /**
262
+ * True if any split showing this buffer has compose mode enabled.
263
+ * Plugins should use this (not view_mode) to decide whether to maintain
264
+ * decorations, since decorations live on the buffer and are filtered
265
+ * per-split at render time.
266
+ */
267
+ is_composing_in_any_split: boolean;
268
+ /**
269
+ * Compose width (if set), from the active split's view state
270
+ */
271
+ compose_width: number | null;
253
272
  };
254
273
  type JsDiagnostic = {
255
274
  /**
@@ -359,61 +378,66 @@ type FormatterPackConfig = {
359
378
  */
360
379
  args: Array<string>;
361
380
  };
362
- type BackgroundProcessResult = {
381
+ type TerminalResult = {
363
382
  /**
364
- * Unique process ID for later reference
383
+ * The created buffer ID (for use with setSplitBuffer, etc.)
365
384
  */
366
- process_id: number;
385
+ bufferId: number;
367
386
  /**
368
- * Process exit code (0 usually means success, -1 if killed)
369
- * Only present when the process has exited
387
+ * The terminal ID (for use with sendTerminalInput, closeTerminal)
370
388
  */
371
- exit_code: number;
372
- };
373
- type BufferSavedDiff = {
374
- equal: boolean;
375
- byte_ranges: Array<[number, number]>;
376
- line_ranges: Array<[number, number]> | null;
377
- };
378
- type TsCompositeHunk = {
389
+ terminalId: number;
379
390
  /**
380
- * Starting line in old buffer (0-indexed)
391
+ * The split ID (if created in a new split)
381
392
  */
382
- oldStart: number;
393
+ splitId: number | null;
394
+ };
395
+ type CreateTerminalOptions = {
383
396
  /**
384
- * Number of lines in old buffer
397
+ * Working directory for the terminal (defaults to editor cwd)
385
398
  */
386
- oldCount: number;
399
+ cwd?: string;
387
400
  /**
388
- * Starting line in new buffer (0-indexed)
401
+ * Split direction: "horizontal" or "vertical" (default: "vertical")
389
402
  */
390
- newStart: number;
403
+ direction?: string;
391
404
  /**
392
- * Number of lines in new buffer
405
+ * Split ratio 0.0-1.0 (default: 0.5)
393
406
  */
394
- newCount: number;
395
- };
396
- type TsCreateCompositeBufferOptions = {
407
+ ratio?: number;
397
408
  /**
398
- * Buffer name (displayed in tabs/title)
409
+ * Whether to focus the new terminal split (default: true)
399
410
  */
400
- name: string;
411
+ focus?: boolean;
412
+ };
413
+ type CursorInfo = {
401
414
  /**
402
- * Mode for keybindings
415
+ * Byte position of the cursor
403
416
  */
404
- mode: string;
417
+ position: number;
405
418
  /**
406
- * Layout configuration
419
+ * Selection range (if any)
407
420
  */
408
- layout: TsCompositeLayoutConfig;
421
+ selection: {
422
+ start: number;
423
+ end: number;
424
+ } | null;
425
+ };
426
+ type BackgroundProcessResult = {
409
427
  /**
410
- * Source pane configurations
428
+ * Unique process ID for later reference
411
429
  */
412
- sources: Array<TsCompositeSourceConfig>;
430
+ process_id: number;
413
431
  /**
414
- * Diff hunks for alignment (optional)
432
+ * Process exit code (0 usually means success, -1 if killed)
433
+ * Only present when the process has exited
415
434
  */
416
- hunks: Array<TsCompositeHunk> | null;
435
+ exit_code: number;
436
+ };
437
+ type BufferSavedDiff = {
438
+ equal: boolean;
439
+ byte_ranges: Array<[number, number]>;
440
+ line_ranges: Array<[number, number]> | null;
417
441
  };
418
442
  type CreateVirtualBufferInExistingSplitOptions = {
419
443
  /**
@@ -495,6 +519,10 @@ type CreateVirtualBufferInSplitOptions = {
495
519
  */
496
520
  lineWrap?: boolean;
497
521
  /**
522
+ * Place the new buffer before (left/top of) the existing content (default: false)
523
+ */
524
+ before?: boolean;
525
+ /**
498
526
  * Initial content entries with optional properties
499
527
  */
500
528
  entries?: Array<TextPropertyEntry>;
@@ -600,28 +628,6 @@ type SpawnResult = {
600
628
  */
601
629
  exit_code: number;
602
630
  };
603
- type PromptSuggestion = {
604
- /**
605
- * The text to display
606
- */
607
- text: string;
608
- /**
609
- * Optional description
610
- */
611
- description?: string;
612
- /**
613
- * The value to use when selected (defaults to text if None)
614
- */
615
- value?: string;
616
- /**
617
- * Whether this suggestion is disabled (greyed out, defaults to false)
618
- */
619
- disabled?: boolean;
620
- /**
621
- * Optional keyboard shortcut
622
- */
623
- keybinding?: string;
624
- };
625
631
  type TextPropertiesAtCursor = Array<Record<string, unknown>>;
626
632
  type TsHighlightSpan = {
627
633
  start: number;
@@ -644,6 +650,11 @@ type VirtualBufferResult = {
644
650
  * Main editor API interface
645
651
  */
646
652
  interface EditorAPI {
653
+ /**
654
+ * Get the plugin API version. Plugins can check this to verify
655
+ * the editor supports the features they need.
656
+ */
657
+ apiVersion(): number;
647
658
  /**
648
659
  * Get the active buffer ID (0 if none)
649
660
  */
@@ -713,15 +724,15 @@ interface EditorAPI {
713
724
  /**
714
725
  * Get primary cursor info for active buffer
715
726
  */
716
- getPrimaryCursor(): unknown;
727
+ getPrimaryCursor(): CursorInfo | null;
717
728
  /**
718
729
  * Get all cursors for active buffer
719
730
  */
720
- getAllCursors(): unknown;
731
+ getAllCursors(): CursorInfo[];
721
732
  /**
722
733
  * Get all cursor positions as byte offsets
723
734
  */
724
- getAllCursorPositions(): unknown;
735
+ getAllCursorPositions(): number[];
725
736
  /**
726
737
  * Get viewport info for active buffer
727
738
  */
@@ -825,6 +836,16 @@ interface EditorAPI {
825
836
  */
826
837
  pathIsAbsolute(path: string): boolean;
827
838
  /**
839
+ * Get the UTF-8 byte length of a JavaScript string.
840
+ *
841
+ * JS strings are UTF-16 internally, so `str.length` returns the number of
842
+ * UTF-16 code units, not the number of bytes in a UTF-8 encoding. The
843
+ * editor API uses byte offsets for all buffer positions (overlays, cursor,
844
+ * getBufferText ranges, etc.). This helper lets plugins convert JS string
845
+ * lengths / regex match indices to the byte offsets the editor expects.
846
+ */
847
+ utf8ByteLength(text: string): number;
848
+ /**
828
849
  * Check if file exists
829
850
  */
830
851
  fileExists(path: string): boolean;
@@ -906,7 +927,7 @@ interface EditorAPI {
906
927
  /**
907
928
  * Check if a background process is still running
908
929
  */
909
- isProcessRunning(ProcessId: number): boolean;
930
+ isProcessRunning(processId: number): boolean;
910
931
  /**
911
932
  * Kill a process by ID (alias for killBackgroundProcess)
912
933
  */
@@ -921,13 +942,13 @@ interface EditorAPI {
921
942
  * Uses typed CreateCompositeBufferOptions - serde validates field names at runtime
922
943
  * via `deny_unknown_fields` attribute
923
944
  */
924
- createCompositeBuffer(opts: CreateCompositeBufferOptions): Promise<number>;
945
+ createCompositeBuffer(opts: TsCreateCompositeBufferOptions): Promise<number>;
925
946
  /**
926
947
  * Update alignment hunks for a composite buffer
927
948
  *
928
949
  * Uses typed Vec<CompositeHunk> - serde validates field names at runtime
929
950
  */
930
- updateCompositeAlignment(bufferId: number, hunks: CompositeHunk[]): boolean;
951
+ updateCompositeAlignment(bufferId: number, hunks: TsCompositeHunk[]): boolean;
931
952
  /**
932
953
  * Close a composite buffer
933
954
  */
@@ -944,12 +965,16 @@ interface EditorAPI {
944
965
  *
945
966
  * Theme key examples: "ui.status_bar_fg", "editor.selection_bg", "syntax.keyword"
946
967
  *
968
+ * Options: fg, bg (RGB array or theme key string), bold, italic, underline,
969
+ * strikethrough, extend_to_line_end (all booleans, default false).
970
+ *
947
971
  * Example usage in TypeScript:
948
972
  * ```typescript
949
973
  * editor.addOverlay(bufferId, "my-namespace", 0, 10, {
950
974
  * fg: "syntax.keyword", // theme key
951
975
  * bg: [40, 40, 50], // RGB array
952
976
  * bold: true,
977
+ * strikethrough: true,
953
978
  * });
954
979
  * ```
955
980
  */
@@ -971,6 +996,30 @@ interface EditorAPI {
971
996
  */
972
997
  removeOverlay(bufferId: number, handle: string): boolean;
973
998
  /**
999
+ * Add a conceal range that hides or replaces a byte range during rendering
1000
+ */
1001
+ addConceal(bufferId: number, namespace: string, start: number, end: number, replacement: string | null): boolean;
1002
+ /**
1003
+ * Clear all conceal ranges in a namespace
1004
+ */
1005
+ clearConcealNamespace(bufferId: number, namespace: string): boolean;
1006
+ /**
1007
+ * Clear all conceal ranges that overlap with a byte range
1008
+ */
1009
+ clearConcealsInRange(bufferId: number, start: number, end: number): boolean;
1010
+ /**
1011
+ * Add a soft break point for marker-based line wrapping
1012
+ */
1013
+ addSoftBreak(bufferId: number, namespace: string, position: number, indent: number): boolean;
1014
+ /**
1015
+ * Clear all soft breaks in a namespace
1016
+ */
1017
+ clearSoftBreakNamespace(bufferId: number, namespace: string): boolean;
1018
+ /**
1019
+ * Clear all soft breaks that fall within a byte range
1020
+ */
1021
+ clearSoftBreaksInRange(bufferId: number, start: number, end: number): boolean;
1022
+ /**
974
1023
  * Submit a view transform for a buffer/split
975
1024
  *
976
1025
  * Accepts tokens in the simple format:
@@ -985,6 +1034,11 @@ interface EditorAPI {
985
1034
  */
986
1035
  clearViewTransform(bufferId: number, splitId: number | null): boolean;
987
1036
  /**
1037
+ * Set layout hints (compose width, column guides) for a buffer/split
1038
+ * without going through the view_transform pipeline.
1039
+ */
1040
+ setLayoutHints(bufferId: number, splitId: number | null, hints: LayoutHints): boolean;
1041
+ /**
988
1042
  * Set file explorer decorations for a namespace
989
1043
  */
990
1044
  setFileExplorerDecorations(namespace: string, decorations: Record<string, unknown>[]): boolean;
@@ -1034,7 +1088,8 @@ interface EditorAPI {
1034
1088
  *
1035
1089
  * Uses typed Vec<Suggestion> - serde validates field names at runtime
1036
1090
  */
1037
- setPromptSuggestions(suggestions: Suggestion[]): boolean;
1091
+ setPromptSuggestions(suggestions: PromptSuggestion[]): boolean;
1092
+ setPromptInputSync(sync: boolean): boolean;
1038
1093
  /**
1039
1094
  * Define a buffer mode (takes bindings as array of [key, command] pairs)
1040
1095
  */
@@ -1068,6 +1123,18 @@ interface EditorAPI {
1068
1123
  */
1069
1124
  setSplitRatio(splitId: number, ratio: number): boolean;
1070
1125
  /**
1126
+ * Set a label on a split (e.g., "sidebar")
1127
+ */
1128
+ setSplitLabel(splitId: number, label: string): boolean;
1129
+ /**
1130
+ * Remove a label from a split
1131
+ */
1132
+ clearSplitLabel(splitId: number): boolean;
1133
+ /**
1134
+ * Find a split by label (async)
1135
+ */
1136
+ getSplitByLabel(label: string): Promise<number | null>;
1137
+ /**
1071
1138
  * Distribute all splits evenly
1072
1139
  */
1073
1140
  distributeSplitsEvenly(): boolean;
@@ -1088,10 +1155,22 @@ interface EditorAPI {
1088
1155
  */
1089
1156
  setLineNumbers(bufferId: number, enabled: boolean): boolean;
1090
1157
  /**
1158
+ * Set the view mode for a buffer ("source" or "compose")
1159
+ */
1160
+ setViewMode(bufferId: number, mode: string): boolean;
1161
+ /**
1091
1162
  * Enable or disable line wrapping for a buffer/split
1092
1163
  */
1093
1164
  setLineWrap(bufferId: number, splitId: number | null, enabled: boolean): boolean;
1094
1165
  /**
1166
+ * Set plugin-managed per-buffer view state (write-through to snapshot + command for persistence)
1167
+ */
1168
+ setViewState(bufferId: number, key: string, value: unknown): boolean;
1169
+ /**
1170
+ * Get plugin-managed per-buffer view state (reads from snapshot)
1171
+ */
1172
+ getViewState(bufferId: number, key: string): unknown;
1173
+ /**
1095
1174
  * Create a scroll sync group for anchor-based synchronized scrolling
1096
1175
  */
1097
1176
  createScrollSyncGroup(groupId: number, leftSplit: number, rightSplit: number): boolean;
@@ -1183,6 +1262,18 @@ interface EditorAPI {
1183
1262
  */
1184
1263
  killBackgroundProcess(processId: number): boolean;
1185
1264
  /**
1265
+ * Create a new terminal in a split (async, returns TerminalResult)
1266
+ */
1267
+ createTerminal(opts?: CreateTerminalOptions): Promise<TerminalResult>;
1268
+ /**
1269
+ * Send input data to a terminal
1270
+ */
1271
+ sendTerminalInput(terminalId: number, data: string): boolean;
1272
+ /**
1273
+ * Close a terminal
1274
+ */
1275
+ closeTerminal(terminalId: number): boolean;
1276
+ /**
1186
1277
  * Force refresh of line display
1187
1278
  */
1188
1279
  refreshLines(bufferId: number): boolean;