feat(core): file generator for file suggestion
This commit is contained in:
@@ -0,0 +1,209 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
dir := "."
|
||||||
|
filePrefix := partial
|
||||||
|
|
||||||
|
// check if the partial string contains path separators
|
||||||
|
if i := strings.LastIndexAny(partial, "/\\"); i != -1 {
|
||||||
|
dir = 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() {
|
||||||
|
results = append(results, Suggestion{
|
||||||
|
Cmd: prefix + " " + fullPath + "/",
|
||||||
|
Desc: "directory",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if dirOnly {
|
||||||
|
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: prefix + " " + fullPath,
|
||||||
|
Desc: fileDesc(name),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileDesc(name string) string {
|
||||||
|
ext := strings.ToLower(filepath.Ext(name))
|
||||||
|
|
||||||
|
// special cases without extensions
|
||||||
|
if ext == "" {
|
||||||
|
switch name {
|
||||||
|
case "Dockerfile", "dockerfile":
|
||||||
|
return "dockerfile"
|
||||||
|
case "Makefile", "makefile":
|
||||||
|
return "makefile"
|
||||||
|
case "LICENSE", "license":
|
||||||
|
return "license"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ext {
|
||||||
|
case ".go":
|
||||||
|
return "go"
|
||||||
|
case ".js":
|
||||||
|
return "javascript"
|
||||||
|
case ".ts":
|
||||||
|
return "typescript"
|
||||||
|
case ".py":
|
||||||
|
return "python"
|
||||||
|
case ".rs":
|
||||||
|
return "rust"
|
||||||
|
case ".c", ".h":
|
||||||
|
return "c source"
|
||||||
|
case ".cpp", ".hpp", ".cc":
|
||||||
|
return "c++ source"
|
||||||
|
case ".java":
|
||||||
|
return "java"
|
||||||
|
case ".rb":
|
||||||
|
return "ruby"
|
||||||
|
case ".php":
|
||||||
|
return "php"
|
||||||
|
case ".kt":
|
||||||
|
return "kotlin"
|
||||||
|
case ".swift":
|
||||||
|
return "swift"
|
||||||
|
case ".sh":
|
||||||
|
return "shell script"
|
||||||
|
case ".lua":
|
||||||
|
return "lua"
|
||||||
|
case ".zig":
|
||||||
|
return "zig"
|
||||||
|
case ".ex", ".exs":
|
||||||
|
return "elixir"
|
||||||
|
|
||||||
|
case ".html", ".htm":
|
||||||
|
return "html"
|
||||||
|
case ".css":
|
||||||
|
return "stylesheet"
|
||||||
|
case ".scss", ".sass":
|
||||||
|
return "sass"
|
||||||
|
case ".jsx":
|
||||||
|
return "react (js)"
|
||||||
|
case ".tsx":
|
||||||
|
return "react (ts)"
|
||||||
|
case ".vue":
|
||||||
|
return "vue"
|
||||||
|
case ".svelte":
|
||||||
|
return "svelte"
|
||||||
|
|
||||||
|
case ".json":
|
||||||
|
return "json"
|
||||||
|
case ".yaml", ".yml":
|
||||||
|
return "yaml"
|
||||||
|
case ".toml":
|
||||||
|
return "toml"
|
||||||
|
case ".sql":
|
||||||
|
return "sql"
|
||||||
|
case ".xml":
|
||||||
|
return "xml"
|
||||||
|
case ".csv":
|
||||||
|
return "csv"
|
||||||
|
case ".env":
|
||||||
|
return "env file"
|
||||||
|
case ".lock":
|
||||||
|
return "lock file"
|
||||||
|
|
||||||
|
case ".md", ".markdown":
|
||||||
|
return "markdown"
|
||||||
|
case ".txt":
|
||||||
|
return "text file"
|
||||||
|
case ".pdf":
|
||||||
|
return "pdf"
|
||||||
|
case ".log":
|
||||||
|
return "log file"
|
||||||
|
|
||||||
|
case ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico":
|
||||||
|
return "image"
|
||||||
|
case ".mp4", ".mkv", ".avi", ".mov", ".webm":
|
||||||
|
return "video"
|
||||||
|
case ".mp3", ".wav", ".flac", ".ogg":
|
||||||
|
return "audio"
|
||||||
|
|
||||||
|
case ".dockerfile":
|
||||||
|
return "dockerfile"
|
||||||
|
case ".tf":
|
||||||
|
return "terraform"
|
||||||
|
case ".proto":
|
||||||
|
return "protobuf"
|
||||||
|
|
||||||
|
case ".zip", ".tar", ".gz", ".bz2", ".xz", ".7z", ".rar":
|
||||||
|
return "archive"
|
||||||
|
|
||||||
|
case ".mod":
|
||||||
|
return "go module"
|
||||||
|
case ".sum":
|
||||||
|
return "go checksum"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "file"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user