Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sinelaw/fresh/llms.txt
Use this file to discover all available pages before exploring further.
Virtual buffers are special buffers created by plugins to display structured data like search results, diagnostics, git logs, or file explorers. Unlike regular buffers, they’re typically read-only and contain metadata (text properties) that plugins can query.
Creating Virtual Buffers
createVirtualBufferInSplit
Create a virtual buffer in a new split below the current pane.
createvirtualBufferInSplit(options: CreateVirtualBufferOptions): Promise<CreateVirtualBufferResult>
options
CreateVirtualBufferOptions
required
Buffer configuration object
returns
Promise<CreateVirtualBufferResult>
Result containing buffer_id and optional split_id
CreateVirtualBufferOptions:
interface CreateVirtualBufferOptions {
name: string; // Buffer name (convention: "*Name*")
mode: string; // Mode for keybindings
read_only: boolean; // Prevent text modifications
entries: TextPropertyEntry[]; // Content with embedded metadata
ratio: number; // Split ratio (0.3 = 30% of space)
direction?: string | null; // "horizontal" or "vertical"
panel_id?: string | null; // For idempotent updates
show_line_numbers?: boolean | null; // Show line numbers
show_cursors?: boolean | null; // Show cursor
editing_disabled?: boolean | null; // Disable editing
line_wrap?: boolean | null; // Enable line wrapping
}
TextPropertyEntry:
interface TextPropertyEntry {
text: string; // Text to display (include \n for separate lines)
properties: Record<string, unknown>; // Arbitrary metadata
}
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.
Example:
// First define the mode with keybindings
editor.defineMode("search-results", "special", [
["Return", "search_goto"],
["q", "close_buffer"]
], true);
// Then create the buffer
const result = await editor.createVirtualBufferInSplit({
name: "*Search*",
mode: "search-results",
read_only: true,
entries: [
{
text: "src/main.rs:42: match found\n",
properties: { file: "src/main.rs", line: 42 }
},
{
text: "src/lib.rs:15: another match\n",
properties: { file: "src/lib.rs", line: 15 }
}
],
ratio: 0.3,
panel_id: "search"
});
editor.debug(`Created buffer ${result.buffer_id}`);
createVirtualBufferInExistingSplit
Create a virtual buffer in an existing split.
createVirtualBufferInExistingSplit(options: CreateVirtualBufferInExistingSplitOptions): Promise<number>
options
CreateVirtualBufferInExistingSplitOptions
required
Configuration for the virtual buffer
CreateVirtualBufferInExistingSplitOptions:
interface CreateVirtualBufferInExistingSplitOptions {
name: string;
mode: string;
read_only: boolean;
entries: TextPropertyEntry[];
split_id: number; // Target split ID
show_line_numbers?: boolean | null;
show_cursors?: boolean | null;
editing_disabled?: boolean | null;
line_wrap?: boolean | null;
}
Example:
const splitId = editor.getActiveSplitId();
const bufferId = await editor.createVirtualBufferInExistingSplit({
name: "*Output*",
mode: "output-mode",
read_only: true,
entries: [
{ text: "Build output:\n", properties: {} },
{ text: "Success!\n", properties: { status: "success" } }
],
split_id: splitId
});
createVirtualBuffer
Create a virtual buffer in the current split as a new tab.
createVirtualBuffer(options: CreateVirtualBufferInCurrentSplitOptions): Promise<number>
options
CreateVirtualBufferInCurrentSplitOptions
required
Configuration for the virtual buffer
CreateVirtualBufferInCurrentSplitOptions:
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; // Hide from tabs
}
Example:
// Create help buffer in current split
const bufferId = await editor.createVirtualBuffer({
name: "*Help*",
mode: "help-mode",
read_only: true,
entries: [
{ text: "# Help\n", properties: {} },
{ text: "Press q to close\n", properties: {} }
],
show_line_numbers: false
});
Managing Virtual Buffers
setVirtualBufferContent
Set the content of a virtual buffer with text properties.
setVirtualBufferContent(buffer_id: number, entries: TextPropertyEntry[]): boolean
entries
TextPropertyEntry[]
required
Array of text entries with properties
true if content was set successfully
Example:
// Update search results
editor.setVirtualBufferContent(bufferId, [
{ text: "Updated results:\n", properties: {} },
{ text: "src/new.rs:10: found\n", properties: { file: "src/new.rs", line: 10 } }
]);
getTextPropertiesAtCursor
Get text properties at the cursor position in a buffer.
getTextPropertiesAtCursor(buffer_id: number): Record<string, unknown>[]
ID of the buffer to query
returns
Record<string, unknown>[]
Array of property objects at cursor position
Example:
// Implement "go to definition" from search results
globalThis.searchGoto = () => {
const bufferId = editor.getActiveBufferId();
const props = editor.getTextPropertiesAtCursor(bufferId);
if (props.length > 0 && props[0].file && props[0].line) {
editor.openFile(props[0].file as string, props[0].line as number, 0);
}
};
Modes and Keybindings
defineMode
Define a buffer mode with keybindings.
defineMode(
name: string,
parent: string,
bindings: [string, string][],
read_only: boolean
): boolean
Mode name (e.g., “diagnostics-list”)
Parent mode name for inheritance (e.g., “special”), or null
bindings
[string, string][]
required
Array of [key_string, command_name] pairs
Whether buffers in this mode are read-only
true if mode was defined successfully
Example:
editor.defineMode("diagnostics-list", "special", [
["Return", "diagnostics_goto"],
["n", "diagnostics_next"],
["p", "diagnostics_prev"],
["q", "close_buffer"]
], true);
Split Management
getActiveSplitId
Get the ID of the focused split pane.
getActiveSplitId(): number
focusSplit
Focus a specific split.
focusSplit(split_id: number): boolean
setSplitBuffer
Set the buffer displayed in a specific split.
setSplitBuffer(split_id: number, buffer_id: number): boolean
ID of the buffer to display
closeSplit
Close a split (if not the last one).
closeSplit(split_id: number): boolean
setSplitRatio
Set the ratio of a split container.
setSplitRatio(split_id: number, ratio: number): boolean
Ratio between 0.0 and 1.0 (0.5 = equal split)
distributeSplitsEvenly
Distribute all visible splits evenly.
distributeSplitsEvenly(): boolean
This adjusts the ratios of all container splits so each leaf split gets equal space.
Complete Example: Search Results Panel
// Define the mode
editor.defineMode("search-results", "special", [
["Return", "search_goto"],
["n", "search_next"],
["p", "search_prev"],
["q", "close_buffer"]
], true);
// Search function
async function performSearch(query: string) {
// Run search command
const result = await editor.spawnProcess("rg", [
"--line-number",
"--no-heading",
query
]);
if (result.exit_code !== 0) {
editor.setStatus("No matches found");
return;
}
// Parse results
const entries: TextPropertyEntry[] = [];
for (const line of result.stdout.split("\n")) {
if (!line) continue;
const match = line.match(/^([^:]+):(\d+):(.*)$/);
if (match) {
const [, file, lineNum, text] = match;
entries.push({
text: `${file}:${lineNum}: ${text}\n`,
properties: {
file: file,
line: parseInt(lineNum)
}
});
}
}
// Create or update panel
const panel = await editor.createVirtualBufferInSplit({
name: "*Search*",
mode: "search-results",
read_only: true,
entries: entries,
ratio: 0.3,
panel_id: "search" // Reuse existing panel
});
editor.setStatus(`Found ${entries.length} matches`);
}
// Go to selected result
globalThis.search_goto = () => {
const bufferId = editor.getActiveBufferId();
const props = editor.getTextPropertiesAtCursor(bufferId);
if (props.length > 0 && props[0].file && props[0].line) {
editor.openFile(props[0].file as string, props[0].line as number, 0);
}
};
// Register command
editor.registerCommand(
"Search: Grep",
"Search for text in files",
"search_grep",
"normal",
"plugin"
);
globalThis.search_grep = () => {
editor.startPrompt("Search: ", "search-input");
};
// Handle prompt submission
globalThis.handleSearchPrompt = async (data) => {
if (data.prompt_type === "search-input" && data.confirmed) {
await performSearch(data.value);
}
};
editor.on("prompt_submit", "handleSearchPrompt");