feat: now pressing space show alias as full command
This commit is contained in:
+6
-17
@@ -8,6 +8,11 @@ import (
|
|||||||
|
|
||||||
var shellAliases = make(map[string]string)
|
var shellAliases = make(map[string]string)
|
||||||
|
|
||||||
|
func GetAlias(name string) (string, bool) {
|
||||||
|
target, ok := shellAliases[name]
|
||||||
|
return target, ok
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup finds matching suggestions for your input by looking at how many words you typed
|
// Lookup finds matching suggestions for your input by looking at how many words you typed
|
||||||
// it changes aliases to real commands, finds subcommands inside others, and runs generators for more suggestions
|
// it changes aliases to real commands, finds subcommands inside others, and runs generators for more suggestions
|
||||||
// e.g. Lookup("git che") -> suggests "git checkout"
|
// e.g. Lookup("git che") -> suggests "git checkout"
|
||||||
@@ -18,15 +23,13 @@ func Lookup(input string) []Suggestion {
|
|||||||
} else {
|
} else {
|
||||||
shellAliases = make(map[string]string)
|
shellAliases = make(map[string]string)
|
||||||
}
|
}
|
||||||
// if input is empty, we show nothing
|
|
||||||
if input == "" {
|
if input == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert raw input into tokens to find out how many words you typed
|
|
||||||
tokens := tokenize(input)
|
tokens := tokenize(input)
|
||||||
|
|
||||||
// if the only word is empty, we show nothing
|
|
||||||
if len(tokens) == 1 && tokens[0] == "" {
|
if len(tokens) == 1 && tokens[0] == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -49,7 +52,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if you only typed one word, we show root commands and their first subcommands if there is a space
|
|
||||||
if len(tokens) == 1 {
|
if len(tokens) == 1 {
|
||||||
query := tokens[0]
|
query := tokens[0]
|
||||||
results := topLevelSuggestions(query)
|
results := topLevelSuggestions(query)
|
||||||
@@ -79,14 +81,12 @@ func Lookup(input string) []Suggestion {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the first command name and check if it is in our registry
|
|
||||||
rootCmdName := tokens[0]
|
rootCmdName := tokens[0]
|
||||||
spec, exists := registry[rootCmdName]
|
spec, exists := registry[rootCmdName]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// look deep into subcommands to find exactly where you are typing right now
|
|
||||||
currentSubs, currentOpts, currentGen := spec.Subcommands, spec.Options, spec.Generator
|
currentSubs, currentOpts, currentGen := spec.Subcommands, spec.Options, spec.Generator
|
||||||
depth := 1
|
depth := 1
|
||||||
|
|
||||||
@@ -125,7 +125,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
|
|
||||||
results := []Suggestion{}
|
results := []Suggestion{}
|
||||||
|
|
||||||
// find out how many words this command is allowed to have
|
|
||||||
currentLimit := spec.MaxArgs
|
currentLimit := spec.MaxArgs
|
||||||
tempSubs := spec.Subcommands
|
tempSubs := spec.Subcommands
|
||||||
for i := 1; i < depth; i++ {
|
for i := 1; i < depth; i++ {
|
||||||
@@ -139,7 +138,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// count how many words you already typed so we can follow the command rules
|
|
||||||
argCount := 0
|
argCount := 0
|
||||||
for i := depth; i < len(tokens)-1; i++ {
|
for i := depth; i < len(tokens)-1; i++ {
|
||||||
t := tokens[i]
|
t := tokens[i]
|
||||||
@@ -154,7 +152,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
debugLog("[core] query tokens: %v (partial: '%s')", tokens, partial)
|
debugLog("[core] query tokens: %v (partial: '%s')", tokens, partial)
|
||||||
debugLog("[core] depth: %d, argCount: %d, limit: %d, allowMore: %v", depth, argCount, currentLimit, allowMoreArgs)
|
debugLog("[core] depth: %d, argCount: %d, limit: %d, allowMore: %v", depth, argCount, currentLimit, allowMoreArgs)
|
||||||
|
|
||||||
// make the start of the command line to show it in the suggestion menu
|
|
||||||
prefixBuilder := strings.Builder{}
|
prefixBuilder := strings.Builder{}
|
||||||
for i := 0; i < depth; i++ {
|
for i := 0; i < depth; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
@@ -173,7 +170,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
linePrefix := linePrefixBuilder.String()
|
linePrefix := linePrefixBuilder.String()
|
||||||
|
|
||||||
// run special code to find things like git branch names or file names
|
|
||||||
if currentGen != nil && allowMoreArgs {
|
if currentGen != nil && allowMoreArgs {
|
||||||
genResults := currentGen(tokens, prefix, partial)
|
genResults := currentGen(tokens, prefix, partial)
|
||||||
|
|
||||||
@@ -188,7 +184,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
finalCmd = cleanLinePrefix + " " + g.Cmd
|
finalCmd = cleanLinePrefix + " " + g.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not suggest words that you already typed to avoid repeating the same word
|
|
||||||
newTokens := tokenize(finalCmd)
|
newTokens := tokenize(finalCmd)
|
||||||
if len(newTokens) > 0 {
|
if len(newTokens) > 0 {
|
||||||
lastToken := newTokens[len(newTokens)-1]
|
lastToken := newTokens[len(newTokens)-1]
|
||||||
@@ -212,7 +207,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add normal subcommands that match the letters you are typing
|
|
||||||
if allowMoreArgs {
|
if allowMoreArgs {
|
||||||
for _, sub := range currentSubs {
|
for _, sub := range currentSubs {
|
||||||
if partial == "" || hasPrefix(sub.Name, partial) {
|
if partial == "" || hasPrefix(sub.Name, partial) {
|
||||||
@@ -223,7 +217,6 @@ func Lookup(input string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// show flags or options only if you start typing with a dash character
|
|
||||||
if len(partial) > 0 && partial[0] == '-' {
|
if len(partial) > 0 && partial[0] == '-' {
|
||||||
usedOpts := make(map[string]bool)
|
usedOpts := make(map[string]bool)
|
||||||
for _, t := range tokens {
|
for _, t := range tokens {
|
||||||
@@ -243,11 +236,9 @@ func Lookup(input string) []Suggestion {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
// topLevelSuggestions looks for matches in your aliases, iris specs, and system commands
|
|
||||||
func topLevelSuggestions(query string) []Suggestion {
|
func topLevelSuggestions(query string) []Suggestion {
|
||||||
results, seen := []Suggestion{}, make(map[string]bool)
|
results, seen := []Suggestion{}, make(map[string]bool)
|
||||||
|
|
||||||
// check the shell aliases first because they are the most important
|
|
||||||
for name, target := range shellAliases {
|
for name, target := range shellAliases {
|
||||||
if !seen[name] && (query == "" || hasPrefix(name, query)) {
|
if !seen[name] && (query == "" || hasPrefix(name, query)) {
|
||||||
results = append(results, Suggestion{
|
results = append(results, Suggestion{
|
||||||
@@ -257,7 +248,6 @@ func topLevelSuggestions(query string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we search for iris commands that were registered in the code
|
|
||||||
for name, spec := range registry {
|
for name, spec := range registry {
|
||||||
if seen[name] {
|
if seen[name] {
|
||||||
continue
|
continue
|
||||||
@@ -279,7 +269,6 @@ func topLevelSuggestions(query string) []Suggestion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we still find nothing, we look for system commands in your path folders
|
|
||||||
for name := range pathCmds {
|
for name := range pathCmds {
|
||||||
if !seen[name] && (query == "" || hasPrefix(name, query)) {
|
if !seen[name] && (query == "" || hasPrefix(name, query)) {
|
||||||
results = append(results, Suggestion{
|
results = append(results, Suggestion{
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ type procInfo struct {
|
|||||||
comm string
|
comm string
|
||||||
}
|
}
|
||||||
|
|
||||||
// detectShell identifies the shell type by scanning parent processes
|
|
||||||
func detectShell() string {
|
func detectShell() string {
|
||||||
pid := os.Getppid()
|
pid := os.Getppid()
|
||||||
for i := 0; i < 5 && pid > 1; i++ {
|
for i := 0; i < 5 && pid > 1; i++ {
|
||||||
@@ -55,8 +54,6 @@ func detectShell() string {
|
|||||||
return "bash"
|
return "bash"
|
||||||
}
|
}
|
||||||
|
|
||||||
// getActiveInnerShell retrieves the most recently started shell in the process tree
|
|
||||||
// example: getActiveInnerShell(1234, "bash")
|
|
||||||
func getActiveInnerShell(rootPid int, defaultShell string) string {
|
func getActiveInnerShell(rootPid int, defaultShell string) string {
|
||||||
cmd := exec.Command("ps", "-e", "-o", "pid,ppid,comm")
|
cmd := exec.Command("ps", "-e", "-o", "pid,ppid,comm")
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
|
|||||||
+14
-1
@@ -47,7 +47,7 @@ func runWrapper() {
|
|||||||
c.ExtraFiles[10] = w
|
c.ExtraFiles[10] = w
|
||||||
c.Env = adapter.GetEnv(10, os.Getpid())
|
c.Env = adapter.GetEnv(10, os.Getpid())
|
||||||
|
|
||||||
ptmx, err := pty.Start(c) // start shell in a pseudo-terminal
|
ptmx, err := pty.Start(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "[IRIS] failed to start PTY: %v\n", err)
|
fmt.Fprintf(os.Stderr, "[IRIS] failed to start PTY: %v\n", err)
|
||||||
return
|
return
|
||||||
@@ -287,6 +287,8 @@ func runWrapper() {
|
|||||||
|
|
||||||
if !intercepted {
|
if !intercepted {
|
||||||
ptmx.Write([]byte{b})
|
ptmx.Write([]byte{b})
|
||||||
|
// we handle line editing keys manually to keep naiveBuffer in sync
|
||||||
|
// since terminal is in raw mode, we must update our state for every change
|
||||||
switch b {
|
switch b {
|
||||||
case 127, 0x08: // backspace: remove last character from buffer
|
case 127, 0x08: // backspace: remove last character from buffer
|
||||||
if len(naiveBuffer) > 0 {
|
if len(naiveBuffer) > 0 {
|
||||||
@@ -309,6 +311,17 @@ func runWrapper() {
|
|||||||
default:
|
default:
|
||||||
// track normal printable characters in the buffer for matching
|
// track normal printable characters in the buffer for matching
|
||||||
if b >= 32 && b <= 126 {
|
if b >= 32 && b <= 126 {
|
||||||
|
// if user presses space, check if the current word is an alias
|
||||||
|
if b == ' ' && naiveBuffer != "" && !strings.Contains(naiveBuffer, " ") {
|
||||||
|
if target, ok := core.GetAlias(naiveBuffer); ok {
|
||||||
|
// clear the current alias and replace it with the full command
|
||||||
|
ptmx.Write([]byte{0x15}) // ctrl+u to clear the current input line
|
||||||
|
ptmx.Write([]byte(target + " "))
|
||||||
|
naiveBuffer = target + " "
|
||||||
|
shouldOverlayDraw = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
naiveBuffer += string(b)
|
naiveBuffer += string(b)
|
||||||
shouldOverlayDraw = true
|
shouldOverlayDraw = true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user