mirror of
https://github.com/zellij-org/zellij.git
synced 2024-12-24 01:34:38 +03:00
feat(ux): initial layout engine (#50)
* prototype * refactor(layout): move stuff around * style(format): make rustfmt happy
This commit is contained in:
parent
a2914066bf
commit
47954166a2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -457,6 +457,7 @@ dependencies = [
|
||||
"libc",
|
||||
"nix",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"signal-hook",
|
||||
"structopt",
|
||||
"termios",
|
||||
|
@ -18,6 +18,7 @@ futures = "0.3.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
bincode = "1.3.1"
|
||||
structopt = "0.3"
|
||||
serde_yaml = "0.8"
|
||||
|
||||
[dependencies.async-std]
|
||||
version = "1.3.0"
|
||||
|
134
src/layout.rs
Normal file
134
src/layout.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::terminal_pane::PositionAndSize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn _debug_log_to_file(message: String) {
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::prelude::*;
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open("/tmp/mosaic-log.txt")
|
||||
.unwrap();
|
||||
file.write_all(message.as_bytes()).unwrap();
|
||||
file.write_all("\n".as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
fn split_space_to_parts_vertically(
|
||||
space_to_split: &PositionAndSize,
|
||||
percentages: Vec<u8>,
|
||||
) -> Vec<PositionAndSize> {
|
||||
let mut split_parts = vec![];
|
||||
let mut current_x_position = space_to_split.x;
|
||||
let width = space_to_split.columns - (percentages.len() - 1); // minus space for gaps
|
||||
for percentage in percentages.iter() {
|
||||
let columns = (width as f32 * (*percentage as f32 / 100.0)) as usize; // TODO: round properly
|
||||
split_parts.push(PositionAndSize {
|
||||
x: current_x_position,
|
||||
y: space_to_split.y,
|
||||
columns,
|
||||
rows: space_to_split.rows,
|
||||
});
|
||||
current_x_position += columns + 1; // 1 for gap
|
||||
}
|
||||
let total_width = split_parts
|
||||
.iter()
|
||||
.fold(0, |total_width, part| total_width + part.columns);
|
||||
if total_width < width {
|
||||
// we have some extra space left, let's add it to the last part
|
||||
let last_part_index = split_parts.len() - 1;
|
||||
let mut last_part = split_parts.get_mut(last_part_index).unwrap();
|
||||
last_part.columns += width - total_width;
|
||||
}
|
||||
split_parts
|
||||
}
|
||||
|
||||
fn split_space_to_parts_horizontally(
|
||||
space_to_split: &PositionAndSize,
|
||||
percentages: Vec<u8>,
|
||||
) -> Vec<PositionAndSize> {
|
||||
let mut split_parts = vec![];
|
||||
let mut current_y_position = space_to_split.y;
|
||||
let height = space_to_split.rows - (percentages.len() - 1); // minus space for gaps
|
||||
for percentage in percentages.iter() {
|
||||
let rows = (height as f32 * (*percentage as f32 / 100.0)) as usize; // TODO: round properly
|
||||
split_parts.push(PositionAndSize {
|
||||
x: space_to_split.x,
|
||||
y: current_y_position,
|
||||
columns: space_to_split.columns,
|
||||
rows,
|
||||
});
|
||||
current_y_position += rows + 1; // 1 for gap
|
||||
}
|
||||
let total_height = split_parts
|
||||
.iter()
|
||||
.fold(0, |total_height, part| total_height + part.rows);
|
||||
if total_height < height {
|
||||
// we have some extra space left, let's add it to the last part
|
||||
let last_part_index = split_parts.len() - 1;
|
||||
let mut last_part = split_parts.get_mut(last_part_index).unwrap();
|
||||
last_part.rows += height - total_height;
|
||||
}
|
||||
split_parts
|
||||
}
|
||||
|
||||
fn split_space(space_to_split: &PositionAndSize, layout: &Layout) -> Vec<PositionAndSize> {
|
||||
let mut pane_positions: Vec<PositionAndSize> = vec![];
|
||||
let percentages: Vec<u8> = layout
|
||||
.parts
|
||||
.iter()
|
||||
.map(|part| {
|
||||
let split_size = part.split_size.as_ref().unwrap(); // TODO: if there is no split size, it should get the remaining "free space"
|
||||
match split_size {
|
||||
SplitSize::Percent(percent) => *percent,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let split_parts = match layout.direction {
|
||||
Direction::Vertical => split_space_to_parts_vertically(space_to_split, percentages),
|
||||
Direction::Horizontal => split_space_to_parts_horizontally(space_to_split, percentages),
|
||||
};
|
||||
for (i, part) in layout.parts.iter().enumerate() {
|
||||
let part_position_and_size = split_parts.get(i).unwrap();
|
||||
if part.parts.len() > 0 {
|
||||
let mut part_positions = split_space(&part_position_and_size, part);
|
||||
pane_positions.append(&mut part_positions);
|
||||
} else {
|
||||
pane_positions.push(*part_position_and_size);
|
||||
}
|
||||
}
|
||||
pane_positions
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum Direction {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SplitSize {
|
||||
Percent(u8), // 1 to 100
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Layout {
|
||||
pub direction: Direction,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub parts: Vec<Layout>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub split_size: Option<SplitSize>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn total_panes(&self) -> usize {
|
||||
let mut total_panes = 0;
|
||||
total_panes += self.parts.len();
|
||||
for part in self.parts.iter() {
|
||||
total_panes += part.total_panes();
|
||||
}
|
||||
total_panes
|
||||
}
|
||||
pub fn position_panes_in_space(&self, space: &PositionAndSize) -> Vec<PositionAndSize> {
|
||||
split_space(space, &self)
|
||||
}
|
||||
}
|
31
src/main.rs
31
src/main.rs
@ -2,6 +2,7 @@
|
||||
mod tests;
|
||||
|
||||
mod boundaries;
|
||||
mod layout;
|
||||
mod os_input_output;
|
||||
mod pty_bus;
|
||||
mod screen;
|
||||
@ -14,8 +15,10 @@ use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use crate::layout::Layout;
|
||||
use crate::os_input_output::{get_os_input, OsApi};
|
||||
use crate::pty_bus::{PtyBus, PtyInstruction, VteEvent};
|
||||
use crate::screen::{Screen, ScreenInstruction};
|
||||
@ -43,7 +46,9 @@ pub struct Opt {
|
||||
#[structopt(long)]
|
||||
/// Maximum panes on screen, caution: opening more panes will close old ones
|
||||
max_panes: Option<usize>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
/// Path to a layout yaml file
|
||||
layout: Option<PathBuf>,
|
||||
#[structopt(short, long)]
|
||||
debug: bool,
|
||||
}
|
||||
@ -140,7 +145,26 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
|
||||
.name("pty".to_string())
|
||||
.spawn({
|
||||
move || {
|
||||
pty_bus.spawn_terminal_vertically(None);
|
||||
match opts.layout {
|
||||
Some(layout_path) => {
|
||||
use std::fs::File;
|
||||
let mut layout_file = File::open(&layout_path)
|
||||
.expect(&format!("cannot find layout {}", layout_path.display()));
|
||||
let mut layout = String::new();
|
||||
layout_file.read_to_string(&mut layout).expect(&format!(
|
||||
"could not read layout {}",
|
||||
layout_path.display()
|
||||
));
|
||||
let layout: Layout = serde_yaml::from_str(&layout).expect(&format!(
|
||||
"could not parse layout {}",
|
||||
layout_path.display()
|
||||
));
|
||||
pty_bus.spawn_terminals_for_layout(layout);
|
||||
}
|
||||
None => {
|
||||
pty_bus.spawn_terminal_vertically(None);
|
||||
}
|
||||
}
|
||||
loop {
|
||||
let event = pty_bus
|
||||
.receive_pty_instructions
|
||||
@ -230,6 +254,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
|
||||
ScreenInstruction::ToggleActiveTerminalFullscreen => {
|
||||
screen.toggle_active_terminal_fullscreen();
|
||||
}
|
||||
ScreenInstruction::ApplyLayout((layout, new_pane_pids)) => {
|
||||
screen.apply_layout(layout, new_pane_pids)
|
||||
}
|
||||
ScreenInstruction::Quit => {
|
||||
break;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use ::std::time::{Duration, Instant};
|
||||
use ::vte;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::layout::Layout;
|
||||
use crate::os_input_output::OsApi;
|
||||
use crate::ScreenInstruction;
|
||||
|
||||
@ -317,6 +318,29 @@ impl PtyBus {
|
||||
.send(ScreenInstruction::HorizontalSplit(pid_primary))
|
||||
.unwrap();
|
||||
}
|
||||
pub fn spawn_terminals_for_layout(&mut self, layout: Layout) {
|
||||
let total_panes = layout.total_panes();
|
||||
let mut new_pane_pids = vec![];
|
||||
for _ in 0..total_panes {
|
||||
let (pid_primary, pid_secondary): (RawFd, RawFd) = self.os_input.spawn_terminal(None);
|
||||
self.id_to_child_pid.insert(pid_primary, pid_secondary);
|
||||
new_pane_pids.push(pid_primary);
|
||||
}
|
||||
&self
|
||||
.send_screen_instructions
|
||||
.send(ScreenInstruction::ApplyLayout((
|
||||
layout,
|
||||
new_pane_pids.clone(),
|
||||
)));
|
||||
for id in new_pane_pids {
|
||||
stream_terminal_bytes(
|
||||
id,
|
||||
self.send_screen_instructions.clone(),
|
||||
self.os_input.clone(),
|
||||
self.debug_to_file,
|
||||
);
|
||||
}
|
||||
}
|
||||
pub fn close_pane(&mut self, id: RawFd) {
|
||||
let child_pid = self.id_to_child_pid.get(&id).unwrap();
|
||||
self.os_input.kill(*child_pid).unwrap();
|
||||
|
@ -5,9 +5,10 @@ use std::os::unix::io::RawFd;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
|
||||
use crate::boundaries::Boundaries;
|
||||
use crate::layout::Layout;
|
||||
use crate::os_input_output::OsApi;
|
||||
use crate::pty_bus::{PtyInstruction, VteEvent};
|
||||
use crate::terminal_pane::TerminalPane;
|
||||
use crate::terminal_pane::{PositionAndSize, TerminalPane};
|
||||
use crate::AppInstruction;
|
||||
|
||||
/*
|
||||
@ -80,6 +81,7 @@ pub enum ScreenInstruction {
|
||||
CloseFocusedPane,
|
||||
ToggleActiveTerminalFullscreen,
|
||||
ClosePane(RawFd),
|
||||
ApplyLayout((Layout, Vec<RawFd>)),
|
||||
}
|
||||
|
||||
pub struct Screen {
|
||||
@ -115,6 +117,64 @@ impl Screen {
|
||||
os_api,
|
||||
}
|
||||
}
|
||||
pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec<RawFd>) {
|
||||
self.panes_to_hide.clear();
|
||||
// TODO: this should be an attribute on Screen instead of full_screen_ws
|
||||
let free_space = PositionAndSize {
|
||||
x: 0,
|
||||
y: 0,
|
||||
rows: self.full_screen_ws.ws_row as usize,
|
||||
columns: self.full_screen_ws.ws_col as usize,
|
||||
};
|
||||
let positions_in_layout = layout.position_panes_in_space(&free_space);
|
||||
let mut positions_and_size = positions_in_layout.iter();
|
||||
for (pid, terminal_pane) in self.terminals.iter_mut() {
|
||||
match positions_and_size.next() {
|
||||
Some(position_and_size) => {
|
||||
terminal_pane.reset_size_and_position_override();
|
||||
terminal_pane.change_size_p(&position_and_size);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*pid,
|
||||
position_and_size.columns as u16,
|
||||
position_and_size.rows as u16,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
// we filled the entire layout, no room for this pane
|
||||
// TODO: handle active terminal
|
||||
self.panes_to_hide.insert(*pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut new_pids = new_pids.iter();
|
||||
for position_and_size in positions_and_size {
|
||||
// there are still panes left to fill, use the pids we received in this method
|
||||
let pid = new_pids.next().unwrap(); // if this crashes it means we got less pids than there are panes in this layout
|
||||
let mut new_terminal = TerminalPane::new(
|
||||
*pid,
|
||||
self.full_screen_ws.clone(),
|
||||
position_and_size.x,
|
||||
position_and_size.y,
|
||||
);
|
||||
new_terminal.change_size_p(position_and_size);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
new_terminal.pid,
|
||||
new_terminal.get_columns() as u16,
|
||||
new_terminal.get_rows() as u16,
|
||||
);
|
||||
self.terminals.insert(*pid, new_terminal);
|
||||
}
|
||||
for unused_pid in new_pids {
|
||||
// this is a bit of a hack and happens because we don't have any central location that
|
||||
// can query the screen as to how many panes it needs to create a layout
|
||||
// fixing this will require a bit of an architecture change
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::ClosePane(*unused_pid))
|
||||
.unwrap();
|
||||
}
|
||||
self.active_terminal = Some(*self.terminals.iter().next().unwrap().0);
|
||||
self.render();
|
||||
}
|
||||
pub fn new_pane(&mut self, pid: RawFd) {
|
||||
self.close_down_to_max_terminals();
|
||||
if self.terminals.is_empty() {
|
||||
|
@ -17,6 +17,7 @@ pub struct PositionAndSize {
|
||||
pub columns: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TerminalPane {
|
||||
pub pid: RawFd,
|
||||
pub scroll: Scroll,
|
||||
@ -134,6 +135,12 @@ impl TerminalPane {
|
||||
self.reflow_lines();
|
||||
self.should_render = true;
|
||||
}
|
||||
pub fn change_size_p(&mut self, position_and_size: &PositionAndSize) {
|
||||
self.position_and_size = *position_and_size;
|
||||
self.reflow_lines();
|
||||
self.should_render = true;
|
||||
}
|
||||
// TODO: merge these two methods
|
||||
pub fn change_size(&mut self, ws: &Winsize) {
|
||||
self.position_and_size.columns = ws.ws_col as usize;
|
||||
self.position_and_size.rows = ws.ws_row as usize;
|
||||
|
@ -143,7 +143,7 @@ impl OsApi for FakeInputOutput {
|
||||
.push(IoEvent::UnsetRawMode(pid));
|
||||
}
|
||||
fn spawn_terminal(&mut self, _file_to_open: Option<PathBuf>) -> (RawFd, RawFd) {
|
||||
let next_terminal_id = { self.read_buffers.lock().unwrap().keys().len() as RawFd + 1 };
|
||||
let next_terminal_id = self.stdin_writes.lock().unwrap().keys().len() as RawFd + 1;
|
||||
self.add_terminal(next_terminal_id);
|
||||
(next_terminal_id as i32, next_terminal_id + 1000) // secondary number is arbitrary here
|
||||
}
|
||||
|
16
src/tests/fixtures/layouts/three-panes-with-nesting.yaml
vendored
Normal file
16
src/tests/fixtures/layouts/three-panes-with-nesting.yaml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
direction: Horizontal
|
||||
parts:
|
||||
- direction: Vertical
|
||||
parts:
|
||||
- direction: Horizontal
|
||||
split_size:
|
||||
Percent: 20
|
||||
- direction: Horizontal
|
||||
split_size:
|
||||
Percent: 80
|
||||
split_size:
|
||||
Percent: 80
|
||||
- direction: Vertical
|
||||
split_size:
|
||||
Percent: 20
|
51
src/tests/integration/layouts.rs
Normal file
51
src/tests/integration/layouts.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use ::insta::assert_snapshot;
|
||||
use ::nix::pty::Winsize;
|
||||
|
||||
use crate::tests::fakes::FakeInputOutput;
|
||||
use crate::tests::utils::commands::QUIT;
|
||||
use crate::tests::utils::get_output_frame_snapshots;
|
||||
use crate::{start, Opt};
|
||||
|
||||
fn get_fake_os_input(fake_win_size: &Winsize) -> FakeInputOutput {
|
||||
FakeInputOutput::new(fake_win_size.clone())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn accepts_basic_layout() {
|
||||
let fake_win_size = Winsize {
|
||||
ws_col: 121,
|
||||
ws_row: 20,
|
||||
ws_xpixel: 0,
|
||||
ws_ypixel: 0,
|
||||
};
|
||||
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||
fake_input_output.add_terminal_input(&[QUIT]);
|
||||
use std::path::PathBuf;
|
||||
let mut opts = Opt::default();
|
||||
opts.layout = Some(PathBuf::from(
|
||||
"src/tests/fixtures/layouts/three-panes-with-nesting.yaml",
|
||||
));
|
||||
start(Box::new(fake_input_output.clone()), opts);
|
||||
let output_frames = fake_input_output
|
||||
.stdout_writer
|
||||
.output_frames
|
||||
.lock()
|
||||
.unwrap();
|
||||
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||
|
||||
let snapshot_count = snapshots.len();
|
||||
let first_snapshot = snapshots.get(0).unwrap();
|
||||
let next_to_last_snapshot = snapshots.get(snapshot_count - 2).unwrap();
|
||||
let last_snapshot = snapshots.last().unwrap();
|
||||
// here we only test the first, next to last and last snapshot because there's a race condition
|
||||
// with the other snapshots. Namely all the terminals are created asynchronously and read in an
|
||||
// async task, so we have no way to guarantee the order in which their bytes will be read, and
|
||||
// it doesn't really matter in this context. We just want to see that the layout is initially
|
||||
// created properly and that in the end it's populated properly with its content
|
||||
//
|
||||
// we read the next to last as well as the last, because the last includes the "Bye from
|
||||
// Mosaic" message, and we also want to make sure things are fine before that
|
||||
assert_snapshot!(first_snapshot);
|
||||
assert_snapshot!(next_to_last_snapshot);
|
||||
assert_snapshot!(last_snapshot);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
pub mod basic;
|
||||
pub mod close_pane;
|
||||
pub mod compatibility;
|
||||
pub mod layouts;
|
||||
pub mod resize_down;
|
||||
pub mod resize_left;
|
||||
pub mod resize_right;
|
||||
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
source: src/tests/integration/layouts.rs
|
||||
expression: next_to_last_snapshot
|
||||
---
|
||||
line6-bbbbbbbbbbbbbbbbbb│line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line7-bbbbbbbbbbbbbbbbbb│line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line8-bbbbbbbbbbbbbbbbbb│line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line9-bbbbbbbbbbbbbbbbbb│line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line10-bbbbbbbbbbbbbbbbb│line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line11-bbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line12-bbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line13-bbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line14-bbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line15-bbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line16-bbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line17-bbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line18-bbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line19-bbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
prompt $ █ │prompt $
|
||||
────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
prompt $
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
source: src/tests/integration/layouts.rs
|
||||
expression: last_snapshot
|
||||
---
|
||||
line7-bbbbbbbbbbbbbbbbbb│line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line8-bbbbbbbbbbbbbbbbbb│line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line9-bbbbbbbbbbbbbbbbbb│line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line10-bbbbbbbbbbbbbbbbb│line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line11-bbbbbbbbbbbbbbbbb│line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line12-bbbbbbbbbbbbbbbbb│line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line13-bbbbbbbbbbbbbbbbb│line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line14-bbbbbbbbbbbbbbbbb│line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line15-bbbbbbbbbbbbbbbbb│line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line16-bbbbbbbbbbbbbbbbb│line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line17-bbbbbbbbbbbbbbbbb│line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line18-bbbbbbbbbbbbbbbbb│line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
line19-bbbbbbbbbbbbbbbbb│line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
prompt $ │prompt $
|
||||
────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
prompt $
|
||||
Bye from Mosaic!█
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
source: src/tests/integration/layouts.rs
|
||||
expression: first_snapshot
|
||||
---
|
||||
█ │
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::tests::tty_inputs::{
|
||||
COL_10, COL_121, COL_14, COL_15, COL_19, COL_20, COL_24, COL_29, COL_30, COL_34, COL_39,
|
||||
COL_40, COL_50, COL_60, COL_70, COL_90,
|
||||
COL_40, COL_50, COL_60, COL_70, COL_90, COL_96,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@ -65,6 +65,7 @@ pub fn get_possible_tty_inputs() -> HashMap<u16, Bytes> {
|
||||
let col_60_bytes = Bytes::new().content_from_str(&COL_60);
|
||||
let col_70_bytes = Bytes::new().content_from_str(&COL_70);
|
||||
let col_90_bytes = Bytes::new().content_from_str(&COL_90);
|
||||
let col_96_bytes = Bytes::new().content_from_str(&COL_96);
|
||||
let col_121_bytes = Bytes::new().content_from_str(&COL_121);
|
||||
possible_inputs.insert(10, col_10_bytes);
|
||||
possible_inputs.insert(14, col_14_bytes);
|
||||
@ -81,6 +82,7 @@ pub fn get_possible_tty_inputs() -> HashMap<u16, Bytes> {
|
||||
possible_inputs.insert(60, col_60_bytes);
|
||||
possible_inputs.insert(70, col_70_bytes);
|
||||
possible_inputs.insert(90, col_90_bytes);
|
||||
possible_inputs.insert(96, col_96_bytes);
|
||||
possible_inputs.insert(121, col_121_bytes);
|
||||
possible_inputs
|
||||
}
|
||||
|
@ -364,3 +364,26 @@ pub const COL_90: [&str; 20] = [
|
||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"prompt $ ",
|
||||
];
|
||||
|
||||
pub const COL_96: [&str; 20] = [
|
||||
"line1-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line2-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line3-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line4-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line5-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line6-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line7-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line8-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line9-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line10-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line11-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line12-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line13-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line14-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line15-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line16-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line17-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line18-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"line19-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n",
|
||||
"prompt $ ",
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user