mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 18:51:41 +02:00
Implement only dir selection mode
This commit is contained in:
@@ -15,8 +15,7 @@ import (
|
||||
"github.com/kovidgoyal/kitty/tools/utils"
|
||||
)
|
||||
|
||||
// TODO: Comboboxes, multifile selections, save file name, file/dir modes. Make
|
||||
// window title conditional on mode
|
||||
// TODO: Comboboxes, multifile selections, save file name, file/dir modes
|
||||
|
||||
var _ = fmt.Print
|
||||
var debugprintln = tty.DebugPrintln
|
||||
@@ -27,6 +26,54 @@ type ScorePattern struct {
|
||||
val float64
|
||||
}
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
SELECT_SINGLE_FILE Mode = iota
|
||||
SELECT_MULTIPLE_FILES
|
||||
SELECT_SAVE_FILE
|
||||
SELECT_SAVE_DIR
|
||||
SELECT_SINGLE_DIR
|
||||
SELECT_MULTIPLE_DIRS
|
||||
SELECT_SAVE_DIR_FOR_FILES // select a dir for saving one or more pre-sent filenames, must be an existing one
|
||||
)
|
||||
|
||||
func (m Mode) AllowsMultipleSelection() bool {
|
||||
switch m {
|
||||
case SELECT_MULTIPLE_FILES, SELECT_MULTIPLE_DIRS:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m Mode) OnlyDirs() bool {
|
||||
switch m {
|
||||
case SELECT_SINGLE_DIR, SELECT_MULTIPLE_DIRS, SELECT_SAVE_DIR, SELECT_SAVE_DIR_FOR_FILES:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m Mode) WindowTitle() string {
|
||||
switch m {
|
||||
case SELECT_SINGLE_FILE:
|
||||
return "Choose an existing file"
|
||||
case SELECT_MULTIPLE_FILES:
|
||||
return "Choose one or more existing files"
|
||||
case SELECT_SAVE_FILE:
|
||||
return "Choose a file to save"
|
||||
case SELECT_SAVE_DIR:
|
||||
return "Choose a directory to save"
|
||||
case SELECT_SINGLE_DIR:
|
||||
return "Choose an existing directory"
|
||||
case SELECT_MULTIPLE_DIRS:
|
||||
return "Choose one or more directories"
|
||||
case SELECT_SAVE_DIR_FOR_FILES:
|
||||
return "Choose a directory to save multiple files in"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type State struct {
|
||||
base_dir string
|
||||
current_dir string
|
||||
@@ -34,6 +81,8 @@ type State struct {
|
||||
multiselect bool
|
||||
score_patterns []ScorePattern
|
||||
search_text string
|
||||
mode Mode
|
||||
window_title string
|
||||
|
||||
current_idx int
|
||||
num_of_matches_at_last_render int
|
||||
@@ -67,6 +116,12 @@ func (s *State) SetCurrentIndex(val int) { s.current_idx = max(0, val) }
|
||||
func (s State) CurrentDir() string {
|
||||
return utils.IfElse(s.current_dir == "", s.BaseDir(), s.current_dir)
|
||||
}
|
||||
func (s State) WindowTitle() string {
|
||||
if s.window_title == "" {
|
||||
return s.mode.WindowTitle()
|
||||
}
|
||||
return s.window_title
|
||||
}
|
||||
|
||||
type ScreenSize struct {
|
||||
width, height, cell_width, cell_height, width_px, height_px int
|
||||
@@ -81,7 +136,7 @@ type Handler struct {
|
||||
|
||||
func (h *Handler) draw_screen() (err error) {
|
||||
matches, in_progress := h.get_results()
|
||||
h.lp.SetWindowTitle("Select a file") // TODO: make this conditional on mode
|
||||
h.lp.SetWindowTitle(h.state.WindowTitle())
|
||||
h.lp.StartAtomicUpdate()
|
||||
defer h.lp.EndAtomicUpdate()
|
||||
h.lp.ClearScreen()
|
||||
@@ -175,7 +230,7 @@ func sub(a, b float64) float64 { return a - b }
|
||||
func add(a, b float64) float64 { return a + b }
|
||||
func div(a, b float64) float64 { return a / b }
|
||||
|
||||
func (h *Handler) set_state_from_config(conf *Config) (err error) {
|
||||
func (h *Handler) set_state_from_config(conf *Config, opts *Options) (err error) {
|
||||
h.state = State{}
|
||||
fmap := map[string]func(float64, float64) float64{
|
||||
"*=": mult, "+=": add, "-=": sub, "/=": div}
|
||||
@@ -196,6 +251,24 @@ func (h *Handler) set_state_from_config(conf *Config) (err error) {
|
||||
}
|
||||
|
||||
}
|
||||
switch opts.Mode {
|
||||
case "file":
|
||||
h.state.mode = SELECT_SINGLE_FILE
|
||||
case "files":
|
||||
h.state.mode = SELECT_MULTIPLE_FILES
|
||||
case "save-file":
|
||||
h.state.mode = SELECT_SAVE_FILE
|
||||
case "dir":
|
||||
h.state.mode = SELECT_SINGLE_DIR
|
||||
case "dirs":
|
||||
h.state.mode = SELECT_MULTIPLE_DIRS
|
||||
case "save-dir":
|
||||
h.state.mode = SELECT_SAVE_DIR
|
||||
case "dir-for-files":
|
||||
h.state.mode = SELECT_SAVE_DIR_FOR_FILES
|
||||
default:
|
||||
h.state.mode = SELECT_SINGLE_FILE
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -211,7 +284,7 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||
return 1, err
|
||||
}
|
||||
handler := Handler{lp: lp}
|
||||
if err = handler.set_state_from_config(conf); err != nil {
|
||||
if err = handler.set_state_from_config(conf, opts); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
switch len(args) {
|
||||
|
||||
@@ -48,6 +48,11 @@ completion=type:file ext:conf group:"Config files" kwds:none,NONE
|
||||
{config_help}
|
||||
|
||||
|
||||
--mode
|
||||
type=choices
|
||||
choices=file,files,save-file,dir,save-dir,dirs,dir-for-files
|
||||
default=file
|
||||
The type of object(s) to select
|
||||
'''.format(config_help=CONFIG_HELP.format(conf_name='diff', appname=appname)).format
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ type ScanCache struct {
|
||||
mutex sync.Mutex
|
||||
root_dir, search_text string
|
||||
in_progress bool
|
||||
only_dirs bool
|
||||
matches []*ResultItem
|
||||
}
|
||||
|
||||
@@ -158,6 +159,10 @@ func (sc *ScanCache) scan_dir(abspath string, patterns []string, positions []pos
|
||||
}
|
||||
is_last := pattern == "" || len(patterns) <= 1
|
||||
for i, n := range names {
|
||||
e := entries[i]
|
||||
if sc.only_dirs && !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
child_abspath := filepath.Join(abspath, n)
|
||||
if pattern == "" || scores[i].Score > 0 {
|
||||
npos[len(positions)] = pos_in_name{name: n, positions: scores[i].Positions}
|
||||
@@ -165,7 +170,7 @@ func (sc *ScanCache) scan_dir(abspath string, patterns []string, positions []pos
|
||||
r := &ResultItem{score: score + scores[i].Score, dir_entry: entries[i], abspath: child_abspath}
|
||||
r.finalize(npos)
|
||||
ans = append(ans, r)
|
||||
} else if entries[i].IsDir() {
|
||||
} else if e.IsDir() {
|
||||
ans = append(ans, sc.scan_dir(child_abspath, patterns[1:], npos, scores[i].Score+score)...)
|
||||
}
|
||||
}
|
||||
@@ -217,23 +222,25 @@ func (h *Handler) get_results() (ans []*ResultItem, in_progress bool) {
|
||||
}
|
||||
cd := h.state.CurrentDir()
|
||||
st := h.state.SearchText()
|
||||
only_dirs := h.state.mode.OnlyDirs()
|
||||
if st != "" {
|
||||
st = filepath.Clean(st)
|
||||
}
|
||||
if sc.root_dir == cd && sc.search_text == st {
|
||||
if sc.root_dir == cd && sc.search_text == st && sc.only_dirs == only_dirs {
|
||||
return sc.matches, sc.in_progress
|
||||
}
|
||||
sc.in_progress = true
|
||||
sc.matches = nil
|
||||
sc.root_dir = cd
|
||||
sc.search_text = st
|
||||
sc.only_dirs = only_dirs
|
||||
sp := h.state.ScorePatterns()
|
||||
go func() {
|
||||
defer h.lp.RecoverFromPanicInGoRoutine()
|
||||
results := sc.scan(cd, st, sp)
|
||||
sc.mutex.Lock()
|
||||
defer sc.mutex.Unlock()
|
||||
if cd == sc.root_dir && st == sc.search_text {
|
||||
if cd == sc.root_dir && st == sc.search_text && sc.only_dirs == only_dirs {
|
||||
sc.matches = results
|
||||
sc.in_progress = false
|
||||
h.lp.WakeupMainThread()
|
||||
|
||||
Reference in New Issue
Block a user