跳到內容

用程式碼圖搜尋程式碼

本指南說明如何把儲存庫納入程式碼圖,再用它回答你在重構之前真正想問的問題:什麼依賴它?

程式碼圖是一套由符號與邊構成的資料庫,做法是用 tree-sitter 剖析你已註冊的簽出來建構。它的工具是面向代理的——你必須請代理執行,才能用到它們。

程式碼圖會索引 Dart、JavaScript、TypeScript、TSX、PHP、Python、Rust、Zig、C、C++、Go、Java、Ruby、C#、Swift、Kotlin、R、Assembly、MATLAB 與 Ada。其他語言的檔案不會被剖析,因此不會出現在 search_code、code_symbol、code_callers、code_callees 或 code_impact 裡。

還有兩件事會影響哪些內容會被索引:

  • 在 git 工作樹中,列舉檔案的工作交由 git ls-files --cached --others --exclude-standard 處理,因此每一個 .gitignore、巢狀忽略檔、.git/info/exclude 以及全域排除檔都會被遵循。這正是把 node_modules 與建置產物擋在程式碼圖之外的原因。
  • 無論如何,產生的 Dart 一律會被排除。產生的檔案通常是已提交的,所以單靠 git 不會排除它們,而它們每次執行程式碼產生時都會變動。

註冊簽出時會觸發 RepoAdded,它會自動為該簽出啟動 index_code 管線。參閱將儲存庫加入工作區。

若要手動重新索引:

  1. 開啟 設定 → 工作區 → 存放庫。
  2. 在該儲存庫的資料列上點選 建立程式碼索引 按鈕。
  3. 執行期間,按鈕會顯示已完成檔案數與總數的比例,並附有取消控制項。完成後,它會變成一個帶有符號數量的核取記號。

程式碼圖依工作區、儲存庫與簽出分割:已連結的簽出是一個分割區,而每一個空間工作樹各有自己的分割區(以其隔離儲存庫 id 為鍵)。

有兩項節流機制值得了解,因為它們能解釋那種看起來像當掉的等待:

  • 檔案監看器在主機上一次只允許一個索引執行——第二個簽出必須等待。index_code 管線另外還被限制為每個工作區只能執行一次,因此同一個工作區裡的兩個儲存庫會排隊;不同的工作區則可以平行索引。索引器本身會把同一個簽出的兩次執行序列化,這樣管線啟動與監看器掃描就不會把同一份內容剖析兩次。
  • 屬於休眠空間(過去一週沒有任何訊息)的工作樹既不會被監看,也不會被索引。已連結的簽出仍會持續受到監看。跳過的決定會在五分鐘後重新檢查,因此重新活躍起來的空間會再度被納入。

請代理執行搜尋。工具是 search_code,它同時需要工作區與儲存庫:

search_code(workspace_id: "...", repo_id: "...", query: "authentication middleware")

儲存庫 id 來自 list_repos。選用的 mode 引數是 keyword、semantic 或 hybrid,預設為 hybrid——對名稱、簽章與文件註解執行 BM25,再與向量相似度融合。

每一筆結果都會帶有該符號的 id、名稱、完整限定名稱、種類、檔案路徑、起始與結束行號,以及簽章(如果有的話)。id 就是你傳給本頁其他每一個工具的識別碼。

當你知道確切名稱時,改為直接查詢:

code_symbol(workspace_id: "...", repo_id: "...", name: "MyClass")

兩者都接受來自搜尋結果的 symbol_id,外加一個選用的 limit(預設 50):

code_callers(workspace_id: "...", symbol_id: "...")
code_callees(workspace_id: "...", symbol_id: "...")

code_callers 會傳回有連入邊指向此符號的那些符號;code_callees 則傳回它所依賴的符號。

這就是整頁存在的目的所在:

code_impact(workspace_id: "...", symbol_id: "...", depth: 3)

它會計算反向相依半徑:沿著 calls、extends 與 implements 邊,直接或間接依賴該符號的一切(imports、mixes-in 與泛型參照雖然存放在程式碼圖中,但這裡不會沿著它們走訪)。depth 是最大躍點數,介於 1 與 6 之間,預設為 2。

結果包含三個欄位:

  • root——你查詢的符號
  • impacted——可到達的集合,包含深度為 0 的根符號,每一項都帶有它與根之間的 depth
  • edgeCount——走訪跨越了多少條邊,以計數呈現,而不是邊本身

在重新命名或變更簽章之前先執行它,並把 impacted 清單交給代理,當作它的作業範圍。

結果會對照呼叫端自己的工作複本進行驗證

標題為「結果會對照呼叫端自己的工作複本進行驗證」的章節

對代理呼叫端而言,空間 id 會自動注入,而結果會對照該空間的工作複本進行驗證。如果某個符號的檔案已不存在於呼叫端的樹中,該符號會被省略,而回應會帶有 staleOmitted 計數,外加一則註記,說明索引中這些符號已經過期。

這就是為什麼你和代理對同一個查詢可能得到不同的答案,也是為什麼某個空間裡的代理可能會和另一個空間裡的代理得到不同答案。一個空間裡的每個對話都共用同一個工作樹。驗證採取失敗時開放的做法:寧可給出過期的答案,也不給出空白的答案。

當你想知道某項變更的爆炸半徑時,請代理執行 code_impact(或 review_studio.blastRadius)。參閱審查運算。

符號與事實是在寫入時建立嵌入,而且只有在裝置上的嵌入模型已安裝時才會這麼做。在那之前,mode: "semantic" 以及 hybrid 的語意那一半都沒有東西可以比對,搜尋實際上只等同於關鍵字搜尋。

在建立索引之前,先到 設定 → 伺服器 → 診斷與隱私 → 語意搜尋 安裝模型。符號會在它所屬的檔案被收錄時取得向量。

另外也請注意,任何一次伺服器執行檔的重新建置都會重新備妥文法 dylib 並改變它們的 mtime,這會讓每一個索引檢查點失效,並在下一次執行時迫使每個簽出完整重走一遍。它會重新計算雜湊,但不會重新擷取未變更的檔案。

符號種類: function、method、class、field、enum、constructor、getter、setter、typedef、extension、mixin、variable。

邊的種類: calls、imports、extends、implements、mixes in、references。

這些工具的標準簽章位於 MCP 工具。