summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md9
-rw-r--r--Cargo.lock15
-rw-r--r--Cargo.toml3
-rw-r--r--src/cli/mod.rs5
-rw-r--r--src/conf/conf.rs47
-rw-r--r--src/conf/import.rs45
-rw-r--r--src/conf/mod.rs2
-rw-r--r--src/display/luma.rs52
-rw-r--r--src/display/mod.rs8
-rw-r--r--src/errors.rs1
10 files changed, 173 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f43f29..b17fc36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+### next
+Major Feature: imports
+A configuration file can now import one or several other ones.
+An import can have a condition on the terminal's background color, which makes it possible to import either a dark or a light theme depending on the current terminal settings.
+You're also encouraged to split your configuration in several files.
+
### v1.13.3 - 2022-06-19
<a name="v1.13.2"></a>
- fix default_flags in conf not working anymore - Fix #566
@@ -10,7 +16,8 @@
- the --file-export-path launch argument which was deprecated since broot 1.6 has been removed (redirect the output of broot instead)
- better built-in verbs for Windows - Thanks @Spacelord-XaN
- take the .git/info/exclude file into account for ignoring - Thanks @refi64
-The released archive doesn't include an Android build - see https://github.com/Canop/broot/issues/565
+
+Note: The released archive doesn't include an Android build - see https://github.com/Canop/broot/issues/565
### v1.13.1 - 2022-05-30
<a name="v1.13.1"></a>
diff --git a/Cargo.lock b/Cargo.lock
index 72dc1f7..132a9dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -137,7 +137,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "broot"
-version = "1.13.4-dev"
+version = "1.14.0-dev"
dependencies = [
"ahash 0.7.6",
"ansi_colours",
@@ -181,6 +181,7 @@ dependencies = [
"tempfile",
"termimad",
"terminal-clipboard",
+ "terminal-light",
"toml",
"umask",
"unicode-width",
@@ -1840,6 +1841,18 @@ dependencies = [
]
[[package]]
+name = "terminal-light"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f279e95099c18b04b1b5dcab98fa6f2a50908754cbf453ddbb99c392b7d662d1"
+dependencies = [
+ "coolor",
+ "crossterm",
+ "thiserror",
+ "xterm-query",
+]
+
+[[package]]
name = "termux-clipboard"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 83b95fa..bbd3115 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "broot"
-version = "1.13.4-dev"
+version = "1.14.0-dev"
authors = ["dystroy <denys.seguret@gmail.com>"]
repository = "https://github.com/Canop/broot"
documentation = "https://dystroy.org/broot"
@@ -58,6 +58,7 @@ syntect = { package = "syntect-no-panic", version = "4.6.1" } # see issue #485
tempfile = "3.2"
termimad = "0.20.2"
terminal-clipboard = { version = "0.3.1", optional = true }
+terminal-light = "0.8.1"
toml = "0.5"
umask = "2.0.0"
unicode-width = "0.1.8"
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index 681d0e7..c261be1 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -88,7 +88,6 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> {
};
debug!("config: {:#?}", &config);
-
// verb store is completed from the config file(s)
let verb_store = VerbStore::new(&mut config)?;
@@ -105,7 +104,9 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> {
let message = Message::Sequence(Sequence::new_local(seq.to_string()));
client.send(&message)?;
} else if !context.launch_args.get_root {
- let message = Message::Command(format!(":focus {}", context.initial_root.to_string_lossy()));
+ let message = Message::Command(
+ format!(":focus {}", context.initial_root.to_string_lossy())
+ );
client.send(&message)?;
};
if context.launch_args.get_root {
diff --git a/src/conf/conf.rs b/src/conf/conf.rs
index 1b42044..1fe2df0 100644
--- a/src/conf/conf.rs
+++ b/src/conf/conf.rs
@@ -5,8 +5,13 @@ use {
super::*,
crate::{
display::ColsConf,
- errors::ProgramError,
- path::{Glob, SpecialHandling},
+ errors::{ConfError, ProgramError},
+ path::{
+ Glob,
+ SpecialHandling,
+ path_from,
+ PathAnchor,
+ },
skin::SkinEntry,
syntactic::SyntaxTheme,
},
@@ -96,6 +101,10 @@ pub struct Conf {
#[serde(alias="max_staged_count")]
pub max_staged_count: Option<usize>,
+
+ #[serde(default)]
+ pub imports: Vec<Import>,
+
}
impl Conf {
@@ -130,10 +139,8 @@ impl Conf {
println!("You should have a look at it.");
}
let mut conf = Conf::default();
- match conf.read_file(conf_filepath) {
- Err(e) => Err(e),
- _ => Ok(conf),
- }
+ conf.read_file(conf_filepath.clone())?;
+ Ok(conf)
}
/// assume the file doesn't yet exist
@@ -143,11 +150,24 @@ impl Conf {
Ok(())
}
+ pub fn solve_conf_path(&self, path: &str) -> Option<PathBuf> {
+ if path.ends_with(".toml") || path.ends_with(".hjson") {
+ for conf_file in self.files.iter().rev() {
+ let solved = path_from(conf_file, PathAnchor::Parent, path);
+ if solved.exists() {
+ return Some(solved)
+ }
+ }
+ }
+ None
+ }
+
/// read the configuration from a given path. Assume it exists.
/// Values set in the read file replace the ones of self.
/// Errors are printed on stderr (assuming this function is called
/// before terminal alternation).
pub fn read_file(&mut self, path: PathBuf) -> Result<(), ProgramError> {
+ debug!("reading conf file: {:?}", &path);
let mut conf: Conf = SerdeFormat::read_file(&path)?;
overwrite!(self, default_flags, conf);
overwrite!(self, date_time_format, conf);
@@ -171,6 +191,21 @@ impl Conf {
overwrite_map!(self, special_paths, conf);
overwrite_map!(self, ext_colors, conf);
self.files.push(path);
+ // read the imports
+ for import in &conf.imports {
+ let file = import.file();
+ if !import.applies() {
+ debug!("skipping not applying conf file : {:?}", file);
+ continue;
+ }
+ let import_path = self.solve_conf_path(file)
+ .ok_or_else(|| ConfError::ImportNotFound { path: file.to_string() })?;
+ if self.files.contains(&import_path) {
+ debug!("skipping import already read: {:?}", import_path);
+ continue;
+ }
+ self.read_file(import_path)?;
+ }
Ok(())
}
}
diff --git a/src/conf/import.rs b/src/conf/import.rs
new file mode 100644
index 0000000..0a9db29
--- /dev/null
+++ b/src/conf/import.rs
@@ -0,0 +1,45 @@
+use {
+ crate::{
+ display::LumaCondition,
+ },
+ serde::Deserialize,
+};
+
+
+/// A file to import, with optionally a condition
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum Import {
+ Simple(String),
+ Detailed(DetailedImport),
+}
+
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct DetailedImport {
+
+ /// a condition on terminal light
+ pub luma: Option<LumaCondition>,
+
+ /// path, either absolute or relative to the current file
+ /// or the conf directory
+ pub file: String,
+}
+
+impl Import {
+ pub fn applies(&self) -> bool {
+ self.luma().map_or(true, |luma| luma.is_verified())
+ }
+ pub fn luma(&self) -> Option<&LumaCondition> {
+ match self {
+ Self::Simple(_) => None,
+ Self::Detailed(detailed) => detailed.luma.as_ref(),
+ }
+ }
+ pub fn file(&self) -> &str {
+ match self {
+ Self::Simple(s) => s,
+ Self::Detailed(detailed) => &detailed.file
+ }
+ }
+}
diff --git a/src/conf/mod.rs b/src/conf/mod.rs
index cc84322..8a9f1f6 100644
--- a/src/conf/mod.rs
+++ b/src/conf/mod.rs
@@ -5,11 +5,13 @@ use {
mod conf;
mod format;
+mod import;
mod verb_conf;
pub use {
conf::Conf,
format::*,
+ import::*,
once_cell::sync::Lazy,
verb_conf::VerbConf,
};
diff --git a/src/display/luma.rs b/src/display/luma.rs
new file mode 100644
index 0000000..27bf877
--- /dev/null
+++ b/src/display/luma.rs
@@ -0,0 +1,52 @@
+pub use {
+ once_cell::sync::Lazy,
+ serde::Deserialize,
+};
+
+#[derive(Debug, Clone, Copy, Deserialize, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum Luma {
+ Light,
+ Unknown,
+ Dark,
+}
+
+/// Return the light of the terminal background, which is a value
+/// between 0 (black) and 1 (white).
+pub fn luma() -> &'static Result<f32, terminal_light::TlError> {
+ static LUMA: Lazy<Result<f32, terminal_light::TlError>> = Lazy::new(|| {
+ let luma = time!(Debug, terminal_light::luma());
+ info!("terminal's luma: {:?}", &luma);
+ luma
+ });
+ &*LUMA
+}
+
+impl Luma {
+ pub fn read() -> Self {
+ match luma() {
+ Ok(luma) if *luma > 0.6 => Self::Light,
+ Ok(_) => Self::Dark,
+ _ => Self::Unknown,
+ }
+ }
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum LumaCondition {
+ Simple(Luma),
+ Array(Vec<Luma>),
+}
+
+impl LumaCondition {
+ pub fn is_verified(&self) -> bool {
+ self.includes(Luma::read())
+ }
+ pub fn includes(&self, other: Luma) -> bool {
+ match self {
+ Self::Simple(luma) => other == *luma,
+ Self::Array(arr) => arr.contains(&other),
+ }
+ }
+}
diff --git a/src/display/mod.rs b/src/display/mod.rs
index 702aa90..a9eceff 100644
--- a/src/display/mod.rs
+++ b/src/display/mod.rs
@@ -22,15 +22,16 @@ macro_rules! cond_bg {
}
mod areas;
+mod cell_size;
mod col;
mod displayable_tree;
-mod git_status_display;
pub mod flags_display;
-pub mod status_line;
+mod git_status_display;
+mod luma;
mod matched_string;
mod num_format;
mod screen;
-mod cell_size;
+pub mod status_line;
#[cfg(not(any(target_family="windows",target_os="android")))]
mod permissions;
@@ -41,6 +42,7 @@ pub use {
cond_bg,
displayable_tree::DisplayableTree,
git_status_display::GitStatusDisplay,
+ luma::*,
matched_string::MatchedString,
screen::Screen,
cell_size::*,
diff --git a/src/errors.rs b/src/errors.rs
index 76c1d64..aaaa70e 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -41,6 +41,7 @@ custom_error! {pub TreeBuildError
custom_error! {pub ConfError
Io {source: io::Error} = "unable to read from the file: {}",
+ ImportNotFound {path: String} = "import file not found: {:?}",
UnknownFileExtension { path: String} = "unexpected file extension in {:?}",
Toml {source: toml::de::Error} = "unable to parse TOML: {}",
Hjson {source: deser_hjson::Error} = "unable to parse Hjson: {}",