Something went wrong. Try again.
A neovim plugin for OpenCode
Something went wrong. Try again.
3.1 kB · 81 lines
TypeScript
at master
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182import { Plugin } from "@opencode/plugin"import { Buffer } from "node:buffer"import { mkdir, readFile } from "node:fs/promises"import { dirname, join } from "node:path"
type Input = { action: "read" | "open" | "replace_lines" | "cursor" | "diagnostics" path?: string line?: number end_line?: number column?: number text?: string}
function locator(directory: string): string { const encoded = Buffer.from(directory).toString("base64").replaceAll(/[\/=+]/g, "_") return join(process.env.XDG_RUNTIME_DIR ?? "/tmp", "brokencode-nvim", encoded)}
async function call(directory: string, input: Input): Promise<string> { const file = locator(directory) await mkdir(dirname(file), { recursive: true }) const address = (await readFile(file, "utf8")).trim() const payload = Buffer.from(JSON.stringify(input)).toString("base64") const expression = `v:lua.brokencode_rpc('${payload}')` const process = Bun.spawn(["nvim", "--server", address, "--remote-expr", expression], { stdout: "pipe", stderr: "pipe", }) const [output, error, status] = await Promise.all([ new Response(process.stdout).text(), new Response(process.stderr).text(), process.exited, ])
if (status !== 0) throw new Error(error.trim() || "Neovim RPC failed")
const content = output.trim() const result = JSON.parse(content) as { error?: string } if (result.error) throw new Error(result.error) return content}
function validate(input: Input): void { if (input.action === "replace_lines" && (!input.path || !input.line || !input.end_line || input.text === undefined)) { throw new Error("replace_lines requires path, line, end_line, and text") } if ((input.action === "read" || input.action === "open" || input.action === "diagnostics") && !input.path) { throw new Error(`${input.action} requires path`) }}
export default Plugin.define({ id: "brokencode.nvim", async setup(ctx) { await ctx.tool.transform((editor) => { editor.namespace({ name: "nvim", description: "Read, edit, and navigate through the user's Neovim instance." }) editor.add({ name: "editor", description: "Use Neovim buffers for editor reads, line edits, navigation, cursor state, and diagnostics. Lines are 1-based and inclusive. Columns are 0-based.", input: { type: "object", properties: { action: { type: "string", enum: ["read", "open", "replace_lines", "cursor", "diagnostics"] }, path: { type: "string", description: "Absolute path or path relative to the project." }, line: { type: "integer", minimum: 1 }, end_line: { type: "integer", minimum: 1 }, column: { type: "integer", minimum: 0 }, text: { type: "string" }, }, required: ["action"], additionalProperties: false, }, execute: async (input) => { validate(input as Input) return { content: await call(ctx.location.directory, input as Input) } }, }) }) },})