@fresh-editor/fresh-editor 0.3.4 → 0.3.6
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 +72 -0
- package/README.md +9 -2
- package/package.json +1 -1
- package/plugins/config-schema.json +7 -1
- package/plugins/dashboard.ts +16 -93
- package/plugins/git_grep.ts +3 -1
- package/plugins/git_log.ts +196 -224
- package/plugins/goto_with_selection.i18n.json +58 -0
- package/plugins/goto_with_selection.ts +17 -0
- package/plugins/lib/finder.ts +27 -6
- package/plugins/lib/fresh.d.ts +620 -14
- package/plugins/lib/index.ts +34 -0
- package/plugins/lib/widgets.ts +796 -0
- package/plugins/live_diff.ts +324 -29
- package/plugins/live_grep.ts +114 -48
- package/plugins/orchestrator.ts +1685 -0
- package/plugins/pkg.ts +234 -53
- package/plugins/rust-lsp.ts +58 -40
- package/plugins/schemas/theme.schema.json +4 -0
- package/plugins/search_replace.ts +780 -517
- package/plugins/theme_editor.i18n.json +84 -0
- package/plugins/theme_editor.ts +30 -5
- package/plugins/tsconfig.json +2 -0
- package/plugins/vi_mode.ts +38 -17
- package/themes/terminal.json +3 -0
package/plugins/lib/fresh.d.ts
CHANGED
|
@@ -116,6 +116,18 @@ type TextPropertyEntry = {
|
|
|
116
116
|
* Optional sub-range styling within this entry
|
|
117
117
|
*/
|
|
118
118
|
inlineOverlays?: Array<InlineOverlay>;
|
|
119
|
+
/**
|
|
120
|
+
* See `TextPropertyEntry::pad_to_chars`.
|
|
121
|
+
*/
|
|
122
|
+
padToChars?: number;
|
|
123
|
+
/**
|
|
124
|
+
* See `TextPropertyEntry::truncate_to_chars`.
|
|
125
|
+
*/
|
|
126
|
+
truncateToChars?: number;
|
|
127
|
+
/**
|
|
128
|
+
* See `TextPropertyEntry::segments`.
|
|
129
|
+
*/
|
|
130
|
+
segments?: Array<StyledSegment>;
|
|
119
131
|
};
|
|
120
132
|
type TsCompositeLayoutConfig = {
|
|
121
133
|
/**
|
|
@@ -420,6 +432,20 @@ type BufferInfo = {
|
|
|
420
432
|
*/
|
|
421
433
|
splits: number[];
|
|
422
434
|
};
|
|
435
|
+
type WindowInfo = {
|
|
436
|
+
/**
|
|
437
|
+
* Stable session id. The base session is always `1`.
|
|
438
|
+
*/
|
|
439
|
+
id: number;
|
|
440
|
+
/**
|
|
441
|
+
* User-visible label (defaults to root basename).
|
|
442
|
+
*/
|
|
443
|
+
label: string;
|
|
444
|
+
/**
|
|
445
|
+
* Absolute project root.
|
|
446
|
+
*/
|
|
447
|
+
root: string;
|
|
448
|
+
};
|
|
423
449
|
type JsDiagnostic = {
|
|
424
450
|
/**
|
|
425
451
|
* Document URI
|
|
@@ -500,6 +526,17 @@ type ActionPopupOptions = {
|
|
|
500
526
|
*/
|
|
501
527
|
actions: Array<TsActionPopupAction>;
|
|
502
528
|
};
|
|
529
|
+
type TsLspMenuItem = {
|
|
530
|
+
/**
|
|
531
|
+
* Stable identifier used as the `action_id` in the resulting
|
|
532
|
+
* `action_popup_result` event (prefixed by `{plugin_id}|`).
|
|
533
|
+
*/
|
|
534
|
+
id: string;
|
|
535
|
+
/**
|
|
536
|
+
* Display label shown in the popup row.
|
|
537
|
+
*/
|
|
538
|
+
label: string;
|
|
539
|
+
};
|
|
503
540
|
type FileExplorerDecoration = {
|
|
504
541
|
/**
|
|
505
542
|
* File path to decorate
|
|
@@ -582,6 +619,16 @@ type CreateTerminalOptions = {
|
|
|
582
619
|
* across editor restarts.
|
|
583
620
|
*/
|
|
584
621
|
persistent?: boolean;
|
|
622
|
+
/**
|
|
623
|
+
* Optional session id to attach the new terminal buffer to.
|
|
624
|
+
* Defaults to the active session at creation time. Setting this
|
|
625
|
+
* lets Orchestrator and similar plugins spawn a terminal *into* an
|
|
626
|
+
* inactive session (e.g. an agent in a worktree the user hasn't
|
|
627
|
+
* dived into yet). The terminal's split is created in that
|
|
628
|
+
* session's stashed split tree; the buffer is attached to the
|
|
629
|
+
* target session's membership set rather than the active one's.
|
|
630
|
+
*/
|
|
631
|
+
windowId?: WindowId;
|
|
585
632
|
};
|
|
586
633
|
type CursorInfo = {
|
|
587
634
|
/**
|
|
@@ -635,11 +682,11 @@ type OverlayOptions = {
|
|
|
635
682
|
type OverlayColorSpec = [number, number, number] | string;
|
|
636
683
|
type InlineOverlay = {
|
|
637
684
|
/**
|
|
638
|
-
* Start
|
|
685
|
+
* Start offset within the entry's text. See `unit`.
|
|
639
686
|
*/
|
|
640
687
|
start: number;
|
|
641
688
|
/**
|
|
642
|
-
* End
|
|
689
|
+
* End offset within the entry's text (exclusive). See `unit`.
|
|
643
690
|
*/
|
|
644
691
|
end: number;
|
|
645
692
|
/**
|
|
@@ -650,6 +697,29 @@ type InlineOverlay = {
|
|
|
650
697
|
* Optional properties for this sub-range (e.g., click target metadata)
|
|
651
698
|
*/
|
|
652
699
|
properties?: Record<string, any>;
|
|
700
|
+
/**
|
|
701
|
+
* Unit for `start` / `end`. Defaults to `byte`.
|
|
702
|
+
*/
|
|
703
|
+
unit?: OffsetUnit;
|
|
704
|
+
};
|
|
705
|
+
type OffsetUnit = "byte" | "char";
|
|
706
|
+
type StyledSegment = {
|
|
707
|
+
/**
|
|
708
|
+
* Verbatim text for this segment.
|
|
709
|
+
*/
|
|
710
|
+
text: string;
|
|
711
|
+
/**
|
|
712
|
+
* When set, the host emits an `InlineOverlay` covering this
|
|
713
|
+
* segment's text in the final entry.
|
|
714
|
+
*/
|
|
715
|
+
style?: Partial<OverlayOptions>;
|
|
716
|
+
/**
|
|
717
|
+
* Additional overlays inside this segment. Offsets are in
|
|
718
|
+
* the overlay's own `unit`, relative to the segment's start
|
|
719
|
+
* (NOT the final entry text); the host shifts them by the
|
|
720
|
+
* segment's position during concatenation.
|
|
721
|
+
*/
|
|
722
|
+
overlays?: Array<InlineOverlay>;
|
|
653
723
|
};
|
|
654
724
|
type GrammarInfoSnapshot = {
|
|
655
725
|
/**
|
|
@@ -682,6 +752,296 @@ type PluginAnimationKind = {
|
|
|
682
752
|
durationMs: number;
|
|
683
753
|
delayMs: number;
|
|
684
754
|
};
|
|
755
|
+
type HintEntry = {
|
|
756
|
+
/**
|
|
757
|
+
* The key chord, e.g. `"Tab"`, `"Alt+P"`, `"Esc"`.
|
|
758
|
+
*/
|
|
759
|
+
keys: string;
|
|
760
|
+
/**
|
|
761
|
+
* The human-readable label for the action.
|
|
762
|
+
*/
|
|
763
|
+
label: string;
|
|
764
|
+
};
|
|
765
|
+
type ButtonKind = "normal" | "primary" | "danger";
|
|
766
|
+
type TreeNode = {
|
|
767
|
+
/**
|
|
768
|
+
* The pre-rendered row content (text + per-row overlays).
|
|
769
|
+
* The host renders this verbatim after the indent + disclosure
|
|
770
|
+
* prefix; plugin overlays are byte-shifted by the prefix
|
|
771
|
+
* length.
|
|
772
|
+
*/
|
|
773
|
+
text: TextPropertyEntry;
|
|
774
|
+
/**
|
|
775
|
+
* 0-based depth — controls leading indent (`depth * 2` spaces).
|
|
776
|
+
*/
|
|
777
|
+
depth: number;
|
|
778
|
+
/**
|
|
779
|
+
* When true, render a disclosure glyph (`▶` collapsed / `▼`
|
|
780
|
+
* expanded) and emit a hit area over it that fires the `expand`
|
|
781
|
+
* event. Leaf nodes (`false`) get no glyph and no expand hit;
|
|
782
|
+
* the row width occupies the full row.
|
|
783
|
+
*/
|
|
784
|
+
hasChildren: boolean;
|
|
785
|
+
/**
|
|
786
|
+
* Per-node checkbox state. Only rendered when the parent
|
|
787
|
+
* `Tree` has `checkable: true`. `None` = no checkbox glyph;
|
|
788
|
+
* `Some(true)` = `[v]`; `Some(false)` = `[ ]`. The plugin
|
|
789
|
+
* owns the truth — the host fires `widget_event { event_type:
|
|
790
|
+
* "toggle" }` and the plugin pushes the new state back via
|
|
791
|
+
* `WidgetMutation::SetCheckedKeys`.
|
|
792
|
+
*/
|
|
793
|
+
checked?: boolean | null;
|
|
794
|
+
};
|
|
795
|
+
type WidgetSpec = {
|
|
796
|
+
"kind": "row";
|
|
797
|
+
children: Array<WidgetSpec>;
|
|
798
|
+
key?: string | null;
|
|
799
|
+
} | {
|
|
800
|
+
"kind": "col";
|
|
801
|
+
children: Array<WidgetSpec>;
|
|
802
|
+
key?: string | null;
|
|
803
|
+
} | {
|
|
804
|
+
"kind": "hintBar";
|
|
805
|
+
entries: Array<HintEntry>;
|
|
806
|
+
key?: string | null;
|
|
807
|
+
} | {
|
|
808
|
+
"kind": "toggle";
|
|
809
|
+
checked: boolean;
|
|
810
|
+
label: string;
|
|
811
|
+
focused: boolean;
|
|
812
|
+
key?: string | null;
|
|
813
|
+
} | {
|
|
814
|
+
"kind": "button";
|
|
815
|
+
label: string;
|
|
816
|
+
focused: boolean;
|
|
817
|
+
intent: ButtonKind;
|
|
818
|
+
key?: string | null;
|
|
819
|
+
} | {
|
|
820
|
+
"kind": "spacer";
|
|
821
|
+
cols: number;
|
|
822
|
+
flex: boolean;
|
|
823
|
+
key?: string | null;
|
|
824
|
+
} | {
|
|
825
|
+
"kind": "list";
|
|
826
|
+
items: Array<TextPropertyEntry>;
|
|
827
|
+
itemKeys: Array<string>;
|
|
828
|
+
selectedIndex: number;
|
|
829
|
+
/**
|
|
830
|
+
* Number of rows of the panel's available height the list
|
|
831
|
+
* should occupy. Plugin computes from its viewport. The
|
|
832
|
+
* host shows up to this many items per render.
|
|
833
|
+
*/
|
|
834
|
+
visibleRows: number;
|
|
835
|
+
/**
|
|
836
|
+
* Whether `Tab` / `Shift+Tab` will land focus on this
|
|
837
|
+
* list. Defaults to `true` (lists are normal tabbable
|
|
838
|
+
* widgets). Picker-style usage typically sets this to
|
|
839
|
+
* `false` so Tab moves between the filter input and
|
|
840
|
+
* the action buttons, while Up/Down on the focused
|
|
841
|
+
* filter still forwards to the list via host smart-key
|
|
842
|
+
* dispatch.
|
|
843
|
+
*/
|
|
844
|
+
focusable: boolean;
|
|
845
|
+
key?: string | null;
|
|
846
|
+
} | {
|
|
847
|
+
"kind": "tree";
|
|
848
|
+
nodes: Array<TreeNode>;
|
|
849
|
+
itemKeys: Array<string>;
|
|
850
|
+
selectedIndex: number;
|
|
851
|
+
visibleRows: number;
|
|
852
|
+
/**
|
|
853
|
+
* Initial-only set of expanded item keys. Once the widget
|
|
854
|
+
* has rendered, the host's instance-state `expanded_keys`
|
|
855
|
+
* is authoritative; updating this field on subsequent specs
|
|
856
|
+
* has no effect (use `WidgetMutation::SetExpandedKeys` to
|
|
857
|
+
* override host state).
|
|
858
|
+
*/
|
|
859
|
+
expandedKeys: Array<string>;
|
|
860
|
+
/**
|
|
861
|
+
* When true, every node with `checked: Some(_)` renders a
|
|
862
|
+
* `[v]` / `[ ]` glyph and emits a `toggle` hit area over
|
|
863
|
+
* the glyph. Click on the glyph fires `widget_event {
|
|
864
|
+
* event_type: "toggle", payload: { key, checked: <new> } }`;
|
|
865
|
+
* the plugin updates its model and pushes the new state
|
|
866
|
+
* back via `WidgetMutation::SetCheckedKeys`.
|
|
867
|
+
*/
|
|
868
|
+
checkable: boolean;
|
|
869
|
+
key?: string | null;
|
|
870
|
+
} | {
|
|
871
|
+
"kind": "text";
|
|
872
|
+
/**
|
|
873
|
+
* Initial text. Spec value is read at first render only;
|
|
874
|
+
* instance state takes over thereafter.
|
|
875
|
+
*/
|
|
876
|
+
value: string;
|
|
877
|
+
/**
|
|
878
|
+
* Initial byte-offset cursor within `value`. Negative
|
|
879
|
+
* (encoded as `i32` in JSON) means "no cursor" — clamped
|
|
880
|
+
* to `[0, value.len()]` host-side.
|
|
881
|
+
*/
|
|
882
|
+
cursorByte: number;
|
|
883
|
+
/**
|
|
884
|
+
* Whether this widget has visual focus.
|
|
885
|
+
*/
|
|
886
|
+
focused: boolean;
|
|
887
|
+
/**
|
|
888
|
+
* Optional label rendered before / above the editing
|
|
889
|
+
* region. Empty = omitted.
|
|
890
|
+
*/
|
|
891
|
+
label?: string;
|
|
892
|
+
/**
|
|
893
|
+
* Placeholder shown when unfocused and `value` is empty.
|
|
894
|
+
*/
|
|
895
|
+
placeholder?: string | null;
|
|
896
|
+
/**
|
|
897
|
+
* Number of visible rows of editing region. `0` falls back
|
|
898
|
+
* to `1` (single-line). `1` = single-line behaviour;
|
|
899
|
+
* `>= 2` = multi-line behaviour. See the type-level doc
|
|
900
|
+
* for the per-mode semantics.
|
|
901
|
+
*/
|
|
902
|
+
rows: number;
|
|
903
|
+
/**
|
|
904
|
+
* Visible column width. `0` = auto-fit (single-line) or
|
|
905
|
+
* panel width (multi-line). When set, single-line
|
|
906
|
+
* head-truncates with `…` and multi-line tail-truncates
|
|
907
|
+
* per-line.
|
|
908
|
+
*/
|
|
909
|
+
fieldWidth: number;
|
|
910
|
+
/**
|
|
911
|
+
* Single-line soft cap on visible chars after the
|
|
912
|
+
* `field_width` pad. `0` = no cap. Ignored when `rows > 1`.
|
|
913
|
+
*/
|
|
914
|
+
maxVisibleChars: number;
|
|
915
|
+
/**
|
|
916
|
+
* Stretch the visible field to fill the available
|
|
917
|
+
* width of the enclosing container. Overrides
|
|
918
|
+
* `field_width` when set: the renderer computes
|
|
919
|
+
* `panel_width - label_overhead - bracket_overhead` as
|
|
920
|
+
* the effective visible width. Multi-line widgets
|
|
921
|
+
* already fill the panel width by default; this flag is
|
|
922
|
+
* most useful for single-line inputs inside a
|
|
923
|
+
* `LabeledSection` or a flexible row.
|
|
924
|
+
*/
|
|
925
|
+
fullWidth: boolean;
|
|
926
|
+
key?: string | null;
|
|
927
|
+
} | {
|
|
928
|
+
"kind": "labeledSection";
|
|
929
|
+
/**
|
|
930
|
+
* Legend text printed in the top border. Empty = no
|
|
931
|
+
* legend (the top border becomes one unbroken line).
|
|
932
|
+
*/
|
|
933
|
+
label: string;
|
|
934
|
+
/**
|
|
935
|
+
* The single wrapped widget. Boxed because `WidgetSpec`
|
|
936
|
+
* is recursive.
|
|
937
|
+
*/
|
|
938
|
+
child: WidgetSpec;
|
|
939
|
+
/**
|
|
940
|
+
* When this section is a Block child of a Row, request
|
|
941
|
+
* `width_pct` percent of the row's `panel_width` instead
|
|
942
|
+
* of the equal-split default. Multiple siblings with
|
|
943
|
+
* `width_pct` set sum to ≤ 100; the remainder splits
|
|
944
|
+
* equally among siblings without an explicit width.
|
|
945
|
+
* Out-of-range values (0 or > 100) fall back to the
|
|
946
|
+
* equal-split path.
|
|
947
|
+
*/
|
|
948
|
+
widthPct?: number | null;
|
|
949
|
+
key?: string | null;
|
|
950
|
+
} | {
|
|
951
|
+
"kind": "windowEmbed";
|
|
952
|
+
/**
|
|
953
|
+
* Numeric editor-window id, matching `WindowId(N).0`.
|
|
954
|
+
* `0` (or any unknown id) renders empty placeholder
|
|
955
|
+
* rows without dispatching the per-window render.
|
|
956
|
+
* `u32` rather than `u64` to keep the TS binding a
|
|
957
|
+
* plain `number`; window ids never exceed 4B in
|
|
958
|
+
* practice.
|
|
959
|
+
*/
|
|
960
|
+
windowId: number;
|
|
961
|
+
/**
|
|
962
|
+
* Number of visible rows the embed should occupy.
|
|
963
|
+
*/
|
|
964
|
+
rows: number;
|
|
965
|
+
key?: string | null;
|
|
966
|
+
} | {
|
|
967
|
+
"kind": "raw";
|
|
968
|
+
entries: Array<TextPropertyEntry>;
|
|
969
|
+
key?: string | null;
|
|
970
|
+
};
|
|
971
|
+
type WidgetAction = {
|
|
972
|
+
"kind": "focusAdvance";
|
|
973
|
+
delta: number;
|
|
974
|
+
} | {
|
|
975
|
+
"kind": "activate";
|
|
976
|
+
} | {
|
|
977
|
+
"kind": "selectMove";
|
|
978
|
+
delta: number;
|
|
979
|
+
} | {
|
|
980
|
+
"kind": "textInputKey";
|
|
981
|
+
key: string;
|
|
982
|
+
} | {
|
|
983
|
+
"kind": "textInputChar";
|
|
984
|
+
text: string;
|
|
985
|
+
} | {
|
|
986
|
+
"kind": "key";
|
|
987
|
+
key: string;
|
|
988
|
+
};
|
|
989
|
+
type WidgetMutation = {
|
|
990
|
+
"kind": "setValue";
|
|
991
|
+
widgetKey: string;
|
|
992
|
+
value: string;
|
|
993
|
+
cursorByte?: number | null;
|
|
994
|
+
} | {
|
|
995
|
+
"kind": "setChecked";
|
|
996
|
+
widgetKey: string;
|
|
997
|
+
checked: boolean;
|
|
998
|
+
} | {
|
|
999
|
+
"kind": "setSelectedIndex";
|
|
1000
|
+
widgetKey: string;
|
|
1001
|
+
index: number;
|
|
1002
|
+
} | {
|
|
1003
|
+
"kind": "setItems";
|
|
1004
|
+
widgetKey: string;
|
|
1005
|
+
items: Array<TextPropertyEntry>;
|
|
1006
|
+
itemKeys: Array<string>;
|
|
1007
|
+
} | {
|
|
1008
|
+
"kind": "setExpandedKeys";
|
|
1009
|
+
widgetKey: string;
|
|
1010
|
+
keys: Array<string>;
|
|
1011
|
+
} | {
|
|
1012
|
+
"kind": "setCheckedKeys";
|
|
1013
|
+
widgetKey: string;
|
|
1014
|
+
checked: boolean;
|
|
1015
|
+
keys: Array<string>;
|
|
1016
|
+
};
|
|
1017
|
+
type SearchTakeResult = {
|
|
1018
|
+
/**
|
|
1019
|
+
* Matches discovered since the previous take()
|
|
1020
|
+
*/
|
|
1021
|
+
matches: Array<GrepMatch>;
|
|
1022
|
+
/**
|
|
1023
|
+
* Whether the producer has finished (no more matches will arrive)
|
|
1024
|
+
*/
|
|
1025
|
+
done: boolean;
|
|
1026
|
+
/**
|
|
1027
|
+
* Total number of matches the producer has emitted across all batches
|
|
1028
|
+
* (including ones already drained on prior take() calls)
|
|
1029
|
+
*/
|
|
1030
|
+
totalSeen: number;
|
|
1031
|
+
/**
|
|
1032
|
+
* Whether the producer stopped early because it hit `maxResults`
|
|
1033
|
+
*/
|
|
1034
|
+
truncated: boolean;
|
|
1035
|
+
/**
|
|
1036
|
+
* Producer error, if any (e.g., invalid regex). When set, `done` is also true.
|
|
1037
|
+
*/
|
|
1038
|
+
error?: string | null;
|
|
1039
|
+
};
|
|
1040
|
+
interface SearchHandle {
|
|
1041
|
+
searchId: number;
|
|
1042
|
+
take(): SearchTakeResult;
|
|
1043
|
+
cancel(): void;
|
|
1044
|
+
}
|
|
685
1045
|
type AuthorityFilesystem = {
|
|
686
1046
|
kind: "local";
|
|
687
1047
|
};
|
|
@@ -989,6 +1349,10 @@ type SpawnResult = {
|
|
|
989
1349
|
*/
|
|
990
1350
|
exit_code: number;
|
|
991
1351
|
};
|
|
1352
|
+
type StyledText = {
|
|
1353
|
+
text: string;
|
|
1354
|
+
style?: Partial<OverlayOptions>;
|
|
1355
|
+
};
|
|
992
1356
|
type TextPropertiesAtCursor = Array<Record<string, unknown>>;
|
|
993
1357
|
type TsHighlightSpan = {
|
|
994
1358
|
start: number;
|
|
@@ -1207,6 +1571,16 @@ interface EditorAPI {
|
|
|
1207
1571
|
*/
|
|
1208
1572
|
openFile(path: string, line: number | null, column: number | null): boolean;
|
|
1209
1573
|
/**
|
|
1574
|
+
* Open a file in the background — no focus change, no
|
|
1575
|
+
* active-split mutation. `windowId` defaults to the active
|
|
1576
|
+
* session. Setting it to an inactive session id loads the
|
|
1577
|
+
* file's buffer and adds it as a tab in that session's
|
|
1578
|
+
* stashed split tree, ready to be revealed on next dive.
|
|
1579
|
+
* Orchestrator uses this to populate worktree sessions with
|
|
1580
|
+
* preselected files.
|
|
1581
|
+
*/
|
|
1582
|
+
openFileInBackground(path: string, windowId?: number): boolean;
|
|
1583
|
+
/**
|
|
1210
1584
|
* Open a file in a specific split
|
|
1211
1585
|
*/
|
|
1212
1586
|
openFileInSplit(splitId: number, path: string, line: number, column: number): boolean;
|
|
@@ -1735,11 +2109,34 @@ interface EditorAPI {
|
|
|
1735
2109
|
setPromptInputSync(sync: boolean): boolean;
|
|
1736
2110
|
/**
|
|
1737
2111
|
* Set the title shown in the floating-overlay prompt's frame
|
|
1738
|
-
* header (issue #1796)
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
|
|
1742
|
-
|
|
2112
|
+
* header (issue #1796) as styled segments. Each segment
|
|
2113
|
+
* carries optional `Partial<OverlayOptions>`, the same
|
|
2114
|
+
* styling primitive used by virtual text — plugins mark
|
|
2115
|
+
* keybinding hints with `{ fg: "ui.help_key_fg" }`,
|
|
2116
|
+
* separators with `{ fg: "ui.popup_border_fg" }`, etc. Pass
|
|
2117
|
+
* an empty array to clear the title and fall back to the
|
|
2118
|
+
* prompt-type default. Has no visible effect on non-overlay
|
|
2119
|
+
* prompts.
|
|
2120
|
+
*/
|
|
2121
|
+
setPromptTitle(title: StyledText[]): boolean;
|
|
2122
|
+
/**
|
|
2123
|
+
* Set the footer chrome row of the floating-overlay prompt's
|
|
2124
|
+
* results pane. Plugins use this for hotkey-hint banners
|
|
2125
|
+
* (Orchestrator's `[n] new [d] dive [Esc] close` row).
|
|
2126
|
+
* Empty array clears the footer. Has no visible effect on
|
|
2127
|
+
* non-overlay prompts.
|
|
2128
|
+
*/
|
|
2129
|
+
setPromptFooter(footer: StyledText[]): boolean;
|
|
2130
|
+
/**
|
|
2131
|
+
* Override the currently-highlighted suggestion row in the
|
|
2132
|
+
* open prompt. The editor clamps `index` to the suggestion
|
|
2133
|
+
* list's bounds and the renderer scrolls it into view on
|
|
2134
|
+
* the next frame. No-op when no prompt is open or the
|
|
2135
|
+
* suggestion list is empty. Typical use: re-opening a
|
|
2136
|
+
* picker and pre-selecting the entry the user last acted on
|
|
2137
|
+
* (Orchestrator highlights the active session).
|
|
2138
|
+
*/
|
|
2139
|
+
setPromptSelectedIndex(index: number): boolean;
|
|
1743
2140
|
/**
|
|
1744
2141
|
* Define a buffer mode (takes bindings as array of [key, command] pairs)
|
|
1745
2142
|
*/
|
|
@@ -1765,6 +2162,81 @@ interface EditorAPI {
|
|
|
1765
2162
|
*/
|
|
1766
2163
|
focusSplit(splitId: number): boolean;
|
|
1767
2164
|
/**
|
|
2165
|
+
* Create a new editor session rooted at `root`. `root` must be
|
|
2166
|
+
* an absolute path; relative paths are rejected by the editor
|
|
2167
|
+
* (logged, no session created). The new session's id is
|
|
2168
|
+
* reported via the `window_created` hook payload — plugins
|
|
2169
|
+
* that need the id should listen for that event rather than
|
|
2170
|
+
* polling `listWindows`.
|
|
2171
|
+
*
|
|
2172
|
+
* Returns `false` only when the IPC channel to the editor is
|
|
2173
|
+
* closed (editor is shutting down).
|
|
2174
|
+
*/
|
|
2175
|
+
createWindow(root: string, label: string): boolean;
|
|
2176
|
+
/**
|
|
2177
|
+
* Make the session with id `id` the active one. No-op if
|
|
2178
|
+
* already active. Errors (id not found) are logged on the
|
|
2179
|
+
* editor side; the JS caller can verify by reading
|
|
2180
|
+
* `activeWindow()` after.
|
|
2181
|
+
*/
|
|
2182
|
+
setActiveWindow(id: number): boolean;
|
|
2183
|
+
/**
|
|
2184
|
+
* Close session `id`. Refuses to close the active session or
|
|
2185
|
+
* the base session (id 1). Logs and no-ops on failure.
|
|
2186
|
+
*/
|
|
2187
|
+
closeWindow(id: number): boolean;
|
|
2188
|
+
/**
|
|
2189
|
+
* Eagerly initialise an inactive session's per-session state
|
|
2190
|
+
* (file tree walk, ignore matcher, etc.) without diving.
|
|
2191
|
+
* No-op for the active session or unknown id.
|
|
2192
|
+
*/
|
|
2193
|
+
prewarmWindow(id: number): boolean;
|
|
2194
|
+
/**
|
|
2195
|
+
* Register a `notify`-backed watch on `path`. Returns a
|
|
2196
|
+
* promise that resolves to a numeric `handle` (also passed
|
|
2197
|
+
* in subsequent `path_changed` event payloads). The promise
|
|
2198
|
+
* rejects on `notify` errors (path missing, kernel limit).
|
|
2199
|
+
*
|
|
2200
|
+
* `recursive` defaults to `false`. Non-recursive watches
|
|
2201
|
+
* cover the path itself plus its direct children for
|
|
2202
|
+
* directories — see `services/file_watcher.rs` for the
|
|
2203
|
+
* rationale.
|
|
2204
|
+
*/
|
|
2205
|
+
watchPath(path: string, recursive?: boolean): Promise<number>;
|
|
2206
|
+
/**
|
|
2207
|
+
* Drop a watcher by its handle. Unknown handles are
|
|
2208
|
+
* silently ignored.
|
|
2209
|
+
*/
|
|
2210
|
+
unwatchPath(handle: number): boolean;
|
|
2211
|
+
/**
|
|
2212
|
+
* Tell the editor that the floating-overlay prompt's
|
|
2213
|
+
* preview pane should render the entire split tree of
|
|
2214
|
+
* session `id` natively. `0` (or any unknown id) clears the
|
|
2215
|
+
* override and the preview falls back to the existing
|
|
2216
|
+
* path-based phantom-leaf renderer.
|
|
2217
|
+
*
|
|
2218
|
+
* Orchestrator calls this on each prompt-selection-change so
|
|
2219
|
+
* the right pane shows the highlighted session's full
|
|
2220
|
+
* editor UI live — splits, terminals, syntax highlighting,
|
|
2221
|
+
* decorations — at native rendering cost.
|
|
2222
|
+
*/
|
|
2223
|
+
previewWindowInRect(id: number): boolean;
|
|
2224
|
+
/**
|
|
2225
|
+
* Clear the session-preview override. Equivalent to
|
|
2226
|
+
* `previewWindowInRect(0)` but reads better at call sites.
|
|
2227
|
+
*/
|
|
2228
|
+
clearWindowPreview(): boolean;
|
|
2229
|
+
/**
|
|
2230
|
+
* All editor sessions, sorted by id (creation order). Always
|
|
2231
|
+
* non-empty (the base session is always present).
|
|
2232
|
+
*/
|
|
2233
|
+
listWindows(): WindowInfo[];
|
|
2234
|
+
/**
|
|
2235
|
+
* The currently active session id. Always present in
|
|
2236
|
+
* `listWindows()`.
|
|
2237
|
+
*/
|
|
2238
|
+
activeWindow(): number;
|
|
2239
|
+
/**
|
|
1768
2240
|
* Set scroll position of a split
|
|
1769
2241
|
*/
|
|
1770
2242
|
setSplitScroll(splitId: number, topByte: number): boolean;
|
|
@@ -1846,6 +2318,22 @@ interface EditorAPI {
|
|
|
1846
2318
|
*/
|
|
1847
2319
|
getGlobalState(key: string): unknown;
|
|
1848
2320
|
/**
|
|
2321
|
+
* Set per-session state on the **active** session. Same
|
|
2322
|
+
* shape as `setGlobalState` (write-through to snapshot +
|
|
2323
|
+
* dispatched to editor; null/undefined deletes), but the
|
|
2324
|
+
* underlying storage lives on `Session.plugin_state` and
|
|
2325
|
+
* swaps with the rest of session state on `setActiveWindow`.
|
|
2326
|
+
* Plugins that genuinely want per-project state use this;
|
|
2327
|
+
* Orchestrator itself uses `setGlobalState` because its session
|
|
2328
|
+
* list lives above session boundaries.
|
|
2329
|
+
*/
|
|
2330
|
+
setWindowState(key: string, value: unknown): boolean;
|
|
2331
|
+
/**
|
|
2332
|
+
* Get per-session state from the **active** session
|
|
2333
|
+
* (snapshot read). `undefined` if missing.
|
|
2334
|
+
*/
|
|
2335
|
+
getWindowState(key: string): unknown;
|
|
2336
|
+
/**
|
|
1849
2337
|
* Create a scroll sync group for anchor-based synchronized scrolling
|
|
1850
2338
|
*/
|
|
1851
2339
|
createScrollSyncGroup(groupId: number, leftSplit: number, rightSplit: number): boolean;
|
|
@@ -1870,6 +2358,12 @@ interface EditorAPI {
|
|
|
1870
2358
|
*/
|
|
1871
2359
|
showActionPopup(opts: ActionPopupOptions): boolean;
|
|
1872
2360
|
/**
|
|
2361
|
+
* Contribute (or replace, or clear) menu rows for the LSP-Servers
|
|
2362
|
+
* popup. Pass an empty `items` to clear this plugin's slice for
|
|
2363
|
+
* the given language. See `PluginCommand::SetLspMenuContributions`.
|
|
2364
|
+
*/
|
|
2365
|
+
setLspMenuContributions(pluginId: string, language: string, items: TsLspMenuItem[]): boolean;
|
|
2366
|
+
/**
|
|
1873
2367
|
* Disable LSP for a specific language
|
|
1874
2368
|
*/
|
|
1875
2369
|
disableLspForLanguage(language: string): boolean;
|
|
@@ -1925,6 +2419,60 @@ interface EditorAPI {
|
|
|
1925
2419
|
*/
|
|
1926
2420
|
getTextPropertiesAtCursor(bufferId: number): TextPropertiesAtCursor;
|
|
1927
2421
|
/**
|
|
2422
|
+
* Mount a declarative widget panel inside a virtual buffer.
|
|
2423
|
+
*
|
|
2424
|
+
* `spec` is a `WidgetSpec` JSON tree (see fresh.d.ts for the
|
|
2425
|
+
* shape). The host renders the spec into the buffer; subsequent
|
|
2426
|
+
* `updateWidgetPanel` calls re-render the panel against the
|
|
2427
|
+
* previously-mounted spec.
|
|
2428
|
+
*
|
|
2429
|
+
* Returns true on successful queue, false if the IPC channel is
|
|
2430
|
+
* closed.
|
|
2431
|
+
*/
|
|
2432
|
+
mountWidgetPanel(panelId: number, bufferId: number, specObj: unknown): boolean;
|
|
2433
|
+
/**
|
|
2434
|
+
* Replace the spec of a previously-mounted widget panel.
|
|
2435
|
+
* No-op if the panel id was never mounted.
|
|
2436
|
+
*/
|
|
2437
|
+
updateWidgetPanel(panelId: number, specObj: unknown): boolean;
|
|
2438
|
+
/**
|
|
2439
|
+
* Unmount a previously-mounted widget panel. The plugin retains
|
|
2440
|
+
* ownership of the underlying virtual buffer.
|
|
2441
|
+
*/
|
|
2442
|
+
unmountWidgetPanel(panelId: number): boolean;
|
|
2443
|
+
/**
|
|
2444
|
+
* Route a keystroke / nav action to the panel's focused widget.
|
|
2445
|
+
*
|
|
2446
|
+
* `action` is a `WidgetAction` JSON object — see fresh.d.ts for
|
|
2447
|
+
* the shapes (`{kind: "focusAdvance", delta: 1}` etc.). Plugin's
|
|
2448
|
+
* `defineMode` bindings dispatch into here for keys handled by
|
|
2449
|
+
* the widget layer; the host runtime acts on the panel's
|
|
2450
|
+
* currently focused widget and fires `widget_event` as
|
|
2451
|
+
* appropriate.
|
|
2452
|
+
*/
|
|
2453
|
+
widgetCommand(panelId: number, actionObj: unknown): boolean;
|
|
2454
|
+
/**
|
|
2455
|
+
* Apply a targeted mutation to a mounted widget panel — the
|
|
2456
|
+
* IPC fast path. Use instead of `updateWidgetPanel` when the
|
|
2457
|
+
* model change touches a single widget; the host applies the
|
|
2458
|
+
* mutation in place without re-transmitting the full spec.
|
|
2459
|
+
* See `WidgetMutation` in fresh.d.ts for the shapes.
|
|
2460
|
+
*/
|
|
2461
|
+
widgetMutate(panelId: number, mutationObj: unknown): boolean;
|
|
2462
|
+
/**
|
|
2463
|
+
* Mount a declarative widget panel as a centered floating
|
|
2464
|
+
* overlay (not bound to any virtual buffer).
|
|
2465
|
+
*/
|
|
2466
|
+
mountFloatingWidget(panelId: number, specObj: unknown, widthPct: number, heightPct: number): boolean;
|
|
2467
|
+
/**
|
|
2468
|
+
* Replace the spec of the currently-mounted floating widget panel.
|
|
2469
|
+
*/
|
|
2470
|
+
updateFloatingWidget(panelId: number, specObj: unknown): boolean;
|
|
2471
|
+
/**
|
|
2472
|
+
* Tear down the floating widget panel.
|
|
2473
|
+
*/
|
|
2474
|
+
unmountFloatingWidget(panelId: number): boolean;
|
|
2475
|
+
/**
|
|
1928
2476
|
* Spawn a process (async, returns request_id)
|
|
1929
2477
|
*/
|
|
1930
2478
|
spawnProcess(command: string, args: string[], cwd?: string): ProcessHandle<SpawnResult>;
|
|
@@ -1997,18 +2545,17 @@ interface EditorAPI {
|
|
|
1997
2545
|
*/
|
|
1998
2546
|
grepProject(pattern: string, fixedString: boolean | null, caseSensitive: boolean | null, maxResults: number | null, wholeWords: boolean | null): Promise<GrepMatch[]>;
|
|
1999
2547
|
/**
|
|
2000
|
-
*
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2548
|
+
* Begin a streaming project-wide search and return a `SearchHandle`.
|
|
2549
|
+
* The producer (host) writes matches at full speed into shared state;
|
|
2550
|
+
* the consumer drains via `handle.take()` at its own cadence. Call
|
|
2551
|
+
* `handle.cancel()` to abort.
|
|
2003
2552
|
*/
|
|
2004
|
-
|
|
2553
|
+
beginSearch(pattern: string, opts?: {
|
|
2005
2554
|
fixedString?: boolean;
|
|
2006
2555
|
caseSensitive?: boolean;
|
|
2007
2556
|
maxResults?: number;
|
|
2008
2557
|
wholeWords?: boolean;
|
|
2009
|
-
}
|
|
2010
|
-
searchId: number;
|
|
2011
|
-
};
|
|
2558
|
+
}): SearchHandle;
|
|
2012
2559
|
/**
|
|
2013
2560
|
* Replace matches in a file's buffer (async)
|
|
2014
2561
|
* Opens the file if not already in a buffer, applies edits via the buffer model,
|
|
@@ -2040,6 +2587,15 @@ interface EditorAPI {
|
|
|
2040
2587
|
*/
|
|
2041
2588
|
closeTerminal(terminalId: number): boolean;
|
|
2042
2589
|
/**
|
|
2590
|
+
* Send `signal` ("SIGTERM" / "SIGKILL" / "SIGINT" / "SIGHUP")
|
|
2591
|
+
* to every process group the window `id` is tracking. The
|
|
2592
|
+
* window's authority decides delivery; this is the
|
|
2593
|
+
* canonical entry point for "stop everything this window
|
|
2594
|
+
* owns" rather than reaching at the terminal level. Returns
|
|
2595
|
+
* `false` only when the command channel is closed.
|
|
2596
|
+
*/
|
|
2597
|
+
signalWindow(id: number, signal: string): boolean;
|
|
2598
|
+
/**
|
|
2043
2599
|
* Force refresh of line display
|
|
2044
2600
|
*/
|
|
2045
2601
|
refreshLines(bufferId: number): boolean;
|
|
@@ -2312,6 +2868,56 @@ interface HookEventMap {
|
|
|
2312
2868
|
action: string;
|
|
2313
2869
|
}[];
|
|
2314
2870
|
};
|
|
2871
|
+
// ── PTY terminals (see crates/fresh-core/src/hooks.rs) ───────────────────
|
|
2872
|
+
terminal_output: {
|
|
2873
|
+
terminal_id: number;
|
|
2874
|
+
last_line: string;
|
|
2875
|
+
};
|
|
2876
|
+
terminal_exit: {
|
|
2877
|
+
terminal_id: number;
|
|
2878
|
+
exit_code: number | null;
|
|
2879
|
+
};
|
|
2880
|
+
// ── filesystem watching (watchPath plugin API) ────────────────────────────
|
|
2881
|
+
path_changed: {
|
|
2882
|
+
handle: number;
|
|
2883
|
+
path: string;
|
|
2884
|
+
/** "modify" | "create" | "delete" | "rename" | "other" */
|
|
2885
|
+
kind: string;
|
|
2886
|
+
};
|
|
2887
|
+
// ── editor sessions (Orchestrator; see orchestrator-sessions-design.md) ────────
|
|
2888
|
+
window_created: {
|
|
2889
|
+
id: number;
|
|
2890
|
+
label: string;
|
|
2891
|
+
root: string;
|
|
2892
|
+
};
|
|
2893
|
+
window_closed: {
|
|
2894
|
+
id: number;
|
|
2895
|
+
};
|
|
2896
|
+
active_window_changed: {
|
|
2897
|
+
previous_id: number | null;
|
|
2898
|
+
active_id: number;
|
|
2899
|
+
};
|
|
2900
|
+
// ── widget runtime ───────────────────────────────────────────────────────
|
|
2901
|
+
/**
|
|
2902
|
+
* A widget mounted via `editor.mountWidgetPanel` emitted a
|
|
2903
|
+
* semantic event. Fired when the host's hit-test routes a mouse
|
|
2904
|
+
* click to a `Toggle` / `Button` widget node within a mounted
|
|
2905
|
+
* widget panel. See `docs/internal/plugin-widget-library-design.md`.
|
|
2906
|
+
*
|
|
2907
|
+
* Routing is by `panel_id` (matches the id the plugin allocated
|
|
2908
|
+
* at mount time) plus `widget_key` (the stable `key` set on the
|
|
2909
|
+
* widget spec node, or empty when the spec did not assign one).
|
|
2910
|
+
*
|
|
2911
|
+
* `event_type` and `payload` shapes:
|
|
2912
|
+
* * Toggle: `event_type = "toggle"`, `payload = { checked: <new> }`.
|
|
2913
|
+
* * Button: `event_type = "activate"`, `payload = {}`.
|
|
2914
|
+
*/
|
|
2915
|
+
widget_event: {
|
|
2916
|
+
panel_id: number;
|
|
2917
|
+
widget_key: string;
|
|
2918
|
+
event_type: string;
|
|
2919
|
+
payload: Record<string, unknown>;
|
|
2920
|
+
};
|
|
2315
2921
|
}
|
|
2316
2922
|
/**
|
|
2317
2923
|
* Typed overloads of `editor.on` / `editor.off`.
|