feat(spec): scan shell aliases like .zshrc, .bashrc, ...
This commit is contained in:
+56
-9
@@ -3,6 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -43,11 +44,50 @@ type Suggestion struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
registry = map[string]*Spec{}
|
registry = map[string]*Spec{}
|
||||||
pathCmds = make(map[string]bool)
|
pathCmds = make(map[string]bool)
|
||||||
pathOnce sync.Once
|
shellAliases = make(map[string]string) // alias name -> target command
|
||||||
|
pathOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var aliasRegex = regexp.MustCompile(`^alias\s+([a-zA-Z0-9_\-]+)=['"]?([^'"]+)['"]?`)
|
||||||
|
|
||||||
|
// scanShellAliases parses shell config files for aliases
|
||||||
|
func scanShellAliases() {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
files := []string{".zshrc", ".bashrc", ".bash_profile", ".bash_aliases"}
|
||||||
|
for _, f := range files {
|
||||||
|
content, err := os.ReadFile(filepath.Join(home, f))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(string(content), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
matches := aliasRegex.FindStringSubmatch(line)
|
||||||
|
if len(matches) == 3 {
|
||||||
|
name := matches[1]
|
||||||
|
target := matches[2]
|
||||||
|
fields := strings.Fields(target)
|
||||||
|
if len(fields) > 0 {
|
||||||
|
shellAliases[name] = fields[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanExternalCommands populates pathCmds and shellAliases
|
||||||
|
func scanExternalCommands() {
|
||||||
|
scanPath()
|
||||||
|
scanShellAliases()
|
||||||
|
}
|
||||||
|
|
||||||
// scanPath populates pathCmds with all executable files found in $PATH
|
// scanPath populates pathCmds with all executable files found in $PATH
|
||||||
func scanPath() {
|
func scanPath() {
|
||||||
pathVar := os.Getenv("PATH")
|
pathVar := os.Getenv("PATH")
|
||||||
@@ -89,6 +129,8 @@ func Register(s *Spec) {
|
|||||||
//
|
//
|
||||||
// priority: file/dir -> subcommands -> options
|
// priority: file/dir -> subcommands -> options
|
||||||
func Lookup(input string) []Suggestion {
|
func Lookup(input string) []Suggestion {
|
||||||
|
pathOnce.Do(scanExternalCommands)
|
||||||
|
|
||||||
tokens := tokenize(input)
|
tokens := tokenize(input)
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return topLevelSuggestions(input)
|
return topLevelSuggestions(input)
|
||||||
@@ -99,8 +141,13 @@ func Lookup(input string) []Suggestion {
|
|||||||
return topLevelSuggestions(tokens[0])
|
return topLevelSuggestions(tokens[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
root := tokens[0]
|
rootCmdName := tokens[0]
|
||||||
spec, exists := registry[root]
|
// resolve shell alias (e.g. g -> git)
|
||||||
|
if target, ok := shellAliases[rootCmdName]; ok {
|
||||||
|
rootCmdName = target
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, exists := registry[rootCmdName]
|
||||||
if !exists {
|
if !exists {
|
||||||
// no spec found for this command, return nothing to avoid clutter
|
// no spec found for this command, return nothing to avoid clutter
|
||||||
return nil
|
return nil
|
||||||
@@ -189,7 +236,7 @@ func Lookup(input string) []Suggestion {
|
|||||||
results = append(results, Suggestion{
|
results = append(results, Suggestion{
|
||||||
Cmd: g.Cmd,
|
Cmd: g.Cmd,
|
||||||
Desc: g.Desc,
|
Desc: g.Desc,
|
||||||
Icon: root,
|
Icon: rootCmdName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +248,7 @@ func Lookup(input string) []Suggestion {
|
|||||||
results = append(results, Suggestion{
|
results = append(results, Suggestion{
|
||||||
Cmd: prefix + " " + sub.Name,
|
Cmd: prefix + " " + sub.Name,
|
||||||
Desc: sub.Description,
|
Desc: sub.Description,
|
||||||
Icon: root,
|
Icon: rootCmdName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,7 +273,7 @@ func Lookup(input string) []Suggestion {
|
|||||||
results = append(results, Suggestion{
|
results = append(results, Suggestion{
|
||||||
Cmd: prefix + " " + opt.Name,
|
Cmd: prefix + " " + opt.Name,
|
||||||
Desc: opt.Description,
|
Desc: opt.Description,
|
||||||
Icon: root,
|
Icon: rootCmdName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,7 +283,7 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func topLevelSuggestions(query string) []Suggestion {
|
func topLevelSuggestions(query string) []Suggestion {
|
||||||
pathOnce.Do(scanPath)
|
pathOnce.Do(scanExternalCommands)
|
||||||
|
|
||||||
results := []Suggestion{}
|
results := []Suggestion{}
|
||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
|
|||||||
Reference in New Issue
Block a user