Add regex support and dynamic input prompt

- Add new regex filters
  - `RelativePathDoesMatchRegex`
  - `RelativePathDoesNotMatchRegex`
  - `IRelativePathDoesMatchRegex`
  - `IRelativePathDoesNotMatchRegex`
  - `AbsolutePathDoesMatchRegex`
  - `AbsolutePathDoesNotMatchRegex`
  - `IAbsolutePathDoesMatchRegex`
  - `IAbsolutePathDoesNotMatchRegex`
- Search mode now defaults to regex
- Added new message `SetInputPrompt` to set the input prompt
  dynamically.
pull/475/head
Arijit Basu 2 years ago committed by Arijit Basu
parent 5765698fb7
commit 1de737cefa

12
Cargo.lock generated

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ansi-to-tui-forked"
version = "0.5.2-fix.offset"
@ -693,6 +702,8 @@ version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
@ -1151,6 +1162,7 @@ dependencies = [
"mime_guess",
"mlua",
"natord",
"regex",
"serde",
"serde_yaml",
"tui",

@ -31,6 +31,7 @@ serde_yaml = "0.8.24"
crossterm = "0.23.2"
dirs = "4.0.0"
ansi-to-tui-forked = "0.5.2-fix.offset"
regex = "1.5.5"
[dependencies.lazy_static]
version = "1.4.0"

@ -277,6 +277,17 @@ YAML: `FollowSymlink`
### Reading Input
#### SetInputPrompt
Set the input prompt temporarily, until the input buffer is reset.
Type: { SetInputPrompt = { format = nullable string }
Example:
- Lua: `{ SetInputPrompt = "→" }`
- YAML: `SetInputPrompt: →`
#### UpdateInputBuffer
Update the input buffer using cursor based operations.

@ -107,15 +107,15 @@ The builtin filter mode.
Type: [Mode](https://xplr.dev/en/mode)
#### xplr.config.modes.builtin.relative_path_does_contain
#### xplr.config.modes.builtin.relative_path_does_match_regex
The builtin relative_path_does_contain mode.
The builtin relative_path_does_match_regex mode.
Type: [Mode](https://xplr.dev/en/mode)
#### xplr.config.modes.builtin.relative_path_does_not_contain
#### xplr.config.modes.builtin.relative_path_does_not_match_regex
The builtin relative_path_does_not_contain mode.
The builtin relative_path_does_not_match_regex mode.
Type: [Mode](https://xplr.dev/en/mode)

@ -151,6 +151,12 @@ pub struct LuaContextLight {
pub explorer_config: ExplorerConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InputBuffer {
pub buffer: Option<Input>,
pub prompt: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct App {
pub version: String,
@ -162,7 +168,7 @@ pub struct App {
pub msg_out: VecDeque<MsgOut>,
pub mode: Mode,
pub layout: Layout,
pub input: Option<Input>,
pub input: InputBuffer,
pub pid: u32,
pub session_path: String,
pub pipe: Pipe,
@ -277,6 +283,11 @@ impl App {
env::set_current_dir(&pwd)?;
let pwd = pwd.to_string_lossy().to_string();
let input = InputBuffer {
buffer: Default::default(),
prompt: config.general.prompt.format.clone(),
};
let mut app = Self {
version: VERSION.to_string(),
config,
@ -287,7 +298,7 @@ impl App {
msg_out: Default::default(),
mode,
layout,
input: Default::default(),
input,
pid,
session_path: session_path.clone(),
pipe: Pipe::from_session_path(&session_path)?,
@ -404,6 +415,7 @@ impl App {
LastVisitedPath => self.last_visited_path(),
NextVisitedPath => self.next_visited_path(),
FollowSymlink => self.follow_symlink(),
SetInputPrompt(p) => self.set_input_prompt(p),
UpdateInputBuffer(op) => self.update_input_buffer(op),
UpdateInputBufferFromKey => {
self.update_input_buffer_from_key(key)
@ -655,6 +667,7 @@ impl App {
fn focus_previous_by_relative_index_from_input(self) -> Result<Self> {
if let Some(index) = self
.input
.buffer
.as_ref()
.and_then(|i| i.value().parse::<usize>().ok())
{
@ -699,6 +712,7 @@ impl App {
fn focus_next_by_relative_index_from_input(self) -> Result<Self> {
if let Some(index) = self
.input
.buffer
.as_ref()
.and_then(|i| i.value().parse::<usize>().ok())
{
@ -794,14 +808,19 @@ impl App {
}
}
fn set_input_prompt(mut self, p: Option<String>) -> Result<Self> {
self.input.prompt = p;
Ok(self)
}
fn update_input_buffer(mut self, op: InputOperation) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
if let Some(buf) = self.input.buffer.as_mut() {
buf.handle(op.into());
self.logs_hidden = true;
} else {
let mut buf = Input::default();
if buf.handle(op.into()).is_some() {
self.input = Some(buf);
self.input.buffer = Some(buf);
self.logs_hidden = true;
};
}
@ -817,13 +836,13 @@ impl App {
}
fn buffer_input(mut self, input: &str) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
if let Some(buf) = self.input.buffer.as_mut() {
buf.handle(InputRequest::GoToEnd);
for c in input.chars() {
buf.handle(InputRequest::InsertChar(c));
}
} else {
self.input = Some(Input::default().with_value(input.into()));
self.input.buffer = Some(Input::default().with_value(input.into()));
};
self.logs_hidden = true;
Ok(self)
@ -838,13 +857,13 @@ impl App {
}
fn set_input_buffer(mut self, string: String) -> Result<Self> {
self.input = Some(Input::default().with_value(string));
self.input.buffer = Some(Input::default().with_value(string));
self.logs_hidden = true;
Ok(self)
}
fn remove_input_buffer_last_character(mut self) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
if let Some(buf) = self.input.buffer.as_mut() {
buf.handle(InputRequest::GoToEnd);
buf.handle(InputRequest::DeletePrevChar);
self.logs_hidden = true;
@ -853,7 +872,7 @@ impl App {
}
fn remove_input_buffer_last_word(mut self) -> Result<Self> {
if let Some(buf) = self.input.as_mut() {
if let Some(buf) = self.input.buffer.as_mut() {
buf.handle(InputRequest::GoToEnd);
buf.handle(InputRequest::DeletePrevWord);
self.logs_hidden = true;
@ -862,7 +881,10 @@ impl App {
}
fn reset_input_buffer(mut self) -> Result<Self> {
self.input = None;
self.input = InputBuffer {
buffer: Default::default(),
prompt: self.config.general.prompt.format.clone(),
};
Ok(self)
}
@ -880,6 +902,7 @@ impl App {
fn focus_by_index_from_input(self) -> Result<Self> {
if let Some(index) = self
.input
.buffer
.as_ref()
.and_then(|i| i.value().parse::<usize>().ok())
{
@ -948,7 +971,7 @@ impl App {
}
fn focus_path_from_input(self) -> Result<Self> {
if let Some(p) = self.input.clone() {
if let Some(p) = self.input.buffer.clone() {
self.focus_path(p.value(), true)
} else {
Ok(self)
@ -969,10 +992,8 @@ impl App {
}
fn pop_mode(self) -> Result<Self> {
self.pop_mode_keeping_input_buffer().map(|mut a| {
a.input = None;
a
})
self.pop_mode_keeping_input_buffer()
.and_then(App::reset_input_buffer)
}
fn pop_mode_keeping_input_buffer(mut self) -> Result<Self> {
@ -983,10 +1004,8 @@ impl App {
}
fn switch_mode(self, mode: &str) -> Result<Self> {
self.switch_mode_keeping_input_buffer(mode).map(|mut a| {
a.input = None;
a
})
self.switch_mode_keeping_input_buffer(mode)
.and_then(App::reset_input_buffer)
}
fn switch_mode_keeping_input_buffer(mut self, mode: &str) -> Result<Self> {
@ -1001,10 +1020,7 @@ impl App {
fn switch_mode_builtin(self, mode: &str) -> Result<Self> {
self.switch_mode_builtin_keeping_input_buffer(mode)
.map(|mut a| {
a.input = None;
a
})
.and_then(App::reset_input_buffer)
}
fn switch_mode_builtin_keeping_input_buffer(
@ -1022,10 +1038,7 @@ impl App {
fn switch_mode_custom(self, mode: &str) -> Result<Self> {
self.switch_mode_custom_keeping_input_buffer(mode)
.map(|mut a| {
a.input = None;
a
})
.and_then(App::reset_input_buffer)
}
fn switch_mode_custom_keeping_input_buffer(
@ -1246,7 +1259,7 @@ impl App {
mut self,
filter: NodeFilter,
) -> Result<Self> {
if let Some(input) = self.input.as_ref() {
if let Some(input) = self.input.buffer.as_ref() {
self.explorer_config
.filters
.insert(NodeFilterApplicable::new(
@ -1269,7 +1282,7 @@ impl App {
mut self,
filter: NodeFilter,
) -> Result<Self> {
if let Some(input) = self.input.as_ref() {
if let Some(input) = self.input.buffer.as_ref() {
let nfa = NodeFilterApplicable::new(filter, input.value().into());
self.explorer_config.filters.retain(|f| f != &nfa);
};
@ -1540,8 +1553,8 @@ impl App {
&builtin.delete,
&builtin.sort,
&builtin.filter,
&builtin.relative_path_does_contain,
&builtin.relative_path_does_not_contain,
&builtin.relative_path_does_match_regex,
&builtin.relative_path_does_not_match_regex,
&builtin.switch_layout,
]
.iter().map(|m| (&m.name, m.to_owned()))
@ -1629,7 +1642,7 @@ impl App {
selection: self.selection.clone(),
mode: self.mode.clone(),
layout: self.layout.clone(),
input_buffer: self.input.as_ref().map(|i| i.value().into()),
input_buffer: self.input.buffer.as_ref().map(|i| i.value().into()),
pid: self.pid,
session_path: self.session_path.clone(),
explorer_config: self.explorer_config.clone(),
@ -1646,7 +1659,7 @@ impl App {
selection: self.selection.clone(),
mode: self.mode.clone(),
layout: self.layout.clone(),
input_buffer: self.input.as_ref().map(|i| i.value().into()),
input_buffer: self.input.buffer.as_ref().map(|i| i.value().into()),
pid: self.pid,
session_path: self.session_path.clone(),
explorer_config: self.explorer_config.clone(),

@ -570,10 +570,10 @@ pub struct BuiltinModesConfig {
pub filter: Mode,
#[serde(default)]
pub relative_path_does_contain: Mode,
pub relative_path_does_match_regex: Mode,
#[serde(default)]
pub relative_path_does_not_contain: Mode,
pub relative_path_does_not_match_regex: Mode,
#[serde(default)]
pub sort: Mode,
@ -609,17 +609,17 @@ impl BuiltinModesConfig {
"search" => Some(&self.search),
"sort" => Some(&self.sort),
"filter" => Some(&self.filter),
"relative_path_does_contain" => {
Some(&self.relative_path_does_contain)
"relative_path_does_match_regex" => {
Some(&self.relative_path_does_match_regex)
}
"relative path does contain" => {
Some(&self.relative_path_does_contain)
"relative path does match regex" => {
Some(&self.relative_path_does_match_regex)
}
"relative_path_does_not_contain" => {
Some(&self.relative_path_does_not_contain)
"relative_path_does_not_match_regex" => {
Some(&self.relative_path_does_not_match_regex)
}
"relative path does not contain" => {
Some(&self.relative_path_does_not_contain)
"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),

@ -403,6 +403,28 @@ xplr.config.general.sort_and_filter_ui.sorter_identifiers = {
-- * format: nullable string
-- * style: [Style](https://xplr.dev/en/style)
xplr.config.general.sort_and_filter_ui.filter_identifiers = {
RelativePathDoesContain = { format = "rel=~", style = {} },
RelativePathDoesEndWith = { format = "rel=$", style = {} },
RelativePathDoesNotContain = { format = "rel!~", style = {} },
RelativePathDoesNotEndWith = { format = "rel!$", style = {} },
RelativePathDoesNotStartWith = { format = "rel!^", style = {} },
RelativePathDoesStartWith = { format = "rel=^", style = {} },
RelativePathIs = { format = "rel==", style = {} },
RelativePathIsNot = { format = "rel!=", style = {} },
RelativePathDoesMatchRegex = { format = "rel=/", style = {} },
RelativePathDoesNotMatchRegex = { format = "rel!/", style = {} },
IRelativePathDoesContain = { format = "[i]rel=~", style = {} },
IRelativePathDoesEndWith = { format = "[i]rel=$", style = {} },
IRelativePathDoesNotContain = { format = "[i]rel!~", style = {} },
IRelativePathDoesNotEndWith = { format = "[i]rel!$", style = {} },
IRelativePathDoesNotStartWith = { format = "[i]rel!^", style = {} },
IRelativePathDoesStartWith = { format = "[i]rel=^", style = {} },
IRelativePathIs = { format = "[i]rel==", style = {} },
IRelativePathIsNot = { format = "[i]rel!=", style = {} },
IRelativePathDoesMatchRegex = { format = "[i]rel=/", style = {} },
IRelativePathDoesNotMatchRegex = { format = "[i]rel!/", style = {} },
AbsolutePathDoesContain = { format = "abs=~", style = {} },
AbsolutePathDoesEndWith = { format = "abs=$", style = {} },
AbsolutePathDoesNotContain = { format = "abs!~", style = {} },
@ -411,6 +433,9 @@ xplr.config.general.sort_and_filter_ui.filter_identifiers = {
AbsolutePathDoesStartWith = { format = "abs=^", style = {} },
AbsolutePathIs = { format = "abs==", style = {} },
AbsolutePathIsNot = { format = "abs!=", style = {} },
AbsolutePathDoesMatchRegex = { format = "abs=/", style = {} },
AbsolutePathDoesNotMatchRegex = { format = "abs!/", style = {} },
IAbsolutePathDoesContain = { format = "[i]abs=~", style = {} },
IAbsolutePathDoesEndWith = { format = "[i]abs=$", style = {} },
IAbsolutePathDoesNotContain = { format = "[i]abs!~", style = {} },
@ -419,22 +444,8 @@ xplr.config.general.sort_and_filter_ui.filter_identifiers = {
IAbsolutePathDoesStartWith = { format = "[i]abs=^", style = {} },
IAbsolutePathIs = { format = "[i]abs==", style = {} },
IAbsolutePathIsNot = { format = "[i]abs!=", style = {} },
IRelativePathDoesContain = { format = "[i]rel=~", style = {} },
IRelativePathDoesEndWith = { format = "[i]rel=$", style = {} },
IRelativePathDoesNotContain = { format = "[i]rel!~", style = {} },
IRelativePathDoesNotEndWith = { format = "[i]rel!$", style = {} },
IRelativePathDoesNotStartWith = { format = "[i]rel!^", style = {} },
IRelativePathDoesStartWith = { format = "[i]rel=^", style = {} },
IRelativePathIs = { format = "[i]rel==", style = {} },
IRelativePathIsNot = { format = "[i]rel!=", style = {} },
RelativePathDoesContain = { format = "rel=~", style = {} },
RelativePathDoesEndWith = { format = "rel=$", style = {} },
RelativePathDoesNotContain = { format = "rel!~", style = {} },
RelativePathDoesNotEndWith = { format = "rel!$", style = {} },
RelativePathDoesNotStartWith = { format = "rel!^", style = {} },
RelativePathDoesStartWith = { format = "rel=^", style = {} },
RelativePathIs = { format = "rel==", style = {} },
RelativePathIsNot = { format = "rel!=", style = {} },
IAbsolutePathDoesMatchRegex = { format = "[i]abs=/", style = {} },
IAbsolutePathDoesNotMatchRegex = { format = "[i]abs!/", style = {} },
}
-- The content for panel title by default.
@ -1016,7 +1027,8 @@ xplr.config.modes.builtin.default = {
messages = {
"PopMode",
{ SwitchModeBuiltin = "search" },
{ SetInputBuffer = "" },
{ SetInputPrompt = "/" },
{ SetInputBuffer = "(?i)" },
"ExplorePwdAsync",
},
},
@ -1984,7 +1996,7 @@ xplr.config.modes.builtin.search = {
enter = {
help = "focus",
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"PopMode",
"ExplorePwdAsync",
},
@ -1992,7 +2004,7 @@ xplr.config.modes.builtin.search = {
right = {
help = "enter",
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"Enter",
{ SetInputBuffer = "" },
"ExplorePwdAsync",
@ -2001,7 +2013,7 @@ xplr.config.modes.builtin.search = {
left = {
help = "back",
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"Back",
{ SetInputBuffer = "" },
"ExplorePwdAsync",
@ -2023,9 +2035,9 @@ xplr.config.modes.builtin.search = {
},
default = {
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"UpdateInputBufferFromKey",
{ AddNodeFilterFromInput = "IRelativePathDoesContain" },
{ AddNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"ExplorePwdAsync",
},
},
@ -2046,19 +2058,34 @@ xplr.config.modes.builtin.filter = {
name = "filter",
key_bindings = {
on_key = {
["r"] = {
help = "relative path does match regex",
messages = {
{ SwitchModeBuiltin = "relative_path_does_match_regex" },
{
SetInputPrompt = xplr.config.general.sort_and_filter_ui.filter_identifiers.RelativePathDoesMatchRegex.format,
},
{ SetInputBuffer = "" },
{ AddNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"ExplorePwdAsync",
},
},
["R"] = {
help = "relative does not contain",
help = "relative path does not match regex",
messages = {
{ SwitchModeBuiltin = "relative_path_does_not_contain" },
{ SwitchModeBuiltin = "relative_path_does_not_match_regex" },
{
SetInputPrompt = xplr.config.general.sort_and_filter_ui.filter_identifiers.RelativePathDoesNotMatchRegex.format,
},
{ SetInputBuffer = "" },
{ AddNodeFilterFromInput = "IRelativePathDoesNotContain" },
{ AddNodeFilterFromInput = "RelativePathDoesNotMatchRegex" },
"ExplorePwdAsync",
},
},
["ctrl-c"] = {
help = "terminate",
enter = {
help = "done",
messages = {
"Terminate",
"PopMode",
},
},
["ctrl-r"] = {
@ -2075,19 +2102,10 @@ xplr.config.modes.builtin.filter = {
"ExplorePwdAsync",
},
},
enter = {
help = "done",
messages = {
"PopMode",
},
},
["r"] = {
help = "relative does contain",
["ctrl-c"] = {
help = "terminate",
messages = {
{ SwitchModeBuiltin = "relative_path_does_contain" },
{ SetInputBuffer = "" },
{ AddNodeFilterFromInput = "IRelativePathDoesContain" },
"ExplorePwdAsync",
"Terminate",
},
},
},
@ -2097,11 +2115,11 @@ xplr.config.modes.builtin.filter = {
xplr.config.modes.builtin.filter.key_bindings.on_key["esc"] =
xplr.config.modes.builtin.filter.key_bindings.on_key.enter
-- The builtin relative_path_does_contain mode.
-- The builtin relative_path_does_match_regex mode.
--
-- Type: [Mode](https://xplr.dev/en/mode)
xplr.config.modes.builtin.relative_path_does_contain = {
name = "relative path does contain",
xplr.config.modes.builtin.relative_path_does_match_regex = {
name = "relative path does match regex",
key_bindings = {
on_key = {
["ctrl-c"] = {
@ -2119,7 +2137,7 @@ xplr.config.modes.builtin.relative_path_does_contain = {
esc = {
help = "cancel",
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"PopMode",
"ExplorePwdAsync",
},
@ -2127,20 +2145,20 @@ xplr.config.modes.builtin.relative_path_does_contain = {
},
default = {
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"UpdateInputBufferFromKey",
{ AddNodeFilterFromInput = "IRelativePathDoesContain" },
{ AddNodeFilterFromInput = "RelativePathDoesMatchRegex" },
"ExplorePwdAsync",
},
},
},
}
-- The builtin relative_path_does_not_contain mode.
-- The builtin relative_path_does_not_match_regex mode.
--
-- Type: [Mode](https://xplr.dev/en/mode)
xplr.config.modes.builtin.relative_path_does_not_contain = {
name = "relative path does not contain",
xplr.config.modes.builtin.relative_path_does_not_match_regex = {
name = "relative path does not match regex",
key_bindings = {
on_key = {
["ctrl-c"] = {
@ -2158,7 +2176,7 @@ xplr.config.modes.builtin.relative_path_does_not_contain = {
esc = {
help = "cancel",
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesNotContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesNotMatchRegex" },
"PopMode",
"ExplorePwdAsync",
},
@ -2166,9 +2184,9 @@ xplr.config.modes.builtin.relative_path_does_not_contain = {
},
default = {
messages = {
{ RemoveNodeFilterFromInput = "IRelativePathDoesNotContain" },
{ RemoveNodeFilterFromInput = "RelativePathDoesNotMatchRegex" },
"UpdateInputBufferFromKey",
{ AddNodeFilterFromInput = "IRelativePathDoesNotContain" },
{ AddNodeFilterFromInput = "RelativePathDoesNotMatchRegex" },
"ExplorePwdAsync",
},
},

@ -1,5 +1,6 @@
use crate::{app::Node, input::InputOperation};
use indexmap::IndexSet;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
@ -47,7 +48,7 @@ pub enum ExternalMsg {
///
/// Example:
///
/// - Lua: `"ClearScreen"``
/// - Lua: `"ClearScreen"`
/// - YAML: `ClearScreen`
ClearScreen,
@ -103,7 +104,7 @@ pub enum ExternalMsg {
/// Focus on the `-n`th node relative to the current focus where `n` is a
/// given value.
///
///
/// Type: { FocusPreviousByRelativeIndex = int }
///
/// Example:
@ -237,7 +238,17 @@ pub enum ExternalMsg {
/// YAML: `FollowSymlink`
FollowSymlink,
/// ### Reading Input ------------------------------------------------------
/// ### Reading Input -----------------------------------------------------
/// Set the input prompt temporarily, until the input buffer is reset.
///
/// Type: { SetInputPrompt = { format = nullable string }
///
/// Example:
///
/// - Lua: `{ SetInputPrompt = "→" }`
/// - YAML: `SetInputPrompt: →`
SetInputPrompt(Option<String>),
/// Update the input buffer using cursor based operations.
///
@ -258,7 +269,7 @@ pub enum ExternalMsg {
UpdateInputBufferFromKey,
/// Append/buffer the given string into the input buffer.
///
///
/// Type: { BufferInput = "string" }
///
/// Example:
@ -279,7 +290,7 @@ pub enum ExternalMsg {
/// Set/rewrite the input buffer with the given string.
/// When the input buffer is not-null (even if empty string)
/// it will show in the UI.
///
///
/// Type: { SetInputBuffer = "string" }
///
/// Example:
@ -289,7 +300,7 @@ pub enum ExternalMsg {
SetInputBuffer(String),
/// Remove input buffer's last character.
///
///
/// Example:
///
/// - Lua: `"RemoveInputBufferLastCharacter"`
@ -1208,6 +1219,12 @@ pub enum NodeFilter {
IRelativePathDoesEndWith,
IRelativePathDoesNotEndWith,
RelativePathDoesMatchRegex,
RelativePathDoesNotMatchRegex,
IRelativePathDoesMatchRegex,
IRelativePathDoesNotMatchRegex,
AbsolutePathIs,
AbsolutePathIsNot,
@ -1231,6 +1248,12 @@ pub enum NodeFilter {
IAbsolutePathDoesEndWith,
IAbsolutePathDoesNotEndWith,
AbsolutePathDoesMatchRegex,
AbsolutePathDoesNotMatchRegex,
IAbsolutePathDoesMatchRegex,
IAbsolutePathDoesNotMatchRegex,
}
impl NodeFilter {
@ -1293,6 +1316,24 @@ impl NodeFilter {
.to_lowercase()
.ends_with(&input.to_lowercase()),
Self::RelativePathDoesMatchRegex => Regex::new(input)
.map(|r| r.is_match(&node.relative_path))
.unwrap_or(false),
Self::IRelativePathDoesMatchRegex => {
Regex::new(&input.to_lowercase())
.map(|r| r.is_match(&node.relative_path.to_lowercase()))
.unwrap_or(false)
}
Self::RelativePathDoesNotMatchRegex => !Regex::new(input)
.map(|r| r.is_match(&node.relative_path))
.unwrap_or(false),
Self::IRelativePathDoesNotMatchRegex => {
!Regex::new(&input.to_lowercase())
.map(|r| r.is_match(&node.relative_path.to_lowercase()))
.unwrap_or(false)
}
Self::AbsolutePathIs => node.absolute_path.eq(input),
Self::IAbsolutePathIs => {
node.absolute_path.eq_ignore_ascii_case(input)
@ -1348,6 +1389,24 @@ impl NodeFilter {
.absolute_path
.to_lowercase()
.ends_with(&input.to_lowercase()),
Self::AbsolutePathDoesMatchRegex => Regex::new(input)
.map(|r| r.is_match(&node.absolute_path))
.unwrap_or(false),
Self::IAbsolutePathDoesMatchRegex => {
Regex::new(&input.to_lowercase())
.map(|r| r.is_match(&node.absolute_path.to_lowercase()))
.unwrap_or(false)
}
Self::AbsolutePathDoesNotMatchRegex => !Regex::new(input)
.map(|r| r.is_match(&node.absolute_path))
.unwrap_or(false),
Self::IAbsolutePathDoesNotMatchRegex => {
!Regex::new(&input.to_lowercase())
.map(|r| r.is_match(&node.absolute_path.to_lowercase()))
.unwrap_or(false)
}
}
}
}

@ -80,6 +80,7 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> Result<ExitStatus> {
.env(
"XPLR_INPUT_BUFFER",
app.input
.buffer
.as_ref()
.map(|i| i.value().to_string())
.unwrap_or_default(),

@ -801,7 +801,7 @@ fn draw_input_buffer<B: Backend>(
app: &app::App,
_: &Lua,
) {
if let Some(input) = app.input.as_ref() {
if let Some(input) = app.input.buffer.as_ref() {
let panel_config = &app.config.general.panel_ui;
let config = panel_config
.default
@ -818,10 +818,8 @@ fn draw_input_buffer<B: Backend>(
} else {
0
} + app
.config
.general
.input
.prompt
.format
.as_ref()
.map(|t| t.chars().count() as u16)
.unwrap_or(0);
@ -843,12 +841,7 @@ fn draw_input_buffer<B: Backend>(
let input_buf = Paragraph::new(Spans::from(vec![
Span::styled(
app.config
.general
.prompt
.format
.to_owned()
.unwrap_or_default(),
app.input.prompt.to_owned().unwrap_or_default(),
app.config.general.prompt.style.to_owned().into(),
),
Span::raw(input.value()),
@ -1271,7 +1264,7 @@ pub fn draw_layout<B: Backend>(
draw_selection(f, screen_size, layout_size, app, lua)
}
Layout::InputAndLogs => {
if app.input.is_some() {
if app.input.buffer.is_some() {
draw_input_buffer(f, screen_size, layout_size, app, lua);
} else {
draw_logs(f, screen_size, layout_size, app, lua);

Loading…
Cancel
Save