feat(symbols): add dashed borders (#1573)

Adds several new border sets:
- ratatui::symbols::border::LIGHT_DOUBLE_DASHED
- ratatui::symbols::border::HEAVY_DOUBLE_DASHED
- ratatui::symbols::border::LIGHT_TRIPLE_DASHED
- ratatui::symbols::border::HEAVY_TRIPLE_DASHED
- ratatui::symbols::border::LIGHT_QUADRUPLE_DASHED
- ratatui::symbols::border::HEAVY_QUADRUPLE_DASHED

And corresponding variants to the ratatui::widgets::BorderType enum

Fixes: https://github.com/ratatui/ratatui/issues/1355
Signed-off-by: Théo Tchilinguirian <theo.tchlx@gmail.com>
This commit is contained in:
Théo Tchilinguirian
2025-01-20 09:36:19 +01:00
committed by GitHub
parent 57c2326574
commit 985cd05573
4 changed files with 437 additions and 0 deletions

View File

@@ -18,6 +18,20 @@ impl Default for Set {
}
}
// Helper function to convert a line set to a border set
const fn from_line_set(line_set: line::Set) -> Set {
Set {
top_left: line_set.top_left,
top_right: line_set.top_right,
bottom_left: line_set.bottom_left,
bottom_right: line_set.bottom_right,
vertical_left: line_set.vertical,
vertical_right: line_set.vertical,
horizontal_top: line_set.horizontal,
horizontal_bottom: line_set.horizontal,
}
}
/// Border Set with a single line width
///
/// ```text
@@ -94,6 +108,66 @@ pub const THICK: Set = Set {
horizontal_bottom: line::THICK.horizontal,
};
/// Border Set with light double-dashed border lines
///
/// ```text
/// ┌╌╌╌╌╌┐
/// ╎xxxxx╎
/// ╎xxxxx╎
/// └╌╌╌╌╌┘
/// ```
pub const LIGHT_DOUBLE_DASHED: Set = from_line_set(line::LIGHT_DOUBLE_DASHED);
/// Border Set with thick double-dashed border lines
///
/// ```text
/// ┏╍╍╍╍╍┓
/// ╏xxxxx╏
/// ╏xxxxx╏
/// ┗╍╍╍╍╍┛
/// ```
pub const HEAVY_DOUBLE_DASHED: Set = from_line_set(line::HEAVY_DOUBLE_DASHED);
/// Border Set with light triple-dashed border lines
///
/// ```text
/// ┌┄┄┄┄┄┐
/// ┆xxxxx┆
/// ┆xxxxx┆
/// └┄┄┄┄┄┘
/// ```
pub const LIGHT_TRIPLE_DASHED: Set = from_line_set(line::LIGHT_TRIPLE_DASHED);
/// Border Set with thick triple-dashed border lines
///
/// ```text
/// ┏┅┅┅┅┅┓
/// ┇xxxxx┇
/// ┇xxxxx┇
/// ┗┅┅┅┅┅┛
/// ```
pub const HEAVY_TRIPLE_DASHED: Set = from_line_set(line::HEAVY_TRIPLE_DASHED);
/// Border Set with light quadruple-dashed border lines
///
/// ```text
/// ┌┈┈┈┈┈┐
/// ┊xxxxx┊
/// ┊xxxxx┊
/// └┈┈┈┈┈┘
/// ```
pub const LIGHT_QUADRUPLE_DASHED: Set = from_line_set(line::LIGHT_QUADRUPLE_DASHED);
/// Border Set with thick quadruple-dashed border lines
///
/// ```text
/// ┏┉┉┉┉┉┓
/// ┋xxxxx┋
/// ┋xxxxx┋
/// ┗┉┉┉┉┉┛
/// ```
pub const HEAVY_QUADRUPLE_DASHED: Set = from_line_set(line::HEAVY_QUADRUPLE_DASHED);
pub const QUADRANT_TOP_LEFT: &str = "";
pub const QUADRANT_TOP_RIGHT: &str = "";
pub const QUADRANT_BOTTOM_LEFT: &str = "";
@@ -327,6 +401,39 @@ mod tests {
)
}
#[test]
fn border_set_from_line_set() {
let custom_line_set = line::Set {
top_left: "a",
top_right: "b",
bottom_left: "c",
bottom_right: "d",
vertical: "e",
horizontal: "f",
vertical_left: "g",
vertical_right: "h",
horizontal_down: "i",
horizontal_up: "j",
cross: "k",
};
let border_set = from_line_set(custom_line_set);
assert_eq!(
border_set,
Set {
top_left: "a",
top_right: "b",
bottom_left: "c",
bottom_right: "d",
vertical_left: "e",
vertical_right: "e",
horizontal_bottom: "f",
horizontal_top: "f",
}
);
}
#[test]
fn plain() {
assert_eq!(
@@ -387,6 +494,96 @@ mod tests {
);
}
#[test]
fn light_double_dashed() {
assert_eq!(
render(LIGHT_DOUBLE_DASHED),
indoc!(
"░░░░░░
░┌╌╌┐░
░╎░░╎░
░╎░░╎░
░└╌╌┘░
░░░░░░"
)
);
}
#[test]
fn heavy_double_dashed() {
assert_eq!(
render(HEAVY_DOUBLE_DASHED),
indoc!(
"░░░░░░
░┏╍╍┓░
░╏░░╏░
░╏░░╏░
░┗╍╍┛░
░░░░░░"
)
);
}
#[test]
fn light_triple_dashed() {
assert_eq!(
render(LIGHT_TRIPLE_DASHED),
indoc!(
"░░░░░░
░┌┄┄┐░
░┆░░┆░
░┆░░┆░
░└┄┄┘░
░░░░░░"
)
);
}
#[test]
fn heavy_triple_dashed() {
assert_eq!(
render(HEAVY_TRIPLE_DASHED),
indoc!(
"░░░░░░
░┏┅┅┓░
░┇░░┇░
░┇░░┇░
░┗┅┅┛░
░░░░░░"
)
);
}
#[test]
fn light_quadruple_dashed() {
assert_eq!(
render(LIGHT_QUADRUPLE_DASHED),
indoc!(
"░░░░░░
░┌┈┈┐░
░┊░░┊░
░┊░░┊░
░└┈┈┘░
░░░░░░"
)
);
}
#[test]
fn heavy_quadruple_dashed() {
assert_eq!(
render(HEAVY_QUADRUPLE_DASHED),
indoc!(
"░░░░░░
░┏┉┉┓░
░┋░░┋░
░┋░░┋░
░┗┉┉┛░
░░░░░░"
)
);
}
#[test]
fn quadrant_outside() {
assert_eq!(

View File

@@ -1,10 +1,22 @@
pub const VERTICAL: &str = "";
pub const DOUBLE_VERTICAL: &str = "";
pub const THICK_VERTICAL: &str = "";
pub const LIGHT_DOUBLE_DASH_VERTICAL: &str = "";
pub const HEAVY_DOUBLE_DASH_VERTICAL: &str = "";
pub const LIGHT_TRIPLE_DASH_VERTICAL: &str = "";
pub const HEAVY_TRIPLE_DASH_VERTICAL: &str = "";
pub const LIGHT_QUADRUPLE_DASH_VERTICAL: &str = "";
pub const HEAVY_QUADRUPLE_DASH_VERTICAL: &str = "";
pub const HORIZONTAL: &str = "";
pub const DOUBLE_HORIZONTAL: &str = "";
pub const THICK_HORIZONTAL: &str = "";
pub const LIGHT_DOUBLE_DASH_HORIZONTAL: &str = "";
pub const HEAVY_DOUBLE_DASH_HORIZONTAL: &str = "";
pub const LIGHT_TRIPLE_DASH_HORIZONTAL: &str = "";
pub const HEAVY_TRIPLE_DASH_HORIZONTAL: &str = "";
pub const LIGHT_QUADRUPLE_DASH_HORIZONTAL: &str = "";
pub const HEAVY_QUADRUPLE_DASH_HORIZONTAL: &str = "";
pub const TOP_RIGHT: &str = "";
pub const ROUNDED_TOP_RIGHT: &str = "";
@@ -117,6 +129,42 @@ pub const THICK: Set = Set {
cross: THICK_CROSS,
};
pub const LIGHT_DOUBLE_DASHED: Set = Set {
vertical: LIGHT_DOUBLE_DASH_VERTICAL,
horizontal: LIGHT_DOUBLE_DASH_HORIZONTAL,
..NORMAL
};
pub const HEAVY_DOUBLE_DASHED: Set = Set {
vertical: HEAVY_DOUBLE_DASH_VERTICAL,
horizontal: HEAVY_DOUBLE_DASH_HORIZONTAL,
..THICK
};
pub const LIGHT_TRIPLE_DASHED: Set = Set {
vertical: LIGHT_TRIPLE_DASH_VERTICAL,
horizontal: LIGHT_TRIPLE_DASH_HORIZONTAL,
..NORMAL
};
pub const HEAVY_TRIPLE_DASHED: Set = Set {
vertical: HEAVY_TRIPLE_DASH_VERTICAL,
horizontal: HEAVY_TRIPLE_DASH_HORIZONTAL,
..THICK
};
pub const LIGHT_QUADRUPLE_DASHED: Set = Set {
vertical: LIGHT_QUADRUPLE_DASH_VERTICAL,
horizontal: LIGHT_QUADRUPLE_DASH_HORIZONTAL,
..NORMAL
};
pub const HEAVY_QUADRUPLE_DASHED: Set = Set {
vertical: HEAVY_QUADRUPLE_DASH_VERTICAL,
horizontal: HEAVY_QUADRUPLE_DASH_HORIZONTAL,
..THICK
};
#[cfg(test)]
mod tests {
use indoc::{formatdoc, indoc};

View File

@@ -1389,6 +1389,30 @@ mod tests {
assert_eq!(format!("{}", BorderType::Rounded), "Rounded");
assert_eq!(format!("{}", BorderType::Double), "Double");
assert_eq!(format!("{}", BorderType::Thick), "Thick");
assert_eq!(
format!("{}", BorderType::LightDoubleDashed),
"LightDoubleDashed"
);
assert_eq!(
format!("{}", BorderType::HeavyDoubleDashed),
"HeavyDoubleDashed"
);
assert_eq!(
format!("{}", BorderType::LightTripleDashed),
"LightTripleDashed"
);
assert_eq!(
format!("{}", BorderType::HeavyTripleDashed),
"HeavyTripleDashed"
);
assert_eq!(
format!("{}", BorderType::LightQuadrupleDashed),
"LightQuadrupleDashed"
);
assert_eq!(
format!("{}", BorderType::HeavyQuadrupleDashed),
"HeavyQuadrupleDashed"
);
}
#[test]
@@ -1397,6 +1421,30 @@ mod tests {
assert_eq!("Rounded".parse(), Ok(BorderType::Rounded));
assert_eq!("Double".parse(), Ok(BorderType::Double));
assert_eq!("Thick".parse(), Ok(BorderType::Thick));
assert_eq!(
"LightDoubleDashed".parse(),
Ok(BorderType::LightDoubleDashed)
);
assert_eq!(
"HeavyDoubleDashed".parse(),
Ok(BorderType::HeavyDoubleDashed)
);
assert_eq!(
"LightTripleDashed".parse(),
Ok(BorderType::LightTripleDashed)
);
assert_eq!(
"HeavyTripleDashed".parse(),
Ok(BorderType::HeavyTripleDashed)
);
assert_eq!(
"LightQuadrupleDashed".parse(),
Ok(BorderType::LightQuadrupleDashed)
);
assert_eq!(
"HeavyQuadrupleDashed".parse(),
Ok(BorderType::HeavyQuadrupleDashed)
);
assert_eq!("".parse::<BorderType>(), Err(ParseError::VariantNotFound));
}
@@ -1490,6 +1538,96 @@ mod tests {
assert_eq!(buffer, expected);
}
#[test]
fn render_light_double_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::LightDoubleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┌╌╌╌╌╌╌╌╌┐",
"╎ ╎",
"└╌╌╌╌╌╌╌╌┘",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_heavy_double_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::HeavyDoubleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┏╍╍╍╍╍╍╍╍┓",
"╏ ╏",
"┗╍╍╍╍╍╍╍╍┛",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_light_triple_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::LightTripleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┌┄┄┄┄┄┄┄┄┐",
"┆ ┆",
"└┄┄┄┄┄┄┄┄┘",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_heavy_triple_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::HeavyTripleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┏┅┅┅┅┅┅┅┅┓",
"┇ ┇",
"┗┅┅┅┅┅┅┅┅┛",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_light_quadruple_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::LightQuadrupleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┌┈┈┈┈┈┈┈┈┐",
"┊ ┊",
"└┈┈┈┈┈┈┈┈┘",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_heavy_quadruple_dashed_border() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
Block::bordered()
.border_type(BorderType::HeavyQuadrupleDashed)
.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let expected = Buffer::with_lines([
"┏┉┉┉┉┉┉┉┉┓",
"┋ ┋",
"┗┉┉┉┉┉┉┉┉┛",
]);
assert_eq!(buffer, expected);
}
#[test]
fn render_custom_border_set() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));

View File

@@ -74,6 +74,54 @@ pub enum BorderType {
/// ┗━━━━━━━┛
/// ```
Thick,
/// A light double-dashed border.
///
/// ```plain
/// ┌╌╌╌╌╌╌╌┐
/// ╎ ╎
/// └╌╌╌╌╌╌╌┘
/// ```
LightDoubleDashed,
/// A heavy double-dashed border.
///
/// ```plain
/// ┏╍╍╍╍╍╍╍┓
/// ╏ ╏
/// ┗╍╍╍╍╍╍╍┛
/// ```
HeavyDoubleDashed,
/// A light triple-dashed border.
///
/// ```plain
/// ┌┄┄┄┄┄┄┄┐
/// ┆ ┆
/// └┄┄┄┄┄┄┄┘
/// ```
LightTripleDashed,
/// A heavy triple-dashed border.
///
/// ```plain
/// ┏┅┅┅┅┅┅┅┓
/// ┇ ┇
/// ┗┅┅┅┅┅┅┅┛
/// ```
HeavyTripleDashed,
/// A light quadruple-dashed border.
///
/// ```plain
/// ┌┈┈┈┈┈┈┈┐
/// ┊ ┊
/// └┈┈┈┈┈┈┈┘
/// ```
LightQuadrupleDashed,
/// A heavy quadruple-dashed border.
///
/// ```plain
/// ┏┉┉┉┉┉┉┉┓
/// ┋ ┋
/// ┗┉┉┉┉┉┉┉┛
/// ```
HeavyQuadrupleDashed,
/// A border with a single line on the inside of a half block.
///
/// # Example
@@ -105,6 +153,12 @@ impl BorderType {
Self::Rounded => border::ROUNDED,
Self::Double => border::DOUBLE,
Self::Thick => border::THICK,
Self::LightDoubleDashed => border::LIGHT_DOUBLE_DASHED,
Self::HeavyDoubleDashed => border::HEAVY_DOUBLE_DASHED,
Self::LightTripleDashed => border::LIGHT_TRIPLE_DASHED,
Self::HeavyTripleDashed => border::HEAVY_TRIPLE_DASHED,
Self::LightQuadrupleDashed => border::LIGHT_QUADRUPLE_DASHED,
Self::HeavyQuadrupleDashed => border::HEAVY_QUADRUPLE_DASHED,
Self::QuadrantInside => border::QUADRANT_INSIDE,
Self::QuadrantOutside => border::QUADRANT_OUTSIDE,
}