mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 05:43:55 +00:00
🤖 Generated with [opencode](https://opencode.ai) Co-Authored-By: opencode <noreply@opencode.ai>
130 lines
3.9 KiB
TypeScript
130 lines
3.9 KiB
TypeScript
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 { $ } from "bun"
|
|
import { Fzf } from "./fzf"
|
|
|
|
export namespace Ripgrep {
|
|
const PLATFORM = {
|
|
darwin: { platform: "apple-darwin", extension: "tar.gz" },
|
|
linux: { platform: "unknown-linux-musl", extension: "tar.gz" },
|
|
win32: { platform: "pc-windows-msvc", extension: "zip" },
|
|
} as const
|
|
|
|
export const ExtractionFailedError = NamedError.create(
|
|
"RipgrepExtractionFailedError",
|
|
z.object({
|
|
filepath: z.string(),
|
|
stderr: z.string(),
|
|
}),
|
|
)
|
|
|
|
export const UnsupportedPlatformError = NamedError.create(
|
|
"RipgrepUnsupportedPlatformError",
|
|
z.object({
|
|
platform: z.string(),
|
|
}),
|
|
)
|
|
|
|
export const DownloadFailedError = NamedError.create(
|
|
"RipgrepDownloadFailedError",
|
|
z.object({
|
|
url: z.string(),
|
|
status: z.number(),
|
|
}),
|
|
)
|
|
|
|
const state = lazy(async () => {
|
|
let filepath = Bun.which("rg")
|
|
if (filepath) return { filepath }
|
|
filepath = path.join(
|
|
Global.Path.bin,
|
|
"rg" + (process.platform === "win32" ? ".exe" : ""),
|
|
)
|
|
|
|
const file = Bun.file(filepath)
|
|
if (!(await file.exists())) {
|
|
const archMap = { x64: "x86_64", arm64: "aarch64" } as const
|
|
const arch = archMap[process.arch as keyof typeof archMap] ?? process.arch
|
|
|
|
const config = PLATFORM[process.platform as keyof typeof PLATFORM]
|
|
if (!config)
|
|
throw new UnsupportedPlatformError({ platform: process.platform })
|
|
|
|
const version = "14.1.1"
|
|
const filename = `ripgrep-${version}-${arch}-${config.platform}.${config.extension}`
|
|
const url = `https://github.com/BurntSushi/ripgrep/releases/download/${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 args = ["tar", "-xzf", archivePath, "--strip-components=1"]
|
|
|
|
if (process.platform === "darwin") args.push("--include=*/rg")
|
|
if (process.platform === "linux") args.push("--wildcards", "*/rg")
|
|
|
|
const proc = Bun.spawn(args, {
|
|
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, "*/rg.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 files(input: {
|
|
cwd: string
|
|
query?: string
|
|
limit?: number
|
|
}) {
|
|
const commands = [`${await filepath()} --files --hidden --glob='!.git/*'`]
|
|
if (input.query)
|
|
commands.push(`${await Fzf.filepath()} --filter=${input.query}`)
|
|
if (input.limit) commands.push(`head -n ${input.limit}`)
|
|
const joined = commands.join(" | ")
|
|
const result = await $`${{ raw: joined }}`.cwd(input.cwd).text()
|
|
return result.split("\n").filter(Boolean)
|
|
}
|
|
}
|