Files
kitty/kittens/choose_files/save-file.go
2026-02-22 16:44:57 +05:30

163 lines
4.0 KiB
Go

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
}