Add a new "file" mode to the ask kitten

This commit is contained in:
Kovid Goyal 2025-08-15 21:18:25 +05:30
parent 7b1647a5f7
commit 23d8648f5d
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 67 additions and 46 deletions

View file

@ -9,6 +9,7 @@ import (
"path/filepath"
"time"
"github.com/kovidgoyal/kitty/kittens/choose_files"
"github.com/kovidgoyal/kitty/tools/tui/loop"
"github.com/kovidgoyal/kitty/tools/tui/readline"
"github.com/kovidgoyal/kitty/tools/utils"
@ -16,13 +17,16 @@ import (
var _ = fmt.Print
func get_line(o *Options) (result string, err error) {
func get_line(o *Options, complete_file_names bool) (result string, err error) {
lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors)
if err != nil {
return
}
cwd, _ := os.Getwd()
ropts := readline.RlInit{Prompt: o.Prompt}
if complete_file_names {
ropts.Completer = choose_files.FilePromptCompleter(nil)
}
if o.Name != "" {
base := filepath.Join(utils.CacheDir(), "ask")
ropts.HistoryPath = filepath.Join(base, o.Name+".history.json")

View file

@ -50,7 +50,13 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
result.Response = pw
case "line":
show_message(o.Message)
result.Response, err = get_line(o)
result.Response, err = get_line(o, false)
if err != nil {
return 1, err
}
case "file":
show_message(o.Message)
result.Response, err = get_line(o, true)
if err != nil {
return 1, err
}

View file

@ -11,7 +11,7 @@ from ..tui.handler import result_handler
def option_text() -> str:
return '''\
--type -t
choices=line,yesno,choices,password
choices=line,yesno,choices,password,file
default=line
Type of input. Defaults to asking for a line of text.

View file

@ -776,7 +776,7 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
lp.ColorSchemeChangeNotifications()
handler := Handler{lp: lp, err_chan: make(chan error, 8), msg_printer: message.NewPrinter(utils.LanguageTag()), spinner: tui.NewSpinner("dots")}
handler.rl = readline.New(lp, readline.RlInit{
Prompt: "> ", ContinuationPrompt: ". ", Completer: handler.complete_save_prompt,
Prompt: "> ", ContinuationPrompt: ". ", Completer: FilePromptCompleter(handler.state.CurrentDir),
})
if err = handler.set_state_from_config(conf, opts); err != nil {
return 1, err

View file

@ -13,51 +13,62 @@ import (
var _ = fmt.Print
func (h *Handler) complete_save_prompt(before_cursor, after_cursor string) *cli.Completions {
path := before_cursor
prefix := ""
if idx := strings.Index(path, string(os.PathSeparator)); idx > -1 {
prefix = filepath.Dir(path) + string(os.PathSeparator)
}
dir := ""
if path == "" {
path = h.state.CurrentDir()
dir = path
} else {
if !filepath.IsAbs(path) {
path = filepath.Join(h.state.CurrentDir(), 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
}
ans := cli.NewCompletions()
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
func FilePromptCompleter(getcwd func() string) func(string, string) *cli.Completions {
if getcwd == nil {
getcwd = func() string {
ans, err := os.Getwd()
if err != nil {
ans = "."
}
collection.Matches = append(collection.Matches, &cli.Match{Word: word})
return ans
}
}
return ans
return func(before_cursor, after_cursor string) *cli.Completions {
path := before_cursor
prefix := ""
if idx := strings.Index(path, string(os.PathSeparator)); idx > -1 {
prefix = filepath.Dir(path) + 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
}
ans := cli.NewCompletions()
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 {