From ed574f4ca07f6dbc86a06c26998255c928b86432 Mon Sep 17 00:00:00 2001 From: wxy Date: Thu, 30 Apr 2026 18:05:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0rg=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tools/rg.ts | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/tools/rg.ts diff --git a/src/tools/rg.ts b/src/tools/rg.ts new file mode 100644 index 0000000..ad6a01b --- /dev/null +++ b/src/tools/rg.ts @@ -0,0 +1,73 @@ +import { rgPath } from "@vscode/ripgrep"; + +// 建议使用你之前用的颜色库 + +/** + * 获取搜索结果及其上下文代码块 + * @param pattern 搜索词 + * @param contextLines 上下文行数 (前后各取几行) + * @param targetPath 搜索路径 + */ +async function getCodeBlocks(pattern: string, contextLines: number = 5, targetPath: string = ".") { + const args = [ + pattern, + targetPath, + "--json", // 输出 JSON 格式以便解析 + "--context", String(contextLines), // 带出上下文 + "--max-columns", "500", // 防止单行过长 + "--heading", // 保持文件分组 + ]; + + const proc = Bun.spawn([rgPath, ...args]); + const text = await new Response(proc.stdout).text(); + + // Ripgrep 的 JSON 输出是每行一个 JSON 对象 + const lines = text.split("\n").filter(Boolean); + + const results: any[] = []; + let currentFile = ""; + let currentBlock: any = null; + + for (const line of lines) { + const node = JSON.parse(line); + + // 1. 处理文件路径切换 + if (node.type === "begin") { + currentFile = node.data.path.text; + } + + // 2. 处理匹配行和上下文行 + if (node.type === "match" || node.type === "context") { + const isMatch = node.type === "match"; + const lineText = node.data.lines.text; + const lineNumber = node.data.line_number; + + // 这里简单的逻辑:如果是连续行,就放进同一个 block + if (!currentBlock || (lineNumber !== currentBlock.endLine + 1)) { + if (currentBlock) results.push(currentBlock); + currentBlock = { + file: currentFile, + startLine: lineNumber, + endLine: lineNumber, + code: lineText, + hasMatch: isMatch + }; + } else { + currentBlock.code += lineText; + currentBlock.endLine = lineNumber; + if (isMatch) currentBlock.hasMatch = true; + } + } + + if (node.type === "end" && currentBlock) { + results.push(currentBlock); + currentBlock = null; + } + } + + return results; +} + +// 使用示例 +const blocks = await getCodeBlocks("deepseek", 3); +console.log(JSON.stringify(blocks, null, 2)); \ No newline at end of file