Browse Source

formatter config

Dax Raad 6 months ago
parent
commit
30e10127f2

+ 6 - 0
opencode.json

@@ -19,6 +19,12 @@
       }
     }
   },
+  "formatter": {
+    "test": {
+      "extensions": [".json"],
+      "command": ["sed", "-i", "s/name/poop/g", "$FILE"]
+    }
+  },
   "mcp": {
     "context7": {
       "type": "remote",

+ 3 - 0
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(),

+ 3 - 1
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
   },
 }
 

+ 24 - 5
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<string, boolean> = {}
+    const cfg = await Config.get()
+
+    const formatters = { ...Formatter } as Record<string, Formatter.Info>
+    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)
     }

+ 1 - 0
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)