mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-21 17:54:23 +01:00
[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.
This commit is contained in:
committed by
Kujtim Hoxha
parent
9738886620
commit
3c2b0f4dd0
@@ -1,11 +1,13 @@
|
|||||||
package tools
|
package tools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -132,6 +134,73 @@ func (g *globTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func globFiles(pattern, searchPath string, limit int) ([]string, bool, error) {
|
func globFiles(pattern, searchPath string, limit int) ([]string, bool, error) {
|
||||||
|
matches, err := globWithRipgrep(pattern, searchPath, limit)
|
||||||
|
if err == nil {
|
||||||
|
return matches, len(matches) >= limit, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return globWithDoublestar(pattern, searchPath, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func globWithRipgrep(
|
||||||
|
pattern, searchRoot string,
|
||||||
|
limit int,
|
||||||
|
) ([]string, error) {
|
||||||
|
|
||||||
|
if searchRoot == "" {
|
||||||
|
searchRoot = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
rgBin, err := exec.LookPath("rg")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ripgrep not found in $PATH: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !filepath.IsAbs(pattern) && !strings.HasPrefix(pattern, "/") {
|
||||||
|
pattern = "/" + pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"--files",
|
||||||
|
"--null",
|
||||||
|
"--glob", pattern,
|
||||||
|
"-L",
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(rgBin, args...)
|
||||||
|
cmd.Dir = searchRoot
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
if ee, ok := err.(*exec.ExitError); ok && ee.ExitCode() == 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("ripgrep: %w\n%s", err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches []string
|
||||||
|
for _, p := range bytes.Split(out, []byte{0}) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
abs := filepath.Join(searchRoot, string(p))
|
||||||
|
if skipHidden(abs) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matches = append(matches, abs)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(matches, func(i, j int) bool {
|
||||||
|
return len(matches[i]) < len(matches[j])
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(matches) > limit {
|
||||||
|
matches = matches[:limit]
|
||||||
|
}
|
||||||
|
return matches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func globWithDoublestar(pattern, searchPath string, limit int) ([]string, bool, error) {
|
||||||
if !strings.HasPrefix(pattern, "/") && !strings.HasPrefix(pattern, searchPath) {
|
if !strings.HasPrefix(pattern, "/") && !strings.HasPrefix(pattern, searchPath) {
|
||||||
if !strings.HasSuffix(searchPath, "/") {
|
if !strings.HasSuffix(searchPath, "/") {
|
||||||
searchPath += "/"
|
searchPath += "/"
|
||||||
|
|||||||
Reference in New Issue
Block a user