package input_parser import ( "bbash/environment" "bufio" "fmt" "os" "strings" "golang.org/x/term" ) var prevGhostString string type Input struct { // The instruction a.k.a first argument Instruction string // The args, currently just the string after the instruction Args []string Args_raw string Flags []string } func Parse(env *environment.Env) Input { input := input_str(env) return Parse_input(input) } func Parse_input(input string) Input { split := strings.Split(string(input), " ") instruction := strings.TrimSpace(split[0]) args_raw := "" if len(split) > 1 { args_raw = split[1] } var flags []string var args []string for _, arg := range split[1:] { if len(arg) == 0 { continue } else if len(arg) == 1 { if arg[0] == '-' { continue } else { args = append(args, strings.TrimSpace(arg)) } } else if arg[0:2] == "--" { var result = strings.TrimSpace(arg) flags = append(flags, string(result[2:])) continue } else if arg[0] == '-' { var result = strings.TrimSpace(arg) for _, c := range result[1:] { flags = append(flags, string(c)) } continue } else { args = append(args, strings.TrimSpace(arg)) } } return Input{ Instruction: instruction, Args: args, Flags: flags, Args_raw: args_raw, } } func input_str(env *environment.Env) string { std_fd := os.Stdin.Fd() term_restore, err := term.MakeRaw(int(std_fd)) if err != nil { fmt.Println(fmt.Sprintf("Error opening terminal: %s", err.Error())) panic(err.Error()) } reader := bufio.NewReader(os.Stdin) var input string history_index := len(env.History) // not -1 since we start at the new one env.History = append(env.History, input) env.History[len(env.History)-1] = input fmt.Print("\r\033[K") fmt.Print(env.Path) fmt.Print(" > ") fmt.Print(input) for { r_rune, _, err := reader.ReadRune() // fmt.Printf("Rune: %d\n", r_rune) if err != nil { fmt.Print(fmt.Sprintf("Error reading user input: ", err.Error())) } switch r_rune { case 3: // ^C fmt.Println("^C") input = "" case 4: // ^D input = "exit" goto loop_exit case 9: // Tab // fmt.Println("test tab") input = AutoComplete(input) // fmt.Println(input) case 27: // arrow? if r, _, _ := reader.ReadRune(); r != 91 { break } if r, _, _ := reader.ReadRune(); r == 65 { // UPP if history_index > 0 { history_index-- input = env.History[history_index] } break } if r, _, _ := reader.ReadRune(); r != 66 { //DOWN if history_index < len(env.History)-1 { history_index++ input = env.History[history_index] } else { input = "" } break } case 62: input = input + prevGhostString case 127: //packspace if len(input) > 0 { input = input[:len(input)-1] } case 13: // Enter goto loop_exit default: input = input + string(r_rune) } ghost_input := AutoCompleteHistory(input, *env) env.History[len(env.History)-1] = input //fmt.Println(r_rune) fmt.Print("\r") // fmt.Print("\r\033[K") fmt.Print(env.Path) fmt.Print(" > ") fmt.Print("\033[K") fmt.Print(input) fmt.Print("\033[2m", ghost_input, "\033[0m") prevGhostString = "" backwardSteps := len(ghost_input) if backwardSteps != 0 { fmt.Printf("\033[%dD", backwardSteps) prevGhostString = ghost_input } } loop_exit: term.Restore(int(std_fd), term_restore) fmt.Println() return input }