Add selection navigation

- FocusNextSelection      (ctrl-n)
- FocusPreviousSelection  (ctrl-p)

Also improve batch operations
pull/583/head
Arijit Basu 1 year ago
parent 0e43198093
commit b62765156a

@ -24,7 +24,9 @@ of [modes][4] and the key mappings for each mode.
| V | ctrl-a | select/unselect all |
| 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 |
@ -47,47 +49,17 @@ of [modes][4] and the key mappings for each mode.
| ~ | | go home |
| [0-9] | | input |
### duplicate_as
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
### vroot
| key | remaps | action |
| ------ | ------ | ------------ |
| . | | vroot $PWD |
| / | | vroot / |
| ctrl-r | | reset vroot |
| ctrl-u | | unset vroot |
| v | | toggle vroot |
| ~ | | vroot $HOME |
### quit
| key | remaps | action |
| ----- | ------ | ----------------------- |
| enter | | just quit |
| f | | quit printing focus |
| p | | quit printing pwd |
| r | | quit printing result |
| s | | quit printing selection |
### action
### search
| key | remaps | action |
| ----- | ------ | -------------------- |
| ! | | shell |
| c | | create |
| e | | open in editor |
| l | | logs |
| m | | toggle mouse |
| q | | quit options |
| s | | selection operations |
| v | | vroot |
| [0-9] | | go to index |
| key | remaps | action |
| ------ | ------ | ---------------- |
| ctrl-n | down | down |
| ctrl-p | up | up |
| enter | | submit |
| esc | | cancel |
| left | | back |
| right | | enter |
| tab | | toggle selection |
### go_to
@ -99,6 +71,44 @@ of [modes][4] and the key mappings for each mode.
| p | | path |
| x | | open in gui |
### go_to_path
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
### duplicate_as
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
### sort
| key | remaps | action |
| --------- | ------ | --------------------------------- |
| ! | | reverse sorters |
| C | | by created reverse |
| E | | by canonical extension reverse |
| L | | by last modified reverse |
| M | | by canonical mime essence reverse |
| N | | by node type reverse |
| R | | by relative path reverse |
| S | | by size reverse |
| backspace | | remove last sorter |
| c | | by created |
| ctrl-r | | reset sorters |
| ctrl-u | | clear sorters |
| e | | by canonical extension |
| enter | | submit |
| l | | by last modified |
| m | | by canonical mime essence |
| n | | by node type |
| r | | by relative path |
| s | | by size |
### debug_error
| key | remaps | action |
@ -106,39 +116,53 @@ of [modes][4] and the key mappings for each mode.
| enter | | open logs in editor |
| q | | quit |
### recover
### delete
| key | remaps | action |
| --- | ------ | ------ |
| key | remaps | action |
| --- | ------ | ------------ |
| D | | force delete |
| d | | delete |
### relative_path_does_not_match_regex
### create
| key | remaps | action |
| ----- | ------ | ------ |
| enter | | submit |
| key | remaps | action |
| --- | ------ | ---------------- |
| d | | create directory |
| f | | create file |
### rename
### create_directory
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
### switch_layout
### vroot
| key | remaps | action |
| --- | ------ | -------------------- |
| 1 | | default |
| 2 | | no help menu |
| 3 | | no selection panel |
| 4 | | no help or selection |
| key | remaps | action |
| ------ | ------ | ------------ |
| . | | vroot $PWD |
| / | | vroot / |
| ctrl-r | | reset vroot |
| ctrl-u | | unset vroot |
| v | | toggle vroot |
| ~ | | vroot $HOME |
### create_file
### relative_path_does_match_regex
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
| key | remaps | action |
| ----- | ------ | ------ |
| enter | | submit |
### quit
| key | remaps | action |
| ----- | ------ | ----------------------- |
| enter | | just quit |
| f | | quit printing focus |
| p | | quit printing pwd |
| r | | quit printing result |
| s | | quit printing selection |
### filter
@ -150,7 +174,7 @@ of [modes][4] and the key mappings for each mode.
| ctrl-u | | clear filters |
| r | | relative path does match regex |
### create_directory
### create_file
| key | remaps | action |
| ----- | ------ | ------------ |
@ -169,74 +193,52 @@ of [modes][4] and the key mappings for each mode.
| s | | softlink here |
| u | | clear selection |
### search
| key | remaps | action |
| ------ | ------ | ---------------- |
| ctrl-n | down | down |
| ctrl-p | up | up |
| enter | | submit |
| esc | | cancel |
| left | | back |
| right | | enter |
| tab | | toggle selection |
### number
| key | remaps | action |
| ----- | ------ | -------- |
| down | j | to down |
| enter | | to index |
| k | up | to up |
| [0-9] | | input |
### delete
### switch_layout
| key | remaps | action |
| --- | ------ | ------------ |
| D | | force delete |
| d | | delete |
| key | remaps | action |
| --- | ------ | -------------------- |
| 1 | | default |
| 2 | | no help menu |
| 3 | | no selection panel |
| 4 | | no help or selection |
### go_to_path
### rename
| key | remaps | action |
| ----- | ------ | ------------ |
| enter | | submit |
| tab | | try complete |
### relative_path_does_match_regex
### relative_path_does_not_match_regex
| key | remaps | action |
| ----- | ------ | ------ |
| enter | | submit |
### create
### number
| key | remaps | action |
| --- | ------ | ---------------- |
| d | | create directory |
| f | | create file |
| key | remaps | action |
| ----- | ------ | -------- |
| down | j | to down |
| enter | | to index |
| k | up | to up |
| [0-9] | | input |
### sort
### recover
| key | remaps | action |
| --------- | ------ | --------------------------------- |
| ! | | reverse sorters |
| C | | by created reverse |
| E | | by canonical extension reverse |
| L | | by last modified reverse |
| M | | by canonical mime essence reverse |
| N | | by node type reverse |
| R | | by relative path reverse |
| S | | by size reverse |
| backspace | | remove last sorter |
| c | | by created |
| ctrl-r | | reset sorters |
| ctrl-u | | clear sorters |
| e | | by canonical extension |
| enter | | submit |
| l | | by last modified |
| m | | by canonical mime essence |
| n | | by node type |
| r | | by relative path |
| s | | by size |
| key | remaps | action |
| --- | ------ | ------ |
### action
| key | remaps | action |
| ----- | ------ | -------------------- |
| ! | | shell |
| c | | create |
| e | | open in editor |
| l | | logs |
| m | | toggle mouse |
| q | | quit options |
| s | | selection operations |
| v | | vroot |
| [0-9] | | go to index |

@ -97,6 +97,15 @@ Example:
- Lua: `"FocusNext"`
- YAML: `FocusNext`
#### FocusNextSelection
Focus on the next selected node.
Example:
- Lua: `"FocusNextSelection"`
- YAML: `FocusNextSelection`
#### FocusNextByRelativeIndex
Focus on the `n`th node relative to the current focus where `n` is a
@ -128,6 +137,15 @@ Example:
- Lua: `"FocusPrevious"`
- YAML: `FocusPrevious`
#### FocusPreviousSelection
Focus on the previous item.
Example:
- Lua: `"FocusPreviousSelection"`
- YAML: `FocusPreviousSelection`
#### FocusPreviousByRelativeIndex
Focus on the `-n`th node relative to the current focus where `n` is a

@ -427,6 +427,7 @@ impl App {
FocusFirst => self.focus_first(true),
FocusLast => self.focus_last(),
FocusPrevious => self.focus_previous(),
FocusPreviousSelection => self.focus_previous_selection(),
FocusPreviousByRelativeIndex(i) => {
self.focus_previous_by_relative_index(i)
}
@ -435,6 +436,7 @@ impl App {
self.focus_previous_by_relative_index_from_input()
}
FocusNext => self.focus_next(),
FocusNextSelection => self.focus_next_selection(),
FocusNextByRelativeIndex(i) => self.focus_next_by_relative_index(i),
FocusNextByRelativeIndexFromInput => {
self.focus_next_by_relative_index_from_input()
@ -689,6 +691,46 @@ impl App {
Ok(self)
}
fn focus_previous_selection(mut self) -> Result<Self> {
let total = self.selection.len();
if total == 0 {
return Ok(self);
}
let bounded = self.config.general.enforce_bounded_index_navigation;
if let Some(n) = self
.directory_buffer
.as_ref()
.and_then(|d| d.focused_node())
{
if let Some(idx) = self.selection.get_index_of(n) {
let idx = if idx == 0 {
if bounded {
idx
} else {
total.max(1) - 1
}
} else {
idx.max(1) - 1
};
if let Some(p) = self
.selection
.get_index(idx)
.map(|n| n.absolute_path.clone())
{
self = self.focus_path(&p, true)?;
}
} else if let Some(p) =
self.selection.last().map(|n| n.absolute_path.clone())
{
self = self.focus_path(&p, true)?;
}
}
Ok(self)
}
pub fn focus_previous_by_relative_index(mut self, index: usize) -> Result<Self> {
let mut history = self.history.clone();
if let Some(dir) = self.directory_buffer_mut() {
@ -734,6 +776,46 @@ impl App {
Ok(self)
}
fn focus_next_selection(mut self) -> Result<Self> {
let total = self.selection.len();
if total == 0 {
return Ok(self);
}
let bounded = self.config.general.enforce_bounded_index_navigation;
if let Some(n) = self
.directory_buffer
.as_ref()
.and_then(|d| d.focused_node())
{
if let Some(idx) = self.selection.get_index_of(n) {
let idx = if idx + 1 == total {
if bounded {
idx
} else {
0
}
} else {
idx + 1
};
if let Some(p) = self
.selection
.get_index(idx)
.map(|n| n.absolute_path.clone())
{
self = self.focus_path(&p, true)?;
}
} else if let Some(p) =
self.selection.first().map(|n| n.absolute_path.clone())
{
self = self.focus_path(&p, true)?;
}
}
Ok(self)
}
pub fn focus_next_by_relative_index(mut self, index: usize) -> Result<Self> {
let mut history = self.history.clone();
if let Some(dir) = self.directory_buffer_mut() {

@ -1242,6 +1242,18 @@ xplr.config.modes.builtin.default = {
"ScrollDownHalf",
},
},
["ctrl-n"] = {
help = "next selection",
messages = {
"FocusNextSelection",
},
},
["ctrl-p"] = {
help = "prev selection",
messages = {
"FocusPreviousSelection",
},
},
},
on_number = {
help = "input",
@ -1468,6 +1480,7 @@ xplr.config.modes.builtin.selection_ops = {
if cp -vr -- "${PTH:?}" "./${BASENAME:?}"; then
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC copied to ./$BASENAME_ESC"
"$XPLR" -m 'UnSelectPath: %q' "$PTH"
"$XPLR" -m 'FocusPath: %q' "$BASENAME"
else
"$XPLR" -m 'LogError: %q' "Failed to copy $PTH_ESC to ./$BASENAME_ESC"
fi
@ -1494,7 +1507,7 @@ xplr.config.modes.builtin.selection_ops = {
done
if mv -v -- "${PTH:?}" "./${BASENAME:?}"; then
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC moved to ./$BASENAME_ESC"
"$XPLR" -m 'UnSelectPath: %q' "$PTH"
"$XPLR" -m 'FocusPath: %q' "$BASENAME"
else
"$XPLR" -m 'LogError: %q' "Failed to move $PTH_ESC to ./$BASENAME_ESC"
fi
@ -1522,6 +1535,7 @@ xplr.config.modes.builtin.selection_ops = {
if ln -sv -- "${PTH:?}" "./${BASENAME:?}"; then
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC softlinked as ./$BASENAME_ESC"
"$XPLR" -m 'UnSelectPath: %q' "$PTH"
"$XPLR" -m 'FocusPath: %q' "$BASENAME"
else
"$XPLR" -m 'LogError: %q' "Failed to softlink $PTH_ESC as ./$BASENAME_ESC"
fi
@ -1549,6 +1563,7 @@ xplr.config.modes.builtin.selection_ops = {
if ln -v -- "${PTH:?}" "./${BASENAME:?}"; then
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC hardlinked as ./$BASENAME_ESC"
"$XPLR" -m 'UnSelectPath: %q' "$PTH"
"$XPLR" -m 'FocusPath: %q' "$BASENAME"
else
"$XPLR" -m 'LogError: %q' "Failed to hardlink $PTH_ESC as ./$BASENAME_ESC"
fi

@ -74,6 +74,14 @@ pub enum ExternalMsg {
/// - YAML: `FocusNext`
FocusNext,
/// Focus on the next selected node.
///
/// Example:
///
/// - Lua: `"FocusNextSelection"`
/// - YAML: `FocusNextSelection`
FocusNextSelection,
/// Focus on the `n`th node relative to the current focus where `n` is a
/// given value.
///
@ -102,6 +110,14 @@ pub enum ExternalMsg {
/// - YAML: `FocusPrevious`
FocusPrevious,
/// Focus on the previous item.
///
/// Example:
///
/// - Lua: `"FocusPreviousSelection"`
/// - YAML: `FocusPreviousSelection`
FocusPreviousSelection,
/// Focus on the `-n`th node relative to the current focus where `n` is a
/// given value.
///

Loading…
Cancel
Save