Files
iris-context/commands/core/filegen.go
T

111 lines
2.6 KiB
Go

package core
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// for tracking current working dir
var ShellPID int
// GetCWD returns the current working directory of the underlying shell
// on Linux, it reads it from /proc/[pid]/cwd
func GetCWD() string {
if ShellPID > 0 {
path := fmt.Sprintf("/proc/%d/cwd", ShellPID)
cwd, err := os.Readlink(path)
if err == nil {
return cwd
}
}
cwd, _ := os.Getwd()
return cwd
}
// FileGenerator provides directory and file suggestions.
// It handles nested paths (e.g., 'src/main') by resolving the directory
// and filtering based on the last path component
//
// E.g, we have both src/main.go and src/main.py
// you type "cat src/mai", partial = "src/mai"
// dir = "src/", filePrefix = "mai"
// search for which matches "mai" case, and show it (whici is both main.go and main.py)
// but if you type "go run src/mai" -> it will only shows suggestion about src/main.go
// NOTE: it will skip hidden file start with dot prefix
func FileGenerator(filters ...string) GeneratorFunc {
dirOnly := false
filterSet := make(map[string]bool)
for _, f := range filters {
if f == "/" {
dirOnly = true
continue
}
filterSet[strings.ToLower(f)] = true
}
return func(tokens []string, prefix string, partial string) []Suggestion {
base := GetCWD()
dir := base
filePrefix := partial
// check if the partial string contains path separators
if i := strings.LastIndexAny(partial, "/\\"); i != -1 {
dir = filepath.Join(base, partial[:i+1])
filePrefix = partial[i+1:]
}
entries, err := os.ReadDir(dir)
if err != nil {
return nil
}
// build the path prefix for the relative suggestions
// e.g. if partial is "src/m", then pathPrefix is "src/"
pathPrefix := ""
if i := strings.LastIndexAny(partial, "/\\"); i != -1 {
pathPrefix = partial[:i+1]
}
var results []Suggestion
for _, entry := range entries {
name := entry.Name()
// skip hidden files
if strings.HasPrefix(name, ".") {
continue
}
// filter by filePrefix
if filePrefix != "" && !hasPrefix(name, filePrefix) {
continue
}
fullPath := pathPrefix + name
if entry.IsDir() {
if dirOnly || len(filterSet) == 0 {
results = append(results, Suggestion{
Cmd: fullPath + "/",
Desc: "directory",
})
}
continue
}
// if filters are set, only show matching extensions
if len(filterSet) > 0 {
ext := strings.ToLower(filepath.Ext(name))
if !filterSet[ext] {
continue
}
}
results = append(results, Suggestion{
Cmd: fullPath,
Desc: "file",
})
}
return results
}
}