Handle zero-width graphemes (usually ill-formed) more gracefully.

This commit is contained in:
Nathan Vegdahl 2020-02-18 20:13:12 +09:00
parent a28629d8b4
commit d7d98946e5

View File

@ -5,8 +5,7 @@ use std::io::{BufWriter, Write};
use crossterm::{self, execute, queue}; use crossterm::{self, execute, queue};
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use crate::utils::grapheme_width;
use super::smallstring::SmallString; use super::smallstring::SmallString;
@ -93,9 +92,9 @@ impl Screen {
// Write everything to the buffered output. // Write everything to the buffered output.
for y in 0..self.h { for y in 0..self.h {
let mut x = 0; let mut x = 0;
queue!(out, crossterm::cursor::MoveTo(0, y as u16)).unwrap();
while x < self.w { while x < self.w {
if let Some((style, ref text)) = buf[y * self.w + x] { if let Some((style, ref text)) = buf[y * self.w + x] {
queue!(out, crossterm::cursor::MoveTo(x as u16, y as u16)).unwrap();
if style != last_style { if style != last_style {
queue!( queue!(
out, out,
@ -106,10 +105,8 @@ impl Screen {
last_style = style; last_style = style;
} }
write!(out, "{}", text).unwrap(); write!(out, "{}", text).unwrap();
x += 1;
} else {
x += 1;
} }
x += 1;
} }
} }
@ -133,16 +130,26 @@ impl Screen {
let mut buf = self.buf.borrow_mut(); let mut buf = self.buf.borrow_mut();
let mut x = x; let mut x = x;
for g in UnicodeSegmentation::graphemes(text, true) { for g in UnicodeSegmentation::graphemes(text, true) {
let width = grapheme_width(g); if x < self.w {
if width > 0 { let width = UnicodeWidthStr::width(g);
if x < self.w { if width > 0 {
buf[y * self.w + x] = Some((style, g.into())); buf[y * self.w + x] = Some((style, g.into()));
} x += 1;
x += 1; for _ in 1..width {
for _ in 0..(width - 1) { if x < self.w {
if x < self.w { buf[y * self.w + x] = None;
buf[y * self.w + x] = None; }
x += 1;
} }
} else {
// If it's a zero-width character, prepend a space
// to give it width. While this isn't strictly
// unicode compliant, it serves the purpose of this
// type of editor well by making all graphemes visible,
// even if they're otherwise illformed.
let mut graph = SmallString::from_str(" ");
graph.push_str(g);
buf[y * self.w + x] = Some((style, graph));
x += 1; x += 1;
} }
} }