Skip to content

Commit 3c2b0f4

Browse files
isaac-scarrottkujtimiihoxha
authored andcommitted
[feature/ripgrep-glob] Add ripgrep-based file globbing to improve performance
- Introduced `globWithRipgrep` function to perform file globbing using the `rg` (ripgrep) command. - Updated `globFiles` to prioritize ripgrep-based globbing and fall back to doublestar-based globbing if ripgrep fails. - Added logic to handle ripgrep command execution, output parsing, and filtering of hidden files. - Ensured results are sorted by path length and limited to the specified maximum number of matches. - Modified imports to include `os/exec` and `bytes` for ripgrep integration.
1 parent 9738886 commit 3c2b0f4

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

internal/llm/tools/glob.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package tools
22

33
import (
4+
"bytes"
45
"context"
56
"encoding/json"
67
"fmt"
78
"io/fs"
89
"os"
10+
"os/exec"
911
"path/filepath"
1012
"sort"
1113
"strings"
@@ -132,6 +134,73 @@ func (g *globTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
132134
}
133135

134136
func globFiles(pattern, searchPath string, limit int) ([]string, bool, error) {
137+
matches, err := globWithRipgrep(pattern, searchPath, limit)
138+
if err == nil {
139+
return matches, len(matches) >= limit, nil
140+
}
141+
142+
return globWithDoublestar(pattern, searchPath, limit)
143+
}
144+
145+
func globWithRipgrep(
146+
pattern, searchRoot string,
147+
limit int,
148+
) ([]string, error) {
149+
150+
if searchRoot == "" {
151+
searchRoot = "."
152+
}
153+
154+
rgBin, err := exec.LookPath("rg")
155+
if err != nil {
156+
return nil, fmt.Errorf("ripgrep not found in $PATH: %w", err)
157+
}
158+
159+
if !filepath.IsAbs(pattern) && !strings.HasPrefix(pattern, "/") {
160+
pattern = "/" + pattern
161+
}
162+
163+
args := []string{
164+
"--files",
165+
"--null",
166+
"--glob", pattern,
167+
"-L",
168+
}
169+
170+
cmd := exec.Command(rgBin, args...)
171+
cmd.Dir = searchRoot
172+
173+
out, err := cmd.CombinedOutput()
174+
if err != nil {
175+
if ee, ok := err.(*exec.ExitError); ok && ee.ExitCode() == 1 {
176+
return nil, nil
177+
}
178+
return nil, fmt.Errorf("ripgrep: %w\n%s", err, out)
179+
}
180+
181+
var matches []string
182+
for _, p := range bytes.Split(out, []byte{0}) {
183+
if len(p) == 0 {
184+
continue
185+
}
186+
abs := filepath.Join(searchRoot, string(p))
187+
if skipHidden(abs) {
188+
continue
189+
}
190+
matches = append(matches, abs)
191+
}
192+
193+
sort.SliceStable(matches, func(i, j int) bool {
194+
return len(matches[i]) < len(matches[j])
195+
})
196+
197+
if len(matches) > limit {
198+
matches = matches[:limit]
199+
}
200+
return matches, nil
201+
}
202+
203+
func globWithDoublestar(pattern, searchPath string, limit int) ([]string, bool, error) {
135204
if !strings.HasPrefix(pattern, "/") && !strings.HasPrefix(pattern, searchPath) {
136205
if !strings.HasSuffix(searchPath, "/") {
137206
searchPath += "/"

0 commit comments

Comments
 (0)