Add xplr.util.lscolor and xplr.util.paint (#569)

* Add xplr.util.lscolor and xplr.util.style

* Fix formatting

* Fix clippy suggestions

* Remove redundant closures

* Optimize, support NO_COLOR, and rename style to paint

* Use xplr.util.paint and xplr.util.color in init.lua

Co-authored-by: Noah Mayr <dev@noahmayr.com>
pull/567/head
Arijit Basu 2 years ago committed by GitHub
parent 8c4f744bb1
commit c1fc5aee70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

27
Cargo.lock generated

@ -580,6 +580,15 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "lscolors"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dedc85d67baf5327114fad78ab9418f8893b1121c17d5538dd11005ad1ddf2"
dependencies = [
"nu-ansi-term",
]
[[package]]
name = "lua-src"
version = "544.0.1"
@ -681,6 +690,16 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@ -728,6 +747,12 @@ version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1399,9 +1424,11 @@ dependencies = [
"indexmap",
"lazy_static",
"libc",
"lscolors",
"mime_guess",
"mlua",
"natord",
"nu-ansi-term",
"path-absolutize",
"regex",
"serde",

@ -36,6 +36,12 @@ fuzzy-matcher = "0.3.7"
serde_json = "1.0.91"
path-absolutize = "3.0.14"
which = "4.3.0"
nu-ansi-term = "0.46.0"
[dependencies.lscolors]
version = "0.13.0"
default-features = false
features = ["nu-ansi-term"]
[dependencies.lazy_static]
version = "1.4.0"

@ -700,9 +700,7 @@ xplr.config.general.global_key_bindings = {
-- The style for the directory nodes
--
-- Type: [Style](https://xplr.dev/en/style)
xplr.config.node_types.directory.style = {
fg = "Cyan",
}
xplr.config.node_types.directory.style = {}
-- Metadata for the directory nodes.
-- You can set as many metadata as you want.
@ -2554,43 +2552,21 @@ xplr.fn.builtin.fmt_general_table_row_cols_1 = function(m)
end
end
end
return r
local style = xplr.util.lscolor(m.absolute_path)
return xplr.util.paint(r, style)
end
-- Renders the third column in the table
xplr.fn.builtin.fmt_general_table_row_cols_2 = function(m)
local no_color = os.getenv("NO_COLOR")
local function green(x)
if no_color == nil then
return "\x1b[32m" .. x .. "\x1b[0m"
else
return x
end
end
local function yellow(x)
if no_color == nil then
return "\x1b[33m" .. x .. "\x1b[0m"
else
return x
end
end
local function red(x)
if no_color == nil then
return "\x1b[31m" .. x .. "\x1b[0m"
else
return x
end
end
local green = { fg = "Green" }
local yellow = { fg = "Yellow" }
local red = { fg = "Red" }
local function bit(x, color, cond)
if cond then
return color(x)
return xplr.util.paint(x, color)
else
return color("-")
return xplr.util.paint("-", color)
end
end

@ -2,7 +2,10 @@ use crate::app::VERSION;
use crate::explorer;
use crate::lua;
use crate::msg::in_::external::ExplorerConfig;
use crate::ui;
use crate::ui::Style;
use anyhow::Result;
use lscolors::LsColors;
use mlua::Error as LuaError;
use mlua::Lua;
use mlua::LuaSerdeExt;
@ -30,6 +33,8 @@ pub(crate) fn create_table(lua: &Lua) -> Result<Table> {
util = to_json(util, lua)?;
util = from_yaml(util, lua)?;
util = to_yaml(util, lua)?;
util = lscolor(util, lua)?;
util = paint(util, lua)?;
Ok(util)
}
@ -317,3 +322,56 @@ pub fn to_yaml<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
util.set("to_yaml", func)?;
Ok(util)
}
/// Get a style object for the given path
///
/// Type: function( path ) -> style|nil
///
/// Example:
///
/// ```lua
/// xplr.util.lscolor("Desktop")
/// -- { fg = "Red", bg = nil, add_modifiers = {}, sub_modifiers = {} }
/// ```
pub fn lscolor<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
let lscolors = LsColors::from_env().unwrap_or_default();
let func = lua.create_function(move |lua, path: String| {
if *ui::NO_COLOR {
return Ok(mlua::Nil);
}
let style = lscolors.style_for_path(path).map(Style::from);
lua::serialize(lua, &style).map_err(LuaError::custom)
})?;
util.set("lscolor", func)?;
Ok(util)
}
/// Format a string using a style object
///
/// Type: function( string, style|nil ) -> string
///
/// Example:
///
/// ```lua
/// xplr.util.paint("Desktop", { fg = "Red", bg = nil, add_modifiers = {}, sub_modifiers = {} })
/// -- "\u001b[31mDesktop\u001b[0m"
/// ```
pub fn paint<'a>(util: Table<'a>, lua: &Lua) -> Result<Table<'a>> {
let func =
lua.create_function(|lua, (string, style): (String, Option<Table>)| {
if *ui::NO_COLOR {
return Ok(string);
}
let Some(style) = style else {
return Ok(string);
};
let style: Style = lua.from_value(Value::Table(style))?;
let ansi_style: nu_ansi_term::Style = style.into();
Ok::<String, LuaError>(ansi_style.paint(string).to_string())
})?;
util.set("paint", func)?;
Ok(util)
}

@ -7,6 +7,7 @@ use crate::permissions::Permissions;
use ansi_to_tui::IntoText;
use indexmap::IndexSet;
use lazy_static::lazy_static;
use lscolors::{Color as LsColorsColor, Style as LsColorsStyle};
use mlua::Lua;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
@ -292,6 +293,90 @@ impl Into<TuiStyle> for Style {
}
}
impl From<&LsColorsStyle> for Style {
fn from(style: &LsColorsStyle) -> Self {
fn convert_color(color: &LsColorsColor) -> Color {
match color {
LsColorsColor::Black => Color::Black,
LsColorsColor::Red => Color::Red,
LsColorsColor::Green => Color::Green,
LsColorsColor::Yellow => Color::Yellow,
LsColorsColor::Blue => Color::Blue,
LsColorsColor::Magenta => Color::Magenta,
LsColorsColor::Cyan => Color::Cyan,
LsColorsColor::White => Color::Gray,
LsColorsColor::BrightBlack => Color::DarkGray,
LsColorsColor::BrightRed => Color::LightRed,
LsColorsColor::BrightGreen => Color::LightGreen,
LsColorsColor::BrightYellow => Color::LightYellow,
LsColorsColor::BrightBlue => Color::LightBlue,
LsColorsColor::BrightMagenta => Color::LightMagenta,
LsColorsColor::BrightCyan => Color::LightCyan,
LsColorsColor::BrightWhite => Color::White,
LsColorsColor::Fixed(index) => Color::Indexed(*index),
LsColorsColor::RGB(r, g, b) => Color::Rgb(*r, *g, *b),
}
}
Self {
fg: style.foreground.as_ref().map(convert_color),
bg: style.background.as_ref().map(convert_color),
add_modifiers: None,
sub_modifiers: None,
}
}
}
impl Into<nu_ansi_term::Style> for Style {
fn into(self) -> nu_ansi_term::Style {
fn convert_color(color: Color) -> Option<nu_ansi_term::Color> {
match color {
Color::Black => Some(nu_ansi_term::Color::Black),
Color::Red => Some(nu_ansi_term::Color::Red),
Color::Green => Some(nu_ansi_term::Color::Green),
Color::Yellow => Some(nu_ansi_term::Color::Yellow),
Color::Blue => Some(nu_ansi_term::Color::Blue),
Color::Magenta => Some(nu_ansi_term::Color::Purple),
Color::Cyan => Some(nu_ansi_term::Color::Cyan),
Color::Gray => Some(nu_ansi_term::Color::LightGray),
Color::DarkGray => Some(nu_ansi_term::Color::DarkGray),
Color::LightRed => Some(nu_ansi_term::Color::LightRed),
Color::LightGreen => Some(nu_ansi_term::Color::LightGreen),
Color::LightYellow => Some(nu_ansi_term::Color::LightYellow),
Color::LightBlue => Some(nu_ansi_term::Color::LightBlue),
Color::LightMagenta => Some(nu_ansi_term::Color::LightMagenta),
Color::LightCyan => Some(nu_ansi_term::Color::LightCyan),
Color::White => Some(nu_ansi_term::Color::White),
Color::Rgb(r, g, b) => Some(nu_ansi_term::Color::Rgb(r, g, b)),
Color::Indexed(index) => Some(nu_ansi_term::Color::Fixed(index)),
_ => None,
}
}
fn match_modifiers<F>(style: &Style, f: F) -> bool
where
F: Fn(&IndexSet<Modifier>) -> bool,
{
style.add_modifiers.as_ref().map_or(false, f)
}
nu_ansi_term::Style {
foreground: self.fg.and_then(convert_color),
background: self.bg.and_then(convert_color),
is_bold: match_modifiers(&self, |m| m.contains(&Modifier::Bold)),
is_dimmed: match_modifiers(&self, |m| m.contains(&Modifier::Dim)),
is_italic: match_modifiers(&self, |m| m.contains(&Modifier::Italic)),
is_underline: match_modifiers(&self, |m| m.contains(&Modifier::Underlined)),
is_blink: match_modifiers(&self, |m| {
m.contains(&Modifier::SlowBlink) || m.contains(&Modifier::RapidBlink)
}),
is_reverse: match_modifiers(&self, |m| m.contains(&Modifier::Reversed)),
is_hidden: match_modifiers(&self, |m| m.contains(&Modifier::Hidden)),
is_strikethrough: match_modifiers(&self, |m| {
m.contains(&Modifier::CrossedOut)
}),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub enum Constraint {

Loading…
Cancel
Save