From 28429a97a6489ce3c6a80589ceaff3acbb587f15 Mon Sep 17 00:00:00 2001 From: Christian Zangl Date: Sat, 15 Oct 2022 23:58:25 +0200 Subject: [PATCH] Enable focus events through configuration by using focus (option), on-ui-enter/on-ui-exit (events) and echoraw (command). --- app.go | 6 ++++++ doc.go | 15 +++++++++++++++ docstring.go | 20 ++++++++++++++++++++ eval.go | 19 +++++++++++++++++++ lf.1 | 21 +++++++++++++++++++++ opts.go | 2 ++ ui.go | 33 ++++++++++++++++++++++++--------- 7 files changed, 107 insertions(+), 9 deletions(-) diff --git a/app.go b/app.go index 627fcafc..b90d844b 100644 --- a/app.go +++ b/app.go @@ -299,6 +299,8 @@ func (app *app) loop() { }() } + onUiEnter(app) + for { select { case <-app.quitChan: @@ -321,6 +323,7 @@ func (app *app) loop() { cmd.eval(app, nil) } + onUiExit(app) app.quit() app.nav.previewChan <- "" @@ -466,6 +469,7 @@ func (app *app) loop() { app.ui.draw(app.nav) } } + } // This function is used to run a shell command. Modes are as follows: @@ -492,6 +496,7 @@ func (app *app) runShell(s string, args []string, prefix string) { app.nav.previewChan <- "" app.nav.dirPreviewChan <- nil + onUiExit(app) if err := app.ui.suspend(); err != nil { log.Printf("suspend: %s", err) } @@ -501,6 +506,7 @@ func (app *app) runShell(s string, args []string, prefix string) { os.Exit(3) return } + onUiEnter(app) }() defer app.nav.renew() diff --git a/doc.go b/doc.go index 6bdbd102..068f0f2c 100644 --- a/doc.go +++ b/doc.go @@ -52,6 +52,7 @@ The following commands are provided by lf: echo echomsg echoerr + echoraw cd select delete (modal) @@ -188,6 +189,8 @@ The following special shell commands are used to customize the behavior of lf wh pre-cd on-cd on-select + on-ui-enter + on-ui-exit on-quit The following commands/keybindings are provided by default: @@ -388,6 +391,10 @@ Print given arguments to the message line at the bottom and also to the log file Print given arguments to the message line at the bottom as 'errorfmt' and also to the log file. + echoraw + +Print string directly to the terminal. This should only be used to send escape sequences to your terminal program or tmux. + cd Change the working directory to the given argument. @@ -922,6 +929,14 @@ This shell command can be defined to be executed after changing a directory. This shell command can be defined to be executed after the selection changes. + on-ui-enter + +This shell command can be defined to be executed when the UI of lf becomes active. This will be triggered after lf starts and when foreground shell commands finish. + + on-ui-exit + +This shell command can be defined to be executed when the UI of lf becomes inactive. This will be triggered before lf exits and before starting foreground shell commands. + on-quit This shell command can be defined to be executed before quit. diff --git a/docstring.go b/docstring.go index 5148b297..d05d6979 100644 --- a/docstring.go +++ b/docstring.go @@ -55,6 +55,7 @@ The following commands are provided by lf: echo echomsg echoerr + echoraw cd select delete (modal) @@ -192,6 +193,8 @@ when defined: pre-cd on-cd on-select + on-ui-enter + on-ui-exit on-quit The following commands/keybindings are provided by default: @@ -402,6 +405,11 @@ file. Print given arguments to the message line at the bottom as 'errorfmt' and also to the log file. + echoraw + +Print string directly to the terminal. This should only be used to send escape +sequences to your terminal program or tmux. + cd Change the working directory to the given argument. @@ -978,6 +986,18 @@ This shell command can be defined to be executed after changing a directory. This shell command can be defined to be executed after the selection changes. + on-ui-enter + +This shell command can be defined to be executed when the UI of lf becomes +active. This will be triggered after lf starts and when foreground shell +commands finish. + + on-ui-exit + +This shell command can be defined to be executed when the UI of lf becomes +inactive. This will be triggered before lf exits and before starting foreground +shell commands. + on-quit This shell command can be defined to be executed before quit. diff --git a/eval.go b/eval.go index 8dca32ee..b10b1bee 100644 --- a/eval.go +++ b/eval.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "io" "log" "os" @@ -430,6 +431,10 @@ func (e *setExpr) eval(app *app, args []string) { } case "tagfmt": gOpts.tagfmt = e.val + case "focus": + gOpts.hasFocus = e.val == "on" + app.ui.loadFile(app, true) + app.ui.loadFileInfo(app.nav) case "timefmt": gOpts.timefmt = e.val case "infotimefmtnew": @@ -501,6 +506,18 @@ func onSelect(app *app) { } } +func onUiEnter(app *app) { + if cmd, ok := gOpts.cmds["on-ui-enter"]; ok { + cmd.eval(app, nil) + } +} + +func onUiExit(app *app) { + if cmd, ok := gOpts.cmds["on-ui-exit"]; ok { + cmd.eval(app, nil) + } +} + func splitKeys(s string) (keys []string) { for i := 0; i < len(s); { r, w := utf8.DecodeRuneInString(s[i:]) @@ -1540,6 +1557,8 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.echomsg(strings.Join(e.args, " ")) case "echoerr": app.ui.echoerr(strings.Join(e.args, " ")) + case "echoraw": + fmt.Print(strings.Join(e.args, " ")) case "cd": path := "~" if len(e.args) > 0 { diff --git a/lf.1 b/lf.1 index 7a4ac42b..db11fdfd 100644 --- a/lf.1 +++ b/lf.1 @@ -67,6 +67,7 @@ The following commands are provided by lf: echo echomsg echoerr + echoraw cd select delete (modal) @@ -211,6 +212,8 @@ The following special shell commands are used to customize the behavior of lf wh pre-cd on-cd on-select + on-ui-enter + on-ui-exit on-quit .EE .PP @@ -464,6 +467,12 @@ Print given arguments to the message line at the bottom and also to the log file .PP Print given arguments to the message line at the bottom as 'errorfmt' and also to the log file. .PP +.EX + echoraw +.EE +.PP +Print string directly to the terminal. This should only be used to send escape sequences to your terminal program or tmux. +.PP .EX cd .EE @@ -1134,6 +1143,18 @@ This shell command can be defined to be executed after changing a directory. .PP This shell command can be defined to be executed after the selection changes. .PP +.EX + on-ui-enter +.EE +.PP +This shell command can be defined to be executed when the UI of lf becomes active. This will be triggered after lf starts and when foreground shell commands finish. +.PP +.EX + on-ui-exit +.EE +.PP +This shell command can be defined to be executed when the UI of lf becomes inactive. This will be triggered before lf exits and before starting foreground shell commands. +.PP .EX on-quit .EE diff --git a/opts.go b/opts.go index 55a2f7be..641095c6 100644 --- a/opts.go +++ b/opts.go @@ -79,6 +79,7 @@ var gOpts struct { sortType sortType tempmarks string tagfmt string + hasFocus bool } func init() { @@ -129,6 +130,7 @@ func init() { gOpts.sortType = sortType{naturalSort, dirfirstSort} gOpts.tempmarks = "'" gOpts.tagfmt = "\033[31m%s\033[0m" + gOpts.hasFocus = true gOpts.keys = make(map[string]expr) diff --git a/ui.go b/ui.go index 04c35f69..f4925fea 100644 --- a/ui.go +++ b/ui.go @@ -436,7 +436,7 @@ func (win *win) printDir(screen tcell.Screen, dir *dir, context *dirContext, dir } } - if i == dir.pos { + if i == dir.pos && gOpts.hasFocus { st = st.Reverse(true) if dirStyle.previewing { st = st.Foreground(DimCursorColor) @@ -490,8 +490,8 @@ func (win *win) printDir(screen tcell.Screen, dir *dir, context *dirContext, dir tag, ok := context.tags[path] if ok { - if i == dir.pos { - win.print(screen, lnwidth+1, i, st, tag) + if i == dir.pos && gOpts.hasFocus { + win.print(screen, lnwidth+1, i, st.Reverse(true), tag) } else { win.print(screen, lnwidth+1, i, tcell.StyleDefault, fmt.Sprintf(gOpts.tagfmt, tag)) } @@ -1186,17 +1186,32 @@ func (ui *ui) readNormalEvent(ev tcell.Event) expr { return nil } -func readCmdEvent(ev tcell.Event) expr { +func (ui *ui) readCmdEvent(ev tcell.Event) expr { switch tev := ev.(type) { case *tcell.EventKey: if tev.Key() == tcell.KeyRune { if tev.Modifiers() == tcell.ModMask(tcell.ModAlt) { - val := string([]rune{'<', 'a', '-', tev.Rune(), '>'}) - if expr, ok := gOpts.cmdkeys[val]; ok { - return expr + // support multi-key bindings but only for ESC[ at the moment + if tev.Rune() == '[' { + ui.keyAcc = append(ui.keyAcc, '<', 'a', '-', tev.Rune(), '>') + } else { + val := string([]rune{'<', 'a', '-', tev.Rune(), '>'}) + if expr, ok := gOpts.cmdkeys[val]; ok { + return expr + } } } else { - return &callExpr{"cmd-insert", []string{string(tev.Rune())}, 1} + // multi-key bindings + if ui.keyAcc != nil { + ui.keyAcc = append(ui.keyAcc, tev.Rune()) + val := string(ui.keyAcc) + ui.keyAcc = nil + if expr, ok := gOpts.cmdkeys[val]; ok { + return expr + } + } else { + return &callExpr{"cmd-insert", []string{string(tev.Rune())}, 1} + } } } else { val := gKeyVal[tev.Key()] @@ -1214,7 +1229,7 @@ func (ui *ui) readEvent(ev tcell.Event) expr { } if _, ok := ev.(*tcell.EventKey); ok && ui.cmdPrefix != "" { - return readCmdEvent(ev) + return ui.readCmdEvent(ev) } return ui.readNormalEvent(ev)