Fresh Editor Plugin API
This document describes the TypeScript API available to Fresh editor plugins.
Core Concepts
Buffers
A buffer holds text content and may or may not be associated with a file. Each buffer has a unique numeric ID that persists for the editor session. Buffers track their content, modification state, cursor positions, and path. All text operations (insert, delete, read) use byte offsets, not character indices.
Splits
A split is a viewport pane that displays a buffer. The editor can have multiple splits arranged in a tree layout. Each split shows exactly one buffer, but the same buffer can be displayed in multiple splits. Use split IDs to control which pane displays which buffer.
Virtual Buffers
Special buffers created by plugins to display structured data like search results, diagnostics, or git logs. Virtual buffers support text properties (metadata attached to text ranges) that plugins can query when the user selects a line. Unlike normal buffers, virtual buffers are typically read-only and not backed by files.
Text Properties
Metadata attached to text ranges in virtual buffers. Each entry has text content and a properties object with arbitrary key-value pairs. Use getTextPropertiesAtCursor to retrieve properties at the cursor position (e.g., to get file/line info for "go to").
Overlays
Visual decorations applied to buffer text without modifying content. Overlays can change text color and add underlines. Use overlay IDs to manage them; prefix IDs enable batch removal (e.g., "lint:" prefix for all linter highlights).
Modes
Keybinding contexts that determine how keypresses are interpreted. Each buffer has a mode (e.g., "normal", "insert", "special"). Custom modes can inherit from parents and define buffer-local keybindings. Virtual buffers typically use custom modes.
Types
SpawnResult
Result from spawnProcess
interface SpawnResult {
stdout: string;
stderr: string;
exit_code: number;
}| Field | Description |
|---|---|
stdout | Complete stdout as string. Newlines preserved; trailing newline included. |
stderr | Complete stderr as string. Contains error messages and warnings. |
exit_code | Process exit code. 0 usually means success; -1 if process was killed. |
BackgroundProcessResult
Result from spawnBackgroundProcess - just the process ID
interface BackgroundProcessResult {
process_id: number;
}| Field | Description |
|---|---|
process_id | Unique process ID for later reference (kill, status check) |
FileStat
File stat information
interface FileStat {
exists: boolean;
is_file: boolean;
is_dir: boolean;
size: number;
readonly: boolean;
}| Field | Description |
|---|---|
exists | Whether the path exists |
is_file | Whether the path is a file |
is_dir | Whether the path is a directory |
size | File size in bytes |
readonly | Whether the file is read-only |
BufferInfo
Buffer information
interface BufferInfo {
id: number;
path: string;
modified: boolean;
length: number;
}| Field | Description |
|---|---|
id | Unique buffer ID |
path | File path (empty string if no path) |
modified | Whether buffer has unsaved changes |
length | Buffer length in bytes |
TsBufferSavedDiff
Diff vs last save for a buffer
interface TsBufferSavedDiff {
equal: boolean;
byte_ranges: [number, number][];
line_ranges?: [number, number][] | null;
}SelectionRange
Selection range
interface SelectionRange {
start: number;
end: number;
}| Field | Description |
|---|---|
start | Start byte position |
end | End byte position |
CursorInfo
Cursor information with optional selection
interface CursorInfo {
position: number;
selection?: SelectionRange | null;
}| Field | Description |
|---|---|
position | Byte position of the cursor |
selection | Selection range if text is selected, null otherwise |
TsDiagnosticPosition
LSP diagnostic position
interface TsDiagnosticPosition {
line: number;
character: number;
}TsDiagnosticRange
LSP diagnostic range
interface TsDiagnosticRange {
start: TsDiagnosticPosition;
end: TsDiagnosticPosition;
}TsDiagnostic
LSP diagnostic item for TypeScript plugins
interface TsDiagnostic {
uri: string;
severity: number;
message: string;
source?: string | null;
range: TsDiagnosticRange;
}| Field | Description |
|---|---|
uri | File URI (e.g., "file:///path/to/file.rs") |
severity | Diagnostic severity: 1=Error, 2=Warning, 3=Info, 4=Hint |
message | Diagnostic message |
source | Source of the diagnostic (e.g., "rust-analyzer") |
range | Location range in the file |
ViewportInfo
Viewport information
interface ViewportInfo {
top_byte: number;
left_column: number;
width: number;
height: number;
}| Field | Description |
|---|---|
top_byte | Byte offset of the top-left visible position |
left_column | Column offset for horizontal scrolling |
width | Viewport width in columns |
height | Viewport height in rows |
PromptSuggestion
Suggestion for prompt autocomplete
interface PromptSuggestion {
text: string;
description?: string | null;
value?: string | null;
disabled?: boolean | null;
keybinding?: string | null;
}| Field | Description |
|---|---|
text | Display text for the suggestion |
description | Optional description shown alongside |
value | Optional value to use instead of text when selected |
disabled | Whether the suggestion is disabled |
keybinding | Optional keybinding hint |
DirEntry
Directory entry from readDir
interface DirEntry {
name: string;
is_file: boolean;
is_dir: boolean;
}| Field | Description |
|---|---|
name | Entry name only (not full path). Join with parent path to get absolute path. |
is_file | True if entry is a regular file |
is_dir | True if entry is a directory. Note: symlinks report the target type. |
TextPropertyEntry
Entry for virtual buffer content with embedded metadata
interface TextPropertyEntry {
text: string;
properties: Record<string, unknown>;
}| Field | Description |
|---|---|
text | Text to display. Include trailing newline for separate lines. |
properties | Arbitrary metadata queryable via getTextPropertiesAtCursor. |
CreateVirtualBufferResult
Result from createVirtualBufferInSplit
interface CreateVirtualBufferResult {
buffer_id: number;
split_id?: number | null;
}CreateVirtualBufferOptions
Configuration for createVirtualBufferInSplit
interface CreateVirtualBufferOptions {
name: string;
mode: string;
read_only: boolean;
entries: TextPropertyEntry[];
ratio: number;
direction?: string | null;
panel_id?: string | null;
show_line_numbers?: boolean | null;
show_cursors?: boolean | null;
editing_disabled?: boolean | null;
line_wrap?: boolean | null;
}| Field | Description |
|---|---|
name | Buffer name shown in status bar (convention: "Name") |
mode | Mode for keybindings; define with defineMode first |
read_only | Prevent text modifications |
entries | Content with embedded metadata |
ratio | Split ratio (0.3 = new pane gets 30% of space) |
direction | Split direction: "horizontal" (below) or "vertical" (side-by-side). Default: horizontal |
panel_id | If set and panel exists, update content instead of creating new buffer |
show_line_numbers | Show line numbers gutter (default: true) |
show_cursors | Show cursor in buffer (default: true) |
editing_disabled | Disable all editing commands (default: false) |
line_wrap | Enable/disable line wrapping (None = use global setting) |
CreateVirtualBufferInExistingSplitOptions
Options for creating a virtual buffer in an existing split
interface CreateVirtualBufferInExistingSplitOptions {
name: string;
mode: string;
read_only: boolean;
entries: TextPropertyEntry[];
split_id: number;
show_line_numbers?: boolean | null;
show_cursors?: boolean | null;
editing_disabled?: boolean | null;
line_wrap?: boolean | null;
}| Field | Description |
|---|---|
name | Display name (e.g., "Commit Details") |
mode | Mode name for buffer-local keybindings |
read_only | Whether the buffer is read-only |
entries | Entries with text and embedded properties |
split_id | Target split ID where the buffer should be displayed |
show_line_numbers | Whether to show line numbers in the buffer (default true) |
show_cursors | Whether to show cursors in the buffer (default true) |
editing_disabled | Whether editing is disabled for this buffer (default false) |
line_wrap | Enable/disable line wrapping (None = use global setting) |
CreateVirtualBufferInCurrentSplitOptions
Options for creating a virtual buffer in the current split as a new tab
interface CreateVirtualBufferInCurrentSplitOptions {
name: string;
mode: string;
read_only: boolean;
entries: TextPropertyEntry[];
show_line_numbers?: boolean | null;
show_cursors?: boolean | null;
editing_disabled?: boolean | null;
hidden_from_tabs?: boolean | null;
}| Field | Description |
|---|---|
name | Display name (e.g., "Help") |
mode | Mode name for buffer-local keybindings |
read_only | Whether the buffer is read-only |
entries | Entries with text and embedded properties |
show_line_numbers | Whether to show line numbers in the buffer (default false for help/docs) |
show_cursors | Whether to show cursors in the buffer (default true) |
editing_disabled | Whether editing is disabled for this buffer (default false) |
hidden_from_tabs | Whether this buffer should be hidden from tabs (for composite source buffers) |
TsCompositeLayoutConfig
Layout configuration for composite buffers
interface TsCompositeLayoutConfig {
layout_type: string;
ratios?: number[] | null;
show_separator?: boolean | null;
spacing?: u16 | null;
}| Field | Description |
|---|---|
layout_type | Layout type: "side-by-side", "stacked", or "unified" |
ratios | Relative widths for side-by-side layout (e.g., [0.5, 0.5]) |
show_separator | Show separator between panes |
spacing | Spacing between stacked panes |
TsCompositePaneStyle
Pane style configuration
interface TsCompositePaneStyle {
add_bg?: [number, number, number] | null;
remove_bg?: [number, number, number] | null;
modify_bg?: [number, number, number] | null;
gutter_style?: string | null;
}| Field | Description |
|---|---|
add_bg | Background color for added lines (RGB tuple) |
remove_bg | Background color for removed lines (RGB tuple) |
modify_bg | Background color for modified lines (RGB tuple) |
gutter_style | Gutter style: "line-numbers", "diff-markers", "both", "none" |
TsCompositeSourceConfig
Source pane configuration for composite buffers
interface TsCompositeSourceConfig {
buffer_id: number;
label?: string | null;
editable: boolean;
style?: TsCompositePaneStyle | null;
}| Field | Description |
|---|---|
buffer_id | Buffer ID to display in this pane |
label | Label for the pane (shown in header) |
editable | Whether the pane is editable |
style | Pane styling options |
TsCompositeHunk
Diff hunk configuration
interface TsCompositeHunk {
old_start: number;
old_count: number;
new_start: number;
new_count: number;
}| Field | Description |
|---|---|
old_start | Start line in old file (0-indexed) |
old_count | Number of lines in old file |
new_start | Start line in new file (0-indexed) |
new_count | Number of lines in new file |
CreateCompositeBufferOptions
Options for creating a composite buffer
interface CreateCompositeBufferOptions {
name: string;
mode: string;
layout: TsCompositeLayoutConfig;
sources: TsCompositeSourceConfig[];
hunks?: TsCompositeHunk[] | null;
}| Field | Description |
|---|---|
name | Display name for the composite buffer (shown in tab) |
mode | Mode for keybindings (e.g., "diff-view") |
layout | Layout configuration |
sources | Source panes to display |
hunks | Optional diff hunks for line alignment |
ActionSpecJs
JavaScript representation of ActionSpec (with optional count)
interface ActionSpecJs {
action: string;
count?: number | null;
}TsActionPopupAction
TypeScript struct for action popup action
interface TsActionPopupAction {
id: string;
label: string;
}TsActionPopupOptions
TypeScript struct for action popup options
interface TsActionPopupOptions {
id: string;
title: string;
message: string;
actions: TsActionPopupAction[];
}API Reference
Status and Logging
setStatus
Display a transient message in the editor's status bar The message will be shown until the next status update or user action. Use for feedback on completed operations (e.g., "File saved", "2 matches found").
setStatus(message: string): voidParameters:
| Name | Type | Description |
|---|---|---|
message | string | Text to display; keep short (status bar has limited width) |
debug
Log a debug message from a plugin Messages appear in log file when running with RUST_LOG=debug. Useful for plugin development and troubleshooting.
debug(message: string): voidParameters:
| Name | Type | Description |
|---|---|---|
message | string | Debug message; include context like function name and relevant values |
Buffer Queries
getThemeSchema
Get the theme JSON Schema for the theme editor Returns the raw JSON Schema generated by schemars for ThemeFile. The schema uses standard JSON Schema format with $ref for type references. Plugins are responsible for parsing the schema and resolving $ref references.
getThemeSchema(): unknowngetConfig
Get the current editor configuration Returns the merged configuration (user config file + compiled-in defaults). This is the runtime config that the editor is actually using, including all default values for LSP servers, languages, keybindings, etc.
getConfig(): unknowngetUserConfig
Get the user's configuration (only explicitly set values) Returns only the configuration from the user's config file. Fields not present here are using default values. Use this with getConfig() to determine which values are defaults.
getUserConfig(): unknowngetActiveBufferId
Get the buffer ID of the focused editor pane Returns 0 if no buffer is active (rare edge case). Use this ID with other buffer operations like insertText.
getActiveBufferId(): numbergetCursorPosition
Get the byte offset of the primary cursor in the active buffer Returns 0 if no cursor exists. For multi-cursor scenarios, use getAllCursors to get all cursor positions with selection info. Note: This is a byte offset, not a character index (UTF-8 matters).
getCursorPosition(): numbergetBufferPath
Get the absolute file path for a buffer Returns empty string for unsaved buffers or virtual buffers. The path is always absolute. Use this to determine file type, construct related paths, or display to the user.
getBufferPath(buffer_id: number): stringParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
getBufferLength
Get the total byte length of a buffer's content Returns 0 if buffer doesn't exist.
getBufferLength(buffer_id: number): numberParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
isBufferModified
Check if a buffer has been modified since last save Returns false if buffer doesn't exist or has never been saved. Virtual buffers are never considered modified.
isBufferModified(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
getCurrentLocale
Get the currently active locale
getCurrentLocale(): stringgetActiveSplitId
Get the ID of the focused split pane Use with focusSplit, setSplitBuffer, or createVirtualBufferInExistingSplit to manage split layouts.
getActiveSplitId(): numbergetCursorLine
Get the line number of the primary cursor (1-indexed) Line numbers start at 1. Returns 1 if no cursor exists. For byte offset use getCursorPosition instead.
getCursorLine(): numbergetAllCursorPositions
Get byte offsets of all cursors (multi-cursor support) Returns array of positions; empty if no cursors. Primary cursor is typically first. For selection info use getAllCursors instead.
getAllCursorPositions(): number[]isProcessRunning
Check if a background process is still running
isProcessRunning(#[bigint] process_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
#[bigint] process_id | number | - |
getHighlights
Compute syntax highlighting for a buffer range
getHighlights(buffer_id: number, start: number, end: number): Promise<TsHighlightSpan[]>Parameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | - |
start | number | - |
end | number | - |
getBufferSavedDiff
Get diff vs last saved snapshot for a buffer
getBufferSavedDiff(buffer_id: number): TsBufferSavedDiff | nullParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | - |
getAllDiagnostics
Get all LSP diagnostics across all files
getAllDiagnostics(): TsDiagnostic[]getBufferText
Get text from a buffer range Used by vi mode plugin for yank operations - reads text without deleting.
getBufferText(buffer_id: number, start: number, end: number): Promise<string>Parameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Buffer ID |
start | number | Start byte offset |
end | number | End byte offset |
getEditorMode
Get the current global editor mode
getEditorMode(): stringBuffer Info Queries
getBufferInfo
Get full information about a buffer
getBufferInfo(buffer_id: number): BufferInfo | nullParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Buffer ID |
listBuffers
List all open buffers
listBuffers(): BufferInfo[]getPrimaryCursor
Get primary cursor with selection info
getPrimaryCursor(): CursorInfo | nullgetAllCursors
Get all cursors (for multi-cursor support)
getAllCursors(): CursorInfo[]getViewport
Get viewport information
getViewport(): ViewportInfo | nullPrompt Operations
startPrompt
Start an interactive prompt
startPrompt(label: string, prompt_type: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
label | string | Label to display (e.g., "Git grep: ") |
prompt_type | string | Type identifier (e.g., "git-grep") |
setPromptSuggestions
Set suggestions for the current prompt
setPromptSuggestions(suggestions: PromptSuggestion[]): booleanParameters:
| Name | Type | Description |
|---|---|---|
suggestions | PromptSuggestion[] | Array of suggestions to display |
Buffer Mutations
applyTheme
Apply a theme by name Loads and applies the specified theme immediately. The theme can be a built-in theme name or a custom theme from the themes directory.
applyTheme(theme_name: string): voidParameters:
| Name | Type | Description |
|---|---|---|
theme_name | string | Name of the theme to apply (e.g., "dark", "light", "my-custom-theme") |
reloadConfig
Reload configuration from file After a plugin saves config changes to the config file, call this to reload the editor's in-memory configuration. This ensures the editor and plugins stay in sync with the saved config.
reloadConfig(): voiderror
Log an error message from a plugin Messages appear in log file when running with RUST_LOG=error. Use for critical errors that need attention.
error(message: string): voidParameters:
| Name | Type | Description |
|---|---|---|
message | string | Error message |
warn
Log a warning message from a plugin Messages appear in log file when running with RUST_LOG=warn. Use for warnings that don't prevent operation but indicate issues.
warn(message: string): voidParameters:
| Name | Type | Description |
|---|---|---|
message | string | Warning message |
info
Log an info message from a plugin Messages appear in log file when running with RUST_LOG=info. Use for important operational messages.
info(message: string): voidParameters:
| Name | Type | Description |
|---|---|---|
message | string | Info message |
setClipboard
Copy text to the system clipboard Copies the provided text to both the internal and system clipboard. Uses OSC 52 and arboard for cross-platform compatibility.
setClipboard(text: string): voidParameters:
| Name | Type | Description |
|---|---|---|
text | string | Text to copy to clipboard |
insertText
Insert text at a byte position in a buffer Text is inserted before the byte at position. Position must be valid (0 to buffer length). Insertion shifts all text after position. Operation is asynchronous; returns true if command was sent successfully.
insertText(buffer_id: number, position: number, text: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
position | number | Byte offset where text will be inserted (must be at char boundary) |
text | string | UTF-8 text to insert |
deleteRange
Delete a byte range from a buffer Deletes bytes from start (inclusive) to end (exclusive). Both positions must be at valid UTF-8 char boundaries. Operation is asynchronous; returns true if command was sent successfully.
deleteRange(buffer_id: number, start: number, end: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
start | number | Start byte offset (inclusive) |
end | number | End byte offset (exclusive) |
clearNamespace
Clear all overlays in a namespace
clearNamespace(buffer_id: number, namespace: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
namespace | string | The namespace to clear |
setLineNumbers
Enable/disable line numbers for a buffer
setLineNumbers(buffer_id: number, enabled: boolean): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
enabled | boolean | Whether to show line numbers |
addVirtualLine
Add a virtual line above or below a source line
addVirtualLine(buffer_id: number, position: number, text: string, fg_r: number, fg_g: number, fg_b: number, bg_r: i16, bg_g: i16, bg_b: i16, above: boolean, namespace: string, priority: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
position | number | Byte position to anchor the virtual line to |
text | string | The text content of the virtual line |
fg_r | number | Foreground red color component (0-255) |
fg_g | number | Foreground green color component (0-255) |
fg_b | number | Foreground blue color component (0-255) |
bg_r | i16 | Background red color component (0-255), -1 for transparent |
bg_g | i16 | Background green color component (0-255), -1 for transparent |
bg_b | i16 | Background blue color component (0-255), -1 for transparent |
above | boolean | Whether to insert above (true) or below (false) the line |
namespace | string | Namespace for bulk removal (e.g., "git-blame") |
priority | number | Priority for ordering multiple lines at same position |
setLineIndicator
Set a line indicator in the gutter's indicator column
setLineIndicator(buffer_id: number, line: number, namespace: string, symbol: string, r: number, g: number, b: number, priority: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
line | number | Line number (0-indexed) |
namespace | string | Namespace for grouping (e.g., "git-gutter", "breakpoints") |
symbol | string | Symbol to display (e.g., "│", "●", "★") |
r | number | Red color component (0-255) |
g | number | Green color component (0-255) |
b | number | uffer_id - The buffer ID |
priority | number | Priority for display when multiple indicators exist (higher wins) |
clearLineIndicators
Clear all line indicators for a specific namespace
clearLineIndicators(buffer_id: number, namespace: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
namespace | string | Namespace to clear (e.g., "git-gutter") |
submitViewTransform
Submit a transformed view stream for a viewport
submitViewTransform(buffer_id: number, split_id?: number | null, start: number, end: number, tokens: ViewTokenWire[], layout_hints?: LayoutHints | null): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Buffer to apply the transform to |
split_id | `number | null` (optional) |
start | number | Viewport start byte |
end | number | Viewport end byte |
tokens | ViewTokenWire[] | Array of tokens with source offsets |
layout_hints | `LayoutHints | null` (optional) |
clearViewTransform
Clear view transform for a buffer/split (returns to normal rendering)
clearViewTransform(buffer_id: number, split_id?: number | null): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Buffer ID |
split_id | `number | null` (optional) |
insertAtCursor
Insert text at the current cursor position in the active buffer
insertAtCursor(text: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
text | string | The text to insert |
pluginTranslate
Translate a string for a plugin using the current locale
pluginTranslate(plugin_name: string, key: string, args: Record<string, unknown>): stringParameters:
| Name | Type | Description |
|---|---|---|
plugin_name | string | - |
key | string | - |
args | Record<string, unknown> | - |
registerCommand
Register a custom command that can be triggered by keybindings or the command palette
registerCommand(name: string, description: string, action: string, contexts: string, source: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
name | string | - |
description | string | - |
action | string | - |
contexts | string | - |
source | string | - |
unregisterCommand
Unregister a custom command by name
unregisterCommand(name: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
name | string | The name of the command to unregister |
setContext
Set or unset a custom context for command visibility Custom contexts allow plugins to control when their commands are available. For example, setting "config-editor" context makes config editor commands visible.
setContext(name: string, active: boolean): booleanParameters:
| Name | Type | Description |
|---|---|---|
name | string | Context name (e.g., "config-editor") |
active | boolean | Whether the context is active (true = set, false = unset) |
openFile
Open a file in the editor, optionally at a specific location
openFile(path: string, line: number, column: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
path | string | File path to open |
line | number | Line number to jump to (0 for no jump) |
column | number | Column number to jump to (0 for no jump) |
openFileInSplit
Open a file in a specific split pane
openFileInSplit(split_id: number, path: string, line: number, column: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | The split ID to open the file in |
path | string | File path to open |
line | number | Line number to jump to (0 for no jump) |
column | number | Column number to jump to (0 for no jump) |
spawnBackgroundProcess
Spawn a long-running background process Unlike spawnProcess which waits for completion, this starts a process in the background and returns immediately with a process ID. Use killProcess(id) to terminate the process later. Use isProcessRunning(id) to check if it's still running. const proc = await editor.spawnBackgroundProcess("asciinema", ["rec", "output.cast"]); // Later... await editor.killProcess(proc.process_id);
spawnBackgroundProcess(command: string, args: string[], cwd?: string | null): Promise<BackgroundProcessResult>Parameters:
| Name | Type | Description |
|---|---|---|
command | string | Program name (searched in PATH) or absolute path |
args | string[] | Command arguments (each array element is one argument) |
cwd | `string | null` (optional) |
Example:
const proc = await editor.spawnBackgroundProcess("asciinema", ["rec", "output.cast"]);
// Later...
await editor.killProcess(proc.process_id);killProcess
Kill a background or cancellable process by ID Sends SIGTERM to gracefully terminate the process. Returns true if the process was found and killed, false if not found.
killProcess(#[bigint] process_id: number): Promise<boolean>Parameters:
| Name | Type | Description |
|---|---|---|
#[bigint] process_id | number | - |
spawnProcessWait
Wait for a cancellable process to complete and get its result
spawnProcessWait(#[bigint] process_id: number): Promise<SpawnResult>Parameters:
| Name | Type | Description |
|---|---|---|
#[bigint] process_id | number | - |
delay
Delay execution for a specified number of milliseconds Useful for debouncing user input or adding delays between operations. await editor.delay(100); // Wait 100ms
delay(#[bigint] ms: number): Promise<[]>Parameters:
| Name | Type | Description |
|---|---|---|
#[bigint] ms | number | - |
Example:
await editor.delay(100); // Wait 100msfindBufferByPath
Find a buffer ID by its file path
findBufferByPath(path: string): numberParameters:
| Name | Type | Description |
|---|---|---|
path | string | - |
startPromptWithInitial
Start a prompt with pre-filled initial value
startPromptWithInitial(label: string, prompt_type: string, initial_value: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
label | string | Label to display (e.g., "Git grep: ") |
prompt_type | string | Type identifier (e.g., "git-grep") |
initial_value | string | Initial text to pre-fill in the prompt |
createCompositeBuffer
Create a composite buffer that displays multiple source buffers Composite buffers allow displaying multiple underlying buffers in a single tab/view area with custom layouts (side-by-side, stacked, unified). This is useful for diff views, merge conflict resolution, etc.
createCompositeBuffer(options: CreateCompositeBufferOptions): Promise<number>Parameters:
| Name | Type | Description |
|---|---|---|
options | CreateCompositeBufferOptions | Configuration for the composite buffer |
updateCompositeAlignment
Update line alignment for a composite buffer
updateCompositeAlignment(buffer_id: number, hunks: TsCompositeHunk[]): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The composite buffer ID |
hunks | TsCompositeHunk[] | New diff hunks for alignment |
closeCompositeBuffer
Close a composite buffer
closeCompositeBuffer(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The composite buffer ID to close |
sendLspRequest
Send an arbitrary LSP request and receive the raw JSON response
sendLspRequest(language: string, method: string, params?: unknown | null): Promise<unknown>Parameters:
| Name | Type | Description |
|---|---|---|
language | string | Language ID (e.g., "cpp") |
method | string | Full LSP method (e.g., "textDocument/switchSourceHeader") |
params | `unknown | null` (optional) |
setSplitScroll
Set the scroll position of a specific split
setSplitScroll(split_id: number, top_byte: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | The split ID |
top_byte | number | The byte offset of the top visible line |
setSplitRatio
Set the ratio of a split container
setSplitRatio(split_id: number, ratio: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | ID of the split |
ratio | number | Ratio between 0.0 and 1.0 (0.5 = equal split) |
distributeSplitsEvenly
Distribute all visible splits evenly This adjusts the ratios of all container splits so each leaf split gets equal space
distributeSplitsEvenly(): booleansetBufferCursor
Set cursor position in a buffer (also scrolls viewport to show cursor)
setBufferCursor(buffer_id: number, position: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | ID of the buffer |
position | number | Byte offset position for the cursor |
executeAction
Execute a built-in editor action by name This is used by vi mode plugin to run motions and then check cursor position. For example, to implement "dw" (delete word), the plugin:
- Saves current cursor position
- Calls executeAction("move_word_right") - cursor moves
- Gets new cursor position
- Deletes from old to new position
executeAction(action_name: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
action_name | string | Action name (e.g., "move_word_right", "move_line_end") |
executeActions
Execute multiple actions in sequence, each with an optional repeat count Used by vi mode for count prefix (e.g., "3dw" = delete 3 words). All actions execute atomically with no plugin roundtrips between them.
executeActions(actions: ActionSpecJs[]): booleanParameters:
| Name | Type | Description |
|---|---|---|
actions | ActionSpecJs[] | Array of {action: string, count?: number} objects |
setEditorMode
Set the global editor mode (for modal editing like vi mode) When a mode is set, its keybindings take precedence over normal key handling. Pass null/undefined to clear the mode and return to normal editing.
setEditorMode(mode?: string | null): booleanParameters:
| Name | Type | Description |
|---|---|---|
mode | `string | null` (optional) |
showActionPopup
Show an action popup with buttons for user interaction When the user selects an action, the ActionPopupResult hook is fired.
showActionPopup(options: TsActionPopupOptions): booleanParameters:
| Name | Type | Description |
|---|---|---|
options | TsActionPopupOptions | Popup configuration with id, title, message, and actions |
disableLspForLanguage
Disable LSP for a specific language and persist to config This is used by LSP helper plugins to let users disable LSP for languages where the server is not available or not working.
disableLspForLanguage(language: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
language | string | The language to disable LSP for (e.g., "python", "rust") |
createScrollSyncGroup
Create a scroll sync group for anchor-based synchronized scrolling Used for side-by-side diff views where two panes need to scroll together. The plugin provides the group ID (must be unique per plugin).
createScrollSyncGroup(group_id: number, left_split: number, right_split: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
group_id | number | - |
left_split | number | - |
right_split | number | - |
setScrollSyncAnchors
Set sync anchors for a scroll sync group Anchors map corresponding line numbers between left and right buffers. Each anchor is a tuple of (left_line, right_line).
setScrollSyncAnchors(group_id: number, anchors: Vec<(usize, usize): booleanParameters:
| Name | Type | Description |
|---|---|---|
group_id | number | - |
anchors | Vec<(usize, usize | - |
removeScrollSyncGroup
Remove a scroll sync group
removeScrollSyncGroup(group_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
group_id | number | - |
Overlay Operations
addOverlay
Add a colored highlight overlay to text without modifying content Overlays are visual decorations that persist until explicitly removed. Add an overlay (visual decoration) to a buffer Use namespaces for easy batch removal (e.g., "spell", "todo"). Multiple overlays can apply to the same range; colors blend.
addOverlay(buffer_id: number, namespace: string, start: number, end: number, r: number, g: number, b: number, bg_r: i16, bg_g: i16, bg_b: i16, underline: boolean, bold: boolean, italic: boolean, extend_to_line_end: boolean): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | Target buffer ID |
namespace | string | Optional namespace for grouping (use clearNamespace for batch removal) |
start | number | Start byte offset |
end | number | End byte offset |
r | number | Red (0-255) |
g | number | Green (0-255) |
b | number | uffer_id - Target buffer ID |
bg_r | i16 | - |
bg_g | i16 | - |
bg_b | i16 | - |
underline | boolean | Add underline decoration |
bold | boolean | Use bold text |
italic | boolean | Use italic text |
extend_to_line_end | boolean | Extend background to end of visual line |
removeOverlay
Remove a specific overlay by its handle
removeOverlay(buffer_id: number, handle: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
handle | string | The overlay handle to remove |
clearOverlaysInRange
Clear all overlays that overlap with a byte range
clearOverlaysInRange(buffer_id: number, start: number, end: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
start | number | Start byte position (inclusive) |
end | number | End byte position (exclusive) |
clearAllOverlays
Remove all overlays from a buffer
clearAllOverlays(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
addVirtualText
Add virtual text (inline decoration) at a position
addVirtualText(buffer_id: number, virtual_text_id: string, position: number, text: string, r: number, g: number, b: number, before: boolean, use_bg: boolean): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
virtual_text_id | string | Unique identifier for this virtual text |
position | number | Byte position to insert at |
text | string | The virtual text to display |
r | number | Red color component (0-255) |
g | number | Green color component (0-255) |
b | number | uffer_id - The buffer ID |
before | boolean | Whether to insert before (true) or after (false) the position |
use_bg | boolean | Whether to use the color as background (true) or foreground (false) |
removeVirtualText
Remove virtual text by ID
removeVirtualText(buffer_id: number, virtual_text_id: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
virtual_text_id | string | The virtual text ID to remove |
removeVirtualTextsByPrefix
Remove all virtual texts with IDs starting with a prefix
removeVirtualTextsByPrefix(buffer_id: number, prefix: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
prefix | string | The prefix to match virtual text IDs against |
clearVirtualTexts
Remove all virtual texts from a buffer
clearVirtualTexts(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
clearVirtualTextNamespace
Clear all virtual texts in a namespace
clearVirtualTextNamespace(buffer_id: number, namespace: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
namespace | string | The namespace to clear (e.g., "git-blame") |
refreshLines
Force a refresh of line display for a buffer
refreshLines(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | The buffer ID |
File System Operations
readFile
Read entire file contents as UTF-8 string Throws if file doesn't exist, isn't readable, or isn't valid UTF-8. For binary files, this will fail. For large files, consider memory usage.
readFile(path: string): Promise<string>Parameters:
| Name | Type | Description |
|---|---|---|
path | string | File path (absolute or relative to cwd) |
writeFile
Write string content to a file, creating or overwriting Creates parent directories if they don't exist (behavior may vary). Replaces file contents entirely; use readFile + modify + writeFile for edits.
writeFile(path: string, content: string): Promise<[]>Parameters:
| Name | Type | Description |
|---|---|---|
path | string | Destination path (absolute or relative to cwd) |
content | string | UTF-8 string to write |
fileExists
Check if a path exists (file, directory, or symlink) Does not follow symlinks; returns true for broken symlinks. Use fileStat for more detailed information.
fileExists(path: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
path | string | Path to check (absolute or relative to cwd) |
fileStat
Get metadata about a file or directory Follows symlinks. Returns exists=false for non-existent paths rather than throwing. Size is in bytes; directories may report 0.
fileStat(path: string): FileStatParameters:
| Name | Type | Description |
|---|---|---|
path | string | Path to stat (absolute or relative to cwd) |
readDir
List directory contents Returns unsorted entries with type info. Entry names are relative to the directory (use pathJoin to construct full paths). Throws on permission errors or if path is not a directory. const entries = editor.readDir("/home/user"); for (const e of entries) { const fullPath = editor.pathJoin("/home/user", e.name); }
readDir(path: string): DirEntry[]Parameters:
| Name | Type | Description |
|---|---|---|
path | string | Directory path (absolute or relative to cwd) |
Example:
const entries = editor.readDir("/home/user");
for (const e of entries) {
const fullPath = editor.pathJoin("/home/user", e.name);
}Environment Operations
getEnv
Get an environment variable
getEnv(name: string): stringParameters:
| Name | Type | Description |
|---|---|---|
name | string | Name of environment variable |
getCwd
Get the editor's current working directory Returns the editor's working directory (set when the editor was started). Use as base for resolving relative paths and spawning processes. Note: This returns the editor's stored working_dir, not process CWD, which is important for test isolation.
getCwd(): stringPath Operations
pathJoin
Join path segments using the OS path separator Handles empty segments and normalizes separators. If a segment is absolute, previous segments are discarded. pathJoin("/home", "user", "file.txt") // "/home/user/file.txt" pathJoin("relative", "/absolute") // "/absolute"
pathJoin(parts: string[]): stringParameters:
| Name | Type | Description |
|---|---|---|
parts | string[] | Path segments to join |
Example:
pathJoin("/home", "user", "file.txt") // "/home/user/file.txt"
pathJoin("relative", "/absolute") // "/absolute"pathDirname
Get the parent directory of a path Returns empty string for root paths or paths without parent. Does not resolve symlinks or check existence. pathDirname("/home/user/file.txt") // "/home/user" pathDirname("/") // ""
pathDirname(path: string): stringParameters:
| Name | Type | Description |
|---|---|---|
path | string | File or directory path |
Example:
pathDirname("/home/user/file.txt") // "/home/user"
pathDirname("/") // ""pathBasename
Get the final component of a path Returns empty string for root paths. Does not strip file extension; use pathExtname for that. pathBasename("/home/user/file.txt") // "file.txt" pathBasename("/home/user/") // "user"
pathBasename(path: string): stringParameters:
| Name | Type | Description |
|---|---|---|
path | string | File or directory path |
Example:
pathBasename("/home/user/file.txt") // "file.txt"
pathBasename("/home/user/") // "user"pathExtname
Get the file extension including the dot Returns empty string if no extension. Only returns the last extension for files like "archive.tar.gz" (returns ".gz"). pathExtname("file.txt") // ".txt" pathExtname("archive.tar.gz") // ".gz" pathExtname("Makefile") // ""
pathExtname(path: string): stringParameters:
| Name | Type | Description |
|---|---|---|
path | string | File path |
Example:
pathExtname("file.txt") // ".txt"
pathExtname("archive.tar.gz") // ".gz"
pathExtname("Makefile") // ""pathIsAbsolute
Check if a path is absolute On Unix: starts with "/". On Windows: starts with drive letter or UNC path.
pathIsAbsolute(path: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
path | string | Path to check |
Event/Hook Operations
on
Subscribe to an editor event Handler must be a global function name (not a closure). Multiple handlers can be registered for the same event. Events: "buffer_save", "cursor_moved", "buffer_modified", etc. globalThis.onSave = (data) => { editor.setStatus(Saved: ${data.path}); }; editor.on("buffer_save", "onSave");
on(event_name: string, handler_name: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
event_name | string | Event to subscribe to |
handler_name | string | Name of globalThis function to call with event data |
Example:
globalThis.onSave = (data) => {
editor.setStatus(`Saved: ${data.path}`);
};
editor.on("buffer_save", "onSave");off
Unregister an event handler
off(event_name: string, handler_name: string): booleanParameters:
| Name | Type | Description |
|---|---|---|
event_name | string | Name of the event |
handler_name | string | Name of the handler to remove |
getHandlers
Get list of registered handlers for an event
getHandlers(event_name: string): string[]Parameters:
| Name | Type | Description |
|---|---|---|
event_name | string | Name of the event |
Virtual Buffer Operations
createVirtualBufferInSplit
Create a virtual buffer in a new horizontal split below current pane Use for results panels, diagnostics, logs, etc. The panel_id enables idempotent updates: if a panel with that ID exists, its content is replaced instead of creating a new split. Define the mode with defineMode first. // First define the mode with keybindings editor.defineMode("search-results", "special", [ ["Return", "search_goto"], ["q", "close_buffer"] ], true); // Then create the buffer const id = await editor.createVirtualBufferInSplit({ name: "Search", mode: "search-results", read_only: true, entries: [ { text: "src/main.rs:42: match\n", properties: { file: "src/main.rs", line: 42 } } ], ratio: 0.3, panel_id: "search" });
createVirtualBufferInSplit(options: CreateVirtualBufferOptions): Promise<CreateVirtualBufferResult>Parameters:
| Name | Type | Description |
|---|---|---|
options | CreateVirtualBufferOptions | Buffer configuration |
Example:
// First define the mode with keybindings
editor.defineMode("search-results", "special", [
["Return", "search_goto"],
["q", "close_buffer"]
], true);
// Then create the buffer
const id = await editor.createVirtualBufferInSplit({
name: "*Search*",
mode: "search-results",
read_only: true,
entries: [
{ text: "src/main.rs:42: match\n", properties: { file: "src/main.rs", line: 42 } }
],
ratio: 0.3,
panel_id: "search"
});createVirtualBufferInExistingSplit
Create a virtual buffer in an existing split
createVirtualBufferInExistingSplit(options: CreateVirtualBufferInExistingSplitOptions): Promise<number>Parameters:
| Name | Type | Description |
|---|---|---|
options | CreateVirtualBufferInExistingSplitOptions | Configuration for the virtual buffer |
createVirtualBuffer
Create a virtual buffer in the current split as a new tab This is useful for help panels, documentation, etc. that should open alongside other buffers rather than in a separate split.
createVirtualBuffer(options: CreateVirtualBufferInCurrentSplitOptions): Promise<number>Parameters:
| Name | Type | Description |
|---|---|---|
options | CreateVirtualBufferInCurrentSplitOptions | Configuration for the virtual buffer |
defineMode
Define a buffer mode with keybindings editor.defineMode("diagnostics-list", "special", [ ["Return", "diagnostics_goto"], ["q", "close_buffer"] ], true);
defineMode(name: string, parent: string, bindings: Vec<(String, String): booleanParameters:
| Name | Type | Description |
|---|---|---|
name | string | Mode name (e.g., "diagnostics-list") |
parent | string | Parent mode name for inheritance (e.g., "special"), or null |
bindings | Vec<(String, String | Array of [key_string, command_name] pairs |
Example:
editor.defineMode("diagnostics-list", "special", [
["Return", "diagnostics_goto"],
["q", "close_buffer"]
], true);showBuffer
Switch the current split to display a buffer
showBuffer(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | ID of the buffer to show |
closeBuffer
Close a buffer and remove it from all splits
closeBuffer(buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | ID of the buffer to close |
focusSplit
Focus a specific split
focusSplit(split_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | ID of the split to focus |
setSplitBuffer
Set the buffer displayed in a specific split
setSplitBuffer(split_id: number, buffer_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | ID of the split |
buffer_id | number | ID of the buffer to display in the split |
closeSplit
Close a split (if not the last one)
closeSplit(split_id: number): booleanParameters:
| Name | Type | Description |
|---|---|---|
split_id | number | ID of the split to close |
getTextPropertiesAtCursor
Get text properties at the cursor position in a buffer const props = editor.getTextPropertiesAtCursor(bufferId); if (props.length > 0 && props[0].location) { editor.openFile(props[0].location.file, props[0].location.line, 0); }
getTextPropertiesAtCursor(buffer_id: number): Record<string, unknown>[]Parameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | ID of the buffer to query |
Example:
const props = editor.getTextPropertiesAtCursor(bufferId);
if (props.length > 0 && props[0].location) {
editor.openFile(props[0].location.file, props[0].location.line, 0);
}setVirtualBufferContent
Set the content of a virtual buffer with text properties
setVirtualBufferContent(buffer_id: number, entries: TextPropertyEntry[]): booleanParameters:
| Name | Type | Description |
|---|---|---|
buffer_id | number | ID of the virtual buffer |
entries | TextPropertyEntry[] | Array of text entries with properties |