1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use unicode_width::UnicodeWidthChar as _;
const CODEPOINTS_IN_CELL: usize = 6;
/// Represents a single terminal cell.
#[derive(Clone, Debug, Default, Eq)]
pub struct Cell {
contents: [char; CODEPOINTS_IN_CELL],
len: u8,
attrs: crate::attrs::Attrs,
}
impl PartialEq<Self> for Cell {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}
if self.attrs != other.attrs {
return false;
}
let len = self.len();
// self.len() always returns a valid value
self.contents[..len] == other.contents[..len]
}
}
impl Cell {
#[inline]
fn len(&self) -> usize {
usize::from(self.len & 0x0f)
}
pub(crate) fn set(&mut self, c: char, a: crate::attrs::Attrs) {
self.contents[0] = c;
self.len = 1;
// strings in this context should always be an arbitrary character
// followed by zero or more zero-width characters, so we should only
// have to look at the first character
self.set_wide(c.width().unwrap_or(1) > 1);
self.attrs = a;
}
pub(crate) fn append(&mut self, c: char) {
let len = self.len();
if len >= CODEPOINTS_IN_CELL {
return;
}
if len == 0 {
// 0 is always less than 6
self.contents[0] = ' ';
self.len += 1;
}
let len = self.len();
// we already checked that len < CODEPOINTS_IN_CELL
self.contents[len] = c;
self.len += 1;
}
pub(crate) fn clear(&mut self, attrs: crate::attrs::Attrs) {
self.len = 0;
self.attrs = attrs;
}
/// Returns the text contents of the cell.
///
/// Can include multiple unicode characters if combining characters are
/// used, but will contain at most one character with a non-zero character
/// width.
#[must_use]
pub fn contents(&self) -> String {
let mut s = String::with_capacity(CODEPOINTS_IN_CELL * 4);
for c in self.contents.iter().take(self.len()) {
s.push(*c);
}
s
}
/// Returns whether the cell contains any text data.
#[must_use]
pub fn has_contents(&self) -> bool {
self.len > 0
}
/// Returns whether the text data in the cell represents a wide character.
#[must_use]
pub fn is_wide(&self) -> bool {
self.len & 0x80 == 0x80
}
/// Returns whether the cell contains the second half of a wide character
/// (in other words, whether the previous cell in the row contains a wide
/// character)
#[must_use]
pub fn is_wide_continuation(&self) -> bool {
self.len & 0x40 == 0x40
}
fn set_wide(&mut self, wide: bool) {
if wide {
self.len |= 0x80;
} else {
self.len &= 0x7f;
}
}
pub(crate) fn set_wide_continuation(&mut self, wide: bool) {
if wide {
self.len |= 0x40;
} else {
self.len &= 0xbf;
}
}
pub(crate) fn attrs(&self) -> &crate::attrs::Attrs {
&self.attrs
}
/// Returns the foreground color of the cell.
#[must_use]
pub fn fgcolor(&self) -> crate::attrs::Color {
self.attrs.fgcolor
}
/// Returns the background color of the cell.
#[must_use]
pub fn bgcolor(&self) -> crate::attrs::Color {
self.attrs.bgcolor
}
/// Returns whether the cell should be rendered with the bold text
/// attribute.
#[must_use]
pub fn bold(&self) -> bool {
self.attrs.bold()
}
/// Returns whether the cell should be rendered with the italic text
/// attribute.
#[must_use]
pub fn italic(&self) -> bool {
self.attrs.italic()
}
/// Returns whether the cell should be rendered with the underlined text
/// attribute.
#[must_use]
pub fn underline(&self) -> bool {
self.attrs.underline()
}
/// Returns whether the cell should be rendered with the inverse text
/// attribute.
#[must_use]
pub fn inverse(&self) -> bool {
self.attrs.inverse()
}
}