feat: configure interchangeable top and bottom bars
This commit is contained in:
+61
-32
@@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
const STATUS_SEGMENTS: &[&str] = &[
|
||||
const DEFAULT_BOTTOM_SEGMENTS: &[&str] = &[
|
||||
"mode",
|
||||
"pending",
|
||||
"buffer",
|
||||
@@ -43,7 +43,7 @@ impl Default for SegmentConfig {
|
||||
}
|
||||
|
||||
impl ChromeLine {
|
||||
pub fn tabline() -> Self {
|
||||
pub fn top() -> Self {
|
||||
Self {
|
||||
left: vec!["tabs".into()],
|
||||
center: Vec::new(),
|
||||
@@ -52,15 +52,15 @@ impl ChromeLine {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn statusline() -> Self {
|
||||
pub fn bottom() -> Self {
|
||||
Self {
|
||||
left: STATUS_SEGMENTS[..STATUS_SEGMENTS.len() - 1]
|
||||
left: DEFAULT_BOTTOM_SEGMENTS[..DEFAULT_BOTTOM_SEGMENTS.len() - 1]
|
||||
.iter()
|
||||
.map(|name| (*name).into())
|
||||
.collect(),
|
||||
center: Vec::new(),
|
||||
right: vec!["position".into()],
|
||||
segments: STATUS_SEGMENTS
|
||||
segments: DEFAULT_BOTTOM_SEGMENTS
|
||||
.iter()
|
||||
.map(|name| ((*name).into(), default_segment(name)))
|
||||
.collect(),
|
||||
@@ -72,7 +72,7 @@ impl ChromeLine {
|
||||
self.segments.get(name).expect("validated chrome segment")
|
||||
}
|
||||
|
||||
pub fn validate(&mut self, tabline: bool) -> Result<(), String> {
|
||||
pub fn validate(&mut self) -> Result<(), String> {
|
||||
for name in self
|
||||
.left
|
||||
.iter()
|
||||
@@ -81,13 +81,6 @@ impl ChromeLine {
|
||||
.chain(self.segments.keys())
|
||||
{
|
||||
validate_name(name)?;
|
||||
if (tabline && STATUS_SEGMENTS.contains(&name.as_str())) || (!tabline && name == "tabs")
|
||||
{
|
||||
return Err(format!(
|
||||
"Chrome segment {name:?} is only available in the {}",
|
||||
if tabline { "statusline" } else { "tabline" }
|
||||
));
|
||||
}
|
||||
}
|
||||
for (name, segment) in &self.segments {
|
||||
if segment.padding > 64 {
|
||||
@@ -188,7 +181,7 @@ struct SegmentOptions {
|
||||
|
||||
fn deserialize_line<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
tabline: bool,
|
||||
mut line: ChromeLine,
|
||||
) -> Result<ChromeLine, D::Error> {
|
||||
// Decode through a value so explicit null is rejected rather than treated as an omitted option.
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
@@ -207,11 +200,6 @@ fn deserialize_line<'de, D: Deserializer<'de>>(
|
||||
}
|
||||
}
|
||||
let options: LineOptions = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
|
||||
let mut line = if tabline {
|
||||
ChromeLine::tabline()
|
||||
} else {
|
||||
ChromeLine::statusline()
|
||||
};
|
||||
if let Some(left) = options.left {
|
||||
line.left = left;
|
||||
}
|
||||
@@ -242,16 +230,16 @@ fn deserialize_line<'de, D: Deserializer<'de>>(
|
||||
segment.first_leading_edge = Some(edge);
|
||||
}
|
||||
}
|
||||
line.validate(tabline).map_err(serde::de::Error::custom)?;
|
||||
line.validate().map_err(serde::de::Error::custom)?;
|
||||
Ok(line)
|
||||
}
|
||||
|
||||
pub fn tabline<'de, D: Deserializer<'de>>(deserializer: D) -> Result<ChromeLine, D::Error> {
|
||||
deserialize_line(deserializer, true)
|
||||
pub fn top<'de, D: Deserializer<'de>>(deserializer: D) -> Result<ChromeLine, D::Error> {
|
||||
deserialize_line(deserializer, ChromeLine::top())
|
||||
}
|
||||
|
||||
pub fn statusline<'de, D: Deserializer<'de>>(deserializer: D) -> Result<ChromeLine, D::Error> {
|
||||
deserialize_line(deserializer, false)
|
||||
pub fn bottom<'de, D: Deserializer<'de>>(deserializer: D) -> Result<ChromeLine, D::Error> {
|
||||
deserialize_line(deserializer, ChromeLine::bottom())
|
||||
}
|
||||
|
||||
pub fn labels<'de, D: Deserializer<'de>>(
|
||||
@@ -270,9 +258,9 @@ mod tests {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Lines {
|
||||
#[serde(deserialize_with = "tabline")]
|
||||
#[serde(deserialize_with = "top")]
|
||||
top: ChromeLine,
|
||||
#[serde(deserialize_with = "statusline")]
|
||||
#[serde(deserialize_with = "bottom")]
|
||||
bottom: ChromeLine,
|
||||
}
|
||||
|
||||
@@ -290,11 +278,51 @@ mod tests {
|
||||
assert_eq!(lines.bottom.segment("workspace"), &SegmentConfig::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_positions_accept_all_builtins_and_custom_styles() {
|
||||
let names = [
|
||||
"tabs",
|
||||
"mode",
|
||||
"pending",
|
||||
"buffer",
|
||||
"diagnostics",
|
||||
"path",
|
||||
"selections",
|
||||
"count",
|
||||
"language",
|
||||
"position",
|
||||
"workspace",
|
||||
];
|
||||
let options = serde_json::json!({
|
||||
"left": names,
|
||||
"center": ["language"],
|
||||
"right": ["tabs"],
|
||||
"tabs": {"title": "{index}:{name}:{path}{modified}", "padding": 0},
|
||||
"mode": {"leading_edge": "<", "trailing_edge": ">"},
|
||||
"workspace": {"first_leading_edge": ""}
|
||||
});
|
||||
let lines: Lines = serde_json::from_value(serde_json::json!({
|
||||
"top": options,
|
||||
"bottom": options,
|
||||
}))
|
||||
.unwrap();
|
||||
for line in [&lines.top, &lines.bottom] {
|
||||
assert_eq!(line.left, names);
|
||||
assert_eq!(line.center, ["language"]);
|
||||
assert_eq!(line.right, ["tabs"]);
|
||||
assert_eq!(line.segment("tabs").padding, 0);
|
||||
assert_eq!(line.segment("mode").leading_edge, "<");
|
||||
assert_eq!(
|
||||
line.segment("workspace").first_leading_edge.as_deref(),
|
||||
Some("")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_chrome_is_rejected_at_the_boundary() {
|
||||
for top in [
|
||||
for options in [
|
||||
serde_json::json!({"left": ["bad-name"]}),
|
||||
serde_json::json!({"left": ["mode"]}),
|
||||
serde_json::json!({"left": null}),
|
||||
serde_json::json!({"tabs": {"padding": 65}}),
|
||||
serde_json::json!({"tabs": {"padding": null}}),
|
||||
@@ -304,10 +332,11 @@ mod tests {
|
||||
serde_json::json!({"tabs": {"title": "name}"}}),
|
||||
serde_json::json!({"tabs": {"colour": "red"}}),
|
||||
] {
|
||||
assert!(
|
||||
serde_json::from_value::<Lines>(serde_json::json!({"top": top, "bottom": {}}))
|
||||
.is_err()
|
||||
);
|
||||
for position in ["top", "bottom"] {
|
||||
let mut frame = serde_json::json!({"top": {}, "bottom": {}});
|
||||
frame[position] = options.clone();
|
||||
assert!(serde_json::from_value::<Lines>(frame).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user