summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/grid/row.rs
diff options
context:
space:
mode:
authorTheodore Dubois <tblodt@icloud.com>2019-04-28 06:24:58 -0700
committerChristian Duerr <chrisduerr@users.noreply.github.com>2019-04-28 13:24:58 +0000
commitdbd8538762ef8968a493e1bf996e8693479ca783 (patch)
tree32ac2a6a5e01238a272d4ba534551d2e42903c7a /alacritty_terminal/src/grid/row.rs
parent9c6d12ea2c863ba76015bdedc00db13b7307725a (diff)
downloadalacritty-dbd8538762ef8968a493e1bf996e8693479ca783.tar.gz
alacritty-dbd8538762ef8968a493e1bf996e8693479ca783.zip
Split alacritty into a separate crates
The crate containing the entry point is called alacritty, and the crate containing everything else is called alacritty_terminal.
Diffstat (limited to 'alacritty_terminal/src/grid/row.rs')
-rw-r--r--alacritty_terminal/src/grid/row.rs264
1 files changed, 264 insertions, 0 deletions
diff --git a/alacritty_terminal/src/grid/row.rs b/alacritty_terminal/src/grid/row.rs
new file mode 100644
index 00000000..88a23871
--- /dev/null
+++ b/alacritty_terminal/src/grid/row.rs
@@ -0,0 +1,264 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// 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.
+
+//! Defines the Row type which makes up lines in the grid
+
+use std::cmp::{max, min};
+use std::ops::{Index, IndexMut};
+use std::ops::{Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive};
+use std::slice;
+
+use crate::grid::GridCell;
+use crate::index::Column;
+
+/// A row in the grid
+#[derive(Default, Clone, Debug, Serialize, Deserialize)]
+pub struct Row<T> {
+ inner: Vec<T>,
+
+ /// occupied entries
+ ///
+ /// Semantically, this value can be understood as the **end** of an
+ /// Exclusive Range. Thus,
+ ///
+ /// - Zero means there are no occupied entries
+ /// - 1 means there is a value at index zero, but nowhere else
+ /// - `occ == inner.len` means every value is occupied
+ pub(crate) occ: usize,
+}
+
+impl<T: PartialEq> PartialEq for Row<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl<T: Copy> Row<T> {
+ pub fn new(columns: Column, template: &T) -> Row<T> {
+ Row { inner: vec![*template; *columns], occ: 0 }
+ }
+
+ pub fn grow(&mut self, cols: Column, template: &T) {
+ if self.inner.len() >= cols.0 {
+ return;
+ }
+
+ self.inner.append(&mut vec![*template; cols.0 - self.len()]);
+ }
+
+ pub fn shrink(&mut self, cols: Column) -> Option<Vec<T>>
+ where
+ T: GridCell,
+ {
+ if self.inner.len() <= cols.0 {
+ return None;
+ }
+
+ // Split off cells for a new row
+ let mut new_row = self.inner.split_off(cols.0);
+ let index = new_row.iter().rposition(|c| !c.is_empty()).map(|i| i + 1).unwrap_or(0);
+ new_row.truncate(index);
+
+ self.occ = min(self.occ, *cols);
+
+ if new_row.is_empty() {
+ None
+ } else {
+ Some(new_row)
+ }
+ }
+
+ /// Resets contents to the contents of `other`
+ #[inline(never)]
+ pub fn reset(&mut self, other: &T) {
+ for item in &mut self.inner[..self.occ] {
+ *item = *other;
+ }
+ self.occ = 0;
+ }
+}
+
+#[allow(clippy::len_without_is_empty)]
+impl<T> Row<T> {
+ #[inline]
+ pub fn from_vec(vec: Vec<T>, occ: usize) -> Row<T> {
+ Row { inner: vec, occ }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn last(&self) -> Option<&T> {
+ self.inner.last()
+ }
+
+ #[inline]
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ self.occ = self.inner.len();
+ self.inner.last_mut()
+ }
+
+ #[inline]
+ pub fn append(&mut self, vec: &mut Vec<T>)
+ where
+ T: GridCell,
+ {
+ self.inner.append(vec);
+ self.occ = self.inner.iter().rposition(|c| !c.is_empty()).map(|i| i + 1).unwrap_or(0);
+ }
+
+ #[inline]
+ pub fn append_front(&mut self, mut vec: Vec<T>) {
+ self.occ += vec.len();
+ vec.append(&mut self.inner);
+ self.inner = vec;
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool
+ where
+ T: GridCell,
+ {
+ self.inner.iter().all(GridCell::is_empty)
+ }
+
+ #[inline]
+ pub fn front_split_off(&mut self, at: usize) -> Vec<T> {
+ self.occ = self.occ.saturating_sub(at);
+
+ let mut split = self.inner.split_off(at);
+ std::mem::swap(&mut split, &mut self.inner);
+ split
+ }
+}
+
+impl<'a, T> IntoIterator for &'a mut Row<T> {
+ type IntoIter = slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+
+ #[inline]
+ fn into_iter(self) -> slice::IterMut<'a, T> {
+ self.occ = self.len();
+ self.inner.iter_mut()
+ }
+}
+
+impl<T> Index<Column> for Row<T> {
+ type Output = T;
+
+ #[inline]
+ fn index(&self, index: Column) -> &T {
+ &self.inner[index.0]
+ }
+}
+
+impl<T> IndexMut<Column> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: Column) -> &mut T {
+ self.occ = max(self.occ, *index + 1);
+ &mut self.inner[index.0]
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Index ranges of columns
+// -----------------------------------------------------------------------------
+
+impl<T> Index<Range<Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: Range<Column>) -> &[T] {
+ &self.inner[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<Range<Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: Range<Column>) -> &mut [T] {
+ self.occ = max(self.occ, *index.end);
+ &mut self.inner[(index.start.0)..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeTo<Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: RangeTo<Column>) -> &[T] {
+ &self.inner[..(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<RangeTo<Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeTo<Column>) -> &mut [T] {
+ self.occ = max(self.occ, *index.end);
+ &mut self.inner[..(index.end.0)]
+ }
+}
+
+impl<T> Index<RangeFrom<Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: RangeFrom<Column>) -> &[T] {
+ &self.inner[(index.start.0)..]
+ }
+}
+
+impl<T> IndexMut<RangeFrom<Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeFrom<Column>) -> &mut [T] {
+ self.occ = self.len();
+ &mut self.inner[(index.start.0)..]
+ }
+}
+
+impl<T> Index<RangeFull> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, _: RangeFull) -> &[T] {
+ &self.inner[..]
+ }
+}
+
+impl<T> IndexMut<RangeFull> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
+ self.occ = self.len();
+ &mut self.inner[..]
+ }
+}
+
+impl<T> Index<RangeToInclusive<Column>> for Row<T> {
+ type Output = [T];
+
+ #[inline]
+ fn index(&self, index: RangeToInclusive<Column>) -> &[T] {
+ &self.inner[..=(index.end.0)]
+ }
+}
+
+impl<T> IndexMut<RangeToInclusive<Column>> for Row<T> {
+ #[inline]
+ fn index_mut(&mut self, index: RangeToInclusive<Column>) -> &mut [T] {
+ self.occ = max(self.occ, *index.end);
+ &mut self.inner[..=(index.end.0)]
+ }
+}