Go to path and native auto completion on tab

- BREAKING: Rename mode `create directory` and `create file` to
  `create_directory` and `create_file`.
- Add key binding `gp` to go to a given path from input.
- Add function `fn.builtin.try_complete_path` to auto complete the path
  in input buffer.
- Use `tab` to auto complete path in `rename`, `create_file`,
  `create_directory` and `go_to_path` modes.
- Show different prompts in different modes.

And some cleanup.
pull/487/head
Arijit Basu 2 years ago committed by Arijit Basu
parent e5576e2990
commit 5370cc2e8c

@ -460,8 +460,8 @@ xplr.fn.custom.preview_pane.render = function(ctx)
end
end
```
</details>
</details>
## Also See:

@ -15,7 +15,7 @@ of the following plugins work for you, it's very easy to
- [**prncss-xyz/type-to-nav.xplr**][28] Inspired by [nnn's type-to-nav mode][29] for xplr,
with some tweaks.
- [**igorepst/term.xplr**][39] Terminal integration for xplr
- [**sayanarijit/wl-clipboard.xplr**][52] Copy and paste with system clipboard using wl-clipboard
- [**sayanarijit/wl-clipboard.xplr**][52] Copy and paste with system clipboard using wl-clipboard
- [**dtomvan/xpm.xplr**][47] The XPLR Plugin Manager
### Integration

@ -43,6 +43,10 @@ See: [Lua Function Calls](https://xplr.dev/en/lua-function-calls)
As always, `xplr.fn.builtin` is where the built-in functions are defined
that can be overwritten.
#### xplr.fn.builtin.try_complete_path
Tries to auto complete the path in the input buffer
#### xplr.fn.builtin.fmt_general_table_row_cols_0
Renders the first column in the table

@ -29,6 +29,12 @@ The builtin recover mode.
Type: [Mode](https://xplr.dev/en/mode)
#### xplr.config.modes.builtin.go_to_path
The builtin go to path mode.
Type: [Mode](https://xplr.dev/en/mode)
#### xplr.config.modes.builtin.selection_ops
The builtin selection ops mode.

@ -956,7 +956,7 @@ impl App {
}
fn push_mode(mut self) -> Self {
if self.mode != self.config.modes.builtin.recover
if Some(&self.mode) != self.config.modes.builtin.get("recover")
&& self
.last_modes
.last()
@ -1492,29 +1492,7 @@ impl App {
let builtin = &self.config.modes.builtin;
let custom = &self.config.modes.custom;
[
&builtin.default,
&builtin.debug_error,
&builtin.recover,
&builtin.selection_ops,
&builtin.create,
&builtin.create_directory,
&builtin.create_file,
&builtin.number,
&builtin.go_to,
&builtin.rename,
&builtin.duplicate_as,
&builtin.delete,
&builtin.action,
&builtin.search,
&builtin.filter,
&builtin.relative_path_does_match_regex,
&builtin.relative_path_does_not_match_regex,
&builtin.sort,
&builtin.switch_layout,
&builtin.quit,
]
.iter().map(|m| (&m.name, m.to_owned()))
builtin.iter()
.chain(custom.iter())
.map(|(name, mode)| {
let help = mode

@ -498,119 +498,11 @@ impl Mode {
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BuiltinModesConfig {
#[serde(default)]
pub default: Mode,
#[serde(default)]
pub debug_error: Mode,
#[serde(default)]
pub recover: Mode,
#[serde(default)]
pub selection_ops: Mode,
#[serde(default)]
pub create: Mode,
#[serde(default)]
pub create_directory: Mode,
#[serde(default)]
pub create_file: Mode,
#[serde(default)]
pub number: Mode,
#[serde(default)]
pub go_to: Mode,
#[serde(default)]
pub rename: Mode,
#[serde(default)]
pub duplicate_as: Mode,
#[serde(default)]
pub delete: Mode,
#[serde(default)]
pub action: Mode,
#[serde(default)]
pub search: Mode,
#[serde(default)]
pub filter: Mode,
#[serde(default)]
pub relative_path_does_match_regex: Mode,
#[serde(default)]
pub relative_path_does_not_match_regex: Mode,
#[serde(default)]
pub sort: Mode,
#[serde(default)]
pub switch_layout: Mode,
#[serde(default)]
pub quit: Mode,
}
impl BuiltinModesConfig {
pub fn get(&self, name: &str) -> Option<&Mode> {
match name {
"default" => Some(&self.default),
"debug_error" => Some(&self.debug_error),
"recover" => Some(&self.recover),
"selection ops" => Some(&self.selection_ops),
"selection_ops" => Some(&self.selection_ops),
"create" => Some(&self.create),
"create file" => Some(&self.create_file),
"create_file" => Some(&self.create_file),
"create directory" => Some(&self.create_directory),
"create_directory" => Some(&self.create_directory),
"number" => Some(&self.number),
"go to" => Some(&self.go_to),
"go_to" => Some(&self.go_to),
"rename" => Some(&self.rename),
"duplicate as" => Some(&self.duplicate_as),
"duplicate_as" => Some(&self.duplicate_as),
"delete" => Some(&self.delete),
"action" => Some(&self.action),
"search" => Some(&self.search),
"sort" => Some(&self.sort),
"filter" => Some(&self.filter),
"relative_path_does_match_regex" => {
Some(&self.relative_path_does_match_regex)
}
"relative path does match regex" => {
Some(&self.relative_path_does_match_regex)
}
"relative_path_does_not_match_regex" => {
Some(&self.relative_path_does_not_match_regex)
}
"relative path does not match regex" => {
Some(&self.relative_path_does_not_match_regex)
}
"switch layout" => Some(&self.switch_layout),
"switch_layout" => Some(&self.switch_layout),
"quit" => Some(&self.quit),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ModesConfig {
#[serde(default)]
pub builtin: BuiltinModesConfig,
pub builtin: HashMap<String, Mode>,
#[serde(default)]
pub custom: HashMap<String, Mode>,
@ -652,42 +544,11 @@ impl PanelUiConfig {
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BuiltinLayoutsConfig {
#[serde(default)]
pub default: Layout,
#[serde(default)]
pub no_help: Layout,
#[serde(default)]
pub no_selection: Layout,
#[serde(default)]
pub no_help_no_selection: Layout,
}
impl BuiltinLayoutsConfig {
pub fn get(&self, name: &str) -> Option<&Layout> {
match name {
"default" => Some(&self.default),
"no_help" => Some(&self.no_help),
"no help" => Some(&self.no_help),
"no_selection" => Some(&self.no_selection),
"no selection" => Some(&self.no_selection),
"no_help_no_selection" => Some(&self.no_help_no_selection),
"no help no selection" => Some(&self.no_help_no_selection),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LayoutsConfig {
#[serde(default)]
pub builtin: BuiltinLayoutsConfig,
pub builtin: HashMap<String, Layout>,
#[serde(default)]
pub custom: HashMap<String, Layout>,

@ -1143,7 +1143,9 @@ xplr.config.modes.builtin.default = {
{ SwitchModeBuiltin = "rename" },
{
BashExecSilently = [===[
echo SetInputBuffer: "'"$(basename "${XPLR_FOCUS_PATH}")"'" >> "${XPLR_PIPE_MSG_IN:?}"
NAME=$(basename "${XPLR_FOCUS_PATH:?}")
echo SetInputPrompt: "'"${NAME:?} "'" >> "${XPLR_PIPE_MSG_IN:?}"
echo SetInputBuffer: "'"${NAME:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
]===],
},
},
@ -1202,6 +1204,7 @@ xplr.config.modes.builtin.default = {
messages = {
"PopMode",
{ SwitchModeBuiltin = "number" },
{ SetInputPrompt = ":" },
"BufferInputFromKey",
},
},
@ -1354,6 +1357,55 @@ xplr.config.modes.builtin.recover = {
},
}
-- The builtin go to path mode.
--
-- Type: [Mode](https://xplr.dev/en/mode)
xplr.config.modes.builtin.go_to_path = {
name = "go to path",
key_bindings = {
on_key = {
enter = {
help = "submit",
messages = {
{
BashExecSilently = [===[
if [ -d "${XPLR_INPUT_BUFFER:?}" ]; then
echo ChangeDirectory: "'"$XPLR_INPUT_BUFFER"'" >> "${XPLR_PIPE_MSG_IN:?}"
else
echo FocusPath: "'"$XPLR_INPUT_BUFFER"'" >> "${XPLR_PIPE_MSG_IN:?}"
fi
]===],
},
"PopMode",
},
},
tab = {
help = "try complete",
messages = {
{ CallLuaSilently = "builtin.try_complete_path" },
},
},
["ctrl-c"] = {
help = "terminate",
messages = {
"Terminate",
},
},
esc = {
help = "cancel",
messages = {
"PopMode",
},
},
},
default = {
messages = {
"UpdateInputBufferFromKey",
},
},
},
}
-- The builtin selection ops mode.
--
-- Type: [Mode](https://xplr.dev/en/mode)
@ -1453,11 +1505,12 @@ xplr.config.modes.builtin.create = {
"Terminate",
},
},
["d"] = {
d = {
help = "create directory",
messages = {
"PopMode",
{ SwitchModeBuiltin = "create directory" },
{ SwitchModeBuiltin = "create_directory" },
{ SetInputPrompt = "ð " },
{ SetInputBuffer = "" },
},
},
@ -1467,11 +1520,12 @@ xplr.config.modes.builtin.create = {
"PopMode",
},
},
["f"] = {
f = {
help = "create file",
messages = {
"PopMode",
{ SwitchModeBuiltin = "create file" },
{ SwitchModeBuiltin = "create_file" },
{ SetInputPrompt = "ƒ " },
{ SetInputBuffer = "" },
},
},
@ -1492,8 +1546,14 @@ xplr.config.modes.builtin.create_directory = {
"Terminate",
},
},
tab = {
help = "try complete",
messages = {
{ CallLuaSilently = "builtin.try_complete_path" },
},
},
enter = {
help = "create directory",
help = "submit",
messages = {
{
BashExecSilently = [===[
@ -1537,8 +1597,14 @@ xplr.config.modes.builtin.create_file = {
help = "terminate",
messages = { "Terminate" },
},
tab = {
help = "try complete",
messages = {
{ CallLuaSilently = "builtin.try_complete_path" },
},
},
enter = {
help = "create file",
help = "submit",
messages = {
{
BashExecSilently = [===[
@ -1651,21 +1717,30 @@ xplr.config.modes.builtin.go_to = {
"PopMode",
},
},
["f"] = {
f = {
help = "follow symlink",
messages = {
"FollowSymlink",
"PopMode",
},
},
["g"] = {
g = {
help = "top",
messages = {
"FocusFirst",
"PopMode",
},
},
["x"] = {
p = {
help = "path",
messages = {
"PopMode",
{ SwitchModeBuiltin = "go_to_path" },
{ SetInputBuffer = "" },
{ SetInputPrompt = " " },
},
},
x = {
help = "open in gui",
messages = {
{
@ -1704,6 +1779,12 @@ xplr.config.modes.builtin.rename = {
"Terminate",
},
},
tab = {
help = "try complete",
messages = {
{ CallLuaSilently = "builtin.try_complete_path" },
},
},
enter = {
help = "rename",
messages = {
@ -1940,6 +2021,7 @@ xplr.config.modes.builtin.action = {
messages = {
"PopMode",
{ SwitchModeBuiltin = "number" },
{ SetInputPrompt = ":" },
"BufferInputFromKey",
},
},
@ -2108,7 +2190,7 @@ xplr.config.modes.builtin.filter = {
},
},
enter = {
help = "done",
help = "submit",
messages = {
"PopMode",
},
@ -2161,7 +2243,7 @@ xplr.config.modes.builtin.relative_path_does_match_regex = {
},
},
enter = {
help = "apply filter",
help = "submit",
messages = {
"PopMode",
},
@ -2200,7 +2282,7 @@ xplr.config.modes.builtin.relative_path_does_not_match_regex = {
},
},
enter = {
help = "apply filter",
help = "submit",
messages = {
"PopMode",
},
@ -2351,7 +2433,7 @@ xplr.config.modes.builtin.sort = {
},
},
enter = {
help = "done",
help = "submit",
messages = {
"PopMode",
},
@ -2526,6 +2608,62 @@ xplr.config.modes.custom = {}
-- As always, `xplr.fn.builtin` is where the built-in functions are defined
-- that can be overwritten.
-- Tries to auto complete the path in the input buffer
xplr.fn.builtin.try_complete_path = function(m)
if not m.input_buffer then
return
end
local function splitlines(str)
local res = {}
for s in str:gmatch("[^\r\n]+") do
table.insert(res, s)
end
return res
end
local function matches_all(str, files)
for _, p in ipairs(files) do
if string.sub(p, 1, #str) ~= str then
return false
end
end
return true
end
local path = m.input_buffer
local p = assert(io.popen(string.format("ls -d %q* 2>/dev/null", path)))
local out = p:read("*all")
p:close()
local found = splitlines(out)
local count = #found
if count == 0 then
return
elseif count == 1 then
return {
{ SetInputBuffer = found[1] },
}
else
local first = found[1]
while #first > #path and matches_all(path, found) do
path = string.sub(found[1], 1, #path + 1)
end
if matches_all(path, found) then
return {
{ SetInputBuffer = path },
}
end
return {
{ SetInputBuffer = string.sub(path, 1, #path - 1) },
}
end
end
-- Renders the first column in the table
xplr.fn.builtin.fmt_general_table_row_cols_0 = function(m)
local r = ""

Loading…
Cancel
Save