From b55013944e738f3c8ed9d5c17201d9e362c30bc7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 20 May 2025 14:16:49 +0530 Subject: [PATCH] More work on choose-files --- kittens/choose_files/main.go | 52 +++++++++++++++++++++++----- kittens/choose_files/search-bar.go | 54 ++++++++++++++++++++++++++++++ tools/tui/loop/api.go | 49 +++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 kittens/choose_files/search-bar.go diff --git a/kittens/choose_files/main.go b/kittens/choose_files/main.go index ec5098361..d641683cd 100644 --- a/kittens/choose_files/main.go +++ b/kittens/choose_files/main.go @@ -7,13 +7,29 @@ import ( "github.com/kovidgoyal/kitty/tools/cli" "github.com/kovidgoyal/kitty/tools/tty" "github.com/kovidgoyal/kitty/tools/tui/loop" + "github.com/kovidgoyal/kitty/tools/utils" ) var _ = fmt.Print var debugprintln = tty.DebugPrintln type State struct { - Base_dir string + base_dir string + current_dir string + select_dirs bool + multiselect bool + max_depth int + search_text string +} + +func (s State) BaseDir() string { return utils.IfElse(s.base_dir == "", default_cwd, s.base_dir) } +func (s State) SelectDirs() bool { return s.select_dirs } +func (s State) Multiselect() bool { return s.multiselect } +func (s State) MaxDepth() int { return utils.IfElse(s.max_depth < 1, 5, s.max_depth) } +func (s State) String() string { return utils.Repr(s) } +func (s State) SearchText() string { return s.search_text } +func (s State) CurrentDir() string { + return utils.IfElse(s.current_dir == "", s.BaseDir(), s.current_dir) } type ScreenSize struct { @@ -29,17 +45,40 @@ type Handler struct { func (h *Handler) draw_screen() (err error) { h.lp.StartAtomicUpdate() defer h.lp.EndAtomicUpdate() + h.lp.ClearScreen() + y := 0 + if dy, err := h.draw_search_bar(y); err != nil { + return err + } else { + y += dy + } return } +func (h *Handler) init_sizes(new_size loop.ScreenSize) { + h.screen_size.width = int(new_size.WidthCells) + h.screen_size.height = int(new_size.HeightCells) + h.screen_size.cell_width = int(new_size.CellWidth) + h.screen_size.cell_height = int(new_size.CellHeight) + h.screen_size.width_px = int(new_size.WidthPx) + h.screen_size.height_px = int(new_size.HeightPx) +} + func (h *Handler) OnInitialize() (ans string, err error) { + if sz, err := h.lp.ScreenSize(); err != nil { + return "", err + } else { + h.init_sizes(sz) + } h.lp.AllowLineWrapping(false) h.lp.SetCursorShape(loop.BAR_CURSOR, true) h.draw_screen() return } +var default_cwd string + func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) { lp, err := loop.New() if err != nil { @@ -49,22 +88,17 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) { switch len(args) { case 0: os.Getwd() - if handler.state.Base_dir, err = os.Getwd(); err != nil { + if default_cwd, err = os.Getwd(); err != nil { return } case 1: - handler.state.Base_dir = args[0] + default_cwd = args[0] default: return 1, fmt.Errorf("Can only specify one directory to search in") } lp.OnInitialize = handler.OnInitialize lp.OnResize = func(old, new_size loop.ScreenSize) (err error) { - handler.screen_size.width = int(new_size.WidthCells) - handler.screen_size.height = int(new_size.HeightCells) - handler.screen_size.cell_width = int(new_size.CellWidth) - handler.screen_size.cell_height = int(new_size.CellHeight) - handler.screen_size.width_px = int(new_size.WidthPx) - handler.screen_size.height_px = int(new_size.HeightPx) + handler.init_sizes(new_size) return handler.draw_screen() } err = lp.Run() diff --git a/kittens/choose_files/search-bar.go b/kittens/choose_files/search-bar.go new file mode 100644 index 000000000..df47a0872 --- /dev/null +++ b/kittens/choose_files/search-bar.go @@ -0,0 +1,54 @@ +package choose_files + +import ( + "fmt" + "strings" + + "github.com/kovidgoyal/kitty/tools/tui/loop" +) + +var _ = fmt.Print + +func (h *Handler) draw_frame(width, height int) { + lp := h.lp + for i := range height { + lp.SaveCursorPosition() + switch i { + case 0: + lp.QueueWriteString("╭") + lp.QueueWriteString(strings.Repeat("─", width-2)) + lp.QueueWriteString("╮") + case height - 1: + lp.QueueWriteString("╰") + lp.QueueWriteString(strings.Repeat("─", width-2)) + lp.QueueWriteString("╯") + default: + lp.QueueWriteString("│") + lp.MoveCursorHorizontally(width - 2) + lp.QueueWriteString("│") + } + lp.RestoreCursorPosition() + lp.MoveCursorVertically(1) + } +} + +func (h *Handler) draw_search_text() { + text := h.state.SearchText() + if text == "" { + h.lp.DrawSizedText(" ", loop.SizedText{Scale: 2}) + h.lp.MoveCursorHorizontally(-2) + return + } +} + +func (h *Handler) draw_search_bar(y int) (height int, err error) { + left_margin, right_margin := 5, 5 + height = 4 + h.lp.MoveCursorTo(1+left_margin, 1+y) + available_width := h.screen_size.width - left_margin - right_margin + h.draw_frame(available_width, height) + h.lp.MoveCursorTo(1+left_margin+1, 2+y) + h.draw_search_text() + + return +} diff --git a/tools/tui/loop/api.go b/tools/tui/loop/api.go index 5baad0dff..7c83dbc4b 100644 --- a/tools/tui/loop/api.go +++ b/tools/tui/loop/api.go @@ -573,3 +573,52 @@ func (self *Loop) QueryCapabilities() { self.EndAtomicUpdate() } } + +type Alignment int + +const ( + ALIGN_START Alignment = iota + ALIGN_CENTER + ALIGN_END +) + +type SizedText struct { + Scale, Subscale_numerator, Subscale_denominator int + Horizontal_alignment, Vertical_alignment Alignment + Width int +} + +func (self *Loop) DrawSizedText(text string, spec SizedText) { + b := strings.Builder{} + b.Grow(len(text) + 24) + b.WriteString("\x1b]66;") + sep := "" + if spec.Scale > 1 { + b.WriteString(fmt.Sprintf("%ss=%d", sep, min(spec.Scale, 7))) + sep = ":" + } + if spec.Width > 0 { + b.WriteString(fmt.Sprintf("%sw=%d", sep, min(spec.Width, 7))) + sep = ":" + } + if spec.Subscale_numerator > 0 { + b.WriteString(fmt.Sprintf("%sn=%d", sep, min(spec.Subscale_numerator, 15))) + sep = ":" + } + if spec.Subscale_denominator > spec.Subscale_numerator { + b.WriteString(fmt.Sprintf("%sd=%d", sep, min(spec.Subscale_denominator, 15))) + sep = ":" + } + if spec.Horizontal_alignment > ALIGN_START { + b.WriteString(fmt.Sprintf("%sh=%d", sep, spec.Horizontal_alignment)) + sep = ":" + } + if spec.Vertical_alignment > ALIGN_START { + b.WriteString(fmt.Sprintf("%sv=%d", sep, spec.Vertical_alignment)) + sep = ":" + } + b.WriteString(";") + b.WriteString(text) + b.WriteString("\a") + self.QueueWriteString(b.String()) +}