mirror of https://github.com/helix-editor/helix
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.8 KiB
Rust
223 lines
5.8 KiB
Rust
1 year ago
|
use std::rc::Rc;
|
||
|
|
||
|
use crate::doc_formatter::{DocumentFormatter, TextFormat};
|
||
|
use crate::text_annotations::{InlineAnnotation, Overlay, TextAnnotations};
|
||
|
|
||
|
impl TextFormat {
|
||
|
fn new_test(softwrap: bool) -> Self {
|
||
|
TextFormat {
|
||
|
soft_wrap: softwrap,
|
||
|
tab_width: 2,
|
||
|
max_wrap: 3,
|
||
|
max_indent_retain: 4,
|
||
|
wrap_indicator: ".".into(),
|
||
|
wrap_indicator_highlight: None,
|
||
|
// use a prime number to allow lining up too often with repeat
|
||
|
viewport_width: 17,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'t> DocumentFormatter<'t> {
|
||
|
fn collect_to_str(&mut self) -> String {
|
||
|
use std::fmt::Write;
|
||
|
let mut res = String::new();
|
||
|
let viewport_width = self.text_fmt.viewport_width;
|
||
|
let mut line = 0;
|
||
|
|
||
|
for (grapheme, pos) in self {
|
||
|
if pos.row != line {
|
||
|
line += 1;
|
||
|
assert_eq!(pos.row, line);
|
||
|
write!(res, "\n{}", ".".repeat(pos.col)).unwrap();
|
||
|
assert!(
|
||
|
pos.col <= viewport_width as usize,
|
||
|
"softwrapped failed {}<={viewport_width}",
|
||
|
pos.col
|
||
|
);
|
||
|
}
|
||
|
write!(res, "{}", grapheme.grapheme).unwrap();
|
||
|
}
|
||
|
|
||
|
res
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn softwrap_text(text: &str) -> String {
|
||
|
DocumentFormatter::new_at_prev_checkpoint(
|
||
|
text.into(),
|
||
|
&TextFormat::new_test(true),
|
||
|
&TextAnnotations::default(),
|
||
|
0,
|
||
|
)
|
||
|
.0
|
||
|
.collect_to_str()
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn basic_softwrap() {
|
||
|
assert_eq!(
|
||
|
softwrap_text(&"foo ".repeat(10)),
|
||
|
"foo foo foo foo \n.foo foo foo foo \n.foo foo "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
softwrap_text(&"fooo ".repeat(10)),
|
||
|
"fooo fooo fooo \n.fooo fooo fooo \n.fooo fooo fooo \n.fooo "
|
||
|
);
|
||
|
|
||
|
// check that we don't wrap unnecessarily
|
||
|
assert_eq!(softwrap_text("\t\txxxx1xxxx2xx\n"), " xxxx1xxxx2xx \n ");
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn softwrap_indentation() {
|
||
|
assert_eq!(
|
||
|
softwrap_text("\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
|
||
|
" foo1 foo2 \n.....foo3 foo4 \n.....foo5 foo6 \n "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
softwrap_text("\t\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
|
||
|
" foo1 foo2 \n.foo3 foo4 foo5 \n.foo6 \n "
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn long_word_softwrap() {
|
||
|
assert_eq!(
|
||
|
softwrap_text("\t\txxxx1xxxx2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
|
||
|
" xxxx1xxxx2xxx\n.....x3xxxx4xxxx5\n.....xxxx6xxxx7xx\n.....xx8xxxx9xxx \n "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
softwrap_text("xxxxxxxx1xxxx2xxx\n"),
|
||
|
"xxxxxxxx1xxxx2xxx\n. \n "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
softwrap_text("\t\txxxx1xxxx 2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
|
||
|
" xxxx1xxxx \n.....2xxxx3xxxx4x\n.....xxx5xxxx6xxx\n.....x7xxxx8xxxx9\n.....xxx \n "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
softwrap_text("\t\txxxx1xxx 2xxxx3xxxx4xxxx5xxxx6xxxx7xxxx8xxxx9xxx\n"),
|
||
|
" xxxx1xxx 2xxx\n.....x3xxxx4xxxx5\n.....xxxx6xxxx7xx\n.....xx8xxxx9xxx \n "
|
||
|
);
|
||
|
}
|
||
|
|
||
|
fn overlay_text(text: &str, char_pos: usize, softwrap: bool, overlays: &[Overlay]) -> String {
|
||
|
DocumentFormatter::new_at_prev_checkpoint(
|
||
|
text.into(),
|
||
|
&TextFormat::new_test(softwrap),
|
||
|
TextAnnotations::default().add_overlay(overlays.into(), None),
|
||
|
char_pos,
|
||
|
)
|
||
|
.0
|
||
|
.collect_to_str()
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn overlay() {
|
||
|
assert_eq!(
|
||
|
overlay_text(
|
||
|
"foobar",
|
||
|
0,
|
||
|
false,
|
||
|
&[
|
||
|
Overlay {
|
||
|
char_idx: 0,
|
||
|
grapheme: "X".into(),
|
||
|
},
|
||
|
Overlay {
|
||
|
char_idx: 2,
|
||
|
grapheme: "\t".into(),
|
||
|
},
|
||
|
]
|
||
|
),
|
||
|
"Xo bar "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
overlay_text(
|
||
|
&"foo ".repeat(10),
|
||
|
0,
|
||
|
true,
|
||
|
&[
|
||
|
Overlay {
|
||
|
char_idx: 2,
|
||
|
grapheme: "\t".into(),
|
||
|
},
|
||
|
Overlay {
|
||
|
char_idx: 5,
|
||
|
grapheme: "\t".into(),
|
||
|
},
|
||
|
Overlay {
|
||
|
char_idx: 16,
|
||
|
grapheme: "X".into(),
|
||
|
},
|
||
|
]
|
||
|
),
|
||
|
"fo f o foo \n.foo Xoo foo foo \n.foo foo foo "
|
||
|
);
|
||
|
}
|
||
|
|
||
|
fn annotate_text(text: &str, softwrap: bool, annotations: &[InlineAnnotation]) -> String {
|
||
|
DocumentFormatter::new_at_prev_checkpoint(
|
||
|
text.into(),
|
||
|
&TextFormat::new_test(softwrap),
|
||
|
TextAnnotations::default().add_inline_annotations(annotations.into(), None),
|
||
|
0,
|
||
|
)
|
||
|
.0
|
||
|
.collect_to_str()
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn annotation() {
|
||
|
assert_eq!(
|
||
|
annotate_text(
|
||
|
"bar",
|
||
|
false,
|
||
|
&[InlineAnnotation {
|
||
|
char_idx: 0,
|
||
|
text: "foo".into(),
|
||
|
}]
|
||
|
),
|
||
|
"foobar "
|
||
|
);
|
||
|
assert_eq!(
|
||
|
annotate_text(
|
||
|
&"foo ".repeat(10),
|
||
|
true,
|
||
|
&[InlineAnnotation {
|
||
|
char_idx: 0,
|
||
|
text: "foo ".into(),
|
||
|
}]
|
||
|
),
|
||
|
"foo foo foo foo \n.foo foo foo foo \n.foo foo foo "
|
||
|
);
|
||
|
}
|
||
|
#[test]
|
||
|
fn annotation_and_overlay() {
|
||
|
assert_eq!(
|
||
|
DocumentFormatter::new_at_prev_checkpoint(
|
||
|
"bbar".into(),
|
||
|
&TextFormat::new_test(false),
|
||
|
TextAnnotations::default()
|
||
|
.add_inline_annotations(
|
||
|
Rc::new([InlineAnnotation {
|
||
|
char_idx: 0,
|
||
|
text: "fooo".into(),
|
||
|
}]),
|
||
|
None
|
||
|
)
|
||
|
.add_overlay(
|
||
|
Rc::new([Overlay {
|
||
|
char_idx: 0,
|
||
|
grapheme: "\t".into(),
|
||
|
}]),
|
||
|
None
|
||
|
),
|
||
|
0,
|
||
|
)
|
||
|
.0
|
||
|
.collect_to_str(),
|
||
|
"fooo bar "
|
||
|
);
|
||
|
}
|