mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-24 03:04:21 +01:00
lsp improvements
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -24,8 +25,10 @@ type GrepParams struct {
|
||||
}
|
||||
|
||||
type grepMatch struct {
|
||||
path string
|
||||
modTime time.Time
|
||||
path string
|
||||
modTime time.Time
|
||||
lineNum int
|
||||
lineText string
|
||||
}
|
||||
|
||||
type GrepResponseMetadata struct {
|
||||
@@ -147,13 +150,26 @@ func (g *grepTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
|
||||
if len(matches) == 0 {
|
||||
output = "No files found"
|
||||
} else {
|
||||
output = fmt.Sprintf("Found %d file%s\n%s",
|
||||
len(matches),
|
||||
pluralize(len(matches)),
|
||||
strings.Join(matches, "\n"))
|
||||
output = fmt.Sprintf("Found %d matches\n", len(matches))
|
||||
|
||||
currentFile := ""
|
||||
for _, match := range matches {
|
||||
if currentFile != match.path {
|
||||
if currentFile != "" {
|
||||
output += "\n"
|
||||
}
|
||||
currentFile = match.path
|
||||
output += fmt.Sprintf("%s:\n", match.path)
|
||||
}
|
||||
if match.lineNum > 0 {
|
||||
output += fmt.Sprintf(" Line %d: %s\n", match.lineNum, match.lineText)
|
||||
} else {
|
||||
output += fmt.Sprintf(" %s\n", match.path)
|
||||
}
|
||||
}
|
||||
|
||||
if truncated {
|
||||
output += "\n\n(Results are truncated. Consider using a more specific path or pattern.)"
|
||||
output += "\n(Results are truncated. Consider using a more specific path or pattern.)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,14 +182,7 @@ func (g *grepTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
|
||||
), nil
|
||||
}
|
||||
|
||||
func pluralize(count int) string {
|
||||
if count == 1 {
|
||||
return ""
|
||||
}
|
||||
return "s"
|
||||
}
|
||||
|
||||
func searchFiles(pattern, rootPath, include string, limit int) ([]string, bool, error) {
|
||||
func searchFiles(pattern, rootPath, include string, limit int) ([]grepMatch, bool, error) {
|
||||
matches, err := searchWithRipgrep(pattern, rootPath, include)
|
||||
if err != nil {
|
||||
matches, err = searchFilesWithRegex(pattern, rootPath, include)
|
||||
@@ -191,12 +200,7 @@ func searchFiles(pattern, rootPath, include string, limit int) ([]string, bool,
|
||||
matches = matches[:limit]
|
||||
}
|
||||
|
||||
results := make([]string, len(matches))
|
||||
for i, m := range matches {
|
||||
results[i] = m.path
|
||||
}
|
||||
|
||||
return results, truncated, nil
|
||||
return matches, truncated, nil
|
||||
}
|
||||
|
||||
func searchWithRipgrep(pattern, path, include string) ([]grepMatch, error) {
|
||||
@@ -205,7 +209,8 @@ func searchWithRipgrep(pattern, path, include string) ([]grepMatch, error) {
|
||||
return nil, fmt.Errorf("ripgrep not found: %w", err)
|
||||
}
|
||||
|
||||
args := []string{"-l", pattern}
|
||||
// Use -n to show line numbers and include the matched line
|
||||
args := []string{"-n", pattern}
|
||||
if include != "" {
|
||||
args = append(args, "--glob", include)
|
||||
}
|
||||
@@ -228,14 +233,29 @@ func searchWithRipgrep(pattern, path, include string) ([]grepMatch, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(line)
|
||||
// Parse ripgrep output format: file:line:content
|
||||
parts := strings.SplitN(line, ":", 3)
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
filePath := parts[0]
|
||||
lineNum, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lineText := parts[2]
|
||||
|
||||
fileInfo, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
continue // Skip files we can't access
|
||||
}
|
||||
|
||||
matches = append(matches, grepMatch{
|
||||
path: line,
|
||||
modTime: fileInfo.ModTime(),
|
||||
path: filePath,
|
||||
modTime: fileInfo.ModTime(),
|
||||
lineNum: lineNum,
|
||||
lineText: lineText,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -276,15 +296,17 @@ func searchFilesWithRegex(pattern, rootPath, include string) ([]grepMatch, error
|
||||
return nil
|
||||
}
|
||||
|
||||
match, err := fileContainsPattern(path, regex)
|
||||
match, lineNum, lineText, err := fileContainsPattern(path, regex)
|
||||
if err != nil {
|
||||
return nil // Skip files we can't read
|
||||
}
|
||||
|
||||
if match {
|
||||
matches = append(matches, grepMatch{
|
||||
path: path,
|
||||
modTime: info.ModTime(),
|
||||
path: path,
|
||||
modTime: info.ModTime(),
|
||||
lineNum: lineNum,
|
||||
lineText: lineText,
|
||||
})
|
||||
|
||||
if len(matches) >= 200 {
|
||||
@@ -301,21 +323,24 @@ func searchFilesWithRegex(pattern, rootPath, include string) ([]grepMatch, error
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
func fileContainsPattern(filePath string, pattern *regexp.Regexp) (bool, error) {
|
||||
func fileContainsPattern(filePath string, pattern *regexp.Regexp) (bool, int, string, error) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, 0, "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
lineNum := 0
|
||||
for scanner.Scan() {
|
||||
if pattern.MatchString(scanner.Text()) {
|
||||
return true, nil
|
||||
lineNum++
|
||||
line := scanner.Text()
|
||||
if pattern.MatchString(line) {
|
||||
return true, lineNum, line, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, scanner.Err()
|
||||
return false, 0, "", scanner.Err()
|
||||
}
|
||||
|
||||
func globToRegex(glob string) string {
|
||||
|
||||
Reference in New Issue
Block a user