on master help sign in
Fix wrapping method to support unicode text

Related issues: - #787 - #811

commit944866affdf919ee1b1a7cbb1dcd9d613f863a9b authorKogia-sima <orcinus4627@gmail.com> dateSat 1 Feb 2020, 18:50 (7 years ago) parent22ded00
1 file changed+62−51
src/printer.rs+62−51
src/printer.rs+62−51
@@ -17,6 +17,8 @@ use content_inspector::ContentType;
1717use encoding::all::{UTF_16BE, UTF_16LE};
1818use encoding::{DecoderTrap, Encoding};
1919
20+use unicode_width::UnicodeWidthChar;
21+
2022use crate::assets::HighlightingAssets;
2123use crate::decorations::{
2224 Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration,
@@ -469,76 +471,85 @@ impl<'a> Printer for InteractivePrinter<'a> {
469471 &mut cursor_total,
470472 );
471473
472− let mut chars = text.chars();
473− let mut remaining = text.chars().count();
474−
475− while remaining > 0 {
476− let available = cursor_max - cursor;
474+ let max_width = cursor_max - cursor;
475+
476+ // line buffer (avoid calling write! for every character)
477+ let mut line_buf = String::with_capacity(max_width * 4);
478+
479+ // Displayed width of line_buf
480+ let mut current_width = 0;
481+
482+ for c in text.chars() {
483+ // calculate the displayed width for next character
484+ let cw = c.width().unwrap_or(0);
485+ current_width += cw;
486+
487+ // if next character cannot be printed on this line,
488+ // flush the buffer.
489+ if current_width > max_width {
490+ // Generate wrap padding if not already generated.
491+ if panel_wrap.is_none() {
492+ panel_wrap = if self.panel_width > 0 {
493+ Some(format!(
494+ "{} ",
495+ self.decorations
496+ .iter()
497+ .map(|ref d| d
498+ .generate(line_number, true, self)
499+ .text)
500+ .collect::<Vec<String>>()
501+ .join(" ")
502+ ))
503+ } else {
504+ Some("".to_string())
505+ }
506+ }
477507
478− // It fits.
479− if remaining <= available {
480− let text = chars.by_ref().take(remaining).collect::<String>();
481− cursor += remaining;
508+ cursor = 0;
482509
510+ // It wraps.
483511 write!(
484512 handle,
485− "{}",
513+ "{}\n{}",
486514 as_terminal_escaped(
487515 style,
488516 &*format!(
489517 "{}{}{}",
490− self.ansi_prefix_sgr, ansi_prefix, text
518+ self.ansi_prefix_sgr, ansi_prefix, line_buf
491519 ),
492520 self.config.true_color,
493521 self.config.colored_output,
494522 self.config.use_italic_text,
495523 background_color
496− )
524+ ),
525+ panel_wrap.clone().unwrap()
497526 )?;
498− break;
499− }
500527
501− // Generate wrap padding if not already generated.
502− if panel_wrap.is_none() {
503− panel_wrap = if self.panel_width > 0 {
504− Some(format!(
505− "{} ",
506− self.decorations
507− .iter()
508− .map(|ref d| d
509− .generate(line_number, true, self)
510− .text)
511− .collect::<Vec<String>>()
512− .join(" ")
513− ))
514− } else {
515− Some("".to_string())
516− }
528+ line_buf.clear();
529+ current_width = cw;
517530 }
518531
519− // It wraps.
520− let text = chars.by_ref().take(available).collect::<String>();
521− cursor = 0;
522− remaining -= available;
523−
524− write!(
525− handle,
526− "{}\n{}",
527− as_terminal_escaped(
528− style,
529− &*format!(
530− "{}{}{}",
531− self.ansi_prefix_sgr, ansi_prefix, text
532− ),
533− self.config.true_color,
534− self.config.colored_output,
535− self.config.use_italic_text,
536− background_color
537− ),
538− panel_wrap.clone().unwrap()
539− )?;
532+ line_buf.push(c);
540533 }
541534
535+ // flush the buffer
536+ cursor += current_width;
537+ write!(
538+ handle,
539+ "{}",
540+ as_terminal_escaped(
541+ style,
542+ &*format!(
543+ "{}{}{}",
544+ self.ansi_prefix_sgr, ansi_prefix, line_buf
545+ ),
546+ self.config.true_color,
547+ self.config.colored_output,
548+ self.config.use_italic_text,
549+ background_color
550+ )
551+ )?;
552+
542553 // Clear the ANSI prefix buffer.
543554 ansi_prefix.clear();
544555 }