Add messages SetVroot and ResetVroot

pull/524/head v0.20.0-beta.2
Arijit Basu 2 years ago committed by Arijit Basu
parent a62b72bf2a
commit e3a5f3c044

12
Cargo.lock generated

@ -1250,6 +1250,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "which"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -1365,4 +1376,5 @@ dependencies = [
"serde_yaml",
"tui",
"tui-input",
"which",
]

@ -35,6 +35,7 @@ gethostname = "0.3.0"
fuzzy-matcher = "0.3.7"
serde_json = "1.0.87"
path-absolutize = "3.0.14"
which = "4.3.0"
[dependencies.lazy_static]
version = "1.4.0"

@ -52,6 +52,7 @@ The other variables are single-line variables containing simple information:
- [XPLR_MODE][34]
- [XPLR_PID][35]
- [XPLR_SESSION_PATH][36]
- [XPLR_VROOT][39]
### Environment variables
@ -90,6 +91,10 @@ Contains the process ID of the current xplr process.
Contains the current session path, like /tmp/runtime-"$USER"/xplr/session/"$XPLR_PID"/,
you can find temporary files here, such as pipes.
#### XPLR_VROOT
Contains the path of current virtual root, is set.
### Pipes
#### Input pipe
@ -214,3 +219,4 @@ xplr.config.modes.builtin.default.key_bindings.on_key.X = {
[36]: #xplr_session_path
[37]: messages.md#reading-input
[38]: #xplr
[39]: #xplr_vroot

@ -384,6 +384,7 @@ Hence, only the following fields are avilable.
- [version][40]
- [pwd][41]
- [vroot][52]
- [focused_node][42]
- [selection][43]
- [mode][44]
@ -448,3 +449,4 @@ Hence, only the following fields are avilable.
[49]: lua-function-calls.md#explorer_config
[50]: lua-function-calls.md#directory_buffer
[51]: layouts.md
[52]: #vroot

@ -17,6 +17,7 @@ It contains the following information:
- [version][29]
- [pwd][31]
- [vroot][75]
- [focused_node][32]
- [directory_buffer][33]
- [selection][34]
@ -39,7 +40,13 @@ xplr version. Can be used to test compatibility.
Type: string
The present working directory/
The present working directory.
### vroot
Type: nullable string
The current virtual root.
### focused_node
@ -384,3 +391,4 @@ xplr.config.modes.builtin.default.key_bindings.on_key.space = {
[72]: #last_modified
[73]: #uid
[74]: #gid
[75]: #vroot

@ -310,6 +310,27 @@ Example:
Lua: `"FollowSymlink"`
YAML: `FollowSymlink`
#### SetVroot
Sets the virtual root for isolating xplr navigation, similar to `--vroot`.
If the $PWD is outside the vroot, xplr will automatically enter vroot.
Type: { SetVroot = "string" }
Example:
Lua: `{ SetVroot = "/tmp" }`
YAML: `SetVroot: /tmp`
#### ResetVroot
Resets the virtual root bach to the value passed by `--vroot` or `/`.
Example:
- Lua: `"ResetVroot"`
- YAML: `ResetVroot`
### Reading Input
#### SetInputPrompt

@ -128,6 +128,7 @@ impl History {
pub struct LuaContextHeavy {
pub version: String,
pub pwd: String,
pub vroot: Option<String>,
pub focused_node: Option<Node>,
pub directory_buffer: Option<DirectoryBuffer>,
pub selection: IndexSet<Node>,
@ -145,6 +146,7 @@ pub struct LuaContextHeavy {
pub struct LuaContextLight {
pub version: String,
pub pwd: String,
pub vroot: Option<String>,
pub focused_node: Option<Node>,
pub selection: IndexSet<Node>,
pub mode: Mode,
@ -167,7 +169,8 @@ pub struct App {
pub version: String,
pub config: Config,
pub hooks: Hooks,
pub vroot: String,
pub vroot: Option<String>,
pub initial_vroot: Option<String>,
pub pwd: String,
pub directory_buffer: Option<DirectoryBuffer>,
pub last_focus: HashMap<String, Option<String>>,
@ -190,7 +193,7 @@ pub struct App {
impl App {
pub fn create(
bin: String,
vroot: PathBuf,
vroot: Option<PathBuf>,
pwd: PathBuf,
lua: &mlua::Lua,
config_file: Option<PathBuf>,
@ -298,15 +301,19 @@ impl App {
let hostname = gethostname().to_string_lossy().to_string();
if !pwd.starts_with(&vroot) {
bail!(
"{:?} is outside of virtual root {:?}",
pwd.to_string_lossy(),
vroot.to_string_lossy()
)
if let Some(vroot) = vroot.as_ref() {
if !pwd.starts_with(&vroot) {
bail!(
"{:?} is outside of virtual root {:?}",
pwd.to_string_lossy(),
vroot.to_string_lossy()
)
}
}
let pwd = pwd.to_string_lossy().to_string();
let vroot = vroot.to_string_lossy().to_string();
let vroot = vroot.map(|v| v.to_string_lossy().to_string());
let initial_vroot = vroot.clone();
env::set_current_dir(&pwd)?;
let input = InputBuffer {
@ -319,6 +326,7 @@ impl App {
version: VERSION.to_string(),
config,
vroot,
initial_vroot,
pwd,
directory_buffer: Default::default(),
last_focus: Default::default(),
@ -440,6 +448,8 @@ impl App {
LastVisitedPath => self.last_visited_path(),
NextVisitedPath => self.next_visited_path(),
FollowSymlink => self.follow_symlink(),
SetVroot(p) => self.set_vroot(&p),
ResetVroot => self.reset_vroot(),
SetInputPrompt(p) => self.set_input_prompt(p),
UpdateInputBuffer(op) => self.update_input_buffer(op),
UpdateInputBufferFromKey => self.update_input_buffer_from_key(key),
@ -755,16 +765,43 @@ impl App {
}
}
fn set_vroot(mut self, path: &String) -> Result<Self> {
let vroot = PathBuf::from(path).absolutize()?.to_path_buf();
if vroot.is_dir() {
self.vroot = Some(vroot.to_string_lossy().to_string());
if !PathBuf::from(&self.pwd).starts_with(&vroot) {
self.change_directory(path, true)
} else {
Ok(self)
}
} else {
self.log_error(format!(
"not a valid directory: {}",
vroot.to_string_lossy()
))
}
}
fn reset_vroot(self) -> Result<Self> {
if let Some(vroot) = self.initial_vroot.clone() {
self.set_vroot(&vroot)
} else {
Ok(self)
}
}
fn change_directory(mut self, dir: &str, save_history: bool) -> Result<Self> {
let dir = PathBuf::from(dir).absolutize()?.to_path_buf();
let vroot = &self.vroot.clone();
if !dir.starts_with(&self.vroot) {
return self.log_error(format!(
"{:?} is outside of virtual root {:?}",
dir.to_string_lossy(),
vroot,
));
if let Some(vroot) = &self.vroot.clone() {
if !dir.starts_with(&vroot) {
return self.log_error(format!(
"{:?} is outside of virtual root {:?}",
dir.to_string_lossy(),
vroot,
));
}
}
match env::set_current_dir(&dir) {
@ -1722,6 +1759,7 @@ impl App {
LuaContextHeavy {
version: self.version.clone(),
pwd: self.pwd.clone(),
vroot: self.vroot.clone(),
focused_node: self.focused_node().cloned(),
directory_buffer: self.directory_buffer.clone(),
selection: self.selection.clone(),
@ -1740,6 +1778,7 @@ impl App {
LuaContextLight {
version: self.version.clone(),
pwd: self.pwd.clone(),
vroot: self.vroot.clone(),
focused_node: self.focused_node().cloned(),
selection: self.selection.clone(),
mode: self.mode.clone(),

@ -36,8 +36,7 @@ fn main() {
"$HOME/.config/xplr/init.lua")
-C, --extra-config <PATH>... Specifies extra config files to load
--on-load <MESSAGE>... Sends messages when xplr loads
--vroot <PATH> Treats the specified path as the virtual root for
navigation, but uses full path for interaction"###;
--vroot <PATH> Treats the specified path as the virtual root"###;
let args = r###"
<PATH> Path to focus on, or enter if directory, (default is `.`)

@ -47,7 +47,15 @@ impl Cli {
pub fn parse(args: env::Args) -> Result<Self> {
let mut cli = Self::default();
let mut args = args.peekable();
cli.bin = args.next().context("failed to parse xplr binary path")?;
cli.bin = args
.next()
.map(which::which)
.context("failed to parse xplr binary path")?
.context("failed to find xplr binary path")?
.absolutize()?
.to_path_buf()
.to_string_lossy()
.to_string();
let mut flag_ends = false;

@ -102,7 +102,7 @@ pub(crate) fn explore_async(
pub(crate) fn explore_recursive_async(
config: ExplorerConfig,
root: PathBuf,
vroot: Option<PathBuf>,
parent: PathBuf,
focused_path: Option<PathBuf>,
fallback_focus: usize,
@ -116,10 +116,14 @@ pub(crate) fn explore_recursive_async(
tx_msg_in.clone(),
);
if let Some(grand_parent) = parent.parent() {
if grand_parent.starts_with(&root) {
if vroot
.as_ref()
.map(|v| grand_parent.starts_with(v))
.unwrap_or(true)
{
explore_recursive_async(
config,
root,
vroot,
grand_parent.into(),
parent.file_name().map(|p| p.into()),
0,

@ -1827,9 +1827,9 @@ xplr.config.modes.builtin.action = {
["!"] = {
help = "shell",
messages = {
"PopMode",
{ Call0 = { command = "bash", args = { "-i" } } },
"ExplorePwdAsync",
"PopModeKeepingInputBuffer",
},
},
["c"] = {

@ -258,7 +258,6 @@ pub enum ExternalMsg {
/// - YAML: `NextVisitedPath`
NextVisitedPath,
///
/// Follow the symlink under focus to its actual location.
///
/// Example:
@ -267,6 +266,25 @@ pub enum ExternalMsg {
/// YAML: `FollowSymlink`
FollowSymlink,
/// Sets the virtual root for isolating xplr navigation, similar to `--vroot`.
/// If the $PWD is outside the vroot, xplr will automatically enter vroot.
///
/// Type: { SetVroot = "string" }
///
/// Example:
///
/// Lua: `{ SetVroot = "/tmp" }`
/// YAML: `SetVroot: /tmp`
SetVroot(String),
/// Resets the virtual root bach to the value passed by `--vroot` or `/`.
///
/// Example:
///
/// - Lua: `"ResetVroot"`
/// - YAML: `ResetVroot`
ResetVroot,
/// ### Reading Input -----------------------------------------------------
/// Set the input prompt temporarily, until the input buffer is reset.

@ -109,6 +109,7 @@ fn call(
let status = Command::new(cmd.command.clone())
.env("XPLR", &app.bin)
.env("XPLR_VROOT", &app.vroot.clone().unwrap_or_default())
.env("XPLR_APP_VERSION", &app.version)
.env("XPLR_PID", &app.pid.to_string())
.env("XPLR_INPUT_BUFFER", input_buffer)
@ -191,7 +192,7 @@ fn start_fifo(path: &str, focus_path: &str) -> Result<fs::File> {
pub struct Runner {
bin: String,
vroot: PathBuf,
vroot: Option<PathBuf>,
pwd: PathBuf,
focused_path: Option<PathBuf>,
config_file: Option<PathBuf>,
@ -224,11 +225,9 @@ impl Runner {
pwd = pwd.parent().map(|p| p.into()).unwrap_or(currdir);
}
let root = cli.vroot.unwrap_or_else(|| "/".into());
Ok(Self {
bin: cli.bin,
vroot: root,
vroot: cli.vroot,
pwd,
focused_path,
config_file: cli.config,
@ -278,7 +277,7 @@ impl Runner {
explorer::explore_recursive_async(
app.explorer_config.clone(),
app.vroot.clone().into(),
app.vroot.as_ref().map(PathBuf::from),
app.pwd.clone().into(),
self.focused_path,
app.directory_buffer.as_ref().map(|d| d.focus).unwrap_or(0),
@ -444,7 +443,7 @@ impl Runner {
ExploreParentsAsync => {
explorer::explore_recursive_async(
app.explorer_config.clone(),
app.vroot.clone().into(),
app.vroot.as_ref().map(PathBuf::from),
app.pwd.clone().into(),
app.focused_node()
.map(|n| n.relative_path.clone().into()),

@ -669,13 +669,16 @@ fn draw_table<B: Backend>(
.map(|c| c.to_tui(screen_size, layout_size))
.collect();
let pwd = app
.pwd
.strip_prefix(&app.vroot)
.unwrap_or(&app.pwd)
.trim_matches('/')
.replace('\\', "\\\\")
.replace('\n', "\\n");
let pwd = if let Some(vroot) = app.vroot.as_ref() {
app.pwd.strip_prefix(vroot).unwrap_or(&app.pwd)
} else {
&app.pwd
}
.trim_matches('/')
.replace('\\', "\\\\")
.replace('\n', "\\n");
let vroot_indicator = if app.vroot.is_some() { "[v] " } else { "" };
let table = Table::new(rows)
.widths(&table_constraints)
@ -685,7 +688,8 @@ fn draw_table<B: Backend>(
.block(block(
config,
format!(
" /{} ({}) ",
" {}/{} ({}) ",
vroot_indicator,
pwd,
app.directory_buffer
.as_ref()

Loading…
Cancel
Save