package choose_files import ( "fmt" "os" "path/filepath" "strings" "github.com/kovidgoyal/go-parallel" "github.com/kovidgoyal/kitty/tools/cli" "github.com/kovidgoyal/kitty/tools/tui/loop" "github.com/kovidgoyal/kitty/tools/utils" ) var _ = fmt.Print func FilePromptCompleter(getcwd func() string) func(string, string) *cli.Completions { if getcwd == nil { getcwd = func() string { ans, err := os.Getwd() if err != nil { ans = "." } return ans } } return func(before_cursor, after_cursor string) (ans *cli.Completions) { defer func() { if r := recover(); r != nil { err := parallel.Format_stacktrace_on_panic(r, 1) debugprintln(err) } }() ans = cli.NewCompletions() path := before_cursor prefix := "" if idx := strings.Index(path, string(os.PathSeparator)); idx > -1 { d := filepath.Dir(path) prefix = d + utils.IfElse(strings.HasSuffix(d, string(os.PathSeparator)), "", string(os.PathSeparator)) } dir := "" if path == "" { path = getcwd() dir = path } else { if !filepath.IsAbs(path) { path = filepath.Join(getcwd(), path) } dir = filepath.Dir(path) if strings.HasSuffix(before_cursor, string(os.PathSeparator)) { dir = path } } entries, err := os.ReadDir(dir) if err != nil { return nil } dirs := ans.AddMatchGroup("Directories") dirs.IsFiles = true dirs.NoTrailingSpace = true files := ans.AddMatchGroup("Files") files.IsFiles = true files.NoTrailingSpace = true leading, _ := filepath.Rel(dir, path) if leading == "." { leading = "" } for _, e := range entries { word := e.Name() if leading == "" || strings.HasPrefix(word, leading) { collection := utils.IfElse(e.Type().IsDir(), dirs, files) if prefix != "" { word = prefix + word } collection.Matches = append(collection.Matches, &cli.Match{Word: word}) } } return ans } } func (h *Handler) current_save_file_path() string { ans := h.rl.AllText() if ans != "" { ans = utils.Expanduser(ans) if !filepath.IsAbs(ans) { ans = filepath.Join(h.state.CurrentDir(), ans) } } return ans } func (h *Handler) save_file_name_handle_key(ev *loop.KeyEvent) (err error) { ac := h.shortcut_tracker.Match(ev, h.state.keyboard_shortcuts) if ac != nil { switch ac.Name { case "accept": if p := h.current_save_file_path(); p != "" { h.state.selections = append(h.state.selections, p) h.lp.Quit(0) } else { h.lp.Beep() } ev.Handled = true return nil case "select": if p := h.current_save_file_path(); p != "" { h.state.selections = append(h.state.selections, p) } ev.Handled = true h.rl.ResetText() return h.draw_screen() case "quit": h.state.screen = NORMAL ev.Handled = true return h.draw_screen() } } if err = h.rl.OnKeyEvent(ev); err == nil { err = h.draw_screen() } return } func (h *Handler) initialize_save_file_name(fname string) { h.state.screen = SAVE_FILE h.rl.ResetText() if len(h.state.selections) > 0 && fname == "" { if q, err := filepath.Abs(h.state.selections[0]); err == nil { if s, err := os.Stat(q); err == nil { if s.IsDir() == h.state.mode.OnlyDirs() { if fname, err = filepath.Rel(h.state.CurrentDir(), q); err != nil { fname = q } } } } } h.rl.SetText(fname) } func (h *Handler) draw_save_file_name_screen() (err error) { h.lp.AllowLineWrapping(true) desc := utils.IfElse(h.state.mode == SELECT_SAVE_FILE, "file", "directory") if h.state.DisplayTitle() { h.lp.Println(h.state.WindowTitle()) } h.lp.Println("Enter the name of the", desc, "below, relative to:") h.lp.Println(h.lp.SprintStyled("fg=green", h.state.CurrentDir())) if h.state.mode.AllowsMultipleSelection() { h.lp.Println("Use shift+enter (or whatever you mapped the select action to) to enter multiple filenames") } h.lp.Println() h.rl.RedrawNonAtomic() h.lp.AllowLineWrapping(false) if len(h.state.selections) > 0 { h.lp.SaveCursorPosition() h.draw_footer() h.lp.RestoreCursorPosition() } return }