func (i *cli) ReadString(delim byte) (line string, err error) { system.SetForegroundGroup(system.Pgid()) uncooked.ApplyMode() defer cooked.ApplyMode() command := cell.List( cell.Cons( cell.NewSymbol("_sys_"), cell.NewSymbol("get-prompt"), ), cell.NewSymbol("> "), ) prompt := task.Call(nil, command, "") if line, err = i.State.Prompt(prompt); err == nil { i.AppendHistory(line) if task.ForegroundTask().Job.Command == "" { task.ForegroundTask().Job.Command = line } line += "\n" } if err == liner.ErrPromptAborted { return line, cell.ErrCtrlCPressed } return }
func (i *cli) ReadString(delim byte) (line string, err error) { task.SetForegroundGroup(task.Pgid()) uncooked.ApplyMode() defer cooked.ApplyMode() if line, err = i.State.Prompt(task.Pgid(), "> "); err == nil { i.AppendHistory(line) if task.ForegroundTask().Job.Command == "" { task.ForegroundTask().Job.Command = line } line += "\n" } return }
func complete(line string, pos int) (head string, completions []string, tail string) { first, state, completing := task.GlobalParser().State(line[:pos]) head = line[:pos] tail = line[pos:] defer func() { r := recover() if r == nil { return } completions = []string{} }() if state == "SkipWhitespace" { return head, []string{" "}, tail } if !strings.HasSuffix(head, completing) { return head, []string{}, tail } // Ensure line == prefix + completing + tail prefix := head[0 : len(head)-len(completing)] if first == "" { completions = executables(completing) } else { completions = files(completing) } completions = append( completions, task.ForegroundTask().Complete(first, completing)..., ) if len(completions) == 0 { return prefix, []string{completing}, tail } unique := make(map[string]bool) for _, completion := range completions { unique[completion] = true } completions = make([]string, 0, len(unique)) for completion := range unique { completions = append(completions, completion) } return prefix, completions, tail }
func complete(line string, pos int) (string, []string, string) { head := line[:pos] tail := line[pos:] fields := strings.Fields(head) if len(fields) == 0 { return head, []string{" "}, tail } word := fields[len(fields)-1] if !strings.HasSuffix(head, word) { return head, []string{}, tail } head = head[0 : len(head)-len(word)] completions := task.ForegroundTask().Complete(word) completions = append(completions, files(word)...) if len(fields) == 1 { completions = append(completions, executables(word)...) } if len(completions) == 0 { return head, []string{word}, tail } unique := make(map[string]bool) for _, completion := range completions { unique[completion] = true } completions = make([]string, 0, len(unique)) for completion := range unique { completions = append(completions, completion) } return head, completions, tail }
func (i *cli) ReadString(delim byte) (line string, err error) { task.SetForegroundGroup(task.Pgid()) uncooked.ApplyMode() defer cooked.ApplyMode() t := task.ForegroundTask() command := cell.List( cell.Cons(cell.NewSymbol("sys"), cell.NewSymbol("get-prompt")), cell.NewSymbol("> "), ) prompt := t.Call(command) if line, err = i.State.Prompt(prompt); err == nil { i.AppendHistory(line) if t.Job.Command == "" { t.Job.Command = line } line += "\n" } return }
func files(word string) []string { completions := []string{} candidate := word if candidate[:1] == "~" { candidate = filepath.Join(os.Getenv("HOME"), candidate[1:]) } candidate = path.Clean(candidate) if !path.IsAbs(candidate) { ft := task.ForegroundTask() n := cell.NewSymbol("$cwd") ref := task.Resolve(ft.Lexical, ft.Dynamic, n) cwd := ref.Get().String() candidate = path.Join(cwd, candidate) } dirname, basename := filepath.Split(candidate) if strings.HasSuffix(word, "/") { dirname, basename = path.Join(dirname, basename)+"/", "" } stat, err := os.Stat(dirname) if err != nil { return completions } else if len(basename) == 0 && !stat.IsDir() { return completions } max := strings.Count(dirname, "/") filepath.Walk(dirname, func(p string, i os.FileInfo, err error) error { depth := strings.Count(p, "/") if depth > max { if i.IsDir() { return filepath.SkipDir } return nil } else if depth < max { return nil } full := path.Join(dirname, basename) if len(basename) == 0 { if p == dirname { return nil } full += "/" } else if !strings.HasPrefix(p, full) { return nil } if i.IsDir() { p += "/" } if len(full) >= len(p) { return nil } completion := word + p[len(full):] completions = append(completions, completion) return nil }) return completions }