@fresh-editor/fresh-editor 0.2.25 → 0.3.1
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 +216 -0
- package/README.md +6 -0
- package/package.json +1 -1
- package/plugins/astro-lsp.ts +6 -12
- package/plugins/audit_mode.i18n.json +14 -14
- package/plugins/audit_mode.ts +182 -146
- package/plugins/bash-lsp.ts +15 -22
- package/plugins/clangd-lsp.ts +15 -24
- package/plugins/clojure-lsp.ts +9 -12
- package/plugins/cmake-lsp.ts +9 -12
- package/plugins/code-tour.ts +15 -16
- package/plugins/config-schema.json +79 -6
- package/plugins/csharp_support.ts +25 -30
- package/plugins/css-lsp.ts +15 -22
- package/plugins/dart-lsp.ts +9 -12
- package/plugins/dashboard.ts +1903 -0
- package/plugins/devcontainer.i18n.json +1472 -0
- package/plugins/devcontainer.ts +2793 -0
- package/plugins/diagnostics_panel.ts +10 -17
- package/plugins/elixir-lsp.ts +9 -12
- package/plugins/erlang-lsp.ts +9 -12
- package/plugins/examples/bookmarks.ts +10 -16
- package/plugins/find_references.ts +5 -9
- package/plugins/flash.ts +577 -0
- package/plugins/fsharp-lsp.ts +9 -12
- package/plugins/git_explorer.ts +16 -20
- package/plugins/git_gutter.ts +65 -79
- package/plugins/git_log.i18n.json +14 -42
- package/plugins/git_log.ts +19 -9
- package/plugins/gleam-lsp.ts +9 -12
- package/plugins/go-lsp.ts +15 -22
- package/plugins/graphql-lsp.ts +9 -12
- package/plugins/haskell-lsp.ts +9 -12
- package/plugins/html-lsp.ts +15 -24
- package/plugins/java-lsp.ts +9 -12
- package/plugins/json-lsp.ts +15 -24
- package/plugins/julia-lsp.ts +9 -12
- package/plugins/kotlin-lsp.ts +15 -22
- package/plugins/latex-lsp.ts +9 -12
- package/plugins/lib/fresh.d.ts +603 -0
- package/plugins/lua-lsp.ts +15 -22
- package/plugins/markdown_compose.ts +132 -128
- package/plugins/markdown_source.ts +8 -10
- package/plugins/marksman-lsp.ts +9 -12
- package/plugins/merge_conflict.ts +15 -17
- package/plugins/nim-lsp.ts +9 -12
- package/plugins/nix-lsp.ts +9 -12
- package/plugins/nushell-lsp.ts +9 -12
- package/plugins/ocaml-lsp.ts +9 -12
- package/plugins/odin-lsp.ts +15 -22
- package/plugins/path_complete.ts +5 -6
- package/plugins/perl-lsp.ts +9 -12
- package/plugins/php-lsp.ts +15 -22
- package/plugins/pkg.ts +10 -21
- package/plugins/protobuf-lsp.ts +9 -12
- package/plugins/python-lsp.ts +15 -24
- package/plugins/r-lsp.ts +9 -12
- package/plugins/ruby-lsp.ts +15 -22
- package/plugins/rust-lsp.ts +18 -28
- package/plugins/scala-lsp.ts +9 -12
- package/plugins/schemas/theme.schema.json +126 -0
- package/plugins/search_replace.ts +10 -13
- package/plugins/solidity-lsp.ts +9 -12
- package/plugins/sql-lsp.ts +9 -12
- package/plugins/svelte-lsp.ts +9 -12
- package/plugins/swift-lsp.ts +9 -12
- package/plugins/tailwindcss-lsp.ts +9 -12
- package/plugins/templ-lsp.ts +9 -12
- package/plugins/terraform-lsp.ts +9 -12
- package/plugins/theme_editor.i18n.json +98 -14
- package/plugins/theme_editor.ts +156 -209
- package/plugins/toml-lsp.ts +15 -22
- package/plugins/tsconfig.json +100 -0
- package/plugins/typescript-lsp.ts +15 -24
- package/plugins/typst-lsp.ts +15 -22
- package/plugins/vi_mode.ts +77 -290
- package/plugins/vue-lsp.ts +9 -12
- package/plugins/yaml-lsp.ts +15 -22
- package/plugins/zig-lsp.ts +9 -12
- package/themes/high-contrast.json +2 -2
- package/themes/nord.json +4 -0
- package/themes/solarized-dark.json +4 -0
package/plugins/lib/fresh.d.ts
CHANGED
|
@@ -70,6 +70,35 @@ interface MouseClickHookArgs {
|
|
|
70
70
|
/** 0-indexed byte column inside the buffer row. */
|
|
71
71
|
buffer_col: number | null;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Registry of typed plugin APIs surfaced through
|
|
75
|
+
* `editor.exportPluginApi` / `editor.getPluginApi`.
|
|
76
|
+
*
|
|
77
|
+
* Plugins that want their surface to be typed for downstream
|
|
78
|
+
* consumers augment this interface in their own source:
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* // in my_plugin.ts
|
|
82
|
+
* export type MyPluginApi = { doThing(): void };
|
|
83
|
+
* declare global {
|
|
84
|
+
* interface FreshPluginRegistry {
|
|
85
|
+
* "my-plugin": MyPluginApi;
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* `editor.getPluginApi("my-plugin")` then returns
|
|
91
|
+
* `MyPluginApi | null` without any `as`-cast on the consumer side.
|
|
92
|
+
* Plugins that skip the augmentation still work — the untyped
|
|
93
|
+
* `getPluginApi<T = unknown>(name: string): T | null` overload
|
|
94
|
+
* takes over.
|
|
95
|
+
*
|
|
96
|
+
* Each plugin's augmentation is emitted to
|
|
97
|
+
* `<config_dir>/types/plugins.d.ts` at load time (via oxc's
|
|
98
|
+
* isolated-declarations), so init.ts sees every loaded plugin's
|
|
99
|
+
* registry entry automatically.
|
|
100
|
+
*/
|
|
101
|
+
interface FreshPluginRegistry {}
|
|
73
102
|
type TextPropertyEntry = {
|
|
74
103
|
/**
|
|
75
104
|
* Text content for this entry
|
|
@@ -211,6 +240,44 @@ type ViewportInfo = {
|
|
|
211
240
|
*/
|
|
212
241
|
height: number;
|
|
213
242
|
};
|
|
243
|
+
type KeyEventPayload = {
|
|
244
|
+
/**
|
|
245
|
+
* Key name (e.g. `"a"`, `"escape"`, `"f1"`).
|
|
246
|
+
*/
|
|
247
|
+
key: string;
|
|
248
|
+
/**
|
|
249
|
+
* Ctrl held.
|
|
250
|
+
*/
|
|
251
|
+
ctrl: boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Alt held.
|
|
254
|
+
*/
|
|
255
|
+
alt: boolean;
|
|
256
|
+
/**
|
|
257
|
+
* Shift held (only meaningful for non-character keys; for
|
|
258
|
+
* printable characters the case is already encoded in `key`).
|
|
259
|
+
*/
|
|
260
|
+
shift: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* Super / Cmd / Meta held.
|
|
263
|
+
*/
|
|
264
|
+
meta: boolean;
|
|
265
|
+
};
|
|
266
|
+
type SplitSnapshot = {
|
|
267
|
+
/**
|
|
268
|
+
* Stable split identifier; matches the values used by
|
|
269
|
+
* `setSplitBuffer`, `focusSplit`, `getSplitByLabel`, etc.
|
|
270
|
+
*/
|
|
271
|
+
splitId: number;
|
|
272
|
+
/**
|
|
273
|
+
* Buffer currently shown in this split.
|
|
274
|
+
*/
|
|
275
|
+
bufferId: BufferId;
|
|
276
|
+
/**
|
|
277
|
+
* Viewport (top byte / dimensions) for this split's active buffer.
|
|
278
|
+
*/
|
|
279
|
+
viewport: ViewportInfo;
|
|
280
|
+
};
|
|
214
281
|
type LayoutHints = {
|
|
215
282
|
/**
|
|
216
283
|
* Optional compose width for centering/wrapping
|
|
@@ -343,6 +410,15 @@ type BufferInfo = {
|
|
|
343
410
|
* refreshing itself for a preview tab.
|
|
344
411
|
*/
|
|
345
412
|
is_preview: boolean;
|
|
413
|
+
/**
|
|
414
|
+
* Split ids that currently hold this buffer (empty when the buffer is
|
|
415
|
+
* open but not visible in any split — e.g. background-opened tabs
|
|
416
|
+
* that haven't been focused). Lets plugins implement "focus existing
|
|
417
|
+
* buffer if visible, else open new" without having to track split
|
|
418
|
+
* ids across editor restarts (which reassign them). The list is a
|
|
419
|
+
* snapshot at the last `update_plugin_state_snapshot` tick.
|
|
420
|
+
*/
|
|
421
|
+
splits: number[];
|
|
346
422
|
};
|
|
347
423
|
type JsDiagnostic = {
|
|
348
424
|
/**
|
|
@@ -497,6 +573,15 @@ type CreateTerminalOptions = {
|
|
|
497
573
|
* Whether to focus the new terminal split (default: true)
|
|
498
574
|
*/
|
|
499
575
|
focus?: boolean;
|
|
576
|
+
/**
|
|
577
|
+
* Whether this terminal is part of the user's persisted workspace.
|
|
578
|
+
* Defaults to `false` for plugin-created terminals — they are typically
|
|
579
|
+
* one-off tool UIs (rebuilds, exec shells, build output) and should
|
|
580
|
+
* start with empty scrollback on each invocation. Set to `true` only
|
|
581
|
+
* when the plugin owns a terminal that the user should see restored
|
|
582
|
+
* across editor restarts.
|
|
583
|
+
*/
|
|
584
|
+
persistent?: boolean;
|
|
500
585
|
};
|
|
501
586
|
type CursorInfo = {
|
|
502
587
|
/**
|
|
@@ -584,6 +669,56 @@ type GrammarInfoSnapshot = {
|
|
|
584
669
|
*/
|
|
585
670
|
short_name: string | null;
|
|
586
671
|
};
|
|
672
|
+
type AnimationRect = {
|
|
673
|
+
x: number;
|
|
674
|
+
y: number;
|
|
675
|
+
width: number;
|
|
676
|
+
height: number;
|
|
677
|
+
};
|
|
678
|
+
type PluginAnimationEdge = "top" | "bottom" | "left" | "right";
|
|
679
|
+
type PluginAnimationKind = {
|
|
680
|
+
"kind": "slideIn";
|
|
681
|
+
from: PluginAnimationEdge;
|
|
682
|
+
durationMs: number;
|
|
683
|
+
delayMs: number;
|
|
684
|
+
};
|
|
685
|
+
type AuthorityFilesystem = {
|
|
686
|
+
kind: "local";
|
|
687
|
+
};
|
|
688
|
+
type AuthoritySpawner = {
|
|
689
|
+
kind: "local";
|
|
690
|
+
} | {
|
|
691
|
+
kind: "docker-exec";
|
|
692
|
+
container_id: string;
|
|
693
|
+
user?: string | null;
|
|
694
|
+
workspace?: string | null;
|
|
695
|
+
env?: [string, string][];
|
|
696
|
+
};
|
|
697
|
+
type AuthorityTerminalWrapper = {
|
|
698
|
+
kind: "host-shell";
|
|
699
|
+
} | {
|
|
700
|
+
kind: "explicit";
|
|
701
|
+
command: string;
|
|
702
|
+
args: string[];
|
|
703
|
+
manages_cwd?: boolean;
|
|
704
|
+
};
|
|
705
|
+
type AuthorityPayload = {
|
|
706
|
+
filesystem: AuthorityFilesystem;
|
|
707
|
+
spawner: AuthoritySpawner;
|
|
708
|
+
terminal_wrapper: AuthorityTerminalWrapper;
|
|
709
|
+
display_label?: string;
|
|
710
|
+
/**
|
|
711
|
+
* Optional host↔remote workspace path mapping. The dev-container
|
|
712
|
+
* authority sets both roots (editor.getCwd() on host;
|
|
713
|
+
* remoteWorkspaceFolder on container) so LSP URIs translate at the
|
|
714
|
+
* host/container boundary. Local and SSH authorities omit it.
|
|
715
|
+
*/
|
|
716
|
+
path_translation?: PathTranslationSpec;
|
|
717
|
+
};
|
|
718
|
+
type PathTranslationSpec = {
|
|
719
|
+
host_root: string;
|
|
720
|
+
remote_root: string;
|
|
721
|
+
};
|
|
587
722
|
type BackgroundProcessResult = {
|
|
588
723
|
/**
|
|
589
724
|
* Unique process ID for later reference
|
|
@@ -808,6 +943,21 @@ type LspServerPackConfig = {
|
|
|
808
943
|
*/
|
|
809
944
|
processLimits: ProcessLimitsPackConfig | null;
|
|
810
945
|
};
|
|
946
|
+
type RemoteIndicatorStatePayload = {
|
|
947
|
+
kind: "local";
|
|
948
|
+
} | {
|
|
949
|
+
kind: "connecting";
|
|
950
|
+
label?: string | null;
|
|
951
|
+
} | {
|
|
952
|
+
kind: "connected";
|
|
953
|
+
label?: string | null;
|
|
954
|
+
} | {
|
|
955
|
+
kind: "failed_attach";
|
|
956
|
+
error?: string | null;
|
|
957
|
+
} | {
|
|
958
|
+
kind: "disconnected";
|
|
959
|
+
label?: string | null;
|
|
960
|
+
};
|
|
811
961
|
type ReplaceResult = {
|
|
812
962
|
/**
|
|
813
963
|
* Number of replacements made
|
|
@@ -860,6 +1010,30 @@ interface EditorAPI {
|
|
|
860
1010
|
*/
|
|
861
1011
|
apiVersion(): number;
|
|
862
1012
|
/**
|
|
1013
|
+
* The name of the plugin this `editor` handle belongs to. Used by the
|
|
1014
|
+
* M3 plugin-API plane (`exportPluginApi` tags the exporter). Plugin
|
|
1015
|
+
* authors generally don't call this directly.
|
|
1016
|
+
*/
|
|
1017
|
+
pluginName(): string;
|
|
1018
|
+
/**
|
|
1019
|
+
* Publish a typed API surface under `name`. Another plugin (typically
|
|
1020
|
+
* `init.ts`) can reach it later via `getPluginApi(name)`. Calling
|
|
1021
|
+
* again with the same `name` replaces the previous registration
|
|
1022
|
+
* (idempotent — reload works). Exports are auto-dropped when the
|
|
1023
|
+
* calling plugin is unloaded.
|
|
1024
|
+
*
|
|
1025
|
+
* Returns `true` on success. Rejects with a TypeError if `name` is
|
|
1026
|
+
* empty or `api` is not an object (functions and primitives are not
|
|
1027
|
+
* valid API surfaces — only objects).
|
|
1028
|
+
*/
|
|
1029
|
+
exportPluginApi(name: string, api: unknown): boolean;
|
|
1030
|
+
/**
|
|
1031
|
+
* Look up a plugin API previously published via `exportPluginApi`.
|
|
1032
|
+
* Returns the api object (restored into the caller's context) or
|
|
1033
|
+
* `null` if no plugin exports under that name.
|
|
1034
|
+
*/
|
|
1035
|
+
getPluginApi(name: string): unknown | null;
|
|
1036
|
+
/**
|
|
863
1037
|
* Get the active buffer ID (0 if none)
|
|
864
1038
|
*/
|
|
865
1039
|
getActiveBufferId(): number;
|
|
@@ -957,6 +1131,15 @@ interface EditorAPI {
|
|
|
957
1131
|
*/
|
|
958
1132
|
getViewport(): ViewportInfo | null;
|
|
959
1133
|
/**
|
|
1134
|
+
* List every split with its active buffer and viewport.
|
|
1135
|
+
*
|
|
1136
|
+
* Plugins that need to operate on every visible buffer
|
|
1137
|
+
* simultaneously (multi-split flash labels, syncing decorations
|
|
1138
|
+
* across panes, …) iterate this list rather than only seeing
|
|
1139
|
+
* `getViewport()`'s active-split data. Order is unspecified.
|
|
1140
|
+
*/
|
|
1141
|
+
listSplits(): SplitSnapshot[];
|
|
1142
|
+
/**
|
|
960
1143
|
* Get the line number (0-indexed) of the primary cursor
|
|
961
1144
|
*/
|
|
962
1145
|
getCursorLine(): number;
|
|
@@ -1029,6 +1212,21 @@ interface EditorAPI {
|
|
|
1029
1212
|
*/
|
|
1030
1213
|
closeBuffer(bufferId: number): boolean;
|
|
1031
1214
|
/**
|
|
1215
|
+
* Start a frame-buffer animation over an arbitrary screen region.
|
|
1216
|
+
* Returns an animation id usable with `cancelAnimation`.
|
|
1217
|
+
*/
|
|
1218
|
+
animateArea(rect: AnimationRect, kind: PluginAnimationKind): number;
|
|
1219
|
+
/**
|
|
1220
|
+
* Start an animation over the on-screen Rect currently occupied by a
|
|
1221
|
+
* virtual buffer. No-op if the buffer is not visible.
|
|
1222
|
+
*/
|
|
1223
|
+
animateVirtualBuffer(bufferId: number, kind: PluginAnimationKind): number;
|
|
1224
|
+
/**
|
|
1225
|
+
* Cancel an animation previously started via `animateArea` or
|
|
1226
|
+
* `animateVirtualBuffer`. No-op if the ID is unknown or already done.
|
|
1227
|
+
*/
|
|
1228
|
+
cancelAnimation(id: number): boolean;
|
|
1229
|
+
/**
|
|
1032
1230
|
* Subscribe to an editor event
|
|
1033
1231
|
*/
|
|
1034
1232
|
on(eventName: string, handlerName: string): void;
|
|
@@ -1045,8 +1243,26 @@ interface EditorAPI {
|
|
|
1045
1243
|
*/
|
|
1046
1244
|
getCwd(): string;
|
|
1047
1245
|
/**
|
|
1246
|
+
* Get the active authority's display label.
|
|
1247
|
+
*
|
|
1248
|
+
* Empty means the local (default) authority. A non-empty value
|
|
1249
|
+
* means a plugin-installed or SSH authority is in effect (e.g.
|
|
1250
|
+
* `"Container:abc123def456"` for a devcontainer). Intended as a
|
|
1251
|
+
* simple "am I already attached?" check that survives editor
|
|
1252
|
+
* restarts — the label lives on the `Editor` state snapshot so it
|
|
1253
|
+
* is fresh after the authority-transition restart flow.
|
|
1254
|
+
*/
|
|
1255
|
+
getAuthorityLabel(): string;
|
|
1256
|
+
/**
|
|
1048
1257
|
* Join path components (variadic - accepts multiple string arguments)
|
|
1049
1258
|
* Always uses forward slashes for cross-platform consistency (like Node.js path.posix.join)
|
|
1259
|
+
*
|
|
1260
|
+
* Preserves up to 2 leading slashes, which matters on Windows: Rust's
|
|
1261
|
+
* `Path::canonicalize` returns `\\?\`-prefixed paths, and `editor.getCwd()`
|
|
1262
|
+
* surfaces that to plugin code verbatim. After the backslash→slash
|
|
1263
|
+
* normalization the prefix becomes `//?/C:/...`; collapsing the leading
|
|
1264
|
+
* `//` to a single `/` yields `/?/C:/...`, which every filesystem API on
|
|
1265
|
+
* Windows rejects, breaking `findConfig()`-style plugin logic.
|
|
1050
1266
|
*/
|
|
1051
1267
|
pathJoin(...parts: string[]): string;
|
|
1052
1268
|
/**
|
|
@@ -1129,6 +1345,17 @@ interface EditorAPI {
|
|
|
1129
1345
|
*/
|
|
1130
1346
|
getTempDir(): string;
|
|
1131
1347
|
/**
|
|
1348
|
+
* Parse a JSONC (JSON with comments) string into a JS value.
|
|
1349
|
+
*
|
|
1350
|
+
* Accepts the JSONC superset: line and block comments, trailing
|
|
1351
|
+
* commas, single-quoted strings, and unquoted object keys — matching
|
|
1352
|
+
* devcontainer.json / tsconfig.json / VS Code settings.json.
|
|
1353
|
+
*
|
|
1354
|
+
* Throws a JS error (catchable with try/catch) when the input is not
|
|
1355
|
+
* valid JSONC, like `JSON.parse` does for invalid JSON.
|
|
1356
|
+
*/
|
|
1357
|
+
parseJsonc(text: string): unknown;
|
|
1358
|
+
/**
|
|
1132
1359
|
* Get current config as JS object.
|
|
1133
1360
|
*
|
|
1134
1361
|
* The snapshot holds an `Arc<serde_json::Value>` that was serialized
|
|
@@ -1146,6 +1373,21 @@ interface EditorAPI {
|
|
|
1146
1373
|
*/
|
|
1147
1374
|
reloadConfig(): void;
|
|
1148
1375
|
/**
|
|
1376
|
+
* Set a single config setting in the runtime layer for this session.
|
|
1377
|
+
*
|
|
1378
|
+
* `path` is dot-separated (e.g. `"editor.tab_size"`). `value` is any JSON
|
|
1379
|
+
* value in the shape the setting expects. The write lives in an
|
|
1380
|
+
* in-memory layer scoped to the calling plugin — it does not modify
|
|
1381
|
+
* `config.json`, and unloading the plugin (or reloading init.ts) drops
|
|
1382
|
+
* it. Intended use is `init.ts` running a conditional:
|
|
1383
|
+
* `if (editor.getEnv("SSH_TTY")) editor.setSetting("terminal.mouse", false);`
|
|
1384
|
+
*
|
|
1385
|
+
* Returns `true` if the write was queued. The actual update is
|
|
1386
|
+
* asynchronous; a subsequent `getConfig()` will reflect it after the
|
|
1387
|
+
* editor processes the command.
|
|
1388
|
+
*/
|
|
1389
|
+
setSetting(path: string, value: unknown): boolean;
|
|
1390
|
+
/**
|
|
1149
1391
|
* Reload theme registry from disk
|
|
1150
1392
|
* Call this after installing theme packages or saving new themes
|
|
1151
1393
|
*/
|
|
@@ -1197,6 +1439,17 @@ interface EditorAPI {
|
|
|
1197
1439
|
*/
|
|
1198
1440
|
applyTheme(themeName: string): boolean;
|
|
1199
1441
|
/**
|
|
1442
|
+
* Override theme colors in-memory for the running session. `overrides`
|
|
1443
|
+
* is a JS object mapping `"section.field"` keys (same namespace as
|
|
1444
|
+
* `getThemeSchema`) to `[r, g, b]` triplets (0–255 each).
|
|
1445
|
+
*
|
|
1446
|
+
* Unknown keys are dropped silently; out-of-range values are clamped
|
|
1447
|
+
* to `0..=255`. Overrides survive until the next `applyTheme` call
|
|
1448
|
+
* (which replaces the whole `Theme`). Intended for fast animation
|
|
1449
|
+
* loops from `init.ts` — no disk I/O, no theme-registry rescan.
|
|
1450
|
+
*/
|
|
1451
|
+
overrideThemeColors(overrides: unknown): boolean;
|
|
1452
|
+
/**
|
|
1200
1453
|
* Get theme schema as JS object
|
|
1201
1454
|
*/
|
|
1202
1455
|
getThemeSchema(): unknown;
|
|
@@ -1380,6 +1633,14 @@ interface EditorAPI {
|
|
|
1380
1633
|
*/
|
|
1381
1634
|
removeVirtualText(bufferId: number, virtualTextId: string): boolean;
|
|
1382
1635
|
/**
|
|
1636
|
+
* Add styled virtual text — richer form of `addVirtualText` whose
|
|
1637
|
+
* `options` accepts an `addOverlay`-style record: `fg`/`bg` may
|
|
1638
|
+
* be RGB arrays or theme-key strings, plus `bold`/`italic`. Theme
|
|
1639
|
+
* keys are resolved at render time so the label follows theme
|
|
1640
|
+
* changes live.
|
|
1641
|
+
*/
|
|
1642
|
+
addVirtualTextStyled(bufferId: number, virtualTextId: string, position: number, text: string, options: Record<string, unknown>, before: boolean): boolean;
|
|
1643
|
+
/**
|
|
1383
1644
|
* Remove virtual texts whose ID starts with the given prefix
|
|
1384
1645
|
*/
|
|
1385
1646
|
removeVirtualTextsByPrefix(bufferId: number, prefix: string): boolean;
|
|
@@ -1411,6 +1672,38 @@ interface EditorAPI {
|
|
|
1411
1672
|
*/
|
|
1412
1673
|
startPrompt(label: string, promptType: string): boolean;
|
|
1413
1674
|
/**
|
|
1675
|
+
* Begin a key-capture window for the calling plugin.
|
|
1676
|
+
*
|
|
1677
|
+
* Pair with `endKeyCapture()` around any `getNextKey()` loop.
|
|
1678
|
+
* While capture is active, keys arriving between two
|
|
1679
|
+
* `getNextKey()` calls are buffered in-order rather than
|
|
1680
|
+
* falling through to the buffer / mode bindings, so fast typing,
|
|
1681
|
+
* pastes, or held-key auto-repeat are delivered losslessly.
|
|
1682
|
+
* Without this, a plugin's input loop has a race where keys
|
|
1683
|
+
* typed while the plugin is mid-redraw can leak into the editor.
|
|
1684
|
+
*/
|
|
1685
|
+
beginKeyCapture(): boolean;
|
|
1686
|
+
/**
|
|
1687
|
+
* End the key-capture window and discard any unconsumed buffered
|
|
1688
|
+
* keys. Call from a `finally` block so capture is released even
|
|
1689
|
+
* if the plugin's loop throws.
|
|
1690
|
+
*/
|
|
1691
|
+
endKeyCapture(): boolean;
|
|
1692
|
+
/**
|
|
1693
|
+
* Wait for the next keypress and resolve with a `KeyEventPayload`.
|
|
1694
|
+
*
|
|
1695
|
+
* While the returned promise is pending the editor consumes the
|
|
1696
|
+
* next key and resolves it; the key does not propagate to mode
|
|
1697
|
+
* bindings or other dispatch. Multiple in-flight requests across
|
|
1698
|
+
* plugins are FIFO. Designed for short input loops (flash labels,
|
|
1699
|
+
* vi find-char, replace-char) that would otherwise need to bind
|
|
1700
|
+
* every printable key in `defineMode`.
|
|
1701
|
+
*
|
|
1702
|
+
* For lossless capture against fast typing or paste, wrap the
|
|
1703
|
+
* loop with `beginKeyCapture()` / `endKeyCapture()`.
|
|
1704
|
+
*/
|
|
1705
|
+
getNextKey(): Promise<KeyEventPayload>;
|
|
1706
|
+
/**
|
|
1414
1707
|
* Start a prompt with initial value
|
|
1415
1708
|
*/
|
|
1416
1709
|
startPromptWithInitial(label: string, promptType: string, initialValue: string): boolean;
|
|
@@ -1610,6 +1903,56 @@ interface EditorAPI {
|
|
|
1610
1903
|
*/
|
|
1611
1904
|
spawnProcess(command: string, args: string[], cwd?: string): ProcessHandle<SpawnResult>;
|
|
1612
1905
|
/**
|
|
1906
|
+
* Spawn a process on the host regardless of the active authority.
|
|
1907
|
+
*
|
|
1908
|
+
* Intended for plugin internals that must run host-side work
|
|
1909
|
+
* (e.g. `devcontainer up`) before installing an authority that
|
|
1910
|
+
* would otherwise route the spawn elsewhere. Same calling shape
|
|
1911
|
+
* as `spawnProcess`.
|
|
1912
|
+
*/
|
|
1913
|
+
spawnHostProcess(command: string, args: string[], cwd?: string): ProcessHandle<SpawnResult>;
|
|
1914
|
+
/**
|
|
1915
|
+
* Install a new authority via an opaque payload.
|
|
1916
|
+
*
|
|
1917
|
+
* The payload is a JS object describing filesystem + spawner +
|
|
1918
|
+
* terminal wrapper + display label. The canonical schema lives in
|
|
1919
|
+
* the `AuthorityPayload` type in `fresh-editor`; plugins should
|
|
1920
|
+
* hand-build objects that match it. Fire-and-forget: the editor
|
|
1921
|
+
* restarts as part of the transition, so the plugin is reloaded
|
|
1922
|
+
* before any follow-up work can run on this call's return value.
|
|
1923
|
+
*/
|
|
1924
|
+
setAuthority(payload: AuthorityPayload): boolean;
|
|
1925
|
+
/**
|
|
1926
|
+
* Restore the default local authority. Same restart semantics as
|
|
1927
|
+
* `setAuthority`.
|
|
1928
|
+
*/
|
|
1929
|
+
clearAuthority(): void;
|
|
1930
|
+
/**
|
|
1931
|
+
* Override the Remote Indicator's displayed state. Plugins call
|
|
1932
|
+
* this to surface lifecycle transitions that the authority layer
|
|
1933
|
+
* doesn't know about yet — "Connecting" while `devcontainer up`
|
|
1934
|
+
* runs, "FailedAttach" after a non-zero exit, etc.
|
|
1935
|
+
*
|
|
1936
|
+
* Accepts a tagged JS object:
|
|
1937
|
+
* ```ts
|
|
1938
|
+
* editor.setRemoteIndicatorState({ kind: "connecting", label: "Building" });
|
|
1939
|
+
* editor.setRemoteIndicatorState({ kind: "failed_attach", error: "exit 1" });
|
|
1940
|
+
* editor.setRemoteIndicatorState({ kind: "connected", label: "Container:abc" });
|
|
1941
|
+
* editor.setRemoteIndicatorState({ kind: "local" });
|
|
1942
|
+
* ```
|
|
1943
|
+
*
|
|
1944
|
+
* The override sticks until replaced or cleared via
|
|
1945
|
+
* `clearRemoteIndicatorState`. Editor restart (e.g. on
|
|
1946
|
+
* `setAuthority`) resets it — plugins must reassert after a
|
|
1947
|
+
* post-restart init if they want the override to persist.
|
|
1948
|
+
*/
|
|
1949
|
+
setRemoteIndicatorState(state: RemoteIndicatorStatePayload): boolean;
|
|
1950
|
+
/**
|
|
1951
|
+
* Drop any active Remote Indicator override. Safe to call even
|
|
1952
|
+
* without a prior `setRemoteIndicatorState`.
|
|
1953
|
+
*/
|
|
1954
|
+
clearRemoteIndicatorState(): void;
|
|
1955
|
+
/**
|
|
1613
1956
|
* Wait for a process to complete and get its result (async)
|
|
1614
1957
|
*/
|
|
1615
1958
|
spawnProcessWait(processId: number): Promise<SpawnResult>;
|
|
@@ -1700,3 +2043,263 @@ interface EditorAPI {
|
|
|
1700
2043
|
enabled: boolean;
|
|
1701
2044
|
}>>;
|
|
1702
2045
|
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Typed overload of `editor.getPluginApi`. When the caller passes a
|
|
2048
|
+
* key that some loaded plugin declared in `FreshPluginRegistry`, the
|
|
2049
|
+
* return type is narrowed to that plugin's API. Unknown names fall
|
|
2050
|
+
* through to the untyped `unknown | null` signature.
|
|
2051
|
+
*/
|
|
2052
|
+
interface EditorAPI {
|
|
2053
|
+
getPluginApi<K extends keyof FreshPluginRegistry>(name: K): FreshPluginRegistry[K] | null;
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Maps every hook event name to its payload type.
|
|
2057
|
+
*
|
|
2058
|
+
* Payloads match the flat JSON produced by `hook_args_to_json` on the Rust
|
|
2059
|
+
* side (`HookArgs` is `#[serde(untagged)]`, so each variant serializes as its
|
|
2060
|
+
* fields only). The TypeScript types here are derived directly from the Rust
|
|
2061
|
+
* field definitions and must be kept in sync with `fresh-core/src/hooks.rs`.
|
|
2062
|
+
*
|
|
2063
|
+
* `action` in `pre_command`/`post_command` is the serde JSON of the `Action`
|
|
2064
|
+
* enum: unit variants serialize as a plain string (e.g. `"MoveLeft"`),
|
|
2065
|
+
* tuple variants as a single-key object (e.g. `{"InsertChar": "a"}`).
|
|
2066
|
+
*/
|
|
2067
|
+
interface HookEventMap {
|
|
2068
|
+
// ── lifecycle ────────────────────────────────────────────────────────────
|
|
2069
|
+
editor_initialized: Record<string, never>;
|
|
2070
|
+
plugins_loaded: Record<string, never>;
|
|
2071
|
+
ready: Record<string, never>;
|
|
2072
|
+
focus_gained: Record<string, never>;
|
|
2073
|
+
authority_changed: {
|
|
2074
|
+
label: string;
|
|
2075
|
+
};
|
|
2076
|
+
// ── buffer lifecycle ─────────────────────────────────────────────────────
|
|
2077
|
+
buffer_activated: {
|
|
2078
|
+
buffer_id: number;
|
|
2079
|
+
};
|
|
2080
|
+
buffer_deactivated: {
|
|
2081
|
+
buffer_id: number;
|
|
2082
|
+
};
|
|
2083
|
+
buffer_closed: {
|
|
2084
|
+
buffer_id: number;
|
|
2085
|
+
};
|
|
2086
|
+
// ── file I/O ─────────────────────────────────────────────────────────────
|
|
2087
|
+
before_file_open: {
|
|
2088
|
+
path: string;
|
|
2089
|
+
};
|
|
2090
|
+
after_file_open: {
|
|
2091
|
+
path: string;
|
|
2092
|
+
buffer_id: number;
|
|
2093
|
+
};
|
|
2094
|
+
before_file_save: {
|
|
2095
|
+
path: string;
|
|
2096
|
+
buffer_id: number;
|
|
2097
|
+
};
|
|
2098
|
+
after_file_save: {
|
|
2099
|
+
path: string;
|
|
2100
|
+
buffer_id: number;
|
|
2101
|
+
};
|
|
2102
|
+
// ── text edits ───────────────────────────────────────────────────────────
|
|
2103
|
+
before_insert: {
|
|
2104
|
+
buffer_id: number;
|
|
2105
|
+
position: number;
|
|
2106
|
+
text: string;
|
|
2107
|
+
};
|
|
2108
|
+
after_insert: {
|
|
2109
|
+
buffer_id: number;
|
|
2110
|
+
position: number;
|
|
2111
|
+
text: string;
|
|
2112
|
+
affected_start: number;
|
|
2113
|
+
affected_end: number;
|
|
2114
|
+
start_line: number;
|
|
2115
|
+
end_line: number;
|
|
2116
|
+
lines_added: number;
|
|
2117
|
+
};
|
|
2118
|
+
before_delete: {
|
|
2119
|
+
buffer_id: number;
|
|
2120
|
+
start: number;
|
|
2121
|
+
end: number;
|
|
2122
|
+
};
|
|
2123
|
+
after_delete: {
|
|
2124
|
+
buffer_id: number;
|
|
2125
|
+
start: number;
|
|
2126
|
+
end: number;
|
|
2127
|
+
deleted_text: string;
|
|
2128
|
+
affected_start: number;
|
|
2129
|
+
deleted_len: number;
|
|
2130
|
+
start_line: number;
|
|
2131
|
+
end_line: number;
|
|
2132
|
+
lines_removed: number;
|
|
2133
|
+
};
|
|
2134
|
+
// ── cursor & viewport ────────────────────────────────────────────────────
|
|
2135
|
+
cursor_moved: {
|
|
2136
|
+
buffer_id: number;
|
|
2137
|
+
cursor_id: number;
|
|
2138
|
+
old_position: number;
|
|
2139
|
+
new_position: number;
|
|
2140
|
+
line: number;
|
|
2141
|
+
text_properties: Record<string, unknown>[];
|
|
2142
|
+
};
|
|
2143
|
+
viewport_changed: {
|
|
2144
|
+
split_id: number;
|
|
2145
|
+
buffer_id: number;
|
|
2146
|
+
top_byte: number;
|
|
2147
|
+
top_line: number | null;
|
|
2148
|
+
width: number;
|
|
2149
|
+
height: number;
|
|
2150
|
+
};
|
|
2151
|
+
// ── rendering ────────────────────────────────────────────────────────────
|
|
2152
|
+
render_start: {
|
|
2153
|
+
buffer_id: number;
|
|
2154
|
+
};
|
|
2155
|
+
render_line: {
|
|
2156
|
+
buffer_id: number;
|
|
2157
|
+
line_number: number;
|
|
2158
|
+
byte_start: number;
|
|
2159
|
+
byte_end: number;
|
|
2160
|
+
content: string;
|
|
2161
|
+
};
|
|
2162
|
+
lines_changed: {
|
|
2163
|
+
buffer_id: number;
|
|
2164
|
+
lines: {
|
|
2165
|
+
line_number: number;
|
|
2166
|
+
byte_start: number;
|
|
2167
|
+
byte_end: number;
|
|
2168
|
+
content: string;
|
|
2169
|
+
}[];
|
|
2170
|
+
};
|
|
2171
|
+
view_transform_request: {
|
|
2172
|
+
buffer_id: number;
|
|
2173
|
+
split_id: number;
|
|
2174
|
+
viewport_start: number;
|
|
2175
|
+
viewport_end: number;
|
|
2176
|
+
tokens: ViewTokenWire[];
|
|
2177
|
+
cursor_positions: number[];
|
|
2178
|
+
};
|
|
2179
|
+
// ── commands ─────────────────────────────────────────────────────────────
|
|
2180
|
+
pre_command: {
|
|
2181
|
+
action: string | Record<string, unknown>;
|
|
2182
|
+
};
|
|
2183
|
+
post_command: {
|
|
2184
|
+
action: string | Record<string, unknown>;
|
|
2185
|
+
};
|
|
2186
|
+
idle: {
|
|
2187
|
+
milliseconds: number;
|
|
2188
|
+
};
|
|
2189
|
+
resize: {
|
|
2190
|
+
width: number;
|
|
2191
|
+
height: number;
|
|
2192
|
+
};
|
|
2193
|
+
// ── prompts ──────────────────────────────────────────────────────────────
|
|
2194
|
+
prompt_changed: {
|
|
2195
|
+
prompt_type: string;
|
|
2196
|
+
input: string;
|
|
2197
|
+
};
|
|
2198
|
+
prompt_confirmed: {
|
|
2199
|
+
prompt_type: string;
|
|
2200
|
+
input: string;
|
|
2201
|
+
selected_index: number | null;
|
|
2202
|
+
};
|
|
2203
|
+
prompt_cancelled: {
|
|
2204
|
+
prompt_type: string;
|
|
2205
|
+
input: string;
|
|
2206
|
+
};
|
|
2207
|
+
prompt_selection_changed: {
|
|
2208
|
+
prompt_type: string;
|
|
2209
|
+
selected_index: number;
|
|
2210
|
+
};
|
|
2211
|
+
// ── mouse ────────────────────────────────────────────────────────────────
|
|
2212
|
+
mouse_click: MouseClickHookArgs;
|
|
2213
|
+
mouse_move: {
|
|
2214
|
+
column: number;
|
|
2215
|
+
row: number;
|
|
2216
|
+
content_x: number;
|
|
2217
|
+
content_y: number;
|
|
2218
|
+
};
|
|
2219
|
+
mouse_scroll: {
|
|
2220
|
+
buffer_id: number;
|
|
2221
|
+
delta: number;
|
|
2222
|
+
col: number;
|
|
2223
|
+
row: number;
|
|
2224
|
+
};
|
|
2225
|
+
// ── LSP ──────────────────────────────────────────────────────────────────
|
|
2226
|
+
diagnostics_updated: {
|
|
2227
|
+
uri: string;
|
|
2228
|
+
count: number;
|
|
2229
|
+
};
|
|
2230
|
+
lsp_references: {
|
|
2231
|
+
symbol: string;
|
|
2232
|
+
locations: {
|
|
2233
|
+
file: string;
|
|
2234
|
+
line: number;
|
|
2235
|
+
column: number;
|
|
2236
|
+
}[];
|
|
2237
|
+
};
|
|
2238
|
+
lsp_server_request: {
|
|
2239
|
+
language: string;
|
|
2240
|
+
method: string;
|
|
2241
|
+
server_command: string;
|
|
2242
|
+
params: string | null;
|
|
2243
|
+
};
|
|
2244
|
+
lsp_server_error: {
|
|
2245
|
+
language: string;
|
|
2246
|
+
server_command: string;
|
|
2247
|
+
error_type: string;
|
|
2248
|
+
message: string;
|
|
2249
|
+
};
|
|
2250
|
+
lsp_status_clicked: {
|
|
2251
|
+
language: string;
|
|
2252
|
+
has_error: boolean;
|
|
2253
|
+
missing_servers: string[];
|
|
2254
|
+
user_dismissed: boolean;
|
|
2255
|
+
};
|
|
2256
|
+
// ── UI events ────────────────────────────────────────────────────────────
|
|
2257
|
+
action_popup_result: {
|
|
2258
|
+
popup_id: string;
|
|
2259
|
+
action_id: string;
|
|
2260
|
+
};
|
|
2261
|
+
process_output: {
|
|
2262
|
+
process_id: number;
|
|
2263
|
+
data: string;
|
|
2264
|
+
};
|
|
2265
|
+
language_changed: {
|
|
2266
|
+
buffer_id: number;
|
|
2267
|
+
language: string;
|
|
2268
|
+
};
|
|
2269
|
+
theme_inspect_key: {
|
|
2270
|
+
theme_name: string;
|
|
2271
|
+
key: string;
|
|
2272
|
+
};
|
|
2273
|
+
keyboard_shortcuts: {
|
|
2274
|
+
bindings: {
|
|
2275
|
+
key: string;
|
|
2276
|
+
action: string;
|
|
2277
|
+
}[];
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Typed overloads of `editor.on` / `editor.off`.
|
|
2282
|
+
*
|
|
2283
|
+
* When the event name is a key of `HookEventMap` the handler receives a
|
|
2284
|
+
* fully-typed payload — TypeScript will flag misspelled field accesses at
|
|
2285
|
+
* compile time. Unknown event names fall through to the untyped base
|
|
2286
|
+
* signatures in the EditorAPI interface.
|
|
2287
|
+
*
|
|
2288
|
+
* Both function-value and handler-name forms are supported:
|
|
2289
|
+
*
|
|
2290
|
+
* ```ts
|
|
2291
|
+
* editor.on("buffer_activated", (args) => { /* args.buffer_id is number *\/ });
|
|
2292
|
+
* editor.on("buffer_activated", "myHandler"); // registerHandler("myHandler", fn)
|
|
2293
|
+
* ```
|
|
2294
|
+
*/
|
|
2295
|
+
interface EditorAPI {
|
|
2296
|
+
on<K extends keyof HookEventMap>(eventName: K, handler: (args: HookEventMap[K]) => boolean | void | Promise<boolean | void>): void;
|
|
2297
|
+
on<K extends keyof HookEventMap>(eventName: K, handlerName: string): void;
|
|
2298
|
+
off<K extends keyof HookEventMap>(eventName: K, handler: (args: HookEventMap[K]) => boolean | void | Promise<boolean | void>): void;
|
|
2299
|
+
off<K extends keyof HookEventMap>(eventName: K, handlerName: string): void;
|
|
2300
|
+
/**
|
|
2301
|
+
* Create a buffer group: multiple panels appearing as one tab.
|
|
2302
|
+
* This is an async runtime binding (not a direct #[qjs] method).
|
|
2303
|
+
*/
|
|
2304
|
+
createBufferGroup(name: string, mode: string, layout: unknown): Promise<BufferGroupResult>;
|
|
2305
|
+
}
|