aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Dürr <contact@christianduerr.com>2018-11-20 12:04:02 +0100
committerChristian Dürr <contact@christianduerr.com>2018-11-21 09:59:21 +0100
commitcf886872d0d2cf0bc7ee1da60e36da001ab13253 (patch)
tree23390be3eba0dab56c36b2105ef581b448a74e56
parent2ede659134936fe294f454a6b2247e1918af6f51 (diff)
downloadalacritty-zerowidth.tar.gz
alacritty-zerowidth.zip
Before cloning everythingzerowidth
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/grid/mod.rs2
-rw-r--r--src/lib.rs1
-rw-r--r--src/renderer/mod.rs57
-rw-r--r--src/term/cell.rs138
-rw-r--r--src/term/mod.rs30
7 files changed, 182 insertions, 48 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ee074986..c9bead4c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -53,6 +53,7 @@ dependencies = [
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"terminfo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 65293281..9ed83952 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -50,6 +50,7 @@ static_assertions = "0.3.0"
terminfo = "0.6.1"
url = "1.7.1"
time = "0.1.40"
+smallvec = "0.6.6"
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies]
x11-dl = "2"
diff --git a/src/grid/mod.rs b/src/grid/mod.rs
index 9e15bd02..ee2d359e 100644
--- a/src/grid/mod.rs
+++ b/src/grid/mod.rs
@@ -758,7 +758,7 @@ impl<'a, T: 'a> DisplayIter<'a, T> {
}
}
-impl<'a, T: Copy + 'a> Iterator for DisplayIter<'a, T> {
+impl<'a, T: Copy + Clone + 'a> Iterator for DisplayIter<'a, T> {
type Item = Indexed<T>;
#[inline]
diff --git a/src/lib.rs b/src/lib.rs
index 7ba3538b..da714a9e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -65,6 +65,7 @@ extern crate base64;
extern crate terminfo;
extern crate url;
extern crate time;
+extern crate smallvec;
#[macro_use]
pub mod macros;
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index ef5a1e76..0676d13d 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -31,7 +31,7 @@ use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use Rgb;
use config::{self, Config, Delta};
-use term::{self, cell, RenderableCell};
+use term::{self, cell, RenderableCell, CellContent};
use glutin::dpi::PhysicalSize;
// Shader paths for live reload
@@ -835,7 +835,7 @@ impl<'a> RenderApi<'a> {
.map(|(i, c)| RenderableCell {
line,
column: col + i,
- c,
+ c: CellContent::SingleChar(c),
bg: color,
fg: Rgb { r: 0, g: 0, b: 0 },
flags: cell::Flags::empty(),
@@ -879,35 +879,38 @@ impl<'a> RenderApi<'a> {
glyph_cache.font_key
};
- let mut glyph_key = GlyphKey {
- font_key,
- size: glyph_cache.font_size,
- c: cell.c,
- };
-
- // Don't render text of HIDDEN cells
- if cell.flags.contains(cell::Flags::HIDDEN) {
- glyph_key.c = ' ';
- }
-
- // Add cell to batch
- {
- let glyph = glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, glyph);
- }
-
- // FIXME This is a super hacky way to do underlined text. During
- // a time crunch to release 0.1, this seemed like a really
- // easy, clean hack.
- if cell.flags.contains(cell::Flags::UNDERLINE) {
- let glyph_key = GlyphKey {
+ // TODO: Skip this iteration if cell is hidden, don't draw underline multiple times
+ for character in cell.c.iter() {
+ let mut glyph_key = GlyphKey {
font_key,
size: glyph_cache.font_size,
- c: '_',
+ c: character,
};
- let underscore = glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, underscore);
+ // Don't render text of HIDDEN cells
+ if cell.flags.contains(cell::Flags::HIDDEN) {
+ glyph_key.c = ' ';
+ }
+
+ // Add cell to batch
+ {
+ let glyph = glyph_cache.get(glyph_key, self);
+ self.add_render_item(&cell, glyph);
+ }
+
+ // FIXME This is a super hacky way to do underlined text. During
+ // a time crunch to release 0.1, this seemed like a really
+ // easy, clean hack.
+ if cell.flags.contains(cell::Flags::UNDERLINE) {
+ let glyph_key = GlyphKey {
+ font_key,
+ size: glyph_cache.font_size,
+ c: '_',
+ };
+
+ let underscore = glyph_cache.get(glyph_key, self);
+ self.add_render_item(&cell, underscore);
+ }
}
}
}
diff --git a/src/term/cell.rs b/src/term/cell.rs
index ef8509dc..9a986088 100644
--- a/src/term/cell.rs
+++ b/src/term/cell.rs
@@ -11,6 +11,13 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+use std::fmt;
+
+use smallvec::SmallVec;
+use serde::de::{SeqAccess, Visitor};
+use serde::ser::SerializeSeq;
+use serde::{Serialize, Deserialize, Serializer, Deserializer};
+
use ansi::{NamedColor, Color};
use grid;
use index::Column;
@@ -31,9 +38,128 @@ bitflags! {
}
}
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum CellContent {
+ SingleChar(char),
+ MultiChar([char; 3]),
+}
+
+impl CellContent {
+ #[inline]
+ fn is_empty(&self) -> bool {
+ match *self {
+ CellContent::SingleChar(c) => c == ' ',
+ CellContent::MultiChar(_) => false,
+ }
+ }
+
+ #[inline]
+ pub fn primary(&self) -> char {
+ match self {
+ CellContent::SingleChar(c) => *c,
+ CellContent::MultiChar(c) => c[0],
+ }
+ }
+
+ #[inline]
+ pub fn iter<'a>(&'a self) -> CellContentIter<'a> {
+ CellContentIter::new(self)
+ }
+}
+
+impl Serialize for CellContent {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match self {
+ CellContent::SingleChar(c) => serializer.serialize_char(*c),
+ CellContent::MultiChar(c) => {
+ let mut seq = serializer.serialize_seq(Some(c.len()))?;
+ for element in c {
+ seq.serialize_element(&element)?;
+ }
+ seq.end()
+ },
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for CellContent {
+ fn deserialize<D>(deserializer: D) -> Result<CellContent, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct CellContentVisitor;
+
+ impl<'a> Visitor<'a> for CellContentVisitor {
+ type Value = CellContent;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "a char or an array of chars")
+ }
+
+ fn visit_char<E>(self, value: char) -> ::std::result::Result<CellContent, E>
+ where E: ::serde::de::Error
+ {
+ Ok(CellContent::SingleChar(value))
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'a>,
+ {
+ let mut array = [' ', 3];
+ let index = 0;
+ while let Some(value) = seq.next_element::<char>()? {
+ array[index] = value;
+ }
+ Ok(CellContent::MultiChar(array))
+ }
+ }
+
+ deserializer.deserialize_any(CellContentVisitor)
+ }
+}
+
+pub struct CellContentIter<'a> {
+ inner: &'a CellContent,
+ index: usize,
+}
+
+impl<'a> CellContentIter<'a> {
+ fn new(inner: &'a CellContent) -> CellContentIter<'a> {
+ CellContentIter {
+ inner,
+ index: 0,
+ }
+ }
+}
+
+impl<'a> Iterator for CellContentIter<'a> {
+ type Item = char;
+
+ fn next(&mut self) -> Option<char> {
+ let res = match self.inner {
+ CellContent::SingleChar(c) => if self.index > 0 {
+ None
+ } else {
+ Some(*c)
+ },
+ CellContent::MultiChar(c) => if self.index >= c.len() {
+ None
+ } else {
+ Some(c[self.index])
+ }
+ };
+ self.index += 1;
+ res
+ }
+}
+
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct Cell {
- pub c: char,
+ pub c: CellContent,
pub fg: Color,
pub bg: Color,
pub flags: Flags,
@@ -65,7 +191,7 @@ impl LineLength for grid::Row<Cell> {
}
for (index, cell) in self[..].iter().rev().enumerate() {
- if cell.c != ' ' {
+ if !cell.c.is_empty() {
length = Column(self.len() - index);
break;
}
@@ -93,7 +219,7 @@ impl Cell {
pub fn new(c: char, fg: Color, bg: Color) -> Cell {
Cell {
- c,
+ c: CellContent::SingleChar(c),
bg,
fg,
flags: Flags::empty(),
@@ -102,9 +228,9 @@ impl Cell {
#[inline]
pub fn is_empty(&self) -> bool {
- self.c == ' ' &&
- self.bg == Color::Named(NamedColor::Background) &&
- !self.flags.intersects(Flags::INVERSE | Flags::UNDERLINE)
+ self.c.is_empty()
+ && self.bg == Color::Named(NamedColor::Background)
+ && !self.flags.intersects(Flags::INVERSE | Flags::UNDERLINE)
}
#[inline]
diff --git a/src/term/mod.rs b/src/term/mod.rs
index 5107dc2d..68eee7f6 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -35,7 +35,7 @@ use logging::LoggerProxy;
pub mod cell;
pub mod color;
-pub use self::cell::Cell;
+pub use self::cell::{Cell, CellContent};
use self::cell::LineLength;
const URL_SEPARATOR_CHARS: [char; 3] = [' ', '"', '\''];
@@ -62,7 +62,7 @@ impl Search for Term {
let last_col = self.grid.num_cols() - Column(1);
while let Some(cell) = iter.prev() {
- if self.semantic_escape_chars.contains(cell.c) {
+ if self.semantic_escape_chars.contains(cell.c.primary()) {
break;
}
@@ -84,7 +84,7 @@ impl Search for Term {
let last_col = self.grid.num_cols() - Column(1);
while let Some(cell) = iter.next() {
- if self.semantic_escape_chars.contains(cell.c) {
+ if self.semantic_escape_chars.contains(cell.c.primary()) {
break;
}
@@ -112,16 +112,16 @@ impl Search for Term {
// Put all characters until separators into a string
let mut buf = String::new();
while let Some(cell) = iterb.prev() {
- if URL_SEPARATOR_CHARS.contains(&cell.c) {
+ if URL_SEPARATOR_CHARS.contains(&cell.c.primary()) {
break;
}
- buf.insert(0, cell.c);
+ buf.insert(0, cell.c.primary());
}
for cell in iterf {
- if URL_SEPARATOR_CHARS.contains(&cell.c) {
+ if URL_SEPARATOR_CHARS.contains(&cell.c.primary()) {
break;
}
- buf.push(cell.c);
+ buf.push(cell.c.primary());
}
// Heuristic to remove all leading '('
@@ -290,7 +290,7 @@ impl<'a> RenderableCellsIter<'a> {
cursor_cell.bg = cursor_color;
let mut wide_cell = cursor_cell;
- wide_cell.c = ' ';
+ wide_cell.c = CellContent::SingleChar(' ');
self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
}
@@ -300,11 +300,11 @@ impl<'a> RenderableCellsIter<'a> {
let mut cursor_cell = self.grid[self.cursor];
let cursor_color = self.config.cursor_cursor_color().unwrap_or(cursor_cell.fg);
- cursor_cell.c = cursor_cell_char;
+ cursor_cell.c = CellContent::SingleChar(cursor_cell_char);
cursor_cell.fg = cursor_color;
let mut wide_cell = cursor_cell;
- wide_cell.c = wide_cell_char;
+ wide_cell.c = CellContent::SingleChar(wide_cell_char);
self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
}
@@ -424,7 +424,7 @@ pub struct RenderableCell {
/// A _Display_ line (not necessarily an _Active_ line)
pub line: Line,
pub column: Column,
- pub c: char,
+ pub c: CellContent,
pub fg: Rgb,
pub bg: Rgb,
pub bg_alpha: f32,
@@ -1029,7 +1029,9 @@ impl Term {
} else if cols.start < line_end {
for cell in &grid_line[cols.start..line_end] {
if !cell.flags.contains(cell::Flags::WIDE_CHAR_SPACER) {
- self.push(cell.c);
+ for character in cell.c.iter() {
+ self.push(character);
+ }
}
}
@@ -1386,7 +1388,7 @@ impl ansi::Handler for Term {
let cell = &mut self.grid[&self.cursor.point];
*cell = self.cursor.template;
- cell.c = self.cursor.charsets[self.active_charset].map(c);
+ cell.c = CellContent::SingleChar(self.cursor.charsets[self.active_charset].map(c));
// Handle wide chars
if width == 2 {
@@ -1416,7 +1418,7 @@ impl ansi::Handler for Term {
fn dectest(&mut self) {
trace!("dectest");
let mut template = self.cursor.template;
- template.c = 'E';
+ template.c = CellContent::SingleChar('E');
self.grid.region_mut(..)
.each(|c| c.reset(&template));