From 6e8f3da9713335e66593acdd8a93d326ab0eb62a Mon Sep 17 00:00:00 2001 From: Arijit Basu Date: Fri, 2 Feb 2024 12:47:26 +0530 Subject: [PATCH] Quick copy and quick move (#692) * Quick copy and quick move - Press `c` to quickly copy the focused or selected path - Press `m` to quickly move the focused or selected path --- docs/en/src/default-key-bindings.md | 293 +++++++++++++++++----------- docs/en/src/modes.md | 12 ++ src/init.lua | 222 ++++++++++++++++++--- 3 files changed, 378 insertions(+), 149 deletions(-) diff --git a/docs/en/src/default-key-bindings.md b/docs/en/src/default-key-bindings.md index fe09f38..dfe2fb9 100644 --- a/docs/en/src/default-key-bindings.md +++ b/docs/en/src/default-key-bindings.md @@ -24,6 +24,7 @@ of [modes][4] and the key mappings for each mode. | ? | f1 | global help menu | | G | | go to bottom | | V | ctrl-a | select/unselect all | +| c | | copy to | | ctrl-d | | duplicate as | | ctrl-i | tab | next visited path | | ctrl-n | | next selection | @@ -40,6 +41,7 @@ of [modes][4] and the key mappings for each mode. | h | left | back | | k | up | up | | l | right | enter | +| m | | move to | | page-down | | scroll down | | page-up | | scroll up | | q | | quit | @@ -51,7 +53,7 @@ of [modes][4] and the key mappings for each mode. | ~ | | go home | | [0-9] | | input | -### duplicate_as +### go_to_path | key | remaps | action | | ----- | ------ | ---------------- | @@ -59,16 +61,37 @@ of [modes][4] and the key mappings for each mode. | f1 | | global help menu | | tab | | try complete | -### filter +### rename -| key | remaps | action | -| --------- | ------ | ---------------------------------- | -| R | | relative path does not match regex | -| backspace | | remove last filter | -| ctrl-r | | reset filters | -| ctrl-u | | clear filters | -| f1 | | global help menu | -| r | | relative path does match regex | +| key | remaps | action | +| ----- | ------ | ---------------- | +| enter | | submit | +| f1 | | global help menu | +| tab | | try complete | + +### recover + +| key | remaps | action | +| --- | ------ | ---------------- | +| f1 | | global help menu | + +### go_to + +| key | remaps | action | +| --- | ------ | ---------------- | +| f | | follow symlink | +| f1 | | global help menu | +| g | | top | +| i | | initial $PWD | +| p | | path | +| x | | open in gui | + +### relative_path_does_match_regex + +| key | remaps | action | +| ----- | ------ | ---------------- | +| enter | | submit | +| f1 | | global help menu | ### action @@ -86,23 +109,62 @@ of [modes][4] and the key mappings for each mode. | v | | vroot | | [0-9] | | go to index | -### create +### default -| key | remaps | action | -| --- | ------ | ---------------- | -| d | | create directory | -| f | | create file | -| f1 | | global help menu | +| key | remaps | action | +| --------- | ------ | ------------------- | +| ( | | prev deep branch | +| ) | | next deep branch | +| . | | show hidden | +| / | ctrl-f | search | +| : | | action | +| ? | f1 | global help menu | +| G | | go to bottom | +| V | ctrl-a | select/unselect all | +| c | | copy to | +| ctrl-d | | duplicate as | +| ctrl-i | tab | next visited path | +| ctrl-n | | next selection | +| ctrl-o | | last visited path | +| ctrl-p | | prev selection | +| ctrl-r | | refresh screen | +| ctrl-u | | clear selection | +| ctrl-w | | switch layout | +| d | | delete | +| down | j | down | +| enter | | quit with result | +| f | | filter | +| g | | go to | +| h | left | back | +| k | up | up | +| l | right | enter | +| m | | move to | +| page-down | | scroll down | +| page-up | | scroll up | +| q | | quit | +| r | | rename | +| s | | sort | +| space | v | toggle selection | +| { | | scroll up half | +| } | | scroll down half | +| ~ | | go home | +| [0-9] | | input | -### switch_layout +### debug_error -| key | remaps | action | -| --- | ------ | -------------------- | -| 1 | | default | -| 2 | | no help menu | -| 3 | | no selection panel | -| 4 | | no help or selection | -| f1 | | global help menu | +| key | remaps | action | +| ----- | ------ | ------------------- | +| enter | | open logs in editor | +| f1 | | global help menu | +| q | | quit | + +### create_directory + +| key | remaps | action | +| ----- | ------ | ---------------- | +| enter | | submit | +| f1 | | global help menu | +| tab | | try complete | ### selection_ops @@ -117,25 +179,14 @@ of [modes][4] and the key mappings for each mode. | s | | softlink here | | u | | clear selection | -### delete - -| key | remaps | action | -| --- | ------ | ---------------- | -| D | | force delete | -| d | | delete | -| f1 | | global help menu | - -### number +### relative_path_does_not_match_regex | key | remaps | action | | ----- | ------ | ---------------- | -| down | j | to down | -| enter | | to index | +| enter | | submit | | f1 | | global help menu | -| k | up | to up | -| [0-9] | | input | -### create_directory +### create_file | key | remaps | action | | ----- | ------ | ---------------- | @@ -143,20 +194,25 @@ of [modes][4] and the key mappings for each mode. | f1 | | global help menu | | tab | | try complete | -### recover +### quit + +| key | remaps | action | +| ----- | ------ | ----------------------- | +| enter | | just quit | +| f | | quit printing focus | +| f1 | | global help menu | +| p | | quit printing pwd | +| r | | quit printing result | +| s | | quit printing selection | + +### create | key | remaps | action | | --- | ------ | ---------------- | +| d | | create directory | +| f | | create file | | f1 | | global help menu | -### rename - -| key | remaps | action | -| ----- | ------ | ---------------- | -| enter | | submit | -| f1 | | global help menu | -| tab | | try complete | - ### vroot | key | remaps | action | @@ -169,43 +225,33 @@ of [modes][4] and the key mappings for each mode. | v | | toggle vroot | | ~ | | vroot $HOME | -### relative_path_does_match_regex - -| key | remaps | action | -| ----- | ------ | ---------------- | -| enter | | submit | -| f1 | | global help menu | - -### relative_path_does_not_match_regex - -| key | remaps | action | -| ----- | ------ | ---------------- | -| enter | | submit | -| f1 | | global help menu | - -### debug_error +### search -| key | remaps | action | -| ----- | ------ | ------------------- | -| enter | | open logs in editor | -| f1 | | global help menu | -| q | | quit | +| key | remaps | action | +| ------ | ------ | ----------------------- | +| ctrl-a | | toggle search algorithm | +| ctrl-f | | fuzzy search | +| ctrl-n | down | down | +| ctrl-p | up | up | +| ctrl-r | | regex search | +| ctrl-s | | sort (no search order) | +| ctrl-z | | toggle ordering | +| enter | | submit | +| esc | | cancel | +| f1 | | global help menu | +| left | | back | +| right | | enter | +| tab | | toggle selection | -### edit_permissions +### switch_layout -| key | remaps | action | -| ------ | ------ | ---------------- | -| G | | -group | -| M | | min | -| O | | -other | -| U | | -user | -| ctrl-r | | reset | -| enter | | submit | -| f1 | | global help menu | -| g | | +group | -| m | | max | -| o | | +other | -| u | | +user | +| key | remaps | action | +| --- | ------ | -------------------- | +| 1 | | default | +| 2 | | no help menu | +| 3 | | no selection panel | +| 4 | | no help or selection | +| f1 | | global help menu | ### sort @@ -232,47 +278,49 @@ of [modes][4] and the key mappings for each mode. | r | | by relative path | | s | | by size | -### go_to +### number -| key | remaps | action | -| --- | ------ | ---------------- | -| f | | follow symlink | -| f1 | | global help menu | -| g | | top | -| i | | initial $PWD | -| p | | path | -| x | | open in gui | +| key | remaps | action | +| ----- | ------ | ---------------- | +| down | j | to down | +| enter | | to index | +| f1 | | global help menu | +| k | up | to up | +| [0-9] | | input | -### quit +### copy_to -| key | remaps | action | -| ----- | ------ | ----------------------- | -| enter | | just quit | -| f | | quit printing focus | -| f1 | | global help menu | -| p | | quit printing pwd | -| r | | quit printing result | -| s | | quit printing selection | +| key | remaps | action | +| ----- | ------ | ---------------- | +| enter | | submit | +| f1 | | global help menu | +| tab | | try complete | -### search +### edit_permissions -| key | remaps | action | -| ------ | ------ | ----------------------- | -| ctrl-a | | toggle search algorithm | -| ctrl-f | | fuzzy search | -| ctrl-n | down | down | -| ctrl-p | up | up | -| ctrl-r | | regex search | -| ctrl-s | | sort (no search order) | -| ctrl-z | | toggle ordering | -| enter | | submit | -| esc | | cancel | -| f1 | | global help menu | -| left | | back | -| right | | enter | -| tab | | toggle selection | +| key | remaps | action | +| ------ | ------ | ---------------- | +| G | | -group | +| M | | min | +| O | | -other | +| U | | -user | +| ctrl-r | | reset | +| enter | | submit | +| f1 | | global help menu | +| g | | +group | +| m | | max | +| o | | +other | +| u | | +user | -### go_to_path +### delete + +| key | remaps | action | +| --- | ------ | ---------------- | +| D | | force delete | +| d | | delete | +| f1 | | global help menu | + +### move_to | key | remaps | action | | ----- | ------ | ---------------- | @@ -280,7 +328,18 @@ of [modes][4] and the key mappings for each mode. | f1 | | global help menu | | tab | | try complete | -### create_file +### filter + +| key | remaps | action | +| --------- | ------ | ---------------------------------- | +| R | | relative path does not match regex | +| backspace | | remove last filter | +| ctrl-r | | reset filters | +| ctrl-u | | clear filters | +| f1 | | global help menu | +| r | | relative path does match regex | + +### duplicate_as | key | remaps | action | | ----- | ------ | ---------------- | diff --git a/docs/en/src/modes.md b/docs/en/src/modes.md index 38d999c..b1afe5f 100644 --- a/docs/en/src/modes.md +++ b/docs/en/src/modes.md @@ -35,6 +35,18 @@ The builtin go to path mode. Type: [Mode](https://xplr.dev/en/mode) +#### xplr.config.modes.builtin.move_to + +The builtin move_to mode. + +Type: [Mode](https://xplr.dev/en/mode) + +#### xplr.config.modes.builtin.copy_to + +The builtin copy_to mode. + +Type: [Mode](https://xplr.dev/en/mode) + #### xplr.config.modes.builtin.selection_ops The builtin selection ops mode. diff --git a/src/init.lua b/src/init.lua index 89d29aa..9e4bea1 100644 --- a/src/init.lua +++ b/src/init.lua @@ -478,7 +478,7 @@ xplr.config.general.sort_and_filter_ui.search_identifiers = { -- -- Type: nullable string xplr.config.general.sort_and_filter_ui.search_direction_identifiers.ordered.format = -"↓" + "↓" -- The shape of unordered indicator for search ordering identifiers in Sort & filter panel. -- @@ -676,7 +676,7 @@ xplr.config.general.panel_ui.sort_and_filter.border_style = {} -- Type: nullable list of [Node Sorter](https://xplr.dev/en/sorting#node-sorter-applicable) xplr.config.general.initial_sorting = { { sorter = "ByCanonicalIsDir", reverse = true }, - { sorter = "ByIRelativePath", reverse = false }, + { sorter = "ByIRelativePath", reverse = false }, } -- The name of one of the modes to use when xplr loads. @@ -1296,6 +1296,22 @@ xplr.config.modes.builtin.default = { "FocusPreviousSelection", }, }, + ["m"] = { + help = "move to", + messages = { + "PopMode", + { SwitchModeBuiltin = "move_to" }, + { SetInputBuffer = "" }, + }, + }, + ["c"] = { + help = "copy to", + messages = { + "PopMode", + { SwitchModeBuiltin = "copy_to" }, + { SetInputBuffer = "" }, + }, + }, }, on_number = { help = "input", @@ -1309,23 +1325,23 @@ xplr.config.modes.builtin.default = { } xplr.config.modes.builtin.default.key_bindings.on_key["v"] = - xplr.config.modes.builtin.default.key_bindings.on_key["space"] + xplr.config.modes.builtin.default.key_bindings.on_key["space"] xplr.config.modes.builtin.default.key_bindings.on_key["V"] = - xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-a"] + xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-a"] xplr.config.modes.builtin.default.key_bindings.on_key["/"] = - xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-f"] + xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-f"] xplr.config.modes.builtin.default.key_bindings.on_key["h"] = - xplr.config.modes.builtin.default.key_bindings.on_key["left"] + xplr.config.modes.builtin.default.key_bindings.on_key["left"] xplr.config.modes.builtin.default.key_bindings.on_key["j"] = - xplr.config.modes.builtin.default.key_bindings.on_key["down"] + xplr.config.modes.builtin.default.key_bindings.on_key["down"] xplr.config.modes.builtin.default.key_bindings.on_key["k"] = - xplr.config.modes.builtin.default.key_bindings.on_key["up"] + xplr.config.modes.builtin.default.key_bindings.on_key["up"] xplr.config.modes.builtin.default.key_bindings.on_key["l"] = - xplr.config.modes.builtin.default.key_bindings.on_key["right"] + xplr.config.modes.builtin.default.key_bindings.on_key["right"] xplr.config.modes.builtin.default.key_bindings.on_key["tab"] = - xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-i"] -- compatibility workaround + xplr.config.modes.builtin.default.key_bindings.on_key["ctrl-i"] -- compatibility workaround xplr.config.modes.builtin.default.key_bindings.on_key["?"] = - xplr.config.general.global_key_bindings.on_key["f1"] + xplr.config.general.global_key_bindings.on_key["f1"] -- The builtin debug error mode. -- @@ -1460,6 +1476,148 @@ xplr.config.modes.builtin.go_to_path = { }, } +-- The builtin move_to mode. +-- +-- Type: [Mode](https://xplr.dev/en/mode) +xplr.config.modes.builtin.move_to = { + name = "move_to", + prompt = "ð ❯ ", + key_bindings = { + on_key = { + ["enter"] = { + help = "submit", + messages = { + { + BashExec0 = [===[ + DEST="$XPLR_INPUT_BUFFER" + [ -z "$DEST" ] && exit + if [ ! -d "$DEST" ] && ! mkdir -p -- "$DEST"; then + "$XPLR" -m 'LogError: %q' "could not create $DEST" + exit + fi + "$XPLR" -m "ChangeDirectory: %q" "$DEST" + ! cd -- "$DEST" && exit + DEST="$(pwd)" && echo "PWD=$DEST" + while IFS= read -r -d '' PTH; do + PTH_ESC=$(printf %q "$PTH") + BASENAME=$(basename -- "$PTH") + BASENAME_ESC=$(printf %q "$BASENAME") + if [ -e "$BASENAME" ]; then + echo + echo "$BASENAME_ESC exists, do you want to overwrite it?" + read -p "[y]es, [n]o, [S]kip: " ANS < /dev/tty + case "$ANS" in + [yY]*) + ;; + [nN]*) + read -p "Enter new name: " BASENAME < /dev/tty + BASENAME_ESC=$(printf %q "$BASENAME") + ;; + *) + continue + ;; + esac + fi + if mv -v -- "${PTH:?}" "./${BASENAME:?}"; then + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC moved to $BASENAME_ESC" + "$XPLR" -m 'FocusPath: %q' "$BASENAME" + else + "$XPLR" -m 'LogError: %q' "could not move $PTH_ESC to $BASENAME_ESC" + fi + done < "${XPLR_PIPE_RESULT_OUT:?}" + echo + read -p "[press enter to continue]" + ]===], + }, + "PopMode", + }, + }, + ["tab"] = { + help = "try complete", + messages = { + { CallLuaSilently = "builtin.try_complete_path" }, + }, + }, + }, + default = { + messages = { + "UpdateInputBufferFromKey", + }, + }, + }, +} + +-- The builtin copy_to mode. +-- +-- Type: [Mode](https://xplr.dev/en/mode) +xplr.config.modes.builtin.copy_to = { + name = "copy_to", + prompt = "ð ❯ ", + key_bindings = { + on_key = { + ["enter"] = { + help = "submit", + messages = { + { + BashExec0 = [===[ + DEST="$XPLR_INPUT_BUFFER" + [ -z "$DEST" ] && exit + if [ ! -d "$DEST" ] && ! mkdir -p -- "$DEST"; then + "$XPLR" -m 'LogError: %q' "could not create $DEST" + exit + fi + "$XPLR" -m "ChangeDirectory: %q" "$DEST" + ! cd -- "$DEST" && exit + DEST="$(pwd)" && echo "PWD=$DEST" + while IFS= read -r -d '' PTH; do + PTH_ESC=$(printf %q "$PTH") + BASENAME=$(basename -- "$PTH") + BASENAME_ESC=$(printf %q "$BASENAME") + if [ -e "$BASENAME" ]; then + echo + echo "$BASENAME_ESC exists, do you want to overwrite it?" + read -p "[y]es, [n]o, [S]kip: " ANS < /dev/tty + case "$ANS" in + [yY]*) + ;; + [nN]*) + read -p "Enter new name: " BASENAME < /dev/tty + BASENAME_ESC=$(printf %q "$BASENAME") + ;; + *) + continue + ;; + esac + fi + if cp -vr -- "${PTH:?}" "./${BASENAME:?}"; then + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC copied to $BASENAME_ESC" + "$XPLR" -m 'FocusPath: %q' "$BASENAME" + else + "$XPLR" -m 'LogError: %q' "could not copy $PTH_ESC to $BASENAME_ESC" + fi + done < "${XPLR_PIPE_RESULT_OUT:?}" + echo + read -p "[press enter to continue]" + ]===], + }, + "PopMode", + }, + }, + ["tab"] = { + help = "try complete", + messages = { + { CallLuaSilently = "builtin.try_complete_path" }, + }, + }, + }, + default = { + messages = { + "UpdateInputBufferFromKey", + }, + }, + }, +} + -- The builtin selection ops mode. -- -- Type: [Mode](https://xplr.dev/en/mode) @@ -1531,10 +1689,10 @@ xplr.config.modes.builtin.selection_ops = { esac fi if cp -vr -- "${PTH:?}" "./${BASENAME:?}"; then - "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC copied to ./$BASENAME_ESC" + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC copied to $BASENAME_ESC" "$XPLR" -m 'FocusPath: %q' "$BASENAME" else - "$XPLR" -m 'LogError: %q' "could not copy $PTH_ESC to ./$BASENAME_ESC" + "$XPLR" -m 'LogError: %q' "could not copy $PTH_ESC to $BASENAME_ESC" fi done < "${XPLR_PIPE_SELECTION_OUT:?}" echo @@ -1571,10 +1729,10 @@ xplr.config.modes.builtin.selection_ops = { esac fi if mv -v -- "${PTH:?}" "./${BASENAME:?}"; then - "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC moved to ./$BASENAME_ESC" + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC moved to $BASENAME_ESC" "$XPLR" -m 'FocusPath: %q' "$BASENAME" else - "$XPLR" -m 'LogError: %q' "could not move $PTH_ESC to ./$BASENAME_ESC" + "$XPLR" -m 'LogError: %q' "could not move $PTH_ESC to $BASENAME_ESC" fi done < "${XPLR_PIPE_SELECTION_OUT:?}" echo @@ -1611,10 +1769,10 @@ xplr.config.modes.builtin.selection_ops = { esac fi if ln -sv -- "${PTH:?}" "./${BASENAME:?}"; then - "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC softlinked as ./$BASENAME_ESC" + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC softlinked as $BASENAME_ESC" "$XPLR" -m 'FocusPath: %q' "$BASENAME" else - "$XPLR" -m 'LogError: %q' "could not softlink $PTH_ESC as ./$BASENAME_ESC" + "$XPLR" -m 'LogError: %q' "could not softlink $PTH_ESC as $BASENAME_ESC" fi done < "${XPLR_PIPE_SELECTION_OUT:?}" echo @@ -1651,10 +1809,10 @@ xplr.config.modes.builtin.selection_ops = { esac fi if ln -v -- "${PTH:?}" "./${BASENAME:?}"; then - "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC hardlinked as ./$BASENAME_ESC" + "$XPLR" -m 'LogSuccess: %q' "$PTH_ESC hardlinked as $BASENAME_ESC" "$XPLR" -m 'FocusPath: %q' "$BASENAME" else - "$XPLR" -m 'LogError: %q' "could not hardlink $PTH_ESC as ./$BASENAME_ESC" + "$XPLR" -m 'LogError: %q' "could not hardlink $PTH_ESC as $BASENAME_ESC" fi done < "${XPLR_PIPE_SELECTION_OUT:?}" echo @@ -1835,9 +1993,9 @@ xplr.config.modes.builtin.number = { } xplr.config.modes.builtin.number.key_bindings.on_key["j"] = - xplr.config.modes.builtin.number.key_bindings.on_key["down"] + xplr.config.modes.builtin.number.key_bindings.on_key["down"] xplr.config.modes.builtin.number.key_bindings.on_key["k"] = - xplr.config.modes.builtin.number.key_bindings.on_key["up"] + xplr.config.modes.builtin.number.key_bindings.on_key["up"] -- The builtin go to mode. -- @@ -2321,9 +2479,9 @@ xplr.config.modes.builtin.search = { } xplr.config.modes.builtin.search.key_bindings.on_key["ctrl-n"] = - xplr.config.modes.builtin.search.key_bindings.on_key["down"] + xplr.config.modes.builtin.search.key_bindings.on_key["down"] xplr.config.modes.builtin.search.key_bindings.on_key["ctrl-p"] = - xplr.config.modes.builtin.search.key_bindings.on_key["up"] + xplr.config.modes.builtin.search.key_bindings.on_key["up"] -- The builtin filter mode. -- @@ -3003,7 +3161,7 @@ xplr.fn.builtin.fmt_general_table_row_cols_1 = function(m) r = r .. "×" else local symlink_path = - xplr.util.shorten(m.symlink.absolute_path, { base = m.parent }) + xplr.util.shorten(m.symlink.absolute_path, { base = m.parent }) if m.symlink.is_dir then symlink_path = symlink_path .. "/" end @@ -3025,14 +3183,14 @@ xplr.fn.builtin.fmt_general_table_row_cols_2 = function(m) local T = xplr.util.paint("T", { fg = "Red" }) return xplr.util - .permissions_rwx(m.permissions) - :gsub("r", r) - :gsub("w", w) - :gsub("x", x) - :gsub("s", s) - :gsub("S", S) - :gsub("t", t) - :gsub("T", T) + .permissions_rwx(m.permissions) + :gsub("r", r) + :gsub("w", w) + :gsub("x", x) + :gsub("s", s) + :gsub("S", S) + :gsub("t", t) + :gsub("T", T) end -- Renders the fourth column in the table