summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-06-11 23:58:13 -0400
committerDax Raad <[email protected]>2025-06-11 23:58:13 -0400
commit83991bee8830400946fe046fa41dfd3901fac0d0 (patch)
tree9be3ad89fe71e0b38f85db4499a73de78be14d23
parent29142eb9409ea84bc41d8c1b6546e3cafd7fdd52 (diff)
downloadopencode-83991bee8830400946fe046fa41dfd3901fac0d0.tar.gz
opencode-83991bee8830400946fe046fa41dfd3901fac0d0.zip
Add search function to fzf and move version constant to namespace level
🤖 Generated with [OpenCode](https://opencode.ai) Co-Authored-By: OpenCode <[email protected]>
-rw-r--r--packages/opencode/src/external/fzf.ts134
1 files changed, 134 insertions, 0 deletions
diff --git a/packages/opencode/src/external/fzf.ts b/packages/opencode/src/external/fzf.ts
new file mode 100644
index 000000000..0c202c158
--- /dev/null
+++ b/packages/opencode/src/external/fzf.ts
@@ -0,0 +1,134 @@
+import { App } from "../app/app"
+import path from "path"
+import { Global } from "../global"
+import fs from "fs/promises"
+import { z } from "zod"
+import { NamedError } from "../util/error"
+import { lazy } from "../util/lazy"
+import { Log } from "../util/log"
+
+export namespace Fzf {
+ const log = Log.create({ service: "fzf" })
+
+ const VERSION = "0.62.0"
+ const PLATFORM = {
+ darwin: { extension: "tar.gz" },
+ linux: { extension: "tar.gz" },
+ win32: { extension: "zip" },
+ } as const
+
+ export const ExtractionFailedError = NamedError.create(
+ "FzfExtractionFailedError",
+ z.object({
+ filepath: z.string(),
+ stderr: z.string(),
+ }),
+ )
+
+ export const UnsupportedPlatformError = NamedError.create(
+ "FzfUnsupportedPlatformError",
+ z.object({
+ platform: z.string(),
+ }),
+ )
+
+ export const DownloadFailedError = NamedError.create(
+ "FzfDownloadFailedError",
+ z.object({
+ url: z.string(),
+ status: z.number(),
+ }),
+ )
+
+ const state = lazy(async () => {
+ let filepath = Bun.which("fzf")
+ if (filepath) {
+ log.info("found", { filepath })
+ return { filepath }
+ }
+ filepath = path.join(
+ Global.Path.bin,
+ "fzf" + (process.platform === "win32" ? ".exe" : ""),
+ )
+
+ const file = Bun.file(filepath)
+ if (!(await file.exists())) {
+ const archMap = { x64: "amd64", arm64: "arm64" } as const
+ const arch = archMap[process.arch as keyof typeof archMap] ?? "amd64"
+
+ const config = PLATFORM[process.platform as keyof typeof PLATFORM]
+ if (!config)
+ throw new UnsupportedPlatformError({ platform: process.platform })
+
+ const version = VERSION
+ const platformName =
+ process.platform === "win32" ? "windows" : process.platform
+ const filename = `fzf-${version}-${platformName}_${arch}.${config.extension}`
+ const url = `https://github.com/junegunn/fzf/releases/download/v${version}/${filename}`
+
+ const response = await fetch(url)
+ if (!response.ok)
+ throw new DownloadFailedError({ url, status: response.status })
+
+ const buffer = await response.arrayBuffer()
+ const archivePath = path.join(Global.Path.bin, filename)
+ await Bun.write(archivePath, buffer)
+ if (config.extension === "tar.gz") {
+ const proc = Bun.spawn(["tar", "-xzf", archivePath, "fzf"], {
+ cwd: Global.Path.bin,
+ stderr: "pipe",
+ stdout: "pipe",
+ })
+ await proc.exited
+ if (proc.exitCode !== 0)
+ throw new ExtractionFailedError({
+ filepath,
+ stderr: await Bun.readableStreamToText(proc.stderr),
+ })
+ }
+ if (config.extension === "zip") {
+ const proc = Bun.spawn(
+ ["unzip", "-j", archivePath, "fzf.exe", "-d", Global.Path.bin],
+ {
+ cwd: Global.Path.bin,
+ stderr: "pipe",
+ stdout: "ignore",
+ },
+ )
+ await proc.exited
+ if (proc.exitCode !== 0)
+ throw new ExtractionFailedError({
+ filepath: archivePath,
+ stderr: await Bun.readableStreamToText(proc.stderr),
+ })
+ }
+ await fs.unlink(archivePath)
+ if (process.platform !== "win32") await fs.chmod(filepath, 0o755)
+ }
+
+ return {
+ filepath,
+ }
+ })
+
+ export async function filepath() {
+ const { filepath } = await state()
+ return filepath
+ }
+
+ export async function search(cwd: string, query: string) {
+ const process = Bun.spawn({
+ cwd,
+ stdin: "inherit",
+ stdout: "pipe",
+ stderr: "pipe",
+ cmd: [await filepath(), "--filter", query],
+ })
+ await process.exited
+ const stdout = await Bun.readableStreamToText(process.stdout)
+ return stdout
+ .trim()
+ .split("\n")
+ .filter((line) => line.length > 0)
+ }
+}