Merge branch 'main' into wasm-status-bar
This commit is contained in:
commit
67dbd1d0e4
7 changed files with 1271 additions and 1215 deletions
795
src/panes/grid.rs
Normal file
795
src/panes/grid.rs
Normal file
|
|
@ -0,0 +1,795 @@
|
||||||
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
|
use crate::panes::terminal_character::{
|
||||||
|
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn get_top_non_canonical_rows(rows: &mut Vec<Row>) -> Vec<Row> {
|
||||||
|
let mut index_of_last_non_canonical_row = None;
|
||||||
|
for (i, row) in rows.iter().enumerate() {
|
||||||
|
if row.is_canonical {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
index_of_last_non_canonical_row = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match index_of_last_non_canonical_row {
|
||||||
|
Some(index_of_last_non_canonical_row) => {
|
||||||
|
rows.drain(..=index_of_last_non_canonical_row).collect()
|
||||||
|
}
|
||||||
|
None => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bottom_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> {
|
||||||
|
let mut index_of_last_non_canonical_row = None;
|
||||||
|
for (i, row) in rows.iter().enumerate().rev() {
|
||||||
|
if row.is_canonical {
|
||||||
|
index_of_last_non_canonical_row = Some(i);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
index_of_last_non_canonical_row = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match index_of_last_non_canonical_row {
|
||||||
|
Some(index_of_last_non_canonical_row) => {
|
||||||
|
rows.drain(index_of_last_non_canonical_row..).collect()
|
||||||
|
}
|
||||||
|
None => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_rows_down(
|
||||||
|
source: &mut Vec<Row>,
|
||||||
|
destination: &mut Vec<Row>,
|
||||||
|
count: usize,
|
||||||
|
max_src_width: Option<usize>,
|
||||||
|
max_dst_width: Option<usize>,
|
||||||
|
) {
|
||||||
|
let mut next_lines: Vec<Row> = vec![];
|
||||||
|
let mut lines_added_to_destination: isize = 0;
|
||||||
|
loop {
|
||||||
|
if lines_added_to_destination as usize == count {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if next_lines.is_empty() {
|
||||||
|
match source.pop() {
|
||||||
|
Some(next_line) => {
|
||||||
|
let mut top_non_canonical_rows_in_dst = get_top_non_canonical_rows(destination);
|
||||||
|
lines_added_to_destination -= top_non_canonical_rows_in_dst.len() as isize;
|
||||||
|
next_lines.push(next_line);
|
||||||
|
next_lines.append(&mut top_non_canonical_rows_in_dst);
|
||||||
|
next_lines = match max_dst_width {
|
||||||
|
Some(max_row_width) => {
|
||||||
|
Row::from_rows(next_lines).split_to_rows_of_length(max_row_width)
|
||||||
|
}
|
||||||
|
None => vec![Row::from_rows(next_lines)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
None => break, // no more rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destination.insert(0, next_lines.pop().unwrap());
|
||||||
|
lines_added_to_destination += 1;
|
||||||
|
}
|
||||||
|
if !next_lines.is_empty() {
|
||||||
|
match max_src_width {
|
||||||
|
Some(max_row_width) => {
|
||||||
|
let mut excess_rows =
|
||||||
|
Row::from_rows(next_lines).split_to_rows_of_length(max_row_width);
|
||||||
|
source.append(&mut excess_rows);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let excess_row = Row::from_rows(next_lines);
|
||||||
|
source.push(excess_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_rows_up(
|
||||||
|
source: &mut Vec<Row>,
|
||||||
|
destination: &mut Vec<Row>,
|
||||||
|
count: usize,
|
||||||
|
max_src_width: Option<usize>,
|
||||||
|
max_dst_width: Option<usize>,
|
||||||
|
) {
|
||||||
|
let mut next_lines: Vec<Row> = vec![];
|
||||||
|
for _ in 0..count {
|
||||||
|
if next_lines.is_empty() {
|
||||||
|
if source.len() > 0 {
|
||||||
|
let next_line = source.remove(0);
|
||||||
|
if !next_line.is_canonical {
|
||||||
|
let mut bottom_canonical_row_and_wraps_in_dst =
|
||||||
|
get_bottom_canonical_row_and_wraps(destination);
|
||||||
|
next_lines.append(&mut bottom_canonical_row_and_wraps_in_dst);
|
||||||
|
}
|
||||||
|
next_lines.push(next_line);
|
||||||
|
next_lines = match max_dst_width {
|
||||||
|
Some(max_row_width) => {
|
||||||
|
Row::from_rows(next_lines).split_to_rows_of_length(max_row_width)
|
||||||
|
}
|
||||||
|
None => vec![Row::from_rows(next_lines)],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
break; // no more rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destination.push(next_lines.remove(0));
|
||||||
|
}
|
||||||
|
if !next_lines.is_empty() {
|
||||||
|
match max_src_width {
|
||||||
|
Some(max_row_width) => {
|
||||||
|
let excess_rows = Row::from_rows(next_lines).split_to_rows_of_length(max_row_width);
|
||||||
|
for row in excess_rows {
|
||||||
|
source.insert(0, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let excess_row = Row::from_rows(next_lines);
|
||||||
|
source.insert(0, excess_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Grid {
|
||||||
|
lines_above: Vec<Row>,
|
||||||
|
viewport: Vec<Row>,
|
||||||
|
lines_below: Vec<Row>,
|
||||||
|
cursor: Cursor,
|
||||||
|
scroll_region: Option<(usize, usize)>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Grid {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
for (i, row) in self.viewport.iter().enumerate() {
|
||||||
|
if row.is_canonical {
|
||||||
|
writeln!(f, "{:?} (C): {:?}", i, row)?;
|
||||||
|
} else {
|
||||||
|
writeln!(f, "{:?} (W): {:?}", i, row)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
pub fn new(rows: usize, columns: usize) -> Self {
|
||||||
|
Grid {
|
||||||
|
lines_above: vec![],
|
||||||
|
viewport: vec![],
|
||||||
|
lines_below: vec![],
|
||||||
|
cursor: Cursor::new(0, 0),
|
||||||
|
scroll_region: None,
|
||||||
|
width: columns,
|
||||||
|
height: rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn cursor_canonical_line_index(&self) -> usize {
|
||||||
|
let mut cursor_canonical_line_index = 0;
|
||||||
|
let mut canonical_lines_traversed = 0;
|
||||||
|
for (i, line) in self.viewport.iter().enumerate() {
|
||||||
|
if line.is_canonical {
|
||||||
|
cursor_canonical_line_index = canonical_lines_traversed;
|
||||||
|
canonical_lines_traversed += 1;
|
||||||
|
}
|
||||||
|
if i == self.cursor.y {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor_canonical_line_index
|
||||||
|
}
|
||||||
|
// TODO: merge these two funtions
|
||||||
|
fn cursor_index_in_canonical_line(&self) -> usize {
|
||||||
|
let mut cursor_canonical_line_index = 0;
|
||||||
|
let mut cursor_index_in_canonical_line = 0;
|
||||||
|
for (i, line) in self.viewport.iter().enumerate() {
|
||||||
|
if line.is_canonical {
|
||||||
|
cursor_canonical_line_index = i;
|
||||||
|
}
|
||||||
|
if i == self.cursor.y {
|
||||||
|
let line_wrap_position_in_line = self.cursor.y - cursor_canonical_line_index;
|
||||||
|
cursor_index_in_canonical_line = line_wrap_position_in_line + self.cursor.x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor_index_in_canonical_line
|
||||||
|
}
|
||||||
|
fn canonical_line_y_coordinates(&self, canonical_line_index: usize) -> usize {
|
||||||
|
let mut canonical_lines_traversed = 0;
|
||||||
|
let mut y_coordinates = 0;
|
||||||
|
for (i, line) in self.viewport.iter().enumerate() {
|
||||||
|
if line.is_canonical {
|
||||||
|
canonical_lines_traversed += 1;
|
||||||
|
if canonical_lines_traversed == canonical_line_index + 1 {
|
||||||
|
y_coordinates = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y_coordinates
|
||||||
|
}
|
||||||
|
pub fn scroll_up_one_line(&mut self) {
|
||||||
|
if self.lines_above.len() > 0 && self.viewport.len() == self.height {
|
||||||
|
let line_to_push_down = self.viewport.pop().unwrap();
|
||||||
|
self.lines_below.insert(0, line_to_push_down);
|
||||||
|
let line_to_insert_at_viewport_top = self.lines_above.pop().unwrap();
|
||||||
|
self.viewport.insert(0, line_to_insert_at_viewport_top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn scroll_down_one_line(&mut self) {
|
||||||
|
if self.lines_below.len() > 0 && self.viewport.len() == self.height {
|
||||||
|
let mut line_to_push_up = self.viewport.remove(0);
|
||||||
|
if line_to_push_up.is_canonical {
|
||||||
|
self.lines_above.push(line_to_push_up);
|
||||||
|
} else {
|
||||||
|
let mut last_line_above = self.lines_above.pop().unwrap();
|
||||||
|
last_line_above.append(&mut line_to_push_up.columns);
|
||||||
|
self.lines_above.push(last_line_above);
|
||||||
|
}
|
||||||
|
let line_to_insert_at_viewport_bottom = self.lines_below.remove(0);
|
||||||
|
self.viewport.push(line_to_insert_at_viewport_bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn change_size(&mut self, new_rows: usize, new_columns: usize) {
|
||||||
|
if new_columns != self.width {
|
||||||
|
let mut cursor_canonical_line_index = self.cursor_canonical_line_index();
|
||||||
|
let cursor_index_in_canonical_line = self.cursor_index_in_canonical_line();
|
||||||
|
let mut viewport_canonical_lines = vec![];
|
||||||
|
for mut row in self.viewport.drain(..) {
|
||||||
|
if !row.is_canonical
|
||||||
|
&& viewport_canonical_lines.is_empty()
|
||||||
|
&& self.lines_above.len() > 0
|
||||||
|
{
|
||||||
|
let mut first_line_above = self.lines_above.pop().unwrap();
|
||||||
|
first_line_above.append(&mut row.columns);
|
||||||
|
viewport_canonical_lines.push(first_line_above);
|
||||||
|
cursor_canonical_line_index += 1;
|
||||||
|
} else if row.is_canonical {
|
||||||
|
viewport_canonical_lines.push(row);
|
||||||
|
} else {
|
||||||
|
match viewport_canonical_lines.last_mut() {
|
||||||
|
Some(last_line) => {
|
||||||
|
last_line.append(&mut row.columns);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// the state is corrupted somehow
|
||||||
|
// this is a bug and I'm not yet sure why it happens
|
||||||
|
// usually it fixes itself and is a result of some race
|
||||||
|
// TODO: investigate why this happens and solve it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut new_viewport_rows = vec![];
|
||||||
|
for mut canonical_line in viewport_canonical_lines {
|
||||||
|
let mut canonical_line_parts: Vec<Row> = vec![];
|
||||||
|
while canonical_line.columns.len() > 0 {
|
||||||
|
let next_wrap = if canonical_line.len() > new_columns {
|
||||||
|
canonical_line.columns.drain(..new_columns)
|
||||||
|
} else {
|
||||||
|
canonical_line.columns.drain(..)
|
||||||
|
};
|
||||||
|
let row = Row::from_columns(next_wrap.collect());
|
||||||
|
// if there are no more parts, this row is canonical as long as it originall
|
||||||
|
// was canonical (it might not have been for example if it's the first row in
|
||||||
|
// the viewport, and the actual canonical row is above it in the scrollback)
|
||||||
|
let row = if canonical_line_parts.len() == 0 && canonical_line.is_canonical {
|
||||||
|
row.canonical()
|
||||||
|
} else {
|
||||||
|
row
|
||||||
|
};
|
||||||
|
canonical_line_parts.push(row);
|
||||||
|
}
|
||||||
|
new_viewport_rows.append(&mut canonical_line_parts);
|
||||||
|
}
|
||||||
|
self.viewport = new_viewport_rows;
|
||||||
|
|
||||||
|
let mut new_cursor_y = self.canonical_line_y_coordinates(cursor_canonical_line_index);
|
||||||
|
let new_cursor_x = (cursor_index_in_canonical_line / new_columns)
|
||||||
|
+ (cursor_index_in_canonical_line % new_columns);
|
||||||
|
let current_viewport_row_count = self.viewport.len();
|
||||||
|
if current_viewport_row_count < self.height {
|
||||||
|
let row_count_to_transfer = self.height - current_viewport_row_count;
|
||||||
|
transfer_rows_down(
|
||||||
|
&mut self.lines_above,
|
||||||
|
&mut self.viewport,
|
||||||
|
row_count_to_transfer,
|
||||||
|
None,
|
||||||
|
Some(new_columns),
|
||||||
|
);
|
||||||
|
let rows_pulled = self.viewport.len() - current_viewport_row_count;
|
||||||
|
new_cursor_y += rows_pulled;
|
||||||
|
} else if current_viewport_row_count > self.height {
|
||||||
|
let row_count_to_transfer = current_viewport_row_count - self.height;
|
||||||
|
if row_count_to_transfer > new_cursor_y {
|
||||||
|
new_cursor_y = 0;
|
||||||
|
} else {
|
||||||
|
new_cursor_y -= row_count_to_transfer;
|
||||||
|
}
|
||||||
|
transfer_rows_up(
|
||||||
|
&mut self.viewport,
|
||||||
|
&mut self.lines_above,
|
||||||
|
row_count_to_transfer,
|
||||||
|
Some(new_columns),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.cursor.y = new_cursor_y;
|
||||||
|
self.cursor.x = new_cursor_x;
|
||||||
|
}
|
||||||
|
if new_rows != self.height {
|
||||||
|
let current_viewport_row_count = self.viewport.len();
|
||||||
|
if current_viewport_row_count < new_rows {
|
||||||
|
let row_count_to_transfer = new_rows - current_viewport_row_count;
|
||||||
|
transfer_rows_down(
|
||||||
|
&mut self.lines_above,
|
||||||
|
&mut self.viewport,
|
||||||
|
row_count_to_transfer,
|
||||||
|
None,
|
||||||
|
Some(new_columns),
|
||||||
|
);
|
||||||
|
let rows_pulled = self.viewport.len() - current_viewport_row_count;
|
||||||
|
self.cursor.y += rows_pulled;
|
||||||
|
} else if current_viewport_row_count > new_rows {
|
||||||
|
let row_count_to_transfer = current_viewport_row_count - new_rows;
|
||||||
|
if row_count_to_transfer > self.cursor.y {
|
||||||
|
self.cursor.y = 0;
|
||||||
|
} else {
|
||||||
|
self.cursor.y -= row_count_to_transfer;
|
||||||
|
}
|
||||||
|
transfer_rows_up(
|
||||||
|
&mut self.viewport,
|
||||||
|
&mut self.lines_above,
|
||||||
|
row_count_to_transfer,
|
||||||
|
Some(new_columns),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.height = new_rows;
|
||||||
|
self.width = new_columns;
|
||||||
|
if self.scroll_region.is_some() {
|
||||||
|
self.set_scroll_region_to_viewport_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn as_character_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
||||||
|
let mut lines: Vec<Vec<TerminalCharacter>> = self
|
||||||
|
.viewport
|
||||||
|
.iter()
|
||||||
|
.map(|r| {
|
||||||
|
let mut line: Vec<TerminalCharacter> = r.columns.iter().copied().collect();
|
||||||
|
for _ in line.len()..self.width {
|
||||||
|
// pad line
|
||||||
|
line.push(EMPTY_TERMINAL_CHARACTER);
|
||||||
|
}
|
||||||
|
line
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let empty_row = vec![EMPTY_TERMINAL_CHARACTER; self.width];
|
||||||
|
for _ in lines.len()..self.height {
|
||||||
|
lines.push(empty_row.clone());
|
||||||
|
}
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
||||||
|
if self.cursor.is_hidden {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((self.cursor.x, self.cursor.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_viewport_up(&mut self, count: usize) {
|
||||||
|
for _ in 0..count {
|
||||||
|
self.scroll_up_one_line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_viewport_down(&mut self, count: usize) {
|
||||||
|
for _ in 0..count {
|
||||||
|
self.scroll_down_one_line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn reset_viewport(&mut self) {
|
||||||
|
let row_count_below = self.lines_below.len();
|
||||||
|
for _ in 0..row_count_below {
|
||||||
|
self.scroll_down_one_line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn rotate_scroll_region_up(&mut self, _count: usize) {
|
||||||
|
// TBD
|
||||||
|
}
|
||||||
|
pub fn rotate_scroll_region_down(&mut self, _count: usize) {
|
||||||
|
// TBD
|
||||||
|
}
|
||||||
|
pub fn add_canonical_line(&mut self) {
|
||||||
|
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
||||||
|
if self.cursor.y == scroll_region_bottom {
|
||||||
|
// end of scroll region
|
||||||
|
// when we have a scroll region set and we're at its bottom
|
||||||
|
// we need to delete its first line, thus shifting all lines in it upwards
|
||||||
|
// then we add an empty line at its end which will be filled by the application
|
||||||
|
// controlling the scroll region (presumably filled by whatever comes next in the
|
||||||
|
// scroll buffer, but that's not something we control)
|
||||||
|
self.viewport.remove(scroll_region_top);
|
||||||
|
self.viewport
|
||||||
|
.insert(scroll_region_bottom, Row::new().canonical());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.viewport.len() <= self.cursor.y + 1 {
|
||||||
|
let new_row = Row::new().canonical();
|
||||||
|
self.viewport.push(new_row);
|
||||||
|
}
|
||||||
|
if self.cursor.y == self.height - 1 {
|
||||||
|
let row_count_to_transfer = 1;
|
||||||
|
transfer_rows_up(
|
||||||
|
&mut self.viewport,
|
||||||
|
&mut self.lines_above,
|
||||||
|
row_count_to_transfer,
|
||||||
|
Some(self.width),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.cursor.y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_cursor_to_beginning_of_line(&mut self) {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
}
|
||||||
|
pub fn move_cursor_backwards(&mut self, count: usize) {
|
||||||
|
if self.cursor.x > count {
|
||||||
|
self.cursor.x -= count;
|
||||||
|
} else {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn insert_character_at_cursor_position(&mut self, terminal_character: TerminalCharacter) {
|
||||||
|
match self.viewport.get_mut(self.cursor.y) {
|
||||||
|
Some(row) => row.add_character_at(terminal_character, self.cursor.x),
|
||||||
|
None => {
|
||||||
|
// pad lines until cursor if they do not exist
|
||||||
|
for _ in self.viewport.len()..self.cursor.y {
|
||||||
|
self.viewport.push(Row::new().canonical());
|
||||||
|
}
|
||||||
|
self.viewport
|
||||||
|
.push(Row::new().with_character(terminal_character).canonical());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_character(&mut self, terminal_character: TerminalCharacter) {
|
||||||
|
// TODO: try to separate adding characters from moving the cursors in this function
|
||||||
|
if self.cursor.x < self.width {
|
||||||
|
self.insert_character_at_cursor_position(terminal_character);
|
||||||
|
} else {
|
||||||
|
// line wrap
|
||||||
|
self.cursor.x = 0;
|
||||||
|
if self.cursor.y == self.height - 1 {
|
||||||
|
let row_count_to_transfer = 1;
|
||||||
|
transfer_rows_up(
|
||||||
|
&mut self.viewport,
|
||||||
|
&mut self.lines_above,
|
||||||
|
row_count_to_transfer,
|
||||||
|
Some(self.width),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let wrapped_row = Row::new();
|
||||||
|
self.viewport.push(wrapped_row);
|
||||||
|
} else {
|
||||||
|
self.cursor.y += 1;
|
||||||
|
if self.viewport.len() <= self.cursor.y {
|
||||||
|
let line_wrapped_row = Row::new();
|
||||||
|
self.viewport.push(line_wrapped_row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.insert_character_at_cursor_position(terminal_character);
|
||||||
|
}
|
||||||
|
self.move_cursor_forward_until_edge(1);
|
||||||
|
}
|
||||||
|
pub fn move_cursor_forward_until_edge(&mut self, count: usize) {
|
||||||
|
let count_to_move = std::cmp::min(count, self.width - (self.cursor.x));
|
||||||
|
self.cursor.x += count_to_move;
|
||||||
|
}
|
||||||
|
pub fn replace_characters_in_line_after_cursor(&mut self, replace_with: TerminalCharacter) {
|
||||||
|
self.viewport
|
||||||
|
.get_mut(self.cursor.y)
|
||||||
|
.unwrap()
|
||||||
|
.truncate(self.cursor.x);
|
||||||
|
if self.cursor.x < self.width - 1 {
|
||||||
|
let mut characters_to_append = vec![replace_with; self.width - self.cursor.x];
|
||||||
|
self.viewport
|
||||||
|
.get_mut(self.cursor.y)
|
||||||
|
.unwrap()
|
||||||
|
.append(&mut characters_to_append);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn replace_characters_in_line_before_cursor(&mut self, replace_with: TerminalCharacter) {
|
||||||
|
let line_part = vec![replace_with; self.cursor.x];
|
||||||
|
let row = self.viewport.get_mut(self.cursor.y).unwrap();
|
||||||
|
row.replace_beginning_with(line_part);
|
||||||
|
}
|
||||||
|
pub fn clear_all_after_cursor(&mut self) {
|
||||||
|
self.viewport
|
||||||
|
.get_mut(self.cursor.y)
|
||||||
|
.unwrap()
|
||||||
|
.truncate(self.cursor.x);
|
||||||
|
self.viewport.truncate(self.cursor.y + 1);
|
||||||
|
}
|
||||||
|
pub fn clear_cursor_line(&mut self) {
|
||||||
|
self.viewport.get_mut(self.cursor.y).unwrap().truncate(0);
|
||||||
|
}
|
||||||
|
pub fn clear_all(&mut self) {
|
||||||
|
self.viewport.clear();
|
||||||
|
self.viewport.push(Row::new().canonical());
|
||||||
|
}
|
||||||
|
fn pad_current_line_until(&mut self, position: usize) {
|
||||||
|
let current_row = self.viewport.get_mut(self.cursor.y).unwrap();
|
||||||
|
for _ in current_row.len()..position {
|
||||||
|
current_row.push(EMPTY_TERMINAL_CHARACTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn pad_lines_until(&mut self, position: usize) {
|
||||||
|
for _ in self.viewport.len()..position {
|
||||||
|
self.viewport.push(Row::new().canonical());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_cursor_to(&mut self, x: usize, y: usize) {
|
||||||
|
self.cursor.x = x;
|
||||||
|
self.cursor.y = y;
|
||||||
|
self.pad_lines_until(self.cursor.y + 1);
|
||||||
|
self.pad_current_line_until(self.cursor.x);
|
||||||
|
}
|
||||||
|
pub fn move_cursor_up(&mut self, count: usize) {
|
||||||
|
self.cursor.y = if self.cursor.y < count {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
self.cursor.y - count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn move_cursor_up_with_scrolling(&mut self, count: usize) {
|
||||||
|
let (scroll_region_top, scroll_region_bottom) =
|
||||||
|
self.scroll_region.unwrap_or((0, self.height - 1));
|
||||||
|
for _ in 0..count {
|
||||||
|
let current_line_index = self.cursor.y;
|
||||||
|
if current_line_index == scroll_region_top {
|
||||||
|
// if we're at the top line, we create a new line and remove the last line that
|
||||||
|
// would otherwise overflow
|
||||||
|
self.viewport.remove(scroll_region_bottom);
|
||||||
|
self.viewport.insert(current_line_index, Row::new()); // TODO: .canonical() ?
|
||||||
|
} else if current_line_index > scroll_region_top
|
||||||
|
&& current_line_index <= scroll_region_bottom
|
||||||
|
{
|
||||||
|
self.move_cursor_up(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_cursor_down(&mut self, count: usize) {
|
||||||
|
let lines_to_add = if self.cursor.y + count > self.height - 1 {
|
||||||
|
(self.cursor.y + count) - (self.height - 1)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
self.cursor.y = if self.cursor.y + count > self.height - 1 {
|
||||||
|
self.height - 1
|
||||||
|
} else {
|
||||||
|
self.cursor.y + count
|
||||||
|
};
|
||||||
|
for _ in 0..lines_to_add {
|
||||||
|
self.add_canonical_line();
|
||||||
|
}
|
||||||
|
self.pad_lines_until(self.cursor.y);
|
||||||
|
}
|
||||||
|
pub fn move_cursor_back(&mut self, count: usize) {
|
||||||
|
if self.cursor.x < count {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
} else {
|
||||||
|
self.cursor.x -= count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn hide_cursor(&mut self) {
|
||||||
|
self.cursor.is_hidden = true;
|
||||||
|
}
|
||||||
|
pub fn show_cursor(&mut self) {
|
||||||
|
self.cursor.is_hidden = false;
|
||||||
|
}
|
||||||
|
pub fn set_scroll_region(&mut self, top_line_index: usize, bottom_line_index: usize) {
|
||||||
|
self.scroll_region = Some((top_line_index, bottom_line_index));
|
||||||
|
}
|
||||||
|
pub fn clear_scroll_region(&mut self) {
|
||||||
|
self.scroll_region = None;
|
||||||
|
}
|
||||||
|
pub fn set_scroll_region_to_viewport_size(&mut self) {
|
||||||
|
self.scroll_region = Some((0, self.height - 1));
|
||||||
|
}
|
||||||
|
pub fn delete_lines_in_scroll_region(&mut self, count: usize) {
|
||||||
|
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
||||||
|
let current_line_index = self.cursor.y;
|
||||||
|
if current_line_index >= scroll_region_top && current_line_index <= scroll_region_bottom
|
||||||
|
{
|
||||||
|
// when deleting lines inside the scroll region, we must make sure it stays the
|
||||||
|
// same size (and that other lines below it aren't shifted inside it)
|
||||||
|
// so we delete the current line(s) and add an empty line at the end of the scroll
|
||||||
|
// region
|
||||||
|
for _ in 0..count {
|
||||||
|
self.viewport.remove(current_line_index);
|
||||||
|
self.viewport.insert(scroll_region_bottom, Row::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_empty_lines_in_scroll_region(&mut self, count: usize) {
|
||||||
|
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
||||||
|
let current_line_index = self.cursor.y;
|
||||||
|
if current_line_index >= scroll_region_top && current_line_index <= scroll_region_bottom
|
||||||
|
{
|
||||||
|
// when adding empty lines inside the scroll region, we must make sure it stays the
|
||||||
|
// same size and that lines don't "leak" outside of it
|
||||||
|
// so we add an empty line where the cursor currently is, and delete the last line
|
||||||
|
// of the scroll region
|
||||||
|
for _ in 0..count {
|
||||||
|
self.viewport.remove(scroll_region_bottom);
|
||||||
|
self.viewport.insert(current_line_index, Row::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_cursor_to_column(&mut self, column: usize) {
|
||||||
|
self.cursor.x = column;
|
||||||
|
self.pad_current_line_until(self.cursor.x);
|
||||||
|
}
|
||||||
|
pub fn move_cursor_to_line(&mut self, line: usize) {
|
||||||
|
self.cursor.y = line;
|
||||||
|
self.pad_lines_until(self.cursor.y + 1);
|
||||||
|
self.pad_current_line_until(self.cursor.x);
|
||||||
|
}
|
||||||
|
pub fn replace_with_empty_chars(&mut self, count: usize, empty_char_style: CharacterStyles) {
|
||||||
|
let mut empty_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
|
empty_character.styles = empty_char_style;
|
||||||
|
let pad_until = std::cmp::min(self.width, self.cursor.x + count);
|
||||||
|
self.pad_current_line_until(pad_until);
|
||||||
|
let current_row = self.viewport.get_mut(self.cursor.y).unwrap();
|
||||||
|
for i in 0..count {
|
||||||
|
current_row.replace_character_at(empty_character, self.cursor.x + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn erase_characters(&mut self, count: usize, empty_char_style: CharacterStyles) {
|
||||||
|
let mut empty_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
|
empty_character.styles = empty_char_style;
|
||||||
|
let current_row = self.viewport.get_mut(self.cursor.y).unwrap();
|
||||||
|
for _ in 0..count {
|
||||||
|
current_row.delete_character(self.cursor.x);
|
||||||
|
}
|
||||||
|
let mut empty_space_to_append = vec![empty_character; count];
|
||||||
|
self.viewport
|
||||||
|
.get_mut(self.cursor.y)
|
||||||
|
.unwrap()
|
||||||
|
.append(&mut empty_space_to_append);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Row {
|
||||||
|
pub columns: Vec<TerminalCharacter>,
|
||||||
|
pub is_canonical: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Row {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
for character in &self.columns {
|
||||||
|
write!(f, "{:?}", character)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Row {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Row {
|
||||||
|
columns: vec![],
|
||||||
|
is_canonical: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_columns(columns: Vec<TerminalCharacter>) -> Self {
|
||||||
|
Row {
|
||||||
|
columns,
|
||||||
|
is_canonical: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_rows(mut rows: Vec<Row>) -> Self {
|
||||||
|
if rows.is_empty() {
|
||||||
|
Row::new()
|
||||||
|
} else {
|
||||||
|
let mut first_row = rows.remove(0);
|
||||||
|
for row in rows.iter_mut() {
|
||||||
|
first_row.append(&mut row.columns);
|
||||||
|
}
|
||||||
|
first_row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn with_character(mut self, terminal_character: TerminalCharacter) -> Self {
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn canonical(mut self) -> Self {
|
||||||
|
self.is_canonical = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn add_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) {
|
||||||
|
if x == self.columns.len() {
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
} else if x > self.columns.len() {
|
||||||
|
for _ in self.columns.len()..x {
|
||||||
|
self.columns.push(EMPTY_TERMINAL_CHARACTER);
|
||||||
|
}
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
} else {
|
||||||
|
// this is much more performant than remove/insert
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
self.columns.swap_remove(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn replace_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) {
|
||||||
|
// this is much more performant than remove/insert
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
self.columns.swap_remove(x);
|
||||||
|
}
|
||||||
|
pub fn push(&mut self, terminal_character: TerminalCharacter) {
|
||||||
|
self.columns.push(terminal_character);
|
||||||
|
}
|
||||||
|
pub fn truncate(&mut self, x: usize) {
|
||||||
|
self.columns.truncate(x);
|
||||||
|
}
|
||||||
|
pub fn append(&mut self, to_append: &mut Vec<TerminalCharacter>) {
|
||||||
|
self.columns.append(to_append);
|
||||||
|
}
|
||||||
|
pub fn replace_beginning_with(&mut self, mut line_part: Vec<TerminalCharacter>) {
|
||||||
|
drop(self.columns.drain(0..line_part.len()));
|
||||||
|
line_part.append(&mut self.columns);
|
||||||
|
self.columns = line_part;
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.columns.len()
|
||||||
|
}
|
||||||
|
pub fn delete_character(&mut self, x: usize) {
|
||||||
|
self.columns.remove(x);
|
||||||
|
}
|
||||||
|
pub fn split_to_rows_of_length(&mut self, max_row_length: usize) -> Vec<Row> {
|
||||||
|
let mut parts: Vec<Row> = vec![];
|
||||||
|
let mut current_part: Vec<TerminalCharacter> = vec![];
|
||||||
|
for character in self.columns.drain(..) {
|
||||||
|
if current_part.len() == max_row_length {
|
||||||
|
parts.push(Row::from_columns(current_part));
|
||||||
|
current_part = vec![];
|
||||||
|
}
|
||||||
|
current_part.push(character);
|
||||||
|
}
|
||||||
|
if current_part.len() > 0 {
|
||||||
|
parts.push(Row::from_columns(current_part))
|
||||||
|
};
|
||||||
|
if parts.len() > 0 && self.is_canonical {
|
||||||
|
parts.get_mut(0).unwrap().is_canonical = true;
|
||||||
|
}
|
||||||
|
parts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Cursor {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
is_hidden: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cursor {
|
||||||
|
pub fn new(x: usize, y: usize) -> Self {
|
||||||
|
Cursor {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
is_hidden: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
mod grid;
|
||||||
mod plugin_pane;
|
mod plugin_pane;
|
||||||
mod scroll;
|
|
||||||
mod terminal_character;
|
mod terminal_character;
|
||||||
mod terminal_pane;
|
mod terminal_pane;
|
||||||
|
|
||||||
|
pub use grid::*;
|
||||||
pub use plugin_pane::*;
|
pub use plugin_pane::*;
|
||||||
pub use scroll::*;
|
|
||||||
pub use terminal_character::*;
|
pub use terminal_character::*;
|
||||||
pub use terminal_pane::*;
|
pub use terminal_pane::*;
|
||||||
|
|
|
||||||
|
|
@ -1,838 +0,0 @@
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::{
|
|
||||||
cmp::max,
|
|
||||||
fmt::{self, Debug, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::panes::terminal_character::{
|
|
||||||
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Scroll
|
|
||||||
*
|
|
||||||
* holds the terminal buffer and controls the viewport (which part of it we see)
|
|
||||||
* its functions include line-wrapping and tracking the location of the cursor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CanonicalLine vs. WrappedFragment
|
|
||||||
*
|
|
||||||
* If the terminal had infinite width and we did not need to line wrap, the CanonicalLine would
|
|
||||||
* be our only unit of line separation.
|
|
||||||
* Each CanonicalLine has one or more WrappedFragments, which are re-calculated when the terminal is
|
|
||||||
* resized, or when characters are added to the line
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CanonicalLine {
|
|
||||||
pub wrapped_fragments: Vec<WrappedFragment>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CanonicalLine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CanonicalLine {
|
|
||||||
wrapped_fragments: vec![WrappedFragment::new()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add_new_wrap(&mut self, terminal_character: TerminalCharacter) {
|
|
||||||
let mut new_fragment = WrappedFragment::new();
|
|
||||||
new_fragment.add_character(terminal_character, 0);
|
|
||||||
self.wrapped_fragments.push(new_fragment);
|
|
||||||
}
|
|
||||||
pub fn change_width(&mut self, new_width: usize) {
|
|
||||||
let characters = self.flattened_characters();
|
|
||||||
let wrapped_fragments =
|
|
||||||
CanonicalLine::fill_fragments_up_to_width(characters, new_width, None);
|
|
||||||
self.wrapped_fragments = wrapped_fragments;
|
|
||||||
}
|
|
||||||
pub fn clear_after(&mut self, fragment_index: usize, column_index: usize) {
|
|
||||||
let fragment_to_clear = self
|
|
||||||
.wrapped_fragments
|
|
||||||
.get_mut(fragment_index)
|
|
||||||
.expect("fragment out of bounds");
|
|
||||||
fragment_to_clear.clear_after_and_including(column_index);
|
|
||||||
self.wrapped_fragments.truncate(fragment_index + 1);
|
|
||||||
}
|
|
||||||
pub fn replace_with_empty_chars(
|
|
||||||
&mut self,
|
|
||||||
fragment_index: usize,
|
|
||||||
from_col: usize,
|
|
||||||
count: usize,
|
|
||||||
style_of_empty_space: CharacterStyles,
|
|
||||||
) {
|
|
||||||
let mut characters_replaced = 0;
|
|
||||||
let mut column_position_in_fragment = from_col;
|
|
||||||
let mut current_fragment = fragment_index;
|
|
||||||
let mut empty_space_character = EMPTY_TERMINAL_CHARACTER;
|
|
||||||
empty_space_character.styles = style_of_empty_space;
|
|
||||||
loop {
|
|
||||||
if characters_replaced == count {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
match self.wrapped_fragments.get_mut(current_fragment) {
|
|
||||||
Some(fragment_to_clear) => {
|
|
||||||
let fragment_characters_count = fragment_to_clear.characters.len();
|
|
||||||
if fragment_characters_count >= column_position_in_fragment {
|
|
||||||
fragment_to_clear
|
|
||||||
.add_character(empty_space_character, column_position_in_fragment);
|
|
||||||
column_position_in_fragment += 1;
|
|
||||||
characters_replaced += 1;
|
|
||||||
} else {
|
|
||||||
current_fragment += 1;
|
|
||||||
column_position_in_fragment = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// end of line, nothing more to clear
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn erase_chars(
|
|
||||||
&mut self,
|
|
||||||
fragment_index: usize,
|
|
||||||
from_col: usize,
|
|
||||||
count: usize,
|
|
||||||
style_of_empty_space: CharacterStyles,
|
|
||||||
) {
|
|
||||||
let mut empty_character = EMPTY_TERMINAL_CHARACTER;
|
|
||||||
empty_character.styles = style_of_empty_space;
|
|
||||||
let current_width = self.wrapped_fragments.get(0).unwrap().characters.len();
|
|
||||||
let mut characters = self.flattened_characters();
|
|
||||||
let absolute_position_of_character = fragment_index * current_width + from_col;
|
|
||||||
for _ in 0..count {
|
|
||||||
characters.remove(absolute_position_of_character);
|
|
||||||
}
|
|
||||||
let wrapped_fragments = CanonicalLine::fill_fragments_up_to_width(
|
|
||||||
characters,
|
|
||||||
current_width,
|
|
||||||
Some(empty_character),
|
|
||||||
);
|
|
||||||
self.wrapped_fragments = wrapped_fragments;
|
|
||||||
}
|
|
||||||
pub fn replace_with_empty_chars_after_cursor(
|
|
||||||
&mut self,
|
|
||||||
fragment_index: usize,
|
|
||||||
from_col: usize,
|
|
||||||
total_columns: usize,
|
|
||||||
style_of_empty_space: CharacterStyles,
|
|
||||||
) {
|
|
||||||
let mut empty_char_character = EMPTY_TERMINAL_CHARACTER;
|
|
||||||
empty_char_character.styles = style_of_empty_space;
|
|
||||||
let current_fragment = self.wrapped_fragments.get_mut(fragment_index).unwrap();
|
|
||||||
let fragment_characters_count = current_fragment.characters.len();
|
|
||||||
|
|
||||||
for i in from_col..fragment_characters_count {
|
|
||||||
current_fragment.add_character(empty_char_character, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in fragment_characters_count..total_columns {
|
|
||||||
current_fragment.add_character(empty_char_character, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.wrapped_fragments.truncate(fragment_index + 1);
|
|
||||||
}
|
|
||||||
pub fn replace_with_empty_chars_before_cursor(
|
|
||||||
&mut self,
|
|
||||||
fragment_index: usize,
|
|
||||||
until_col: usize,
|
|
||||||
style_of_empty_space: CharacterStyles,
|
|
||||||
) {
|
|
||||||
let mut empty_char_character = EMPTY_TERMINAL_CHARACTER;
|
|
||||||
empty_char_character.styles = style_of_empty_space;
|
|
||||||
|
|
||||||
if fragment_index > 0 {
|
|
||||||
for i in 0..(fragment_index - 1) {
|
|
||||||
let fragment = self.wrapped_fragments.get_mut(i).unwrap();
|
|
||||||
for i in 0..fragment.characters.len() {
|
|
||||||
fragment.add_character(empty_char_character, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let current_fragment = self.wrapped_fragments.get_mut(fragment_index).unwrap();
|
|
||||||
for i in 0..until_col {
|
|
||||||
current_fragment.add_character(empty_char_character, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn flattened_characters(&self) -> Vec<TerminalCharacter> {
|
|
||||||
self.wrapped_fragments
|
|
||||||
.iter()
|
|
||||||
.fold(
|
|
||||||
Vec::with_capacity(self.wrapped_fragments.len()),
|
|
||||||
|mut characters, wrapped_fragment| {
|
|
||||||
characters.push(wrapped_fragment.characters.iter().copied());
|
|
||||||
characters
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
fn fill_fragments_up_to_width(
|
|
||||||
mut characters: Vec<TerminalCharacter>,
|
|
||||||
width: usize,
|
|
||||||
padding: Option<TerminalCharacter>,
|
|
||||||
) -> Vec<WrappedFragment> {
|
|
||||||
let mut wrapped_fragments = vec![];
|
|
||||||
while !characters.is_empty() {
|
|
||||||
if characters.len() > width {
|
|
||||||
wrapped_fragments.push(WrappedFragment::from_vec(
|
|
||||||
characters.drain(..width).collect(),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
let mut last_fragment = WrappedFragment::from_vec(characters.drain(..).collect());
|
|
||||||
let last_fragment_len = last_fragment.characters.len();
|
|
||||||
if let Some(empty_char_character) = padding {
|
|
||||||
if last_fragment_len < width {
|
|
||||||
for _ in last_fragment_len..width {
|
|
||||||
last_fragment.characters.push(empty_char_character);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wrapped_fragments.push(last_fragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if wrapped_fragments.is_empty() {
|
|
||||||
wrapped_fragments.push(WrappedFragment::new());
|
|
||||||
}
|
|
||||||
wrapped_fragments
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for CanonicalLine {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
for wrapped_fragment in &self.wrapped_fragments {
|
|
||||||
writeln!(f, "{:?}", wrapped_fragment)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct WrappedFragment {
|
|
||||||
pub characters: Vec<TerminalCharacter>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WrappedFragment {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
WrappedFragment { characters: vec![] }
|
|
||||||
}
|
|
||||||
pub fn add_character(
|
|
||||||
&mut self,
|
|
||||||
terminal_character: TerminalCharacter,
|
|
||||||
position_in_line: usize,
|
|
||||||
) {
|
|
||||||
if position_in_line == self.characters.len() {
|
|
||||||
self.characters.push(terminal_character);
|
|
||||||
} else {
|
|
||||||
// this is much more performant than remove/insert
|
|
||||||
self.characters.push(terminal_character);
|
|
||||||
self.characters.swap_remove(position_in_line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_vec(characters: Vec<TerminalCharacter>) -> Self {
|
|
||||||
WrappedFragment { characters }
|
|
||||||
}
|
|
||||||
pub fn clear_after_and_including(&mut self, character_index: usize) {
|
|
||||||
self.characters.truncate(character_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for WrappedFragment {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
for character in &self.characters {
|
|
||||||
write!(f, "{:?}", character)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct CursorPosition {
|
|
||||||
line_index: (usize, usize), // (canonical line index, fragment index in line)
|
|
||||||
column_index: usize, // 0 is the first character from the pane edge
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CursorPosition {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CursorPosition {
|
|
||||||
line_index: (0, 0),
|
|
||||||
column_index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_forward(&mut self, count: usize) {
|
|
||||||
// TODO: panic if out of bounds?
|
|
||||||
self.column_index += count;
|
|
||||||
}
|
|
||||||
pub fn move_backwards(&mut self, count: usize) {
|
|
||||||
self.column_index = u32::overflowing_sub(self.column_index as u32, count as u32).0 as usize;
|
|
||||||
}
|
|
||||||
pub fn move_to_next_linewrap(&mut self) {
|
|
||||||
self.line_index.1 += 1;
|
|
||||||
}
|
|
||||||
pub fn move_to_next_canonical_line(&mut self) {
|
|
||||||
self.line_index.0 += 1;
|
|
||||||
}
|
|
||||||
pub fn _move_to_prev_canonical_line(&mut self) {
|
|
||||||
self.line_index.0 -= 1;
|
|
||||||
}
|
|
||||||
pub fn move_to_beginning_of_linewrap(&mut self) {
|
|
||||||
self.column_index = 0;
|
|
||||||
}
|
|
||||||
pub fn move_to_beginning_of_canonical_line(&mut self) {
|
|
||||||
self.column_index = 0;
|
|
||||||
self.line_index.1 = 0;
|
|
||||||
}
|
|
||||||
pub fn move_down_by_canonical_lines(&mut self, count: usize) {
|
|
||||||
// this method does not verify that we will not overflow
|
|
||||||
let current_canonical_line_position = self.line_index.0;
|
|
||||||
self.line_index = (current_canonical_line_position + count, 0);
|
|
||||||
}
|
|
||||||
pub fn move_to_canonical_line(&mut self, index: usize) {
|
|
||||||
self.line_index = (index, 0);
|
|
||||||
}
|
|
||||||
pub fn move_to_column(&mut self, col: usize) {
|
|
||||||
self.column_index = col;
|
|
||||||
}
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.column_index = 0;
|
|
||||||
self.line_index = (0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Scroll {
|
|
||||||
canonical_lines: Vec<CanonicalLine>,
|
|
||||||
cursor_position: CursorPosition,
|
|
||||||
total_columns: usize,
|
|
||||||
lines_in_view: usize,
|
|
||||||
viewport_bottom_offset: Option<usize>,
|
|
||||||
scroll_region: Option<(usize, usize)>, // start line, end line (if set, this is the area the will scroll)
|
|
||||||
show_cursor: bool,
|
|
||||||
alternative_buffer: Option<Vec<CanonicalLine>>,
|
|
||||||
alternative_cursor_position: Option<CursorPosition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scroll {
|
|
||||||
pub fn new(total_columns: usize, lines_in_view: usize) -> Self {
|
|
||||||
let mut canonical_lines = vec![];
|
|
||||||
canonical_lines.push(CanonicalLine::new());
|
|
||||||
let cursor_position = CursorPosition::new();
|
|
||||||
Scroll {
|
|
||||||
canonical_lines: vec![CanonicalLine::new()], // The rest will be created by newlines explicitly
|
|
||||||
total_columns,
|
|
||||||
lines_in_view,
|
|
||||||
cursor_position,
|
|
||||||
viewport_bottom_offset: None,
|
|
||||||
scroll_region: None,
|
|
||||||
show_cursor: true,
|
|
||||||
alternative_buffer: None,
|
|
||||||
alternative_cursor_position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn as_character_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
|
||||||
let mut lines: VecDeque<Vec<TerminalCharacter>> = VecDeque::new(); // TODO: with capacity lines_from_end?
|
|
||||||
let canonical_lines = self.canonical_lines.iter().rev();
|
|
||||||
let mut lines_to_skip = self.viewport_bottom_offset.unwrap_or(0);
|
|
||||||
'gather_lines: for current_canonical_line in canonical_lines {
|
|
||||||
for wrapped_fragment in current_canonical_line.wrapped_fragments.iter().rev() {
|
|
||||||
let mut line: Vec<TerminalCharacter> =
|
|
||||||
wrapped_fragment.characters.iter().copied().collect();
|
|
||||||
if lines_to_skip > 0 {
|
|
||||||
lines_to_skip -= 1;
|
|
||||||
} else {
|
|
||||||
// pad line if needed
|
|
||||||
line.resize(self.total_columns, EMPTY_TERMINAL_CHARACTER);
|
|
||||||
lines.push_front(line);
|
|
||||||
}
|
|
||||||
if lines.len() == self.lines_in_view {
|
|
||||||
break 'gather_lines;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if lines.len() < self.lines_in_view {
|
|
||||||
// pad lines in case we don't have enough scrollback to fill the view
|
|
||||||
let empty_line = vec![EMPTY_TERMINAL_CHARACTER; self.total_columns];
|
|
||||||
|
|
||||||
for _ in lines.len()..self.lines_in_view {
|
|
||||||
// pad lines in case we didn't have enough
|
|
||||||
lines.push_back(empty_line.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vec::from(lines)
|
|
||||||
}
|
|
||||||
pub fn add_character(&mut self, terminal_character: TerminalCharacter) {
|
|
||||||
let (canonical_line_position, wrapped_fragment_index_in_line) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let cursor_position_in_line = self.cursor_position.column_index;
|
|
||||||
let current_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(canonical_line_position)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
let current_wrapped_fragment = current_line
|
|
||||||
.wrapped_fragments
|
|
||||||
.get_mut(wrapped_fragment_index_in_line)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
|
|
||||||
if cursor_position_in_line < self.total_columns {
|
|
||||||
current_wrapped_fragment.add_character(terminal_character, cursor_position_in_line);
|
|
||||||
self.cursor_position.move_forward(1);
|
|
||||||
} else {
|
|
||||||
current_line.add_new_wrap(terminal_character);
|
|
||||||
self.cursor_position.move_to_next_linewrap();
|
|
||||||
self.cursor_position.move_to_beginning_of_linewrap();
|
|
||||||
self.cursor_position.move_forward(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn show_cursor(&mut self) {
|
|
||||||
self.show_cursor = true;
|
|
||||||
}
|
|
||||||
pub fn hide_cursor(&mut self) {
|
|
||||||
self.show_cursor = false;
|
|
||||||
}
|
|
||||||
pub fn add_canonical_line(&mut self) {
|
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) =
|
|
||||||
self.scroll_region_absolute_indices()
|
|
||||||
{
|
|
||||||
if current_canonical_line_index == scroll_region_bottom {
|
|
||||||
// end of scroll region
|
|
||||||
// when we have a scroll region set and we're at its bottom
|
|
||||||
// we need to delete its first line, thus shifting all lines in it upwards
|
|
||||||
// then we add an empty line at its end which will be filled by the application
|
|
||||||
// controlling the scroll region (presumably filled by whatever comes next in the
|
|
||||||
// scroll buffer, but that's not something we control)
|
|
||||||
self.canonical_lines.remove(scroll_region_top);
|
|
||||||
self.canonical_lines
|
|
||||||
.insert(scroll_region_bottom, CanonicalLine::new());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
match current_canonical_line_index.cmp(&(self.canonical_lines.len() - 1)) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
self.canonical_lines.push(CanonicalLine::new());
|
|
||||||
self.cursor_position.move_to_next_canonical_line();
|
|
||||||
self.cursor_position.move_to_beginning_of_canonical_line();
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
self.cursor_position.move_to_next_canonical_line();
|
|
||||||
self.cursor_position.move_to_beginning_of_canonical_line();
|
|
||||||
}
|
|
||||||
_ => panic!("cursor out of bounds, cannot add_canonical_line"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn cursor_coordinates_on_screen(&self) -> Option<(usize, usize)> {
|
|
||||||
// (x, y)
|
|
||||||
if !self.show_cursor {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let (canonical_line_cursor_position, line_wrap_cursor_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let x = self.cursor_position.column_index;
|
|
||||||
let mut y = 0;
|
|
||||||
let indices_and_canonical_lines = self.canonical_lines.iter().enumerate().rev();
|
|
||||||
for (current_index, current_line) in indices_and_canonical_lines {
|
|
||||||
if current_index == canonical_line_cursor_position {
|
|
||||||
y += current_line.wrapped_fragments.len() - line_wrap_cursor_position;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
y += current_line.wrapped_fragments.len();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let total_lines = self
|
|
||||||
.canonical_lines
|
|
||||||
.iter()
|
|
||||||
.fold(0, |total_lines, current_line| {
|
|
||||||
total_lines + current_line.wrapped_fragments.len()
|
|
||||||
}); // TODO: is this performant enough? should it be cached or kept track of?
|
|
||||||
let y = if total_lines < self.lines_in_view {
|
|
||||||
total_lines - y
|
|
||||||
} else if y > self.lines_in_view {
|
|
||||||
self.lines_in_view
|
|
||||||
} else {
|
|
||||||
self.lines_in_view - y
|
|
||||||
};
|
|
||||||
Some((x, y))
|
|
||||||
}
|
|
||||||
pub fn move_cursor_forward(&mut self, count: usize) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
let current_fragment = current_canonical_line
|
|
||||||
.wrapped_fragments
|
|
||||||
.get_mut(current_line_wrap_position)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
let move_count = if current_cursor_column_position + count > self.total_columns {
|
|
||||||
// move to last column in the current line wrap
|
|
||||||
self.total_columns - current_cursor_column_position
|
|
||||||
} else {
|
|
||||||
count
|
|
||||||
};
|
|
||||||
|
|
||||||
current_fragment.characters.resize(
|
|
||||||
max(
|
|
||||||
current_fragment.characters.len(),
|
|
||||||
current_cursor_column_position + move_count,
|
|
||||||
),
|
|
||||||
EMPTY_TERMINAL_CHARACTER,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.cursor_position.move_forward(move_count);
|
|
||||||
}
|
|
||||||
pub fn move_cursor_back(&mut self, count: usize) {
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
if current_cursor_column_position < count {
|
|
||||||
self.cursor_position.move_to_beginning_of_linewrap();
|
|
||||||
} else {
|
|
||||||
self.cursor_position.move_backwards(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_cursor_to_beginning_of_linewrap(&mut self) {
|
|
||||||
self.cursor_position.move_to_beginning_of_linewrap();
|
|
||||||
}
|
|
||||||
pub fn _move_cursor_to_beginning_of_canonical_line(&mut self) {
|
|
||||||
self.cursor_position.move_to_beginning_of_canonical_line();
|
|
||||||
}
|
|
||||||
pub fn move_cursor_backwards(&mut self, count: usize) {
|
|
||||||
self.cursor_position.move_backwards(count);
|
|
||||||
}
|
|
||||||
pub fn move_cursor_up(&mut self, count: usize) {
|
|
||||||
for _ in 0..count {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_index) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
if current_line_wrap_index > 0 {
|
|
||||||
// go up one line-wrap
|
|
||||||
self.cursor_position.line_index.1 -= 1;
|
|
||||||
} else if current_canonical_line_index > 0 {
|
|
||||||
// go up to previous canonical line
|
|
||||||
self.cursor_position.line_index.0 -= 1;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get(self.cursor_position.line_index.0)
|
|
||||||
.unwrap();
|
|
||||||
let wraps_in_current_line = current_canonical_line.wrapped_fragments.len();
|
|
||||||
// make sure to only go up to the last wrap of the previous line
|
|
||||||
self.cursor_position.line_index.1 = wraps_in_current_line - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_cursor_down(&mut self, count: usize) {
|
|
||||||
let current_canonical_line = self.cursor_position.line_index.0;
|
|
||||||
let max_count = (self.canonical_lines.len() - 1) - current_canonical_line;
|
|
||||||
let count = std::cmp::min(count, max_count);
|
|
||||||
self.cursor_position.move_down_by_canonical_lines(count);
|
|
||||||
}
|
|
||||||
pub fn change_size(&mut self, columns: usize, lines: usize) {
|
|
||||||
for canonical_line in self.canonical_lines.iter_mut() {
|
|
||||||
canonical_line.change_width(columns);
|
|
||||||
}
|
|
||||||
let cursor_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get(self.cursor_position.line_index.0)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
if cursor_line.wrapped_fragments.len() <= self.cursor_position.line_index.1 {
|
|
||||||
self.cursor_position.line_index.1 = cursor_line.wrapped_fragments.len() - 1;
|
|
||||||
}
|
|
||||||
self.lines_in_view = lines;
|
|
||||||
self.total_columns = columns;
|
|
||||||
}
|
|
||||||
pub fn clear_canonical_line_right_of_cursor(&mut self, style_of_empty_space: CharacterStyles) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
current_canonical_line.replace_with_empty_chars_after_cursor(
|
|
||||||
current_line_wrap_position,
|
|
||||||
current_cursor_column_position,
|
|
||||||
self.total_columns,
|
|
||||||
style_of_empty_space,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn clear_canonical_line_left_of_cursor(&mut self, style_of_empty_space: CharacterStyles) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
current_canonical_line.replace_with_empty_chars_before_cursor(
|
|
||||||
current_line_wrap_position,
|
|
||||||
current_cursor_column_position,
|
|
||||||
style_of_empty_space,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn clear_all_after_cursor(&mut self) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
current_canonical_line
|
|
||||||
.clear_after(current_line_wrap_position, current_cursor_column_position);
|
|
||||||
self.canonical_lines
|
|
||||||
.truncate(current_canonical_line_index + 1);
|
|
||||||
}
|
|
||||||
pub fn replace_with_empty_chars(
|
|
||||||
&mut self,
|
|
||||||
count: usize,
|
|
||||||
style_of_empty_space: CharacterStyles,
|
|
||||||
) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
current_canonical_line.replace_with_empty_chars(
|
|
||||||
current_line_wrap_position,
|
|
||||||
current_cursor_column_position,
|
|
||||||
count,
|
|
||||||
style_of_empty_space,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn erase_characters(&mut self, count: usize, style_of_empty_space: CharacterStyles) {
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_cursor_column_position = self.cursor_position.column_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
current_canonical_line.erase_chars(
|
|
||||||
current_line_wrap_position,
|
|
||||||
current_cursor_column_position,
|
|
||||||
count,
|
|
||||||
style_of_empty_space,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn clear_all(&mut self) {
|
|
||||||
self.canonical_lines.clear();
|
|
||||||
self.canonical_lines.push(CanonicalLine::new());
|
|
||||||
self.cursor_position.reset();
|
|
||||||
}
|
|
||||||
pub fn move_cursor_to(&mut self, line: usize, col: usize) {
|
|
||||||
let line_on_screen = if self.canonical_lines.len() > self.lines_in_view {
|
|
||||||
line + (self.canonical_lines.len() - self.lines_in_view)
|
|
||||||
} else {
|
|
||||||
line
|
|
||||||
};
|
|
||||||
if self.canonical_lines.len() > line_on_screen {
|
|
||||||
self.cursor_position.move_to_canonical_line(line_on_screen);
|
|
||||||
} else {
|
|
||||||
for _ in self.canonical_lines.len()..=line_on_screen {
|
|
||||||
self.canonical_lines.push(CanonicalLine::new());
|
|
||||||
}
|
|
||||||
self.cursor_position.move_to_canonical_line(line_on_screen);
|
|
||||||
}
|
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
|
||||||
self.cursor_position.line_index;
|
|
||||||
let current_canonical_line = self
|
|
||||||
.canonical_lines
|
|
||||||
.get_mut(current_canonical_line_index)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
let current_fragment = current_canonical_line
|
|
||||||
.wrapped_fragments
|
|
||||||
.get_mut(current_line_wrap_position)
|
|
||||||
.expect("cursor out of bounds");
|
|
||||||
|
|
||||||
current_fragment.characters.resize(
|
|
||||||
max(current_fragment.characters.len(), col),
|
|
||||||
EMPTY_TERMINAL_CHARACTER,
|
|
||||||
);
|
|
||||||
self.cursor_position.move_to_column(col);
|
|
||||||
}
|
|
||||||
pub fn move_cursor_to_column(&mut self, col: usize) {
|
|
||||||
let current_canonical_line = self.cursor_position.line_index.0;
|
|
||||||
self.move_cursor_to(current_canonical_line, col);
|
|
||||||
}
|
|
||||||
pub fn move_cursor_to_line(&mut self, line: usize) {
|
|
||||||
let current_column = self.cursor_position.column_index;
|
|
||||||
self.move_cursor_to(line, current_column);
|
|
||||||
}
|
|
||||||
pub fn move_current_buffer_to_alternative_buffer(&mut self) {
|
|
||||||
self.alternative_buffer = Some(self.canonical_lines.drain(..).collect());
|
|
||||||
self.alternative_cursor_position = Some(self.cursor_position);
|
|
||||||
self.clear_all();
|
|
||||||
}
|
|
||||||
pub fn override_current_buffer_with_alternative_buffer(&mut self) {
|
|
||||||
if let Some(alternative_buffer) = self.alternative_buffer.as_mut() {
|
|
||||||
self.canonical_lines = alternative_buffer.drain(..).collect();
|
|
||||||
}
|
|
||||||
if let Some(alternative_cursor_position) = self.alternative_cursor_position {
|
|
||||||
self.cursor_position = alternative_cursor_position;
|
|
||||||
}
|
|
||||||
self.alternative_buffer = None;
|
|
||||||
self.alternative_cursor_position = None;
|
|
||||||
}
|
|
||||||
pub fn set_scroll_region(&mut self, top_line: usize, bottom_line: usize) {
|
|
||||||
self.scroll_region = Some((top_line, bottom_line));
|
|
||||||
}
|
|
||||||
pub fn clear_scroll_region(&mut self) {
|
|
||||||
self.scroll_region = None;
|
|
||||||
}
|
|
||||||
fn scroll_region_absolute_indices(&mut self) -> Option<(usize, usize)> {
|
|
||||||
self.scroll_region?;
|
|
||||||
if self.canonical_lines.len() > self.lines_in_view {
|
|
||||||
let absolute_top = self.canonical_lines.len() - 1 - self.lines_in_view;
|
|
||||||
let absolute_bottom = self.canonical_lines.len() - 1;
|
|
||||||
Some((absolute_top, absolute_bottom))
|
|
||||||
} else {
|
|
||||||
Some((self.scroll_region.unwrap().0, self.scroll_region.unwrap().1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn scroll_region_absolute_indices_or_screen_edges(&mut self) -> (usize, usize) {
|
|
||||||
match self.scroll_region {
|
|
||||||
Some(_scroll_region) => self.scroll_region_absolute_indices().unwrap(),
|
|
||||||
None => {
|
|
||||||
// indices of screen top and bottom edge
|
|
||||||
// TODO: what if we don't have enough lines?
|
|
||||||
// let absolute_top = self.canonical_lines.len() - 1 - self.lines_in_view;
|
|
||||||
let absolute_top = self.canonical_lines.len() - self.lines_in_view;
|
|
||||||
let absolute_bottom = self.canonical_lines.len() - 1;
|
|
||||||
(absolute_top, absolute_bottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn delete_lines_in_scroll_region(&mut self, count: usize) {
|
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) =
|
|
||||||
self.scroll_region_absolute_indices()
|
|
||||||
{
|
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
|
||||||
if current_canonical_line_index >= scroll_region_top
|
|
||||||
&& current_canonical_line_index <= scroll_region_bottom
|
|
||||||
{
|
|
||||||
// when deleting lines inside the scroll region, we must make sure it stays the
|
|
||||||
// same size (and that other lines below it aren't shifted inside it)
|
|
||||||
// so we delete the current line(s) and add an empty line at the end of the scroll
|
|
||||||
// region
|
|
||||||
for _ in 0..count {
|
|
||||||
self.canonical_lines.remove(current_canonical_line_index);
|
|
||||||
self.canonical_lines
|
|
||||||
.insert(scroll_region_bottom, CanonicalLine::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add_empty_lines_in_scroll_region(&mut self, count: usize) {
|
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) =
|
|
||||||
self.scroll_region_absolute_indices()
|
|
||||||
{
|
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
|
||||||
if current_canonical_line_index >= scroll_region_top
|
|
||||||
&& current_canonical_line_index <= scroll_region_bottom
|
|
||||||
{
|
|
||||||
// when adding empty lines inside the scroll region, we must make sure it stays the
|
|
||||||
// same size and that lines don't "leak" outside of it
|
|
||||||
// so we add an empty line where the cursor currently is, and delete the last line
|
|
||||||
// of the scroll region
|
|
||||||
for _ in 0..count {
|
|
||||||
self.canonical_lines.remove(scroll_region_bottom);
|
|
||||||
self.canonical_lines
|
|
||||||
.insert(current_canonical_line_index, CanonicalLine::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_cursor_up_in_scroll_region(&mut self, count: usize) {
|
|
||||||
let (scroll_region_top, scroll_region_bottom) =
|
|
||||||
self.scroll_region_absolute_indices_or_screen_edges();
|
|
||||||
for _ in 0..count {
|
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
|
||||||
if current_canonical_line_index == scroll_region_top {
|
|
||||||
// if we're at the top line, we create a new line and remove the last line that
|
|
||||||
// would otherwise overflow
|
|
||||||
self.canonical_lines.remove(scroll_region_bottom);
|
|
||||||
self.canonical_lines
|
|
||||||
.insert(current_canonical_line_index, CanonicalLine::new());
|
|
||||||
} else if current_canonical_line_index > scroll_region_top
|
|
||||||
&& current_canonical_line_index <= scroll_region_bottom
|
|
||||||
{
|
|
||||||
self.move_cursor_up(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// [scroll_up](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L261)
|
|
||||||
/// This function takes the first line of the scroll region and moves it to the bottom (count times)
|
|
||||||
pub fn rotate_scroll_region_up(&mut self, count: usize) {
|
|
||||||
if let Some((_, scroll_region_bottom)) = self.scroll_region_absolute_indices() {
|
|
||||||
if self.show_cursor {
|
|
||||||
let scroll_region_bottom_index = scroll_region_bottom - 1;
|
|
||||||
self.cursor_position
|
|
||||||
.move_to_canonical_line(scroll_region_bottom_index);
|
|
||||||
|
|
||||||
let new_empty_lines = vec![CanonicalLine::new(); count];
|
|
||||||
self.canonical_lines.splice(
|
|
||||||
scroll_region_bottom_index..scroll_region_bottom_index + 1,
|
|
||||||
new_empty_lines,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.cursor_position
|
|
||||||
.move_to_canonical_line(scroll_region_bottom_index + count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// [scroll_down](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L221)
|
|
||||||
/// This function takes the last line of the scroll region and moves it to the top (count times)
|
|
||||||
pub fn rotate_scroll_region_down(&mut self, count: usize) {
|
|
||||||
if let Some((scroll_region_top, _)) = self.scroll_region_absolute_indices() {
|
|
||||||
if self.show_cursor {
|
|
||||||
let scroll_region_top_index = scroll_region_top - 1;
|
|
||||||
self.cursor_position
|
|
||||||
.move_to_canonical_line(scroll_region_top_index);
|
|
||||||
|
|
||||||
let new_empty_lines = vec![CanonicalLine::new(); count];
|
|
||||||
self.canonical_lines.splice(
|
|
||||||
scroll_region_top_index..scroll_region_top_index,
|
|
||||||
new_empty_lines,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.cursor_position
|
|
||||||
.move_to_canonical_line(scroll_region_top_index + count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_viewport_up(&mut self, count: usize) {
|
|
||||||
if let Some(current_offset) = self.viewport_bottom_offset.as_mut() {
|
|
||||||
*current_offset += count;
|
|
||||||
} else {
|
|
||||||
self.viewport_bottom_offset = Some(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn move_viewport_down(&mut self, count: usize) {
|
|
||||||
if let Some(current_offset) = self.viewport_bottom_offset.as_mut() {
|
|
||||||
if *current_offset > count {
|
|
||||||
*current_offset -= count;
|
|
||||||
} else {
|
|
||||||
self.viewport_bottom_offset = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn reset_viewport(&mut self) {
|
|
||||||
self.viewport_bottom_offset = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Scroll {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
for line in &self.canonical_lines {
|
|
||||||
writeln!(f, "{:?}", line)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,9 +4,13 @@ use crate::tab::Pane;
|
||||||
use ::nix::pty::Winsize;
|
use ::nix::pty::Winsize;
|
||||||
use ::std::os::unix::io::RawFd;
|
use ::std::os::unix::io::RawFd;
|
||||||
use ::vte::Perform;
|
use ::vte::Perform;
|
||||||
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
use crate::panes::terminal_character::{CharacterStyles, TerminalCharacter};
|
use crate::boundaries::Rect;
|
||||||
use crate::panes::Scroll;
|
use crate::panes::grid::{Grid, Row};
|
||||||
|
use crate::panes::terminal_character::{
|
||||||
|
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||||
|
};
|
||||||
use crate::utils::logging::debug_log_to_file;
|
use crate::utils::logging::debug_log_to_file;
|
||||||
use crate::VteEvent;
|
use crate::VteEvent;
|
||||||
|
|
||||||
|
|
@ -35,8 +39,9 @@ impl From<Winsize> for PositionAndSize {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TerminalPane {
|
pub struct TerminalPane {
|
||||||
|
pub grid: Grid,
|
||||||
|
pub alternative_grid: Option<Grid>, // for 1049h/l instructions which tell us to switch between these two
|
||||||
pub pid: RawFd,
|
pub pid: RawFd,
|
||||||
pub scroll: Scroll,
|
|
||||||
pub should_render: bool,
|
pub should_render: bool,
|
||||||
pub selectable: bool,
|
pub selectable: bool,
|
||||||
pub position_and_size: PositionAndSize,
|
pub position_and_size: PositionAndSize,
|
||||||
|
|
@ -112,7 +117,7 @@ impl Pane for TerminalPane {
|
||||||
}
|
}
|
||||||
fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
||||||
// (x, y)
|
// (x, y)
|
||||||
self.scroll.cursor_coordinates_on_screen()
|
self.grid.cursor_coordinates()
|
||||||
}
|
}
|
||||||
fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8> {
|
fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8> {
|
||||||
// there are some cases in which the terminal state means that input sent to it
|
// there are some cases in which the terminal state means that input sent to it
|
||||||
|
|
@ -259,27 +264,28 @@ impl Pane for TerminalPane {
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
fn scroll_up(&mut self, count: usize) {
|
fn scroll_up(&mut self, count: usize) {
|
||||||
self.scroll.move_viewport_up(count);
|
self.grid.move_viewport_up(count);
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
fn scroll_down(&mut self, count: usize) {
|
fn scroll_down(&mut self, count: usize) {
|
||||||
self.scroll.move_viewport_down(count);
|
self.grid.move_viewport_down(count);
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
fn clear_scroll(&mut self) {
|
fn clear_scroll(&mut self) {
|
||||||
self.scroll.reset_viewport();
|
self.grid.reset_viewport();
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalPane {
|
impl TerminalPane {
|
||||||
pub fn new(pid: RawFd, position_and_size: PositionAndSize) -> TerminalPane {
|
pub fn new(pid: RawFd, position_and_size: PositionAndSize) -> TerminalPane {
|
||||||
let scroll = Scroll::new(position_and_size.columns, position_and_size.rows);
|
let grid = Grid::new(position_and_size.rows, position_and_size.columns);
|
||||||
let pending_styles = CharacterStyles::new();
|
let pending_styles = CharacterStyles::new();
|
||||||
|
|
||||||
TerminalPane {
|
TerminalPane {
|
||||||
pid,
|
pid,
|
||||||
scroll,
|
grid,
|
||||||
|
alternative_grid: None,
|
||||||
should_render: true,
|
should_render: true,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
pending_styles,
|
pending_styles,
|
||||||
|
|
@ -318,35 +324,108 @@ impl TerminalPane {
|
||||||
fn reflow_lines(&mut self) {
|
fn reflow_lines(&mut self) {
|
||||||
let rows = self.get_rows();
|
let rows = self.get_rows();
|
||||||
let columns = self.get_columns();
|
let columns = self.get_columns();
|
||||||
self.scroll.change_size(columns, rows);
|
self.grid.change_size(rows, columns);
|
||||||
|
if let Some(alternative_grid) = self.alternative_grid.as_mut() {
|
||||||
|
alternative_grid.change_size(rows, columns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_buffer_as_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
pub fn read_buffer_as_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
||||||
self.scroll.as_character_lines()
|
self.grid.as_character_lines()
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
||||||
// (x, y)
|
// (x, y)
|
||||||
self.scroll.cursor_coordinates_on_screen()
|
self.grid.cursor_coordinates()
|
||||||
|
}
|
||||||
|
pub fn scroll_up(&mut self, count: usize) {
|
||||||
|
self.grid.move_viewport_up(count);
|
||||||
|
self.mark_for_rerender();
|
||||||
|
}
|
||||||
|
pub fn scroll_down(&mut self, count: usize) {
|
||||||
|
self.grid.move_viewport_down(count);
|
||||||
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
pub fn rotate_scroll_region_up(&mut self, count: usize) {
|
pub fn rotate_scroll_region_up(&mut self, count: usize) {
|
||||||
self.scroll.rotate_scroll_region_up(count);
|
self.grid.rotate_scroll_region_up(count);
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
pub fn rotate_scroll_region_down(&mut self, count: usize) {
|
pub fn rotate_scroll_region_down(&mut self, count: usize) {
|
||||||
self.scroll.rotate_scroll_region_down(count);
|
self.grid.rotate_scroll_region_down(count);
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
|
pub fn clear_scroll(&mut self) {
|
||||||
|
self.grid.reset_viewport();
|
||||||
|
self.mark_for_rerender();
|
||||||
|
}
|
||||||
|
pub fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) {
|
||||||
|
let position_and_size_override = PositionAndSize {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
rows: size.rows,
|
||||||
|
columns: size.columns,
|
||||||
|
};
|
||||||
|
self.position_and_size_override = Some(position_and_size_override);
|
||||||
|
self.reflow_lines();
|
||||||
|
self.mark_for_rerender();
|
||||||
|
}
|
||||||
|
pub fn reset_size_and_position_override(&mut self) {
|
||||||
|
self.position_and_size_override = None;
|
||||||
|
self.reflow_lines();
|
||||||
|
self.mark_for_rerender();
|
||||||
|
}
|
||||||
|
pub fn adjust_input_to_terminal(&self, input_bytes: Vec<u8>) -> Vec<u8> {
|
||||||
|
// there are some cases in which the terminal state means that input sent to it
|
||||||
|
// needs to be adjusted.
|
||||||
|
// here we match against those cases - if need be, we adjust the input and if not
|
||||||
|
// we send back the original input
|
||||||
|
match input_bytes.as_slice() {
|
||||||
|
[27, 91, 68] => {
|
||||||
|
// left arrow
|
||||||
|
if self.cursor_key_mode {
|
||||||
|
// please note that in the line below, there is an ANSI escape code (27) at the beginning of the string,
|
||||||
|
// some editors will not show this
|
||||||
|
return "OD".as_bytes().to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[27, 91, 67] => {
|
||||||
|
// right arrow
|
||||||
|
if self.cursor_key_mode {
|
||||||
|
// please note that in the line below, there is an ANSI escape code (27) at the beginning of the string,
|
||||||
|
// some editors will not show this
|
||||||
|
return "OC".as_bytes().to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[27, 91, 65] => {
|
||||||
|
// up arrow
|
||||||
|
if self.cursor_key_mode {
|
||||||
|
// please note that in the line below, there is an ANSI escape code (27) at the beginning of the string,
|
||||||
|
// some editors will not show this
|
||||||
|
return "OA".as_bytes().to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[27, 91, 66] => {
|
||||||
|
// down arrow
|
||||||
|
if self.cursor_key_mode {
|
||||||
|
// please note that in the line below, there is an ANSI escape code (27) at the beginning of the string,
|
||||||
|
// some editors will not show this
|
||||||
|
return "OB".as_bytes().to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
input_bytes
|
||||||
|
}
|
||||||
fn add_newline(&mut self) {
|
fn add_newline(&mut self) {
|
||||||
self.scroll.add_canonical_line();
|
self.grid.add_canonical_line();
|
||||||
// self.reset_all_ansi_codes(); // TODO: find out if we should be resetting here or not
|
// self.reset_all_ansi_codes(); // TODO: find out if we should be resetting here or not
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
fn move_to_beginning_of_line(&mut self) {
|
fn move_to_beginning_of_line(&mut self) {
|
||||||
self.scroll.move_cursor_to_beginning_of_linewrap();
|
self.grid.move_cursor_to_beginning_of_line();
|
||||||
}
|
}
|
||||||
fn move_cursor_backwards(&mut self, count: usize) {
|
fn move_cursor_backwards(&mut self, count: usize) {
|
||||||
self.scroll.move_cursor_backwards(count);
|
self.grid.move_cursor_backwards(count);
|
||||||
}
|
}
|
||||||
fn _reset_all_ansi_codes(&mut self) {
|
fn _reset_all_ansi_codes(&mut self) {
|
||||||
self.pending_styles.clear();
|
self.pending_styles.clear();
|
||||||
|
|
@ -361,7 +440,7 @@ impl vte::Perform for TerminalPane {
|
||||||
character: c,
|
character: c,
|
||||||
styles: self.pending_styles,
|
styles: self.pending_styles,
|
||||||
};
|
};
|
||||||
self.scroll.add_character(terminal_character);
|
self.grid.add_character(terminal_character);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(&mut self, byte: u8) {
|
fn execute(&mut self, byte: u8) {
|
||||||
|
|
@ -377,7 +456,7 @@ impl vte::Perform for TerminalPane {
|
||||||
styles: self.pending_styles,
|
styles: self.pending_styles,
|
||||||
};
|
};
|
||||||
// TODO: handle better with line wrapping
|
// TODO: handle better with line wrapping
|
||||||
self.scroll.add_character(terminal_tab_character);
|
self.grid.add_character(terminal_tab_character);
|
||||||
}
|
}
|
||||||
10 => {
|
10 => {
|
||||||
// 0a, newline
|
// 0a, newline
|
||||||
|
|
@ -417,23 +496,28 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll.move_cursor_forward(move_by);
|
self.grid.move_cursor_forward_until_edge(move_by);
|
||||||
} else if c == 'K' {
|
} else if c == 'K' {
|
||||||
// clear line (0 => right, 1 => left, 2 => all)
|
// clear line (0 => right, 1 => left, 2 => all)
|
||||||
if params[0] == 0 {
|
if params[0] == 0 {
|
||||||
self.scroll
|
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
||||||
.clear_canonical_line_right_of_cursor(self.pending_styles);
|
char_to_replace.styles = self.pending_styles;
|
||||||
|
self.grid
|
||||||
|
.replace_characters_in_line_after_cursor(char_to_replace);
|
||||||
} else if params[0] == 1 {
|
} else if params[0] == 1 {
|
||||||
self.scroll
|
let mut char_to_replace = EMPTY_TERMINAL_CHARACTER;
|
||||||
.clear_canonical_line_left_of_cursor(self.pending_styles);
|
char_to_replace.styles = self.pending_styles;
|
||||||
|
self.grid
|
||||||
|
.replace_characters_in_line_before_cursor(char_to_replace);
|
||||||
|
} else if params[0] == 2 {
|
||||||
|
self.grid.clear_cursor_line();
|
||||||
}
|
}
|
||||||
// TODO: implement 2
|
|
||||||
} else if c == 'J' {
|
} else if c == 'J' {
|
||||||
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
|
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
|
||||||
if params[0] == 0 {
|
if params[0] == 0 {
|
||||||
self.scroll.clear_all_after_cursor();
|
self.grid.clear_all_after_cursor();
|
||||||
} else if params[0] == 2 {
|
} else if params[0] == 2 {
|
||||||
self.scroll.clear_all();
|
self.grid.clear_all();
|
||||||
}
|
}
|
||||||
// TODO: implement 1
|
// TODO: implement 1
|
||||||
} else if c == 'H' {
|
} else if c == 'H' {
|
||||||
|
|
@ -452,22 +536,22 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
(params[0] as usize - 1, params[1] as usize - 1)
|
(params[0] as usize - 1, params[1] as usize - 1)
|
||||||
};
|
};
|
||||||
self.scroll.move_cursor_to(row, col);
|
self.grid.move_cursor_to(col, row);
|
||||||
} else if c == 'A' {
|
} else if c == 'A' {
|
||||||
// move cursor up until edge of screen
|
// move cursor up until edge of screen
|
||||||
let move_up_count = if params[0] == 0 { 1 } else { params[0] };
|
let move_up_count = if params[0] == 0 { 1 } else { params[0] };
|
||||||
self.scroll.move_cursor_up(move_up_count as usize);
|
self.grid.move_cursor_up(move_up_count as usize);
|
||||||
} else if c == 'B' {
|
} else if c == 'B' {
|
||||||
// move cursor down until edge of screen
|
// move cursor down until edge of screen
|
||||||
let move_down_count = if params[0] == 0 { 1 } else { params[0] };
|
let move_down_count = if params[0] == 0 { 1 } else { params[0] };
|
||||||
self.scroll.move_cursor_down(move_down_count as usize);
|
self.grid.move_cursor_down(move_down_count as usize);
|
||||||
} else if c == 'D' {
|
} else if c == 'D' {
|
||||||
let move_back_count = if params[0] == 0 {
|
let move_back_count = if params[0] == 0 {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll.move_cursor_back(move_back_count);
|
self.grid.move_cursor_back(move_back_count);
|
||||||
} else if c == 'l' {
|
} else if c == 'l' {
|
||||||
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
||||||
Some(b'?') => true,
|
Some(b'?') => true,
|
||||||
|
|
@ -477,11 +561,14 @@ impl vte::Perform for TerminalPane {
|
||||||
if first_intermediate_is_questionmark {
|
if first_intermediate_is_questionmark {
|
||||||
match params.get(0) {
|
match params.get(0) {
|
||||||
Some(&1049) => {
|
Some(&1049) => {
|
||||||
self.scroll
|
if let Some(alternative_grid) = self.alternative_grid.as_mut() {
|
||||||
.override_current_buffer_with_alternative_buffer();
|
std::mem::swap(&mut self.grid, alternative_grid);
|
||||||
|
// self.grid = alternative_grid;
|
||||||
|
}
|
||||||
|
self.alternative_grid = None;
|
||||||
}
|
}
|
||||||
Some(&25) => {
|
Some(&25) => {
|
||||||
self.scroll.hide_cursor();
|
self.grid.hide_cursor();
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
Some(&1) => {
|
Some(&1) => {
|
||||||
|
|
@ -499,11 +586,21 @@ impl vte::Perform for TerminalPane {
|
||||||
if first_intermediate_is_questionmark {
|
if first_intermediate_is_questionmark {
|
||||||
match params.get(0) {
|
match params.get(0) {
|
||||||
Some(&25) => {
|
Some(&25) => {
|
||||||
self.scroll.show_cursor();
|
self.grid.show_cursor();
|
||||||
self.mark_for_rerender();
|
self.mark_for_rerender();
|
||||||
}
|
}
|
||||||
Some(&1049) => {
|
Some(&1049) => {
|
||||||
self.scroll.move_current_buffer_to_alternative_buffer();
|
let columns = self
|
||||||
|
.position_and_size_override
|
||||||
|
.map(|x| x.columns)
|
||||||
|
.unwrap_or(self.position_and_size.columns);
|
||||||
|
let rows = self
|
||||||
|
.position_and_size_override
|
||||||
|
.map(|x| x.rows)
|
||||||
|
.unwrap_or(self.position_and_size.rows);
|
||||||
|
let current_grid =
|
||||||
|
std::mem::replace(&mut self.grid, Grid::new(rows, columns));
|
||||||
|
self.alternative_grid = Some(current_grid);
|
||||||
}
|
}
|
||||||
Some(&1) => {
|
Some(&1) => {
|
||||||
self.cursor_key_mode = true;
|
self.cursor_key_mode = true;
|
||||||
|
|
@ -516,11 +613,11 @@ impl vte::Perform for TerminalPane {
|
||||||
// minus 1 because these are 1 indexed
|
// minus 1 because these are 1 indexed
|
||||||
let top_line_index = params[0] as usize - 1;
|
let top_line_index = params[0] as usize - 1;
|
||||||
let bottom_line_index = params[1] as usize - 1;
|
let bottom_line_index = params[1] as usize - 1;
|
||||||
self.scroll
|
self.grid
|
||||||
.set_scroll_region(top_line_index, bottom_line_index);
|
.set_scroll_region(top_line_index, bottom_line_index);
|
||||||
self.scroll.show_cursor();
|
self.grid.show_cursor();
|
||||||
} else {
|
} else {
|
||||||
self.scroll.clear_scroll_region();
|
self.grid.clear_scroll_region();
|
||||||
}
|
}
|
||||||
} else if c == 't' {
|
} else if c == 't' {
|
||||||
// TBD - title?
|
// TBD - title?
|
||||||
|
|
@ -535,7 +632,7 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll
|
self.grid
|
||||||
.delete_lines_in_scroll_region(line_count_to_delete);
|
.delete_lines_in_scroll_region(line_count_to_delete);
|
||||||
} else if c == 'L' {
|
} else if c == 'L' {
|
||||||
// insert blank lines if inside scroll region
|
// insert blank lines if inside scroll region
|
||||||
|
|
@ -544,7 +641,7 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll
|
self.grid
|
||||||
.add_empty_lines_in_scroll_region(line_count_to_add);
|
.add_empty_lines_in_scroll_region(line_count_to_add);
|
||||||
} else if c == 'q' {
|
} else if c == 'q' {
|
||||||
// ignore for now to run on mac
|
// ignore for now to run on mac
|
||||||
|
|
@ -552,10 +649,9 @@ impl vte::Perform for TerminalPane {
|
||||||
let column = if params[0] == 0 {
|
let column = if params[0] == 0 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
// params[0] as usize
|
|
||||||
params[0] as usize - 1
|
params[0] as usize - 1
|
||||||
};
|
};
|
||||||
self.scroll.move_cursor_to_column(column);
|
self.grid.move_cursor_to_column(column);
|
||||||
} else if c == 'd' {
|
} else if c == 'd' {
|
||||||
// goto line
|
// goto line
|
||||||
let line = if params[0] == 0 {
|
let line = if params[0] == 0 {
|
||||||
|
|
@ -564,7 +660,7 @@ impl vte::Perform for TerminalPane {
|
||||||
// minus 1 because this is 1 indexed
|
// minus 1 because this is 1 indexed
|
||||||
params[0] as usize - 1
|
params[0] as usize - 1
|
||||||
};
|
};
|
||||||
self.scroll.move_cursor_to_line(line);
|
self.grid.move_cursor_to_line(line);
|
||||||
} else if c == 'P' {
|
} else if c == 'P' {
|
||||||
// erase characters
|
// erase characters
|
||||||
let count = if params[0] == 0 {
|
let count = if params[0] == 0 {
|
||||||
|
|
@ -572,7 +668,7 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll.erase_characters(count, self.pending_styles);
|
self.grid.erase_characters(count, self.pending_styles);
|
||||||
} else if c == 'X' {
|
} else if c == 'X' {
|
||||||
// erase characters and replace with empty characters of current style
|
// erase characters and replace with empty characters of current style
|
||||||
let count = if params[0] == 0 {
|
let count = if params[0] == 0 {
|
||||||
|
|
@ -580,7 +676,7 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll
|
self.grid
|
||||||
.replace_with_empty_chars(count, self.pending_styles);
|
.replace_with_empty_chars(count, self.pending_styles);
|
||||||
} else if c == 'T' {
|
} else if c == 'T' {
|
||||||
/*
|
/*
|
||||||
|
|
@ -602,16 +698,19 @@ impl vte::Perform for TerminalPane {
|
||||||
} else {
|
} else {
|
||||||
params[0] as usize
|
params[0] as usize
|
||||||
};
|
};
|
||||||
self.scroll.delete_lines_in_scroll_region(count);
|
self.grid.delete_lines_in_scroll_region(count);
|
||||||
self.scroll.add_empty_lines_in_scroll_region(count);
|
self.grid.add_empty_lines_in_scroll_region(count);
|
||||||
} else {
|
} else {
|
||||||
let _ = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
let _ = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) {
|
fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) {
|
||||||
if let (b'M', None) = (byte, intermediates.get(0)) {
|
match (byte, intermediates.get(0)) {
|
||||||
self.scroll.move_cursor_up_in_scroll_region(1);
|
(b'M', None) => {
|
||||||
|
self.grid.move_cursor_up_with_scrolling(1);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ df: /run/user/1000/doc: Operation not permitted
|
||||||
awk '{printf "\\\\t%s\\\\t%4s / %4s %s\\\\n\n", $6, $3, $2, $5}' | \
|
awk '{printf "\\\\t%s\\\\t%4s / %4s %s\\\\n\n", $6, $3, $2, $5}' | \
|
||||||
sed -e 's/^\(.*\([8][5-9]\|[9][0-9]\)%.*\)$/\\\\e[0;31m\1\\\\e[0m/' -e 's/^\(.*\([7][5-9]\|[8][0-4]\)%.*\
|
sed -e 's/^\(.*\([8][5-9]\|[9][0-9]\)%.*\)$/\\\\e[0;31m\1\\\\e[0m/' -e 's/^\(.*\([7][5-9]\|[8][0-4]\)%.*\
|
||||||
)$/\\\\e[0;33m\1\\\\e[0m/' | \
|
)$/\\\\e[0;33m\1\\\\e[0m/' | \
|
||||||
)
|
|
||||||
paste -sd ''\
|
paste -sd ''\
|
||||||
)█
|
)█
|
||||||
|
|
||||||
|
|
@ -30,3 +29,4 @@ df: /run/user/1000/doc: Operation not permitted
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ df: /run/user/1000/doc: Operation not permitted
|
||||||
awk '{printf "\\\\t%s\\\\t%4s / %4s %s\\\\n\n", $6, $3, $2, $5}' | \
|
awk '{printf "\\\\t%s\\\\t%4s / %4s %s\\\\n\n", $6, $3, $2, $5}' | \
|
||||||
sed -e 's/^\(.*\([8][5-9]\|[9][0-9]\)%.*\)$/\\\\e[0;31m\1\\\\e[0m/' -e 's/^\(.*\([7][5-9]\|[8][0-4]\)%.*\
|
sed -e 's/^\(.*\([8][5-9]\|[9][0-9]\)%.*\)$/\\\\e[0;31m\1\\\\e[0m/' -e 's/^\(.*\([7][5-9]\|[8][0-4]\)%.*\
|
||||||
)$/\\\\e[0;33m\1\\\\e[0m/' | \
|
)$/\\\\e[0;33m\1\\\\e[0m/' | \
|
||||||
)
|
|
||||||
paste -sd ''\
|
paste -sd ''\
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,4 +28,5 @@ df: /run/user/1000/doc: Operation not permitted
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Bye from Mosaic!█
|
Bye from Mosaic!█
|
||||||
|
|
|
||||||
|
|
@ -1,389 +1,389 @@
|
||||||
pub const COL_121: [&str; 20] = [
|
pub const COL_121: [&str; 20] = [
|
||||||
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n",
|
"line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_10: [&str; 20] = [
|
pub const COL_10: [&str; 20] = [
|
||||||
"line1-bbbb\n",
|
"line1-bbbb\r\n",
|
||||||
"line2-bbbb\n",
|
"line2-bbbb\r\n",
|
||||||
"line3-bbbb\n",
|
"line3-bbbb\r\n",
|
||||||
"line4-bbbb\n",
|
"line4-bbbb\r\n",
|
||||||
"line5-bbbb\n",
|
"line5-bbbb\r\n",
|
||||||
"line6-bbbb\n",
|
"line6-bbbb\r\n",
|
||||||
"line7-bbbb\n",
|
"line7-bbbb\r\n",
|
||||||
"line8-bbbb\n",
|
"line8-bbbb\r\n",
|
||||||
"line9-bbbb\n",
|
"line9-bbbb\r\n",
|
||||||
"line10-bbb\n",
|
"line10-bbb\r\n",
|
||||||
"line11-bbb\n",
|
"line11-bbb\r\n",
|
||||||
"line12-bbb\n",
|
"line12-bbb\r\n",
|
||||||
"line13-bbb\n",
|
"line13-bbb\r\n",
|
||||||
"line14-bbb\n",
|
"line14-bbb\r\n",
|
||||||
"line15-bbb\n",
|
"line15-bbb\r\n",
|
||||||
"line16-bbb\n",
|
"line16-bbb\r\n",
|
||||||
"line17-bbb\n",
|
"line17-bbb\r\n",
|
||||||
"line18-bbb\n",
|
"line18-bbb\r\n",
|
||||||
"line19-bbb\n",
|
"line19-bbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_14: [&str; 20] = [
|
pub const COL_14: [&str; 20] = [
|
||||||
"line1-bbbbbbbb\n",
|
"line1-bbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbb\n",
|
"line2-bbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbb\n",
|
"line3-bbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbb\n",
|
"line4-bbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbb\n",
|
"line5-bbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbb\n",
|
"line6-bbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbb\n",
|
"line7-bbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbb\n",
|
"line8-bbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbb\n",
|
"line9-bbbbbbbb\r\n",
|
||||||
"line10-bbbbbbb\n",
|
"line10-bbbbbbb\r\n",
|
||||||
"line11-bbbbbbb\n",
|
"line11-bbbbbbb\r\n",
|
||||||
"line12-bbbbbbb\n",
|
"line12-bbbbbbb\r\n",
|
||||||
"line13-bbbbbbb\n",
|
"line13-bbbbbbb\r\n",
|
||||||
"line14-bbbbbbb\n",
|
"line14-bbbbbbb\r\n",
|
||||||
"line15-bbbbbbb\n",
|
"line15-bbbbbbb\r\n",
|
||||||
"line16-bbbbbbb\n",
|
"line16-bbbbbbb\r\n",
|
||||||
"line17-bbbbbbb\n",
|
"line17-bbbbbbb\r\n",
|
||||||
"line18-bbbbbbb\n",
|
"line18-bbbbbbb\r\n",
|
||||||
"line19-bbbbbbb\n",
|
"line19-bbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_15: [&str; 20] = [
|
pub const COL_15: [&str; 20] = [
|
||||||
"line1-bbbbbbbbb\n",
|
"line1-bbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbb\n",
|
"line2-bbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbb\n",
|
"line3-bbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbb\n",
|
"line4-bbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbb\n",
|
"line5-bbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbb\n",
|
"line6-bbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbb\n",
|
"line7-bbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbb\n",
|
"line8-bbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbb\n",
|
"line9-bbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbb\n",
|
"line10-bbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbb\n",
|
"line11-bbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbb\n",
|
"line12-bbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbb\n",
|
"line13-bbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbb\n",
|
"line14-bbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbb\n",
|
"line15-bbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbb\n",
|
"line16-bbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbb\n",
|
"line17-bbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbb\n",
|
"line18-bbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbb\n",
|
"line19-bbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_19: [&str; 20] = [
|
pub const COL_19: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_20: [&str; 20] = [
|
pub const COL_20: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_24: [&str; 20] = [
|
pub const COL_24: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
pub const COL_29: [&str; 20] = [
|
pub const COL_29: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_30: [&str; 20] = [
|
pub const COL_30: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_34: [&str; 20] = [
|
pub const COL_34: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_40: [&str; 20] = [
|
pub const COL_40: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_39: [&str; 20] = [
|
pub const COL_39: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_50: [&str; 20] = [
|
pub const COL_50: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_60: [&str; 20] = [
|
pub const COL_60: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_70: [&str; 20] = [
|
pub const COL_70: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_90: [&str; 20] = [
|
pub const COL_90: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const COL_96: [&str; 20] = [
|
pub const COL_96: [&str; 20] = [
|
||||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\r\n",
|
||||||
"prompt $ ",
|
"prompt $ ",
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue