files.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package completions
  2. import (
  3. "context"
  4. "log/slog"
  5. "sort"
  6. "strconv"
  7. "strings"
  8. "github.com/sst/opencode-sdk-go"
  9. "github.com/sst/opencode/internal/app"
  10. "github.com/sst/opencode/internal/styles"
  11. "github.com/sst/opencode/internal/theme"
  12. )
  13. type filesContextGroup struct {
  14. app *app.App
  15. gitFiles []CompletionSuggestion
  16. }
  17. func (cg *filesContextGroup) GetId() string {
  18. return "files"
  19. }
  20. func (cg *filesContextGroup) GetEmptyMessage() string {
  21. return "no matching files"
  22. }
  23. func (cg *filesContextGroup) getGitFiles() []CompletionSuggestion {
  24. items := make([]CompletionSuggestion, 0)
  25. status, _ := cg.app.Client.File.Status(context.Background())
  26. if status != nil {
  27. files := *status
  28. sort.Slice(files, func(i, j int) bool {
  29. return files[i].Added+files[i].Removed > files[j].Added+files[j].Removed
  30. })
  31. for _, file := range files {
  32. displayFunc := func(s styles.Style) string {
  33. t := theme.CurrentTheme()
  34. green := s.Foreground(t.Success()).Render
  35. red := s.Foreground(t.Error()).Render
  36. display := file.Path
  37. if file.Added > 0 {
  38. display += green(" +" + strconv.Itoa(int(file.Added)))
  39. }
  40. if file.Removed > 0 {
  41. display += red(" -" + strconv.Itoa(int(file.Removed)))
  42. }
  43. return display
  44. }
  45. item := CompletionSuggestion{
  46. Display: displayFunc,
  47. Value: file.Path,
  48. ProviderID: cg.GetId(),
  49. RawData: file,
  50. }
  51. items = append(items, item)
  52. }
  53. }
  54. return items
  55. }
  56. func (cg *filesContextGroup) GetChildEntries(
  57. query string,
  58. ) ([]CompletionSuggestion, error) {
  59. items := make([]CompletionSuggestion, 0)
  60. query = strings.TrimSpace(query)
  61. if query == "" {
  62. items = append(items, cg.gitFiles...)
  63. }
  64. files, err := cg.app.Client.Find.Files(
  65. context.Background(),
  66. opencode.FindFilesParams{Query: opencode.F(query)},
  67. )
  68. if err != nil {
  69. slog.Error("Failed to get completion items", "error", err)
  70. return items, err
  71. }
  72. if files == nil {
  73. return items, nil
  74. }
  75. for _, file := range *files {
  76. exists := false
  77. for _, existing := range cg.gitFiles {
  78. if existing.Value == file {
  79. if query != "" {
  80. items = append(items, existing)
  81. }
  82. exists = true
  83. }
  84. }
  85. if !exists {
  86. displayFunc := func(s styles.Style) string {
  87. // t := theme.CurrentTheme()
  88. // return s.Foreground(t.Text()).Render(file)
  89. return s.Render(file)
  90. }
  91. item := CompletionSuggestion{
  92. Display: displayFunc,
  93. Value: file,
  94. ProviderID: cg.GetId(),
  95. RawData: file,
  96. }
  97. items = append(items, item)
  98. }
  99. }
  100. return items, nil
  101. }
  102. func NewFileContextGroup(app *app.App) CompletionProvider {
  103. cg := &filesContextGroup{
  104. app: app,
  105. }
  106. go func() {
  107. cg.gitFiles = cg.getGitFiles()
  108. }()
  109. return cg
  110. }