From da2d8a297963b80e4da7367bcada18df054b850c Mon Sep 17 00:00:00 2001 From: segf00lt <74469650+segf00lt@users.noreply.github.com> Date: Sun, 10 Jul 2022 09:32:34 -0300 Subject: [PATCH 01/13] added history options (#866) * added history options * sorry forgot to update docs --- app.go | 6 ++++-- doc.go | 1 + docstring.go | 1 + eval.go | 6 ++++++ lf.1 | 1 + opts.go | 2 ++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app.go b/app.go index 5ef53f3..5ccab80 100644 --- a/app.go +++ b/app.go @@ -59,8 +59,10 @@ func newApp(ui *ui, nav *nav) *app { } func (app *app) quit() { - if err := app.writeHistory(); err != nil { - log.Printf("writing history file: %s", err) + if gOpts.history { + if err := app.writeHistory(); err != nil { + log.Printf("writing history file: %s", err) + } } if !gSingleMode { if err := remote(fmt.Sprintf("drop %d", gClientID)); err != nil { diff --git a/doc.go b/doc.go index 1704fcb..de23905 100644 --- a/doc.go +++ b/doc.go @@ -124,6 +124,7 @@ The following options can be used to customize the behavior of lf: globsearch bool (default off) hidden bool (default off) hiddenfiles []string (default '.*') + history bool (default on) icons bool (default off) ifs string (default '') ignorecase bool (default on) diff --git a/docstring.go b/docstring.go index c5c538b..e0ddf7f 100644 --- a/docstring.go +++ b/docstring.go @@ -128,6 +128,7 @@ The following options can be used to customize the behavior of lf: globsearch bool (default off) hidden bool (default off) hiddenfiles []string (default '.*') + history bool (default on) icons bool (default off) ifs string (default '') ignorecase bool (default on) diff --git a/eval.go b/eval.go index 53191b4..af3671d 100644 --- a/eval.go +++ b/eval.go @@ -125,6 +125,12 @@ func (e *setExpr) eval(app *app, args []string) { app.nav.position() app.ui.sort() app.ui.loadFile(app.nav, true) + case "history": + gOpts.history = true + case "nohistory": + gOpts.history = false + case "history!": + gOpts.history = !gOpts.history case "icons": gOpts.icons = true case "noicons": diff --git a/lf.1 b/lf.1 index f0a7311..cf767a0 100644 --- a/lf.1 +++ b/lf.1 @@ -143,6 +143,7 @@ The following options can be used to customize the behavior of lf: globsearch bool (default off) hidden bool (default off) hiddenfiles []string (default '.*') + history bool (default on) icons bool (default off) ifs string (default '') ignorecase bool (default on) diff --git a/opts.go b/opts.go index 2909809..3b7121e 100644 --- a/opts.go +++ b/opts.go @@ -67,6 +67,7 @@ var gOpts struct { truncatechar string ratios []int hiddenfiles []string + history bool info []string shellopts []string keys map[string]expr @@ -117,6 +118,7 @@ func init() { gOpts.truncatechar = "~" gOpts.ratios = []int{1, 2, 3} gOpts.hiddenfiles = []string{".*"} + gOpts.history = true gOpts.info = nil gOpts.shellopts = nil gOpts.sortType = sortType{naturalSort, dirfirstSort} From e03143299d4596bbc9bb8a2d8a1b0931e3183410 Mon Sep 17 00:00:00 2001 From: Christian Zangl Date: Sun, 10 Jul 2022 14:32:55 +0200 Subject: [PATCH 02/13] Add a spacer `%S` to the promptfmt (#867) --- doc.go | 2 +- docstring.go | 9 +++++---- lf.1 | 2 +- ui.go | 7 +++++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc.go b/doc.go index de23905..58bb8c3 100644 --- a/doc.go +++ b/doc.go @@ -709,7 +709,7 @@ Preview filtering is disabled and files are displayed as they are when the value promptfmt string (default "\033[32;1m%u@%h\033[0m:\033[34;1m%d\033[0m\033[1m%f\033[0m") Format string of the prompt shown in the top line. -Special expansions are provided, '%u' as the user name, '%h' as the host name, '%w' as the working directory, '%d' as the working directory with a trailing path separator, '%f' as the file name, and '%F' as the current filter. +Special expansions are provided, '%u' as the user name, '%h' as the host name, '%w' as the working directory, '%d' as the working directory with a trailing path separator, '%f' as the file name, and '%F' as the current filter. '%S' may be used once and will provide a spacer so that the following parts are right aligned on the screen. Home folder is shown as '~' in the working directory expansion. Directory names are automatically shortened to a single character starting from the left most parent when the prompt does not fit to the screen. diff --git a/docstring.go b/docstring.go index e0ddf7f..0fee742 100644 --- a/docstring.go +++ b/docstring.go @@ -755,10 +755,11 @@ value of this option is left empty. Format string of the prompt shown in the top line. Special expansions are provided, '%u' as the user name, '%h' as the host name, '%w' as the working directory, '%d' as the working directory with a trailing path separator, -'%f' as the file name, and '%F' as the current filter. Home folder is shown -as '~' in the working directory expansion. Directory names are automatically -shortened to a single character starting from the left most parent when the -prompt does not fit to the screen. +'%f' as the file name, and '%F' as the current filter. '%S' may be used once +and will provide a spacer so that the following parts are right aligned on +the screen. Home folder is shown as '~' in the working directory expansion. +Directory names are automatically shortened to a single character starting +from the left most parent when the prompt does not fit to the screen. ratios []int (default '1:2:3') diff --git a/lf.1 b/lf.1 index cf767a0..b31cd4f 100644 --- a/lf.1 +++ b/lf.1 @@ -861,7 +861,7 @@ Set the path of a previewer file to filter the content of regular files for prev promptfmt string (default "\e033[32;1m%u@%h\e033[0m:\e033[34;1m%d\e033[0m\e033[1m%f\e033[0m") .EE .PP -Format string of the prompt shown in the top line. Special expansions are provided, '%u' as the user name, '%h' as the host name, '%w' as the working directory, '%d' as the working directory with a trailing path separator, '%f' as the file name, and '%F' as the current filter. Home folder is shown as '~' in the working directory expansion. Directory names are automatically shortened to a single character starting from the left most parent when the prompt does not fit to the screen. +Format string of the prompt shown in the top line. Special expansions are provided, '%u' as the user name, '%h' as the host name, '%w' as the working directory, '%d' as the working directory with a trailing path separator, '%f' as the file name, and '%F' as the current filter. '%S' may be used once and will provide a spacer so that the following parts are right aligned on the screen. Home folder is shown as '~' in the working directory expansion. Directory names are automatically shortened to a single character starting from the left most parent when the prompt does not fit to the screen. .PP .EX ratios []int (default '1:2:3') diff --git a/ui.go b/ui.go index 951c91b..e287235 100644 --- a/ui.go +++ b/ui.go @@ -733,6 +733,13 @@ func (ui *ui) drawPromptLine(nav *nav) { prompt = strings.Replace(prompt, "%F", "", -1) } + // spacer + avail := ui.promptWin.w - printLength(prompt) + 2 + if avail > 0 { + prompt = strings.Replace(prompt, "%S", strings.Repeat(" ", avail), 1) + } + prompt = strings.Replace(prompt, "%S", "", -1) + ui.promptWin.print(ui.screen, 0, 0, st, prompt) } From b0cb9268d802ef22f1dd646274a6ee1213570a7a Mon Sep 17 00:00:00 2001 From: ferreum Date: Sat, 6 Aug 2022 14:53:26 +0200 Subject: [PATCH 03/13] docs: update lifted restrictions on cmap (#886) --- doc.go | 3 ++- docstring.go | 5 +++-- lf.1 | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc.go b/doc.go index 58bb8c3..86e0c42 100644 --- a/doc.go +++ b/doc.go @@ -921,9 +921,10 @@ Command 'map' is used to bind a key to a command which can be builtin command, c map i $less $f # shell command map U !du -csh * # waiting shell command -Command 'cmap' is used to bind a key to a command line command which can only be one of the builtin commands: +Command 'cmap' is used to bind a key on the command line to a command line command or any other command: cmap cmd-escape + cmap set incsearch! You can delete an existing binding by leaving the expression empty: diff --git a/docstring.go b/docstring.go index 0fee742..c0e933f 100644 --- a/docstring.go +++ b/docstring.go @@ -995,10 +995,11 @@ command, custom command, or shell command: map i $less $f # shell command map U !du -csh * # waiting shell command -Command 'cmap' is used to bind a key to a command line command which can -only be one of the builtin commands: +Command 'cmap' is used to bind a key on the command line to a command line +command or any other command: cmap cmd-escape + cmap set incsearch! You can delete an existing binding by leaving the expression empty: diff --git a/lf.1 b/lf.1 index b31cd4f..77c58d1 100644 --- a/lf.1 +++ b/lf.1 @@ -1128,10 +1128,11 @@ Command 'map' is used to bind a key to a command which can be builtin command, c map U !du -csh * # waiting shell command .EE .PP -Command 'cmap' is used to bind a key to a command line command which can only be one of the builtin commands: +Command 'cmap' is used to bind a key on the command line to a command line command or any other command: .PP .EX cmap cmd-escape + cmap set incsearch! .EE .PP You can delete an existing binding by leaving the expression empty: From 17e1a84646909f86ad7f0e76b4acd36650d4d44f Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Thu, 8 Sep 2022 09:10:49 -0400 Subject: [PATCH 04/13] Fix missing completion for a few commands (#929) --- complete.go | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/complete.go b/complete.go index c48b35c..cad63f8 100644 --- a/complete.go +++ b/complete.go @@ -13,7 +13,9 @@ var ( gCmdWords = []string{ "set", "map", + "cmap", "cmd", + "quit", "up", "half-up", "page-up", @@ -24,20 +26,38 @@ var ( "scroll-down", "updir", "open", - "quit", + "jump-next", + "jump-prev", "top", "bottom", + "high", + "middle", + "low", "toggle", "invert", "unselect", + "glob-select", + "glob-unselect", + "calcdirsize", "copy", "cut", "paste", "clear", + "sync", + "draw", "redraw", + "load", "reload", - "read", + "echo", + "echomsg", + "echoerr", + "cd", + "select", + "delete", "rename", + "source", + "push", + "read", "shell", "shell-pipe", "shell-wait", @@ -53,22 +73,8 @@ var ( "filter", "setfilter", "mark-save", - "mark-remove", "mark-load", - "draw", - "load", - "sync", - "echo", - "echomsg", - "echoerr", - "cd", - "calcdirsize", - "select", - "glob-select", - "glob-unselect", - "source", - "push", - "delete", + "mark-remove", "tag", "tag-toggle", } @@ -151,6 +157,7 @@ var ( "errorfmt", "filesep", "hiddenfiles", + "history", "ifs", "info", "previewer", From 01d3b69de0d78e02d1ab43071d04292cac06b20f Mon Sep 17 00:00:00 2001 From: desbma Date: Sat, 1 Oct 2022 15:27:14 +0200 Subject: [PATCH 05/13] feat: case insensitive extension matching for icons & colors (#908) --- colors.go | 2 +- icons.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/colors.go b/colors.go index 949a98e..d8a69ff 100644 --- a/colors.go +++ b/colors.go @@ -319,7 +319,7 @@ func (sm styleMap) get(f *file) tcell.Style { return val } - if val, ok := sm["*"+f.ext]; ok { + if val, ok := sm["*"+strings.ToLower(f.ext)]; ok { return val } diff --git a/icons.go b/icons.go index 3b56293..347645f 100644 --- a/icons.go +++ b/icons.go @@ -156,7 +156,7 @@ func (im iconMap) get(f *file) string { return val } - if val, ok := im["*"+f.ext]; ok { + if val, ok := im["*"+strings.ToLower(f.ext)]; ok { return val } From 5ba70d0f618e07027192030c81b490bc307dc107 Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Sat, 1 Oct 2022 09:29:21 -0400 Subject: [PATCH 06/13] Documentation fixes and updates (#933) - Document history option - Use $() command substitution syntax because backticks are replaced with quotes in gen/docstring.sh - Movement commands no longer close the search prompt (85aa3b9) - Use the -L flag of the file command instead of readlink --- doc.go | 29 ++++++++++++++--------------- docstring.go | 33 ++++++++++++++++----------------- etc/lfrc.example | 3 +-- lf.1 | 28 +++++++++++++++------------- 4 files changed, 46 insertions(+), 47 deletions(-) diff --git a/doc.go b/doc.go index 86e0c42..7abaf34 100644 --- a/doc.go +++ b/doc.go @@ -630,6 +630,10 @@ Patterns can be given as relative or absolute paths. Globbing supports the usual special characters, '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. In addition, if a pattern starts with '!', then its matches are excluded from hidden files. + history bool (default on) + +Save command history. + icons bool (default off) Show icons before each item in the list. @@ -863,7 +867,7 @@ This shell command can be defined to override the default 'paste' command. rename -This shell command can be defined to override the default 'paste' command. +This shell command can be defined to override the default 'rename' command. delete @@ -1048,7 +1052,7 @@ A first attempt to write such a command may look like this: if [ -z "$fs" ]; then mv "$f" ~/.trash else - IFS="`printf '\n\t'`"; mv $fs ~/.trash + IFS="$(printf '\n\t')"; mv $fs ~/.trash fi }} @@ -1059,7 +1063,7 @@ We can use this variable to get rid of the conditional: cmd trash ${{ mkdir -p ~/.trash - IFS="`printf '\n\t'`"; mv $fx ~/.trash + IFS="$(printf '\n\t')"; mv $fx ~/.trash }} The trash directory is checked each time the command is executed. @@ -1067,13 +1071,13 @@ We can move it outside of the command so it would only run once at startup: ${{ mkdir -p ~/.trash }} - cmd trash ${{ IFS="`printf '\n\t'`"; mv $fx ~/.trash }} + cmd trash ${{ IFS="$(printf '\n\t')"; mv $fx ~/.trash }} Since these are one liners, we can drop '{{' and '}}': $mkdir -p ~/.trash - cmd trash $IFS="`printf '\n\t'`"; mv $fx ~/.trash + cmd trash $IFS="$(printf '\n\t')"; mv $fx ~/.trash Finally note that we set 'IFS' variable manually in these commands. Instead we could use the 'ifs' option to set it for all shell commands (i.e. 'set ifs "\n"'). @@ -1219,14 +1223,10 @@ You can enable 'globsearch' option to match with a glob pattern. Globbing supports '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. You can enable 'incsearch' option to jump to the current match at each keystroke while typing. In this mode, you can either use 'cmd-enter' to accept the search or use 'cmd-escape' to cancel the search. -Alternatively, you can also map some other commands with 'cmap' to accept the search and execute the command immediately afterwards. -Possible candidates are 'up', 'down' and their variants, 'top', 'bottom', 'updir', and 'open' commands. -For example, you can use arrow keys to finish the search with the following mappings: +You can also map some other commands with 'cmap' to accept the search and execute the command immediately afterwards. +For example, you can use the right arrow key to finish the search and open the selected file with the following mapping: - cmap up - cmap down - cmap updir - cmap open + cmap :cmd-enter; open Finding mechanism is implemented with commands 'find' (default 'f'), 'find-back' (default 'F'), 'find-next' (default ';'), 'find-prev' (default ','). You can disable 'anchorfind' option to match a pattern at an arbitrary position in the filename instead of the beginning. @@ -1256,8 +1256,7 @@ It is possible to use different command types: You may want to use either file extensions or mime types from 'file' command: cmd open ${{ - test -L $f && f=$(readlink -f $f) - case $(file --mime-type $f -b) in + case $(file --mime-type -Lb $f) in text/*) vi $fx;; *) for f in $fx; do xdg-open $f > /dev/null 2> /dev/null & done;; esac @@ -1276,7 +1275,7 @@ Previewing Files lf previews files on the preview pane by printing the file until the end or the preview pane is filled. This output can be enhanced by providing a custom preview script for filtering. -This can be used to highlight source codes, list contents of archive files or view pdf or image files to name few. +This can be used to highlight source codes, list contents of archive files or view pdf or image files to name a few. For coloring lf recognizes ansi escape codes. In order to use this feature you need to set the value of 'previewer' option to the path of an executable file. diff --git a/docstring.go b/docstring.go index c0e933f..c08e254 100644 --- a/docstring.go +++ b/docstring.go @@ -666,6 +666,10 @@ any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. In addition, if a pattern starts with '!', then its matches are excluded from hidden files. + history bool (default on) + +Save command history. + icons bool (default off) Show icons before each item in the list. @@ -930,7 +934,7 @@ This shell command can be defined to override the default 'paste' command. rename -This shell command can be defined to override the default 'paste' command. +This shell command can be defined to override the default 'rename' command. delete @@ -1138,7 +1142,7 @@ this: if [ -z "$fs" ]; then mv "$f" ~/.trash else - IFS="'printf '\n\t''"; mv $fs ~/.trash + IFS="$(printf '\n\t')"; mv $fs ~/.trash fi }} @@ -1149,7 +1153,7 @@ conditional: cmd trash ${{ mkdir -p ~/.trash - IFS="'printf '\n\t''"; mv $fx ~/.trash + IFS="$(printf '\n\t')"; mv $fx ~/.trash }} The trash directory is checked each time the command is executed. We can @@ -1157,13 +1161,13 @@ move it outside of the command so it would only run once at startup: ${{ mkdir -p ~/.trash }} - cmd trash ${{ IFS="'printf '\n\t''"; mv $fx ~/.trash }} + cmd trash ${{ IFS="$(printf '\n\t')"; mv $fx ~/.trash }} Since these are one liners, we can drop '{{' and '}}': $mkdir -p ~/.trash - cmd trash $IFS="'printf '\n\t''"; mv $fx ~/.trash + cmd trash $IFS="$(printf '\n\t')"; mv $fx ~/.trash Finally note that we set 'IFS' variable manually in these commands. Instead we could use the 'ifs' option to set it for all shell commands (i.e. 'set @@ -1348,16 +1352,12 @@ pattern. Globbing supports '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. You can enable 'incsearch' option to jump to the current match at each keystroke while typing. In this mode, you can either use 'cmd-enter' to accept the -search or use 'cmd-escape' to cancel the search. Alternatively, you can also -map some other commands with 'cmap' to accept the search and execute the -command immediately afterwards. Possible candidates are 'up', 'down' and -their variants, 'top', 'bottom', 'updir', and 'open' commands. For example, -you can use arrow keys to finish the search with the following mappings: +search or use 'cmd-escape' to cancel the search. You can also map some other +commands with 'cmap' to accept the search and execute the command +immediately afterwards. For example, you can use the right arrow key to +finish the search and open the selected file with the following mapping: - cmap up - cmap down - cmap updir - cmap open + cmap :cmd-enter; open Finding mechanism is implemented with commands 'find' (default 'f'), 'find-back' (default 'F'), 'find-next' (default ';'), 'find-prev' (default @@ -1393,8 +1393,7 @@ You may want to use either file extensions or mime types from 'file' command: cmd open ${{ - test -L $f && f=$(readlink -f $f) - case $(file --mime-type $f -b) in + case $(file --mime-type -Lb $f) in text/*) vi $fx;; *) for f in $fx; do xdg-open $f > /dev/null 2> /dev/null & done;; esac @@ -1417,7 +1416,7 @@ Previewing Files lf previews files on the preview pane by printing the file until the end or the preview pane is filled. This output can be enhanced by providing a custom preview script for filtering. This can be used to highlight source -codes, list contents of archive files or view pdf or image files to name +codes, list contents of archive files or view pdf or image files to name a few. For coloring lf recognizes ansi escape codes. In order to use this feature you need to set the value of 'previewer' option diff --git a/etc/lfrc.example b/etc/lfrc.example index 510f14d..1f96c22 100644 --- a/etc/lfrc.example +++ b/etc/lfrc.example @@ -36,8 +36,7 @@ map O $mimeopen --ask $f # use either file extensions and/or mime types here. Below uses an editor for # text files and a file opener for the rest. cmd open ${{ - test -L $f && f=$(readlink -f $f) - case $(file --mime-type $f -b) in + case $(file --mime-type -Lb $f) in text/*) $EDITOR $fx;; *) for f in $fx; do setsid $OPENER $f > /dev/null 2> /dev/null & done;; esac diff --git a/lf.1 b/lf.1 index 77c58d1..00af2b4 100644 --- a/lf.1 +++ b/lf.1 @@ -773,6 +773,12 @@ Show hidden files. On Unix systems, hidden files are determined by the value of .PP List of hidden file glob patterns. Patterns can be given as relative or absolute paths. Globbing supports the usual special characters, '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. In addition, if a pattern starts with '!', then its matches are excluded from hidden files. .PP +.EX + history bool (default on) +.EE +.PP +Save command history. +.PP .EX icons bool (default off) .EE @@ -1061,7 +1067,7 @@ This shell command can be defined to override the default 'paste' command. rename .EE .PP -This shell command can be defined to override the default 'paste' command. +This shell command can be defined to override the default 'rename' command. .PP .EX delete @@ -1278,7 +1284,7 @@ Regular shell commands are the most basic command type that is useful for many p if [ -z "$fs" ]; then mv "$f" ~/.trash else - IFS="`printf '\en\et'`"; mv $fs ~/.trash + IFS="$(printf '\en\et')"; mv $fs ~/.trash fi }} .EE @@ -1288,7 +1294,7 @@ We check '$fs' to see if there are any selected files. Otherwise we just delete .EX cmd trash ${{ mkdir -p ~/.trash - IFS="`printf '\en\et'`"; mv $fx ~/.trash + IFS="$(printf '\en\et')"; mv $fx ~/.trash }} .EE .PP @@ -1299,7 +1305,7 @@ The trash directory is checked each time the command is executed. We can move it .EE .PP .EX - cmd trash ${{ IFS="`printf '\en\et'`"; mv $fx ~/.trash }} + cmd trash ${{ IFS="$(printf '\en\et')"; mv $fx ~/.trash }} .EE .PP Since these are one liners, we can drop '{{' and '}}': @@ -1309,7 +1315,7 @@ Since these are one liners, we can drop '{{' and '}}': .EE .PP .EX - cmd trash $IFS="`printf '\en\et'`"; mv $fx ~/.trash + cmd trash $IFS="$(printf '\en\et')"; mv $fx ~/.trash .EE .PP Finally note that we set 'IFS' variable manually in these commands. Instead we could use the 'ifs' option to set it for all shell commands (i.e. 'set ifs "\en"'). This can be especially useful for interactive use (e.g. '$rm $f' or '$rm $fs' would simply work). This option is not set by default as it can behave unexpectedly for new users. However, use of this option is highly recommended and it is assumed in the rest of the documentation. @@ -1413,13 +1419,10 @@ By default, lf does not assign 'delete' command to a key to protect new users. Y .SH SEARCHING FILES There are two mechanisms implemented in lf to search a file in the current directory. Searching is the traditional method to move the selection to a file matching a given pattern. Finding is an alternative way to search for a pattern possibly using fewer keystrokes. .PP -Searching mechanism is implemented with commands 'search' (default '/'), 'search-back' (default '?'), 'search-next' (default 'n'), and 'search-prev' (default 'N'). You can enable 'globsearch' option to match with a glob pattern. Globbing supports '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. You can enable 'incsearch' option to jump to the current match at each keystroke while typing. In this mode, you can either use 'cmd-enter' to accept the search or use 'cmd-escape' to cancel the search. Alternatively, you can also map some other commands with 'cmap' to accept the search and execute the command immediately afterwards. Possible candidates are 'up', 'down' and their variants, 'top', 'bottom', 'updir', and 'open' commands. For example, you can use arrow keys to finish the search with the following mappings: +Searching mechanism is implemented with commands 'search' (default '/'), 'search-back' (default '?'), 'search-next' (default 'n'), and 'search-prev' (default 'N'). You can enable 'globsearch' option to match with a glob pattern. Globbing supports '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. You can enable 'incsearch' option to jump to the current match at each keystroke while typing. In this mode, you can either use 'cmd-enter' to accept the search or use 'cmd-escape' to cancel the search. You can also map some other commands with 'cmap' to accept the search and execute the command immediately afterwards. For example, you can use the right arrow key to finish the search and open the selected file with the following mapping: .PP .EX - cmap up - cmap down - cmap updir - cmap open + cmap :cmd-enter; open .EE .PP Finding mechanism is implemented with commands 'find' (default 'f'), 'find-back' (default 'F'), 'find-next' (default ';'), 'find-prev' (default ','). You can disable 'anchorfind' option to match a pattern at an arbitrary position in the filename instead of the beginning. You can set the number of keys to match using 'findlen' option. If you set this value to zero, then the the keys are read until there is only a single match. Default values of these two options are set to jump to the first file with the given initial. @@ -1442,8 +1445,7 @@ You may want to use either file extensions or mime types from 'file' command: .PP .EX cmd open ${{ - test -L $f && f=$(readlink -f $f) - case $(file --mime-type $f -b) in + case $(file --mime-type -Lb $f) in text/*) vi $fx;; *) for f in $fx; do xdg-open $f > /dev/null 2> /dev/null & done;; esac @@ -1460,7 +1462,7 @@ Following command is provided by default: .PP You may also use any other existing file openers as you like. Possible options are 'libfile-mimeinfo-perl' (executable name is 'mimeopen'), 'rifle' (ranger's default file opener), or 'mimeo' to name a few. .SH PREVIEWING FILES -lf previews files on the preview pane by printing the file until the end or the preview pane is filled. This output can be enhanced by providing a custom preview script for filtering. This can be used to highlight source codes, list contents of archive files or view pdf or image files to name few. For coloring lf recognizes ansi escape codes. +lf previews files on the preview pane by printing the file until the end or the preview pane is filled. This output can be enhanced by providing a custom preview script for filtering. This can be used to highlight source codes, list contents of archive files or view pdf or image files to name a few. For coloring lf recognizes ansi escape codes. .PP In order to use this feature you need to set the value of 'previewer' option to the path of an executable file. Five arguments are passed to the file, (1) current file name, (2) width, (3) height, (4) horizontal position, and (5) vertical position of preview pane respectively. Output of the execution is printed in the preview pane. You may also want to use the same script in your pager mapping as well: .PP From cb7aa132186009beb8f9ada7e0ce32b8c95d5812 Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Sat, 1 Oct 2022 09:31:58 -0400 Subject: [PATCH 07/13] Fix a few completion bugs and add a few small features (#934) * Fix some multibyte character completion bugs - matchLongest now operates on runes instead of bytes so we don't complete part of a multibyte character. - Fix some places that mixed string and rune slice indices. * Fix wrong menu completion for subdirectories When selecting a menu completion for a file in a subdirectory, the entire filename would be appended to the command line, even if you had already typed part of it. * Escape file completions in menu completion * Minor refactors and typo fixes * Fix cmd-menu-complete-back bug The first use of cmd-menu-complete-back after opening the completion menu was incorrectly selecting the before-last completion instead of the last completion. * Allow completing broken symlinks Also skip files with stat errors instead of returning. * Add command to accept current menu selection This is useful when completing filenames. For example cmap :cmd-menu-accept; cmd-menu-complete can be used to accept the selected directory completion, then complete files in the directory. * Complete command names for map and cmap --- complete.go | 153 ++++++++++++++++++++++++++++------------------- complete_test.go | 7 ++- doc.go | 5 ++ docstring.go | 5 ++ eval.go | 45 ++++++-------- lf.1 | 7 +++ misc.go | 6 +- ui.go | 9 +-- 8 files changed, 137 insertions(+), 100 deletions(-) diff --git a/complete.go b/complete.go index cad63f8..7a7db9c 100644 --- a/complete.go +++ b/complete.go @@ -77,6 +77,33 @@ var ( "mark-remove", "tag", "tag-toggle", + "cmd-escape", + "cmd-complete", + "cmd-menu-complete", + "cmd-menu-complete-back", + "cmd-menu-accept", + "cmd-enter", + "cmd-interrupt", + "cmd-history-next", + "cmd-history-prev", + "cmd-left", + "cmd-right", + "cmd-home", + "cmd-end", + "cmd-delete", + "cmd-delete-back", + "cmd-delete-home", + "cmd-delete-end", + "cmd-delete-unix-word", + "cmd-yank", + "cmd-transpose", + "cmd-transpose-word", + "cmd-word", + "cmd-word-back", + "cmd-delete-word", + "cmd-capitalize-word", + "cmd-uppercase-word", + "cmd-lowercase-word", } gOptWords = []string{ @@ -177,7 +204,7 @@ var ( } ) -func matchLongest(s1, s2 string) string { +func matchLongest(s1, s2 []rune) []rune { i := 0 for ; i < len(s1) && i < len(s2); i++ { if s1[i] != s2[i] { @@ -187,28 +214,28 @@ func matchLongest(s1, s2 string) string { return s1[:i] } -func matchWord(s string, words []string) (matches []string, longest string) { +func matchWord(s string, words []string) (matches []string, longest []rune) { for _, w := range words { if !strings.HasPrefix(w, s) { continue } matches = append(matches, w) - if longest != "" { - longest = matchLongest(longest, w) + if len(longest) != 0 { + longest = matchLongest(longest, []rune(w)) } else if s != "" { - longest = w + " " + longest = []rune(w + " ") } } - if longest == "" { - longest = s + if len(longest) == 0 { + longest = []rune(s) } return } -func matchExec(s string) (matches []string, longest string) { +func matchExec(s string) (matches []string, longest []rune) { var words []string paths := strings.Split(envPath, string(filepath.ListSeparator)) @@ -258,7 +285,8 @@ func matchExec(s string) (matches []string, longest string) { return matchWord(s, words) } -func matchFile(s string) (matches []string, longest string) { +func matchFile(s string) (matches []string, longest []rune) { + s = unescape(s) dir := replaceTilde(s) if !filepath.IsAbs(dir) { @@ -270,7 +298,7 @@ func matchFile(s string) (matches []string, longest string) { } } - dir = unescape(filepath.Dir(dir)) + dir = filepath.Dir(dir) files, err := ioutil.ReadDir(dir) if err != nil { @@ -279,25 +307,20 @@ func matchFile(s string) (matches []string, longest string) { for _, f := range files { name := filepath.Join(dir, f.Name()) - f, err := os.Stat(name) + f, err := os.Lstat(name) if err != nil { - fl, err := os.Lstat(name) - if err == nil && fl.Mode()&os.ModeSymlink != 0 { - continue - } else { - log.Printf("getting file information: %s", err) - return - } + log.Printf("getting file information: %s", err) + continue } _, last := filepath.Split(s) - if !strings.HasPrefix(escape(f.Name()), last) { + if !strings.HasPrefix(f.Name(), last) { continue } name = f.Name() if isRoot(s) || filepath.Base(s) != s { - name = filepath.Join(filepath.Dir(unescape(s)), f.Name()) + name = filepath.Join(filepath.Dir(s), f.Name()) } name = escape(name) @@ -307,66 +330,79 @@ func matchFile(s string) (matches []string, longest string) { } matches = append(matches, item) - if longest != "" { - longest = matchLongest(longest, name) + if len(longest) != 0 { + longest = matchLongest(longest, []rune(name)) } else if s != "" { if f.Mode().IsRegular() { - longest = name + " " + longest = []rune(name + " ") } else { - longest = name + escape(string(filepath.Separator)) + longest = []rune(name + escape(string(filepath.Separator))) } } } - if longest == "" { - longest = s + if len(longest) == 0 { + longest = []rune(s) } return } +func matchCmd(s string) (matches []string, longest []rune) { + words := gCmdWords + for c := range gOpts.cmds { + words = append(words, c) + } + sort.Strings(words) + j := 0 + for i := 1; i < len(words); i++ { + if words[j] == words[i] { + continue + } + j++ + words[i], words[j] = words[j], words[i] + } + words = words[:j+1] + matches, longest = matchWord(s, words) + return +} + func completeCmd(acc []rune) (matches []string, longestAcc []rune) { s := string(acc) f := tokenize(s) - var longest string + var longest []rune switch len(f) { case 1: - words := gCmdWords - for c := range gOpts.cmds { - words = append(words, c) - } - sort.Strings(words) - j := 0 - for i := 1; i < len(words); i++ { - if words[j] == words[i] { - continue - } - j++ - words[i], words[j] = words[j], words[i] - } - words = words[:j+1] - matches, longest = matchWord(s, words) - longestAcc = []rune(longest) + matches, longestAcc = matchCmd(s) case 2: switch f[0] { case "set": matches, longest = matchWord(f[1], gOptWords) - longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...) - case "map", "cmd": + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) + case "map", "cmap", "cmd": longestAcc = acc default: matches, longest = matchFile(f[len(f)-1]) - longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...) + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) + } + case 3: + switch f[0] { + case "map", "cmap": + matches, longest = matchCmd(f[2]) + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) + default: + matches, longest = matchFile(f[len(f)-1]) + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) } default: switch f[0] { - case "set", "map", "cmd": + case "set", "map", "cmap", "cmd": longestAcc = acc default: matches, longest = matchFile(f[len(f)-1]) - longestAcc = append(acc[:len(acc)-len(f[len(f)-1])], []rune(longest)...) + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) } } @@ -386,8 +422,6 @@ func completeFile(acc []rune) (matches []string, longestAcc []rune) { log.Printf("reading directory: %s", err) } - var longest string - for _, f := range files { if !strings.HasPrefix(f.Name(), s) { continue @@ -395,19 +429,17 @@ func completeFile(acc []rune) (matches []string, longestAcc []rune) { matches = append(matches, f.Name()) - if longest != "" { - longest = matchLongest(longest, f.Name()) + if len(longestAcc) != 0 { + longestAcc = matchLongest(longestAcc, []rune(f.Name())) } else if s != "" { - longest = f.Name() + longestAcc = []rune(f.Name()) } } - if longest == "" { - longest = s + if len(longestAcc) == 0 { + longestAcc = acc } - longestAcc = []rune(longest) - return } @@ -415,15 +447,14 @@ func completeShell(acc []rune) (matches []string, longestAcc []rune) { s := string(acc) f := tokenize(s) - var longest string + var longest []rune switch len(f) { case 1: - matches, longest = matchExec(s) - longestAcc = []rune(longest) + matches, longestAcc = matchExec(s) default: matches, longest = matchFile(f[len(f)-1]) - longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], []rune(longest)...) + longestAcc = append(acc[:len(acc)-len([]rune(f[len(f)-1]))], longest...) } return diff --git a/complete_test.go b/complete_test.go index b5044c2..36994dd 100644 --- a/complete_test.go +++ b/complete_test.go @@ -18,10 +18,11 @@ func TestMatchLongest(t *testing.T) { {"foo", "foobar", "foo"}, {"foo", "barfoo", ""}, {"foobar", "foobaz", "fooba"}, + {"год", "гол", "го"}, } for _, test := range tests { - if got := matchLongest(test.s1, test.s2); got != test.exp { + if got := string(matchLongest([]rune(test.s1), []rune(test.s2))); got != test.exp { t.Errorf("at input '%s' and '%s' expected '%s' but got '%s'", test.s1, test.s2, test.exp, got) } } @@ -48,8 +49,8 @@ func TestMatchWord(t *testing.T) { t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.matches, m) } - if l != test.longest { - t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.longest, l) + if ls := string(l); ls != test.longest { + t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.longest, ls) } } } diff --git a/doc.go b/doc.go index 7abaf34..ce9de52 100644 --- a/doc.go +++ b/doc.go @@ -85,6 +85,7 @@ The following command line commands are provided by lf: cmd-complete (default '') cmd-menu-complete cmd-menu-complete-back + cmd-menu-accept cmd-enter (default '' and '') cmd-interrupt (default '') cmd-history-next (default '') @@ -492,6 +493,10 @@ Autocomplete the current word with menu selection. You need to assign keys to these commands (e.g. 'cmap cmd-menu-complete; cmap cmd-menu-complete-back'). You can use the assigned keys assigned to display the menu and then cycle through completion options. + cmd-menu-accept + +Accept the currently selected match in menu completion and close the menu. + cmd-enter (default '' and '') Execute the current line. diff --git a/docstring.go b/docstring.go index c08e254..b37819c 100644 --- a/docstring.go +++ b/docstring.go @@ -89,6 +89,7 @@ The following command line commands are provided by lf: cmd-complete (default '') cmd-menu-complete cmd-menu-complete-back + cmd-menu-accept cmd-enter (default '' and '') cmd-interrupt (default '') cmd-history-next (default '') @@ -520,6 +521,10 @@ to these commands (e.g. 'cmap cmd-menu-complete; cmap cmd-menu-complete-back'). You can use the assigned keys assigned to display the menu and then cycle through completion options. + cmd-menu-accept + +Accept the currently selected match in menu completion and close the menu. + cmd-enter (default '' and '') Execute the current line. diff --git a/eval.go b/eval.go index af3671d..368277b 100644 --- a/eval.go +++ b/eval.go @@ -1587,7 +1587,7 @@ func (e *callExpr) eval(app *app, args []string) { return } - // Reset the completition menu as in bash/vim + // Reset the completion menu as in bash/vim // and update the pertinent variables if app.ui.menuBuf != nil { app.ui.menuBuf = nil @@ -1628,27 +1628,21 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.menuBuf = b } case "cmd-menu-complete": - var target []rune - - // target will store the current menu query // note that, as we will store the current selected value // in cmdAccLeft, we can not call the complete function with its - // value, as it is already a final completition result + // value, as it is already a final completion result if app.ui.menuBuf == nil { - target = app.ui.cmdAccLeft app.ui.cmdTmp = app.ui.cmdAccLeft - } else { - target = app.ui.cmdTmp } var matches []string switch app.ui.cmdPrefix { case ":": - matches, app.ui.cmdAccLeft = completeCmd(target) + matches, app.ui.cmdAccLeft = completeCmd(app.ui.cmdTmp) case "/", "?": - matches, app.ui.cmdAccLeft = completeFile(target) + matches, app.ui.cmdAccLeft = completeFile(app.ui.cmdTmp) case "$", "%", "!", "&": - matches, app.ui.cmdAccLeft = completeShell(target) + matches, app.ui.cmdAccLeft = completeShell(app.ui.cmdTmp) default: return } @@ -1656,13 +1650,12 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.draw(app.nav) if len(matches) > 1 { - step := 1 - - // Check if the tab-selecttion was inited + // Check if the tab-selection was inited if app.ui.menuSelected == -2 { app.ui.menuSelected = -1 } else { - app.ui.menuSelected = mod(app.ui.menuSelected+step, len(matches)) + app.ui.menuSelected++ + app.ui.menuSelected %= len(matches) } if err := listMatchesMenu(app.ui, matches); err != nil { @@ -1673,23 +1666,18 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.menuSelected = -2 } case "cmd-menu-complete-back": - var target []rune - if app.ui.menuBuf == nil { - target = app.ui.cmdAccLeft app.ui.cmdTmp = app.ui.cmdAccLeft - } else { - target = app.ui.cmdTmp } var matches []string switch app.ui.cmdPrefix { case ":": - matches, app.ui.cmdAccLeft = completeCmd(target) + matches, app.ui.cmdAccLeft = completeCmd(app.ui.cmdTmp) case "/", "?": - matches, app.ui.cmdAccLeft = completeFile(target) + matches, app.ui.cmdAccLeft = completeFile(app.ui.cmdTmp) case "$", "%", "!", "&": - matches, app.ui.cmdAccLeft = completeShell(target) + matches, app.ui.cmdAccLeft = completeShell(app.ui.cmdTmp) default: return } @@ -1697,13 +1685,13 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.draw(app.nav) if len(matches) > 1 { - step := -1 - - // Check if the tab-selecttion was inited + // Check if the tab-selection was inited if app.ui.menuSelected == -2 { app.ui.menuSelected = -1 + } else if app.ui.menuSelected <= 0 { + app.ui.menuSelected = len(matches) - 1 } else { - app.ui.menuSelected = mod(app.ui.menuSelected+step, len(matches)) + app.ui.menuSelected-- } if err := listMatchesMenu(app.ui, matches); err != nil { @@ -1713,6 +1701,9 @@ func (e *callExpr) eval(app *app, args []string) { app.ui.menuBuf = nil app.ui.menuSelected = -2 } + case "cmd-menu-accept": + app.ui.menuBuf = nil + app.ui.menuSelected = -2 case "cmd-enter": s := string(append(app.ui.cmdAccLeft, app.ui.cmdAccRight...)) if len(s) == 0 && app.ui.cmdPrefix != "filter: " { diff --git a/lf.1 b/lf.1 index 00af2b4..48d9b40 100644 --- a/lf.1 +++ b/lf.1 @@ -102,6 +102,7 @@ The following command line commands are provided by lf: cmd-complete (default '') cmd-menu-complete cmd-menu-complete-back + cmd-menu-accept cmd-enter (default '' and '') cmd-interrupt (default '') cmd-history-next (default '') @@ -600,6 +601,12 @@ Autocomplete the current word. .PP Autocomplete the current word with menu selection. You need to assign keys to these commands (e.g. 'cmap cmd-menu-complete; cmap cmd-menu-complete-back'). You can use the assigned keys assigned to display the menu and then cycle through completion options. .PP +.EX + cmd-menu-accept +.EE +.PP +Accept the currently selected match in menu completion and close the menu. +.PP .EX cmd-enter (default '' and '') .EE diff --git a/misc.go b/misc.go index 7083cd7..451b760 100644 --- a/misc.go +++ b/misc.go @@ -91,7 +91,7 @@ func unescape(s string) string { } // This function splits the given string by whitespaces. It is aware of escaped -// whitespaces so that they are not splitted unintentionally. +// whitespaces so that they are not split unintentionally. func tokenize(s string) []string { esc := false var buf []rune @@ -295,10 +295,6 @@ func max(a, b int) int { return b } -func mod(a, b int) int { - return (a%b + b) % b -} - // We don't need no generic code // We don't need no type control // No dark templates in compiler diff --git a/ui.go b/ui.go index e287235..02fdd98 100644 --- a/ui.go +++ b/ui.go @@ -1265,13 +1265,14 @@ func listMatchesMenu(ui *ui, matches []string) error { // Handle menu tab match only if wanted if ui.menuSelected == i { + comp := []rune(escape(target)) toks := tokenize(string(ui.cmdAccLeft)) - last := toks[len(toks)-1] + _, last := filepath.Split(toks[len(toks)-1]) - if strings.Contains(target, last) { - ui.cmdAccLeft = append(ui.cmdAccLeft[:len(ui.cmdAccLeft)-len(last)], []rune(target)...) + if last == "" { + ui.cmdAccLeft = append(ui.cmdAccLeft, comp...) } else { - ui.cmdAccLeft = append(ui.cmdAccLeft, []rune(target)...) + ui.cmdAccLeft = append(ui.cmdAccLeft[:len(ui.cmdAccLeft)-len([]rune(last))], comp...) } target = fmt.Sprintf("\033[7m%s\033[0m%*s", target, wcol-len(target), "") From 75869f0ac3d5106744b07421ad2885ff903236c0 Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Sat, 1 Oct 2022 09:32:39 -0400 Subject: [PATCH 08/13] support italic escape code in previews (#936) --- colors.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/colors.go b/colors.go index d8a69ff..e76e5d8 100644 --- a/colors.go +++ b/colors.go @@ -110,6 +110,8 @@ func applyAnsiCodes(s string, st tcell.Style) tcell.Style { st = st.Bold(true) case n == 2: st = st.Dim(true) + case n == 3: + st = st.Italic(true) case n == 4: st = st.Underline(true) case n == 5 || n == 6: From 165fecbea03f1b38bf53f4fbb075f16e41b73fad Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Sat, 1 Oct 2022 09:33:22 -0400 Subject: [PATCH 09/13] Fix minor incsearch weirdness (#944) This fixes an issue where if you stared a search then deleted the search text (with e.g. backspace) it would perform a search for the empty string and move the selection to the next file. --- eval.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eval.go b/eval.go index 368277b..085002e 100644 --- a/eval.go +++ b/eval.go @@ -511,6 +511,9 @@ func update(app *app) { switch { case gOpts.incsearch && app.ui.cmdPrefix == "/": app.nav.search = string(app.ui.cmdAccLeft) + string(app.ui.cmdAccRight) + if app.nav.search == "" { + return + } dir := app.nav.currDir() old := dir.ind @@ -525,6 +528,9 @@ func update(app *app) { } case gOpts.incsearch && app.ui.cmdPrefix == "?": app.nav.search = string(app.ui.cmdAccLeft) + string(app.ui.cmdAccRight) + if app.nav.search == "" { + return + } dir := app.nav.currDir() old := dir.ind From c5dfd6df5124bc4a4b3674a33907731f64c346cf Mon Sep 17 00:00:00 2001 From: Seninha <63266536+phillbush@users.noreply.github.com> Date: Sat, 1 Oct 2022 10:36:26 -0300 Subject: [PATCH 10/13] implement gokcehan#606 (#945) --- nav.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nav.go b/nav.go index 00ed77d..1860e6c 100644 --- a/nav.go +++ b/nav.go @@ -612,17 +612,21 @@ func (nav *nav) previewLoop(ui *ui) { break loop } } + win := ui.wins[len(ui.wins)-1] if clear && len(gOpts.previewer) != 0 && len(gOpts.cleaner) != 0 && nav.volatilePreview { nav.exportFiles() exportOpts() - cmd := exec.Command(gOpts.cleaner, prev) + cmd := exec.Command(gOpts.cleaner, prev, + strconv.Itoa(win.w), + strconv.Itoa(win.h), + strconv.Itoa(win.x), + strconv.Itoa(win.y)) if err := cmd.Run(); err != nil { log.Printf("cleaning preview: %s", err) } nav.volatilePreview = false } if len(path) != 0 { - win := ui.wins[len(ui.wins)-1] nav.preview(path, win) prev = path } From 0906d39676b0c6de3ce92bf60e5334097627212c Mon Sep 17 00:00:00 2001 From: Gokcehan Date: Sat, 1 Oct 2022 16:37:39 +0300 Subject: [PATCH 11/13] update doc cc #945 --- doc.go | 2 +- docstring.go | 7 ++++--- lf.1 | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc.go b/doc.go index ce9de52..e963cb2 100644 --- a/doc.go +++ b/doc.go @@ -576,7 +576,7 @@ Automatically quit server when there are no clients left connected. Set the path of a cleaner file. The file should be executable. This file is called if previewing is enabled, the previewer is set, and the previously selected file had its preview cache disabled. -One argument is passed to the file, path to the file whose preview should be cleaned. +Five arguments are passed to the file, (1) current file name, (2) width, (3) height, (4) horizontal position, and (5) vertical position of preview pane respectively. Preview clearing is disabled when the value of this option is left empty. dircache bool (default on) diff --git a/docstring.go b/docstring.go index b37819c..3efe281 100644 --- a/docstring.go +++ b/docstring.go @@ -606,9 +606,10 @@ Automatically quit server when there are no clients left connected. Set the path of a cleaner file. The file should be executable. This file is called if previewing is enabled, the previewer is set, and the previously -selected file had its preview cache disabled. One argument is passed to the -file, path to the file whose preview should be cleaned. Preview clearing is -disabled when the value of this option is left empty. +selected file had its preview cache disabled. Five arguments are passed to +the file, (1) current file name, (2) width, (3) height, (4) horizontal +position, and (5) vertical position of preview pane respectively. Preview +clearing is disabled when the value of this option is left empty. dircache bool (default on) diff --git a/lf.1 b/lf.1 index 48d9b40..1ac3c42 100644 --- a/lf.1 +++ b/lf.1 @@ -712,7 +712,7 @@ Automatically quit server when there are no clients left connected. cleaner string (default '') (not called if empty) .EE .PP -Set the path of a cleaner file. The file should be executable. This file is called if previewing is enabled, the previewer is set, and the previously selected file had its preview cache disabled. One argument is passed to the file, path to the file whose preview should be cleaned. Preview clearing is disabled when the value of this option is left empty. +Set the path of a cleaner file. The file should be executable. This file is called if previewing is enabled, the previewer is set, and the previously selected file had its preview cache disabled. Five arguments are passed to the file, (1) current file name, (2) width, (3) height, (4) horizontal position, and (5) vertical position of preview pane respectively. Preview clearing is disabled when the value of this option is left empty. .PP .EX dircache bool (default on) From fc71c6f8b9f6601f93f7cebbc0ca33988bf0507f Mon Sep 17 00:00:00 2001 From: Franciosi Date: Sat, 1 Oct 2022 09:38:50 -0400 Subject: [PATCH 12/13] README.md Update (#951) s/MacOS/macOS, simple one --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70e705a..4e4e19d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ See [faq](https://github.com/gokcehan/lf/wiki/FAQ) for more information and [tut ## Features -- Cross-platform (Linux, MacOS, BSDs, Windows) +- Cross-platform (Linux, macOS, BSDs, Windows) - Single binary without any runtime dependencies - Fast startup and low memory footprint due to native code and static binaries - Asynchronous IO operations to avoid UI locking From 4968b1da421b7346a5f894bde46c15d4f9779fba Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Sat, 1 Oct 2022 09:39:11 -0400 Subject: [PATCH 13/13] Reset history position when leaving command line (#953) Previously the history position was only reset when executing the history prev/next command in normal mode, so it was not reset if you entered command-line mode then started moving through the history. --- eval.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/eval.go b/eval.go index 085002e..59596d6 100644 --- a/eval.go +++ b/eval.go @@ -600,6 +600,8 @@ func normal(app *app) { app.ui.cmdAccRight = nil app.ui.cmdTmp = nil app.ui.cmdPrefix = "" + + app.cmdHistoryInd = 0 } func insert(app *app, arg string) { @@ -1884,31 +1886,27 @@ func (e *callExpr) eval(app *app, args []string) { app.cmdHistoryInd-- } if app.cmdHistoryInd == 0 { - app.ui.menuBuf = nil - app.ui.menuSelected = -2 - app.ui.cmdAccLeft = nil - app.ui.cmdAccRight = nil - app.ui.cmdTmp = nil + normal(app) app.ui.cmdPrefix = ":" return } - cmd := app.cmdHistory[len(app.cmdHistory)-app.cmdHistoryInd] + historyInd := app.cmdHistoryInd + cmd := app.cmdHistory[len(app.cmdHistory)-historyInd] normal(app) + app.cmdHistoryInd = historyInd app.ui.cmdPrefix = cmd.prefix app.ui.cmdAccLeft = []rune(cmd.value) case "cmd-history-prev": if app.ui.cmdPrefix == ">" { return } - if app.ui.cmdPrefix == "" { - app.cmdHistoryInd = 0 - } if app.cmdHistoryInd == len(app.cmdHistory) { return } - app.cmdHistoryInd++ - cmd := app.cmdHistory[len(app.cmdHistory)-app.cmdHistoryInd] + historyInd := app.cmdHistoryInd + 1 + cmd := app.cmdHistory[len(app.cmdHistory)-historyInd] normal(app) + app.cmdHistoryInd = historyInd app.ui.cmdPrefix = cmd.prefix app.ui.cmdAccLeft = []rune(cmd.value) case "cmd-delete":