rg.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package tools
  2. import (
  3. "context"
  4. "log/slog"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "sync"
  9. "github.com/charmbracelet/crush/internal/log"
  10. )
  11. var getRg = sync.OnceValue(func() string {
  12. path, err := exec.LookPath("rg")
  13. if err != nil {
  14. if log.Initialized() {
  15. slog.Warn("Ripgrep (rg) not found in $PATH. Some grep features might be limited or slower.")
  16. }
  17. return ""
  18. }
  19. return path
  20. })
  21. func getRgCmd(ctx context.Context, globPattern string) *exec.Cmd {
  22. name := getRg()
  23. if name == "" {
  24. return nil
  25. }
  26. args := []string{"--files", "-L", "--null"}
  27. if globPattern != "" {
  28. if !filepath.IsAbs(globPattern) && !strings.HasPrefix(globPattern, "/") {
  29. globPattern = "/" + globPattern
  30. }
  31. args = append(args, "--glob", globPattern)
  32. }
  33. return exec.CommandContext(ctx, name, args...)
  34. }
  35. func getRgSearchCmd(ctx context.Context, pattern, path, include string) *exec.Cmd {
  36. name := getRg()
  37. if name == "" {
  38. return nil
  39. }
  40. // Use -n to show line numbers, -0 for null separation to handle Windows paths
  41. args := []string{"--json", "-H", "-n", "-0", pattern}
  42. if include != "" {
  43. args = append(args, "--glob", include)
  44. }
  45. args = append(args, path)
  46. return exec.CommandContext(ctx, name, args...)
  47. }