mirror of https://github.com/helix-editor/helix
Merge c67da4552c
into 1315b7e2b1
commit
8b4791fbe4
|
@ -136,10 +136,6 @@ impl<'a> GraphemeWithSource<'a> {
|
||||||
fn width(&self) -> usize {
|
fn width(&self) -> usize {
|
||||||
self.grapheme.width()
|
self.grapheme.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_word_boundary(&self) -> bool {
|
|
||||||
self.grapheme.is_word_boundary()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -170,6 +166,10 @@ impl Default for TextFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap_allowed(x: Option<&Grapheme>, y: &Grapheme) -> bool {
|
||||||
|
x.is_some_and(|x| x.is_word_boundary() && (x.is_whitespace() || !y.is_word_boundary()))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DocumentFormatter<'t> {
|
pub struct DocumentFormatter<'t> {
|
||||||
text_fmt: &'t TextFormat,
|
text_fmt: &'t TextFormat,
|
||||||
|
@ -336,33 +336,25 @@ impl<'t> DocumentFormatter<'t> {
|
||||||
.change_position(visual_x, self.text_fmt.tab_width);
|
.change_position(visual_x, self.text_fmt.tab_width);
|
||||||
word_width += grapheme.width();
|
word_width += grapheme.width();
|
||||||
}
|
}
|
||||||
if let Some(grapheme) = &mut self.peeked_grapheme {
|
|
||||||
let visual_x = self.visual_pos.col + word_width;
|
|
||||||
grapheme
|
|
||||||
.grapheme
|
|
||||||
.change_position(visual_x, self.text_fmt.tab_width);
|
|
||||||
}
|
|
||||||
word_width
|
word_width
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_grapheme(&mut self, col: usize, char_pos: usize) -> Option<&GraphemeWithSource<'t>> {
|
fn peek_grapheme(&mut self, col: usize, char_pos: usize) -> Option<&GraphemeWithSource<'t>> {
|
||||||
if self.peeked_grapheme.is_none() {
|
match &mut self.peeked_grapheme {
|
||||||
self.peeked_grapheme = self.advance_grapheme(col, char_pos);
|
None => self.peeked_grapheme = self.advance_grapheme(col, char_pos),
|
||||||
|
Some(peeked_grapheme) => peeked_grapheme
|
||||||
|
.grapheme
|
||||||
|
.change_position(col, self.text_fmt.tab_width),
|
||||||
}
|
}
|
||||||
self.peeked_grapheme.as_ref()
|
self.peeked_grapheme.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_grapheme(&mut self, col: usize, char_pos: usize) -> Option<GraphemeWithSource<'t>> {
|
|
||||||
self.peek_grapheme(col, char_pos);
|
|
||||||
self.peeked_grapheme.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_to_next_word(&mut self) {
|
fn advance_to_next_word(&mut self) {
|
||||||
self.word_buf.clear();
|
self.word_buf.clear();
|
||||||
let mut word_width = 0;
|
let mut word_width = 0;
|
||||||
let mut word_chars = 0;
|
let mut word_chars = 0;
|
||||||
|
|
||||||
if self.exhausted {
|
if self.exhausted && self.peeked_grapheme.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +376,10 @@ impl<'t> DocumentFormatter<'t> {
|
||||||
if self.text_fmt.soft_wrap_at_text_width
|
if self.text_fmt.soft_wrap_at_text_width
|
||||||
&& self
|
&& self
|
||||||
.peek_grapheme(col, char_pos)
|
.peek_grapheme(col, char_pos)
|
||||||
.is_some_and(|grapheme| grapheme.is_newline() || grapheme.is_eof()) => {
|
.is_some_and(|grapheme| grapheme.is_newline() || grapheme.is_eof()) =>
|
||||||
|
{
|
||||||
|
self.word_buf.push(self.peeked_grapheme.take().unwrap());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Ordering::Equal if word_width > self.text_fmt.max_wrap as usize => return,
|
Ordering::Equal if word_width > self.text_fmt.max_wrap as usize => return,
|
||||||
Ordering::Greater if word_width > self.text_fmt.max_wrap as usize => {
|
Ordering::Greater if word_width > self.text_fmt.max_wrap as usize => {
|
||||||
|
@ -398,9 +393,22 @@ impl<'t> DocumentFormatter<'t> {
|
||||||
Ordering::Less => (),
|
Ordering::Less => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(grapheme) = self.next_grapheme(col, char_pos) else {
|
// It would be nice if this could be written as
|
||||||
|
// let Some(grapheme) = self.peek_grapheme(col, char_pos)
|
||||||
|
// but the borrow checker can't see inside of peek_grapheme and
|
||||||
|
// assumes that the return value borrows mutably from self.
|
||||||
|
let _ = self.peek_grapheme(col, char_pos);
|
||||||
|
let Some(grapheme) = &self.peeked_grapheme else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
if wrap_allowed(
|
||||||
|
self.word_buf.last().map(|g| &g.grapheme),
|
||||||
|
&grapheme.grapheme,
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let grapheme = self.peeked_grapheme.take().unwrap();
|
||||||
word_chars += grapheme.doc_chars();
|
word_chars += grapheme.doc_chars();
|
||||||
|
|
||||||
// Track indentation
|
// Track indentation
|
||||||
|
@ -410,13 +418,8 @@ impl<'t> DocumentFormatter<'t> {
|
||||||
self.indent_level = None;
|
self.indent_level = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_word_boundary = grapheme.is_word_boundary();
|
|
||||||
word_width += grapheme.width();
|
word_width += grapheme.width();
|
||||||
self.word_buf.push(grapheme);
|
self.word_buf.push(grapheme);
|
||||||
|
|
||||||
if is_word_boundary {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,10 @@ fn softwrap_indentation() {
|
||||||
softwrap_text("\t\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
|
softwrap_text("\t\t\tfoo1 foo2 foo3 foo4 foo5 foo6\n"),
|
||||||
" foo1 foo2 \n.foo3 foo4 foo5 \n.foo6 \n "
|
" foo1 foo2 \n.foo3 foo4 foo5 \n.foo6 \n "
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
softwrap_text("\t\tfoo1\n\t\tfoo2\n\t\tfoo3\n"),
|
||||||
|
" foo1 \n foo2 \n foo3 \n "
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -110,6 +114,18 @@ fn softwrap_multichar_grapheme() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn softwrap_punctuation() {
|
||||||
|
assert_eq!(
|
||||||
|
softwrap_text("asdfasdfasdfasd ...\n"),
|
||||||
|
"asdfasdfasdfasd \n.... \n "
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
softwrap_text("asdfasdfasdf a(bc)\n"),
|
||||||
|
"asdfasdfasdf a(\n.bc) \n "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn softwrap_text_at_text_width(text: &str) -> String {
|
fn softwrap_text_at_text_width(text: &str) -> String {
|
||||||
let mut text_fmt = TextFormat::new_test(true);
|
let mut text_fmt = TextFormat::new_test(true);
|
||||||
text_fmt.soft_wrap_at_text_width = true;
|
text_fmt.soft_wrap_at_text_width = true;
|
||||||
|
|
Loading…
Reference in New Issue