|
|
|
@ -10,6 +10,7 @@ use crate::permissions::Octal;
|
|
|
|
|
use crate::permissions::Permissions;
|
|
|
|
|
use crate::ui;
|
|
|
|
|
use crate::ui::Layout;
|
|
|
|
|
use crate::ui::PreviewRendererArgs;
|
|
|
|
|
use crate::ui::Style;
|
|
|
|
|
use crate::ui::WrapOptions;
|
|
|
|
|
use anyhow::Result;
|
|
|
|
@ -26,8 +27,11 @@ use serde::{Deserialize, Serialize};
|
|
|
|
|
use serde_json as json;
|
|
|
|
|
use serde_yaml as yaml;
|
|
|
|
|
use std::borrow::Cow;
|
|
|
|
|
use std::io::BufRead;
|
|
|
|
|
use std::iter;
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
use std::{fs, io};
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
|
static ref LS_COLORS: LsColors = LsColors::from_env().unwrap_or_default();
|
|
|
|
@ -224,12 +228,12 @@ pub fn path_split<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
|
|
|
|
|
Ok(util)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get [Node][5] information of a given path.
|
|
|
|
|
/// Get [Node][2] information of a given path.
|
|
|
|
|
/// Doesn't check if the path exists.
|
|
|
|
|
/// Returns nil if the path is "/".
|
|
|
|
|
/// Errors out if absolute path can't be obtained.
|
|
|
|
|
///
|
|
|
|
|
/// Type: function( path:string ) -> [Node][5]|nil
|
|
|
|
|
/// Type: function( path:string ) -> [Node][2]|nil
|
|
|
|
|
///
|
|
|
|
|
/// Example:
|
|
|
|
|
///
|
|
|
|
@ -259,9 +263,9 @@ pub fn node<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
|
|
|
|
|
Ok(util)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the configured [Node Type][6] of a given [Node][5].
|
|
|
|
|
/// Get the configured [Node Type][6] of a given [Node][2].
|
|
|
|
|
///
|
|
|
|
|
/// Type: function( [Node][5], [xplr.config.node_types][7]|nil ) -> [Node Type][6]
|
|
|
|
|
/// Type: function( [Node][2], [xplr.config.node_types][7]|nil ) -> [Node Type][6]
|
|
|
|
|
///
|
|
|
|
|
/// If the second argument is missing, global config `xplr.config.node_types`
|
|
|
|
|
/// will be used.
|
|
|
|
@ -852,15 +856,130 @@ pub fn permissions_octal<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
|
|
|
|
|
Ok(util)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Renders a preview of the given node as string.
|
|
|
|
|
///
|
|
|
|
|
/// You probably want to use it inside the function mentioned in
|
|
|
|
|
/// [xplr.config.general.preview.renderer.format][9], or inside a
|
|
|
|
|
/// [custom dynamic layout][10].
|
|
|
|
|
///
|
|
|
|
|
/// Type: function( { node:[Node][2]|nil, layout_size:[Size][5] } ) -> string
|
|
|
|
|
///
|
|
|
|
|
/// Example:
|
|
|
|
|
///
|
|
|
|
|
/// ```lua
|
|
|
|
|
/// xplr.util.preview({
|
|
|
|
|
/// node = xplr.util.node("/foo"),
|
|
|
|
|
/// layout_size = { x = 0, y = 0, height = 10, width = 10 },
|
|
|
|
|
/// })
|
|
|
|
|
/// -- "Preview of /foo"
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn preview<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
|
|
|
|
|
fn format_node(node: &Node) -> String {
|
|
|
|
|
format!(
|
|
|
|
|
"• T: {}\n• P: {}\n• O: {}:{}\n• S: {}",
|
|
|
|
|
node.mime_essence,
|
|
|
|
|
node.permissions.to_string(),
|
|
|
|
|
node.uid,
|
|
|
|
|
node.gid,
|
|
|
|
|
node.human_size,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let func = lua.create_function(|lua, args: Table| {
|
|
|
|
|
let args: PreviewRendererArgs = lua.from_value(Value::Table(args))?;
|
|
|
|
|
let Some(node) = args.node else {
|
|
|
|
|
return Ok("".into());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let size = args.layout_size;
|
|
|
|
|
|
|
|
|
|
let preview = if node
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|c| c.is_file)
|
|
|
|
|
.unwrap_or(node.is_file)
|
|
|
|
|
{
|
|
|
|
|
let path = node
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|c| &c.absolute_path)
|
|
|
|
|
.unwrap_or(&node.absolute_path);
|
|
|
|
|
|
|
|
|
|
let file = fs::File::open(path)?;
|
|
|
|
|
let reader = io::BufReader::new(file);
|
|
|
|
|
let mut lines = vec![];
|
|
|
|
|
for line in reader.lines() {
|
|
|
|
|
let Ok(mut line) = line else {
|
|
|
|
|
return Ok(format_node(&node));
|
|
|
|
|
};
|
|
|
|
|
line.truncate(size.width.into());
|
|
|
|
|
lines.push(line);
|
|
|
|
|
if lines.len() >= size.height.into() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lines.join("\n")
|
|
|
|
|
} else if node
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|c| c.is_dir)
|
|
|
|
|
.unwrap_or(node.is_dir)
|
|
|
|
|
{
|
|
|
|
|
let path = node
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|c| &c.absolute_path)
|
|
|
|
|
.unwrap_or(&node.relative_path);
|
|
|
|
|
|
|
|
|
|
match fs::read_dir(path) {
|
|
|
|
|
Ok(nodes) => iter::once(format!("▼ {}/", path))
|
|
|
|
|
.chain(
|
|
|
|
|
nodes
|
|
|
|
|
.filter_map(|d| d.ok())
|
|
|
|
|
.map(|d| {
|
|
|
|
|
if d.file_type()
|
|
|
|
|
.ok()
|
|
|
|
|
.map(|t| t.is_dir())
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
format!(" ▷ {}/", d.file_name().to_string_lossy())
|
|
|
|
|
} else {
|
|
|
|
|
format!(" {}", d.file_name().to_string_lossy())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.take(size.height.into()),
|
|
|
|
|
)
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
.join("\n"),
|
|
|
|
|
Err(err) => err.to_string(),
|
|
|
|
|
}
|
|
|
|
|
} else if node.is_symlink && node.is_broken {
|
|
|
|
|
"-> ×".into()
|
|
|
|
|
} else if node.is_symlink {
|
|
|
|
|
node.symlink
|
|
|
|
|
.map(|s| format!("-> {}", s.absolute_path))
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
} else {
|
|
|
|
|
format_node(&node)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(preview)
|
|
|
|
|
})?;
|
|
|
|
|
util.set("preview", func)?;
|
|
|
|
|
Ok(util)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
/// [1]: https://xplr.dev/en/lua-function-calls#explorer-config
|
|
|
|
|
/// [2]: https://xplr.dev/en/lua-function-calls#node
|
|
|
|
|
/// [3]: https://xplr.dev/en/style
|
|
|
|
|
/// [4]: https://xplr.dev/en/layout
|
|
|
|
|
/// [5]: https://xplr.dev/en/lua-function-calls#node
|
|
|
|
|
/// [5]: https://xplr.dev/en/layout#size
|
|
|
|
|
/// [6]: https://xplr.dev/en/node-type
|
|
|
|
|
/// [7]: https://xplr.dev/en/node_types
|
|
|
|
|
/// [8]: https://xplr.dev/en/column-renderer#permission
|
|
|
|
|
/// [9]: https://xplr.dev/en/general-config#xplrconfiggeneralpreviewrendererformat
|
|
|
|
|
/// [10]: https://xplr.dev/en/layout#dynamic
|
|
|
|
|
|
|
|
|
|
pub(crate) fn create_table(lua: &Lua) -> Result<Table> {
|
|
|
|
|
let mut util = lua.create_table()?;
|
|
|
|
@ -896,6 +1015,7 @@ pub(crate) fn create_table(lua: &Lua) -> Result<Table> {
|
|
|
|
|
util = layout_replace(util, lua)?;
|
|
|
|
|
util = permissions_rwx(util, lua)?;
|
|
|
|
|
util = permissions_octal(util, lua)?;
|
|
|
|
|
util = preview(util, lua)?;
|
|
|
|
|
|
|
|
|
|
Ok(util)
|
|
|
|
|
}
|
|
|
|
|