use codesnake::{Block, CodeWidth, Label, LineIndex};
use core::fmt::{self, Display, Formatter};
use core::ops::Range;
use pretty_assertions::assert_eq;
fn paint(f: &mut Formatter, style: &bool, s: &dyn Display) -> fmt::Result {
if *style {
write!(f, "<span>{s}</span>")
} else {
write!(f, "{s}")
}
}
fn format<const N: usize>(code: &str, labels: [Label<Range<usize>, &str, bool>; N]) -> String {
let idx = LineIndex::new(code);
let mut prev_empty = false;
let block = Block::new(&idx, labels).unwrap();
let block = block.with_paint(paint).map_code(|s| {
let sub = usize::from(core::mem::replace(&mut prev_empty, s.is_empty()));
let s = s.replace('\t', " ");
let w = unicode_width::UnicodeWidthStr::width(&*s);
CodeWidth::new(s, core::cmp::max(w, 1) - sub)
});
format!(
"\n{}\n{}\n{block}{}\n",
block.prologue(),
block.space_vert(),
block.epilogue()
)
}
fn main() {
for ci in SRC.char_indices() {
println!("{ci:?}");
}
println!("{}", format(SRC, [Label::new(4..7)]));
}
const SRC: &str = "foo bar\nbaz toto\nlook, a fish 🐟 and a hook 🪝\nthis is getting silly";
#[test]
fn s1() {
assert_eq!(
format(SRC, [Label::new(4..7).with_snake()]),
"
╭─
│
1 │ foo bar
┆ ───
──╯
"
);
}
#[test]
fn s1s1() {
assert_eq!(
format(
SRC,
[Label::new(0..3).with_snake(), Label::new(4..7).with_snake()]
),
"
╭─
│
1 │ foo bar
┆ ─── ───
──╯
"
);
}
#[test]
fn s1s2() {
assert_eq!(
format(
SRC,
[
Label::new(0..3).with_snake(),
Label::new(4..11).with_snake()
]
),
"
╭─
│
1 │ foo bar
┆ ─── ▲
┆ ╭─────╯
2 │ │ baz toto
┆ │ ▲
┆ │ │
┆ ╰───╯
──╯
"
);
}
#[test]
fn t1t2t1() {
assert_eq!(
format(
SRC,
[
Label::new(0..3).with_text("some foo"),
Label::new(4..11).with_text("more"),
Label::new(12..16).with_text("a band?")
]
),
"
╭─
│
1 │ foo bar
┆ ─┬─ ▲
┆ │ │
┆ ╰────── some foo
┆ ╭─────╯
2 │ │ baz toto
┆ │ ▲ ──┬─
┆ │ │ │
┆ ╰───┴────── more
┆ │
┆ ╰── a band?
──╯
"
);
}
#[test]
fn s3() {
assert_eq!(
format(SRC, [Label::new(4..21).with_snake()]),
"
╭─
│
1 │ foo bar
┆ ▲
┆ ╭─────╯
2 │ │ baz toto
3 │ │ look, a fish 🐟 and a hook 🪝
┆ │ ▲
┆ │ │
┆ ╰────╯
──╯
"
);
}
#[test]
fn s3s1() {
assert_eq!(
format(
SRC,
[
Label::new(4..21).with_snake(),
Label::new(25..34).with_text("thanks for all the ...")
]
),
"
╭─
│
1 │ foo bar
┆ ▲
┆ ╭─────╯
2 │ │ baz toto
3 │ │ look, a fish 🐟 and a hook 🪝
┆ │ ▲ ───┬───
┆ │ │ │
┆ ╰────╯ │
┆ │
┆ ╰────────────────── thanks for all the ...
──╯
"
);
}
#[test]
fn t1t1() {
let labels = [
Label::new(25..34).with_text("animal"),
Label::new(41..50).with_text("object"),
];
let output = "
╭─
│
3 │ look, a fish 🐟 and a hook 🪝
┆ ───┬─── ───┬───
┆ │ │
┆ ╰────────────────── animal
┆ │
┆ ╰──── object
──╯
";
assert_eq!(format(SRC, labels), output);
}
#[test]
fn t2t2() {
assert_eq!(
format(
SRC,
[
Label::new(4..11).with_text("ba?"),
Label::new(12..21).with_text("four-letter words")
]
),
"
╭─
│
1 │ foo bar
┆ ▲
┆ ╭─────╯
2 │ │ baz toto
┆ │ ▲ ▲
┆ │ │ │
┆ ╰───┴────── ba?
┆ ╭─────╯
3 │ │ look, a fish 🐟 and a hook 🪝
┆ │ ▲
┆ │ │
┆ ╰────┴────────────────────────── four-letter words
──╯
"
);
}
#[test]
fn empty() {
assert_eq!(
format(
SRC,
[Label::new(2..2).with_snake(), Label::new(4..7).with_snake()]
),
"
╭─
│
1 │ foo bar
┆ ─ ───
──╯
"
);
}
#[test]
fn adjacent() {
assert_eq!(
format(
SRC,
[Label::new(0..3).with_snake(), Label::new(3..7).with_snake()]
),
"
╭─
│
1 │ foo bar
┆ ───────
──╯
"
);
}
#[test]
fn the_end() {
assert_eq!(
format(SRC, [Label::new(72..72).with_text("the end")]),
"
╭─
│
4 │ this is getting silly
┆ ┬
┆ │
┆ ╰─ the end
──╯
"
);
}
#[test]
fn n1() {
assert_eq!(
format(SRC, [Label::new(25..34)]),
"
╭─
│
3 │ look, a fish 🐟 and a hook 🪝
──╯
"
);
}
#[test]
fn n1t1() {
assert_eq!(
format(
SRC,
[Label::new(24..24), Label::new(25..25).with_text("hello")]
),
"
╭─
│
3 │ look, a fish 🐟 and a hook 🪝
┆ ┬
┆ │
┆ ╰───────────────────── hello
──╯
"
);
}
#[test]
fn t2t2n1() {
assert_eq!(
format(
SRC,
[
Label::new(4..11).with_text("ba?"),
Label::new(12..21).with_text("four-letter words"),
Label::new(72..72),
]
),
"
╭─
│
1 │ foo bar
┆ ▲
┆ ╭─────╯
2 │ │ baz toto
┆ │ ▲ ▲
┆ │ │ │
┆ ╰───┴────── ba?
┆ ╭─────╯
3 │ │ look, a fish 🐟 and a hook 🪝
┆ │ ▲
┆ │ │
┆ ╰────┴────────────────────────── four-letter words
4 │ this is getting silly
──╯
"
);
}
#[test]
fn n1t2n1() {
assert_eq!(
format(
SRC,
[
Label::new(4..11),
Label::new(12..21).with_text("four-letter words"),
Label::new(72..72),
]
),
"
╭─
│
1 │ foo bar
2 │ baz toto
┆ ▲
┆ ╭─────╯
3 │ │ look, a fish 🐟 and a hook 🪝
┆ │ ▲
┆ │ │
┆ ╰────┴────────────────────────── four-letter words
4 │ this is getting silly
──╯
"
);
}
#[test]
fn n4() {
assert_eq!(
format(SRC, [Label::new(0..72)]),
"
╭─
│
1 │ foo bar
2 │ baz toto
3 │ look, a fish 🐟 and a hook 🪝
4 │ this is getting silly
──╯
"
);
}
#[test]
fn n4_style() {
assert_eq!(
format(SRC, [Label::new(0..72).with_style(true)]),
"
╭─
│
1 │ <span>foo bar</span>
2 │ <span>baz toto</span>
3 │ <span>look, a fish 🐟 and a hook 🪝</span>
4 │ <span>this is getting silly</span>
──╯
"
);
}
#[test]
fn n1bt1n1() {
assert_eq!(
format(
SRC,
[
Label::new(4..4),
Label::new(25..25).with_text("hello"),
Label::new(70..70),
],
),
"
╭─
│
1 │ foo bar
┆
3 │ look, a fish 🐟 and a hook 🪝
┆ ┬
┆ │
┆ ╰───────────────────── hello
4 │ this is getting silly
──╯
"
);
}
#[test]
fn n1bn1() {
assert_eq!(
format(SRC, [Label::new(4..4), Label::new(70..70)]),
"
╭─
│
1 │ foo bar
┆
4 │ this is getting silly
──╯
"
);
}
#[test]
fn n1bs1() {
assert_eq!(
format(SRC, [Label::new(4..4), Label::new(70..70).with_snake()]),
"
╭─
│
1 │ foo bar
┆
4 │ this is getting silly
┆ ─
──╯
"
);
}
#[test]
fn n1bs1_style() {
assert_eq!(
format(
SRC,
[
Label::new(0..3).with_style(true),
Label::new(70..70).with_snake(),
],
),
"
╭─
│
1 │ <span>foo</span> bar
┆
4 │ this is getting silly
┆ ─
──╯
"
);
}
#[test]
fn s1bn1() {
assert_eq!(
format(SRC, [Label::new(4..4).with_snake(), Label::new(70..70)],),
"
╭─
│
1 │ foo bar
┆ ─
┆
4 │ this is getting silly
──╯
"
);
}