From 30e10127f220cac74da35c5510673c037eef2f16 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 31 Jul 2025 19:35:55 -0400 Subject: [PATCH] formatter config --- opencode.json | 6 +++++ packages/opencode/src/config/config.ts | 3 +++ packages/opencode/src/format/formatter.ts | 4 +++- packages/opencode/src/format/index.ts | 29 +++++++++++++++++++---- packages/opencode/src/tool/edit.ts | 1 + 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/opencode.json b/opencode.json index 8efc57a7..185b48c0 100644 --- a/opencode.json +++ b/opencode.json @@ -19,6 +19,12 @@ } } }, + "formatter": { + "test": { + "extensions": [".json"], + "command": ["sed", "-i", "s/name/poop/g", "$FILE"] + } + }, "mcp": { "context7": { "type": "remote", diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 3901bb16..533975f1 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -283,6 +283,9 @@ export namespace Config { z.string(), z.object({ disabled: z.boolean().optional(), + command: z.array(z.string()).optional(), + environment: z.record(z.string(), z.string()).optional(), + extensions: z.array(z.string()).optional(), }), ) .optional(), diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index 8cb77df2..8a8bbc9a 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -129,7 +129,9 @@ export const clang: Info = { command: ["clang-format", "-i", "$FILE"], extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"], async enabled() { - return Bun.which("clang-format") !== null + const app = App.info() + const items = await Filesystem.findUp(".clang-format", app.path.cwd, app.path.root) + return items.length > 0 }, } diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index 30d464a3..d4f73c38 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -6,20 +6,39 @@ import path from "path" import * as Formatter from "./formatter" import { Config } from "../config/config" +import { mergeDeep } from "remeda" export namespace Format { const log = Log.create({ service: "format" }) - const state = App.state("format", () => { + const state = App.state("format", async () => { const enabled: Record = {} + const cfg = await Config.get() + + const formatters = { ...Formatter } as Record + for (const [name, item] of Object.entries(cfg.formatter ?? {})) { + if (item.disabled) { + delete formatters[name] + continue + } + const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, { + command: [], + extensions: [], + ...item, + }) + result.enabled = async () => true + result.name = name + formatters[name] = result + } return { enabled, + formatters, } }) async function isEnabled(item: Formatter.Info) { - const s = state() + const s = await state() let status = s.enabled[item.name] if (status === undefined) { status = await item.enabled() @@ -29,11 +48,11 @@ export namespace Format { } async function getFormatter(ext: string) { - const cfg = await Config.get() + const formatters = await state().then((x) => x.formatters) const result = [] - for (const item of Object.values(Formatter)) { + for (const item of Object.values(formatters)) { + log.info("checking", { name: item.name, ext }) if (!item.extensions.includes(ext)) continue - if (cfg.formatter?.[item.name]?.disabled) continue if (!(await isEnabled(item))) continue result.push(item) } diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index 5bed0915..fbda9e4d 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -96,6 +96,7 @@ export const EditTool = Tool.define("edit", { file: filePath, }) contentNew = await file.text() + diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew)) })() FileTime.read(ctx.sessionID, filePath)