github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/globbing.go (about) 1 package expressions 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strings" 7 "sync" 8 9 "github.com/lmorg/murex/utils/ansi/codes" 10 "github.com/lmorg/murex/utils/escape" 11 "github.com/lmorg/murex/utils/readline" 12 ) 13 14 func (tree *ParserT) parseGlob(glob []rune) ([]string, error) { 15 globS := string(glob) 16 17 match, globErr := filepath.Glob(globS) 18 expand, err := expandGlobPrompt(tree.statement.String(), globS, match) 19 if err != nil { 20 return nil, err 21 } 22 if !expand { 23 return nil, nil 24 } 25 26 if globErr != nil { 27 return nil, fmt.Errorf("invalid glob: '%s'\n%s", globS, err.Error()) 28 } 29 if len(match) == 0 { 30 return nil, fmt.Errorf("glob returned zero results.\nglob: '%s'", globS) 31 } 32 33 return match, nil 34 } 35 36 var rlMutex sync.Mutex 37 38 func expandGlobPrompt(cmd string, before string, match []string) (bool, error) { 39 rlMutex.Lock() 40 defer rlMutex.Unlock() // performance doesn't matter here 41 42 rl := readline.NewInstance() 43 prompt := fmt.Sprintf("(%s) Do you wish to expand '%s'? [yN]: ", cmd, before) 44 rl.SetPrompt(prompt) 45 rl.HintText = func(_ []rune, _ int) []rune { return autoGlobPromptHintText(rl, match) } 46 rl.History = new(readline.NullHistory) 47 48 for { 49 line, err := rl.Readline() 50 if err != nil { 51 return false, err 52 } 53 54 switch strings.ToLower(line) { 55 case "y", "yes": 56 return true, nil 57 case "", "n", "no": 58 return false, nil 59 } 60 } 61 } 62 63 const ( 64 warningNoGlobMatch = "Warning: no files match that pattern" 65 globExpandsTo = "Glob expands to: " 66 ) 67 68 func autoGlobPromptHintText(rl *readline.Instance, match []string) []rune { 69 if len(match) == 0 { 70 rl.HintFormatting = codes.FgRed 71 return []rune(warningNoGlobMatch) 72 } 73 74 slice := make([]string, len(match)) 75 copy(slice, match) 76 escape.CommandLine(slice) 77 after := globExpandsTo + strings.Join(slice, ", ") 78 return []rune(after) 79 }