diff options
Diffstat (limited to 'internal/completions')
| -rw-r--r-- | internal/completions/files-folders.go | 191 |
1 files changed, 0 insertions, 191 deletions
diff --git a/internal/completions/files-folders.go b/internal/completions/files-folders.go deleted file mode 100644 index a405b34cd..000000000 --- a/internal/completions/files-folders.go +++ /dev/null @@ -1,191 +0,0 @@ -package completions - -import ( - "bytes" - "fmt" - "os/exec" - "path/filepath" - - "github.com/lithammer/fuzzysearch/fuzzy" - "github.com/sst/opencode/internal/fileutil" - "github.com/sst/opencode/internal/status" - "github.com/sst/opencode/internal/tui/components/dialog" -) - -type filesAndFoldersContextGroup struct { - prefix string -} - -func (cg *filesAndFoldersContextGroup) GetId() string { - return cg.prefix -} - -func (cg *filesAndFoldersContextGroup) GetEntry() dialog.CompletionItemI { - return dialog.NewCompletionItem(dialog.CompletionItem{ - Title: "Files & Folders", - Value: "files", - }) -} - -func processNullTerminatedOutput(outputBytes []byte) []string { - if len(outputBytes) > 0 && outputBytes[len(outputBytes)-1] == 0 { - outputBytes = outputBytes[:len(outputBytes)-1] - } - - if len(outputBytes) == 0 { - return []string{} - } - - split := bytes.Split(outputBytes, []byte{0}) - matches := make([]string, 0, len(split)) - - for _, p := range split { - if len(p) == 0 { - continue - } - - path := string(p) - path = filepath.Join(".", path) - - if !fileutil.SkipHidden(path) { - matches = append(matches, path) - } - } - - return matches -} - -func (cg *filesAndFoldersContextGroup) getFiles(query string) ([]string, error) { - cmdRg := fileutil.GetRgCmd("") // No glob pattern for this use case - cmdFzf := fileutil.GetFzfCmd(query) - - var matches []string - // Case 1: Both rg and fzf available - if cmdRg != nil && cmdFzf != nil { - rgPipe, err := cmdRg.StdoutPipe() - if err != nil { - return nil, fmt.Errorf("failed to get rg stdout pipe: %w", err) - } - defer rgPipe.Close() - - cmdFzf.Stdin = rgPipe - var fzfOut bytes.Buffer - var fzfErr bytes.Buffer - cmdFzf.Stdout = &fzfOut - cmdFzf.Stderr = &fzfErr - - if err := cmdFzf.Start(); err != nil { - return nil, fmt.Errorf("failed to start fzf: %w", err) - } - - errRg := cmdRg.Run() - errFzf := cmdFzf.Wait() - - if errRg != nil { - status.Warn(fmt.Sprintf("rg command failed during pipe: %v", errRg)) - } - - if errFzf != nil { - if exitErr, ok := errFzf.(*exec.ExitError); ok && exitErr.ExitCode() == 1 { - return []string{}, nil // No matches from fzf - } - return nil, fmt.Errorf("fzf command failed: %w\nStderr: %s", errFzf, fzfErr.String()) - } - - matches = processNullTerminatedOutput(fzfOut.Bytes()) - - // Case 2: Only rg available - } else if cmdRg != nil { - status.Debug("Using Ripgrep with fuzzy match fallback for file completions") - var rgOut bytes.Buffer - var rgErr bytes.Buffer - cmdRg.Stdout = &rgOut - cmdRg.Stderr = &rgErr - - if err := cmdRg.Run(); err != nil { - return nil, fmt.Errorf("rg command failed: %w\nStderr: %s", err, rgErr.String()) - } - - allFiles := processNullTerminatedOutput(rgOut.Bytes()) - matches = fuzzy.Find(query, allFiles) - - // Case 3: Only fzf available - } else if cmdFzf != nil { - status.Debug("Using FZF with doublestar fallback for file completions") - files, _, err := fileutil.GlobWithDoublestar("**/*", ".", 0) - if err != nil { - return nil, fmt.Errorf("failed to list files for fzf: %w", err) - } - - allFiles := make([]string, 0, len(files)) - for _, file := range files { - if !fileutil.SkipHidden(file) { - allFiles = append(allFiles, file) - } - } - - var fzfIn bytes.Buffer - for _, file := range allFiles { - fzfIn.WriteString(file) - fzfIn.WriteByte(0) - } - - cmdFzf.Stdin = &fzfIn - var fzfOut bytes.Buffer - var fzfErr bytes.Buffer - cmdFzf.Stdout = &fzfOut - cmdFzf.Stderr = &fzfErr - - if err := cmdFzf.Run(); err != nil { - if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 1 { - return []string{}, nil - } - return nil, fmt.Errorf("fzf command failed: %w\nStderr: %s", err, fzfErr.String()) - } - - matches = processNullTerminatedOutput(fzfOut.Bytes()) - - // Case 4: Fallback to doublestar with fuzzy match - } else { - status.Debug("Using doublestar with fuzzy match for file completions") - allFiles, _, err := fileutil.GlobWithDoublestar("**/*", ".", 0) - if err != nil { - return nil, fmt.Errorf("failed to glob files: %w", err) - } - - filteredFiles := make([]string, 0, len(allFiles)) - for _, file := range allFiles { - if !fileutil.SkipHidden(file) { - filteredFiles = append(filteredFiles, file) - } - } - - matches = fuzzy.Find(query, filteredFiles) - } - - return matches, nil -} - -func (cg *filesAndFoldersContextGroup) GetChildEntries(query string) ([]dialog.CompletionItemI, error) { - matches, err := cg.getFiles(query) - if err != nil { - return nil, err - } - - items := make([]dialog.CompletionItemI, 0, len(matches)) - for _, file := range matches { - item := dialog.NewCompletionItem(dialog.CompletionItem{ - Title: file, - Value: file, - }) - items = append(items, item) - } - - return items, nil -} - -func NewFileAndFolderContextGroup() dialog.CompletionProvider { - return &filesAndFoldersContextGroup{ - prefix: "file", - } -} |
