Fix wrapping method to support unicode text

Related issues:
- #787
- #811
This commit is contained in:
Kogia-sima 2020-02-01 18:50:34 +09:00 committed by David Peter
parent 22ded00824
commit 944866affd
1 changed files with 64 additions and 53 deletions

View File

@ -17,6 +17,8 @@ use content_inspector::ContentType;
use encoding::all::{UTF_16BE, UTF_16LE}; use encoding::all::{UTF_16BE, UTF_16LE};
use encoding::{DecoderTrap, Encoding}; use encoding::{DecoderTrap, Encoding};
use unicode_width::UnicodeWidthChar;
use crate::assets::HighlightingAssets; use crate::assets::HighlightingAssets;
use crate::decorations::{ use crate::decorations::{
Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration, Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration,
@ -469,76 +471,85 @@ impl<'a> Printer for InteractivePrinter<'a> {
&mut cursor_total, &mut cursor_total,
); );
let mut chars = text.chars(); let max_width = cursor_max - cursor;
let mut remaining = text.chars().count();
while remaining > 0 { // line buffer (avoid calling write! for every character)
let available = cursor_max - cursor; let mut line_buf = String::with_capacity(max_width * 4);
// It fits. // Displayed width of line_buf
if remaining <= available { let mut current_width = 0;
let text = chars.by_ref().take(remaining).collect::<String>();
cursor += remaining;
for c in text.chars() {
// calculate the displayed width for next character
let cw = c.width().unwrap_or(0);
current_width += cw;
// if next character cannot be printed on this line,
// flush the buffer.
if current_width > max_width {
// Generate wrap padding if not already generated.
if panel_wrap.is_none() {
panel_wrap = if self.panel_width > 0 {
Some(format!(
"{} ",
self.decorations
.iter()
.map(|ref d| d
.generate(line_number, true, self)
.text)
.collect::<Vec<String>>()
.join(" ")
))
} else {
Some("".to_string())
}
}
cursor = 0;
// It wraps.
write!( write!(
handle, handle,
"{}", "{}\n{}",
as_terminal_escaped( as_terminal_escaped(
style, style,
&*format!( &*format!(
"{}{}{}", "{}{}{}",
self.ansi_prefix_sgr, ansi_prefix, text self.ansi_prefix_sgr, ansi_prefix, line_buf
), ),
self.config.true_color, self.config.true_color,
self.config.colored_output, self.config.colored_output,
self.config.use_italic_text, self.config.use_italic_text,
background_color background_color
)
)?;
break;
}
// Generate wrap padding if not already generated.
if panel_wrap.is_none() {
panel_wrap = if self.panel_width > 0 {
Some(format!(
"{} ",
self.decorations
.iter()
.map(|ref d| d
.generate(line_number, true, self)
.text)
.collect::<Vec<String>>()
.join(" ")
))
} else {
Some("".to_string())
}
}
// It wraps.
let text = chars.by_ref().take(available).collect::<String>();
cursor = 0;
remaining -= available;
write!(
handle,
"{}\n{}",
as_terminal_escaped(
style,
&*format!(
"{}{}{}",
self.ansi_prefix_sgr, ansi_prefix, text
), ),
self.config.true_color, panel_wrap.clone().unwrap()
self.config.colored_output, )?;
self.config.use_italic_text,
background_color line_buf.clear();
), current_width = cw;
panel_wrap.clone().unwrap() }
)?;
line_buf.push(c);
} }
// flush the buffer
cursor += current_width;
write!(
handle,
"{}",
as_terminal_escaped(
style,
&*format!(
"{}{}{}",
self.ansi_prefix_sgr, ansi_prefix, line_buf
),
self.config.true_color,
self.config.colored_output,
self.config.use_italic_text,
background_color
)
)?;
// Clear the ANSI prefix buffer. // Clear the ANSI prefix buffer.
ansi_prefix.clear(); ansi_prefix.clear();
} }