use serde_json::{json, Value};
pub mod config;
pub mod debug;
pub mod dict;
pub mod encoding;
pub mod humanize_bytes;
pub mod inotify;
pub mod memoize;
pub mod monotonic;
pub mod overrides;
pub mod path;
pub mod shell;
pub mod threaded;
pub mod unicode;
pub mod url;
pub mod vcs;
pub mod watcher;
pub struct WrappedOrigin<W, O> {
pub wrapper: W,
pub origin: O,
}
impl<W, O> WrappedOrigin<W, O> {
pub fn new(wrapper: W, origin: O) -> Self {
Self { wrapper, origin }
}
pub fn wrapper(&self) -> &W {
&self.wrapper
}
pub fn origin(&self) -> &O {
&self.origin
}
}
pub fn wraps_saveargs<W>(wrapped: W, wrapper: W) -> WrappedOrigin<W, W> {
WrappedOrigin::new(wrapper, wrapped)
}
pub fn dec<W>(wrapped: W, wrapper: W) -> WrappedOrigin<W, W> {
WrappedOrigin::new(wrapper, wrapped)
}
pub fn f(contents: Option<String>, highlight_group: &str) -> Option<Vec<Value>> {
let r = contents?;
if r.is_empty() {
return None;
}
Some(vec![json!({
"contents": r,
"divider_highlight_group": highlight_group,
})])
}
pub fn add_divider_highlight_group<F>(
highlight_group: impl Into<String>,
mut func: F,
) -> impl FnMut() -> Option<Vec<Value>>
where
F: FnMut() -> Option<String>,
{
let hg = highlight_group.into();
move || {
let r = func()?;
if r.is_empty() {
return None;
}
Some(vec![json!({
"contents": r,
"divider_highlight_group": hg,
})])
}
}
pub fn add_divider_highlight_group_to_list<F>(
highlight_group: impl Into<String>,
mut func: F,
) -> impl FnMut() -> Option<Vec<Value>>
where
F: FnMut() -> Option<Vec<Value>>,
{
let hg = highlight_group.into();
move || {
let segments = func()?;
if segments.is_empty() {
return None;
}
let mut out = Vec::with_capacity(segments.len());
for mut seg in segments {
if let Some(obj) = seg.as_object_mut() {
obj.entry("divider_highlight_group".to_string())
.or_insert_with(|| Value::String(hg.clone()));
}
out.push(seg);
}
Some(out)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn wrapped_origin_exposes_both_callables() {
let wo = WrappedOrigin::new(|| "wrapper".to_string(), || "origin".to_string());
assert_eq!((wo.wrapper)(), "wrapper");
assert_eq!((wo.origin)(), "origin");
}
#[test]
fn wrapped_origin_accessors_match_fields() {
let wo = WrappedOrigin::new(|| 1, || 2);
assert_eq!((wo.wrapper())(), 1);
assert_eq!((wo.origin())(), 2);
}
#[test]
fn add_divider_highlight_group_wraps_non_empty_string() {
let mut wrapped =
add_divider_highlight_group("background:divider", || Some("hello".to_string()));
let r = wrapped().unwrap();
assert_eq!(r.len(), 1);
assert_eq!(r[0]["contents"], "hello");
assert_eq!(r[0]["divider_highlight_group"], "background:divider");
}
#[test]
fn add_divider_highlight_group_none_input_returns_none() {
let mut wrapped = add_divider_highlight_group("background:divider", || None::<String>);
assert!(wrapped().is_none());
}
#[test]
fn add_divider_highlight_group_empty_string_returns_none() {
let mut wrapped =
add_divider_highlight_group("background:divider", || Some("".to_string()));
assert!(wrapped().is_none());
}
#[test]
fn add_divider_highlight_group_to_list_injects_divider_into_each_entry() {
let mut wrapped = add_divider_highlight_group_to_list("seg:divider", || {
Some(vec![json!({"contents": "a"}), json!({"contents": "b"})])
});
let r = wrapped().unwrap();
assert_eq!(r.len(), 2);
assert_eq!(r[0]["divider_highlight_group"], "seg:divider");
assert_eq!(r[1]["divider_highlight_group"], "seg:divider");
}
#[test]
fn add_divider_highlight_group_to_list_preserves_existing_dividers() {
let mut wrapped = add_divider_highlight_group_to_list("default", || {
Some(vec![json!({
"contents": "x",
"divider_highlight_group": "custom",
})])
});
let r = wrapped().unwrap();
assert_eq!(r[0]["divider_highlight_group"], "custom");
}
#[test]
fn add_divider_highlight_group_to_list_empty_returns_none() {
let mut wrapped = add_divider_highlight_group_to_list("seg:divider", || Some(Vec::new()));
assert!(wrapped().is_none());
}
#[test]
fn add_divider_highlight_group_to_list_none_returns_none() {
let mut wrapped = add_divider_highlight_group_to_list::<fn() -> Option<Vec<Value>>>(
"seg:divider",
|| None,
);
assert!(wrapped().is_none());
}
#[test]
fn add_divider_highlight_group_custom_highlight_string() {
let mut wrapped = add_divider_highlight_group("my:divider", || Some("x".to_string()));
let r = wrapped().unwrap();
assert_eq!(r[0]["divider_highlight_group"], "my:divider");
}
#[test]
fn add_divider_highlight_group_invokes_inner_func_each_call() {
use std::cell::Cell;
let call_count = Cell::new(0u32);
let mut wrapped = add_divider_highlight_group("hg", || {
call_count.set(call_count.get() + 1);
Some("hi".to_string())
});
let _ = wrapped();
let _ = wrapped();
let _ = wrapped();
drop(wrapped);
assert_eq!(call_count.get(), 3);
}
#[test]
fn wraps_saveargs_returns_wrapper_origin_pair() {
let result = wraps_saveargs("original_fn", "wrapper_fn");
assert_eq!(result.wrapper(), &"wrapper_fn");
assert_eq!(result.origin(), &"original_fn");
}
#[test]
fn dec_returns_wrapped_origin_pair() {
let result = dec("original_fn", "wrapper_fn");
assert_eq!(result.wrapper(), &"wrapper_fn");
assert_eq!(result.origin(), &"original_fn");
}
#[test]
fn f_returns_single_segment_list_for_non_empty_contents() {
let r = f(Some("hello".to_string()), "branch_divider").unwrap();
assert_eq!(r.len(), 1);
assert_eq!(r[0]["contents"], "hello");
assert_eq!(r[0]["divider_highlight_group"], "branch_divider");
}
#[test]
fn f_returns_none_for_empty_contents() {
assert!(f(None, "x").is_none());
assert!(f(Some("".to_string()), "x").is_none());
}
}