Extract `SizeInfo` from alacritty_terminal

The `SizeInfo` is a SizeInfo used for rendering, which contains
information about padding, and such, however all the terminal need is
number of visible lines and columns.
This commit is contained in:
Kirill Chibisov 2022-04-06 13:06:39 +03:00 committed by GitHub
parent 851dbc328e
commit 673710487a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 392 additions and 352 deletions

View File

@ -2,9 +2,9 @@
use alacritty_terminal::ansi::CursorShape;
use alacritty_terminal::term::color::Rgb;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCursor;
use crate::display::SizeInfo;
use crate::renderer::rects::RenderRect;
/// Trait for conversion into the iterator.

View File

@ -3,7 +3,9 @@ use std::iter::Peekable;
use glutin::Rect;
use alacritty_terminal::term::{LineDamageBounds, SizeInfo, TermDamageIterator};
use alacritty_terminal::term::{LineDamageBounds, TermDamageIterator};
use crate::display::SizeInfo;
/// Iterator which converts `alacritty_terminal` damage information into renderer damaged rects.
pub struct RenderDamageIterator<'a> {

View File

@ -16,6 +16,7 @@ use glutin::window::CursorIcon;
use glutin::Rect as DamageRect;
use log::{debug, info};
use parking_lot::MutexGuard;
use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use wayland_client::EventQueue;
@ -24,15 +25,13 @@ use crossfont::{self, Rasterize, Rasterizer};
use alacritty_terminal::ansi::NamedColor;
use alacritty_terminal::config::MAX_SCROLLBACK_LINES;
use alacritty_terminal::event::{EventListener, OnResize};
use alacritty_terminal::grid::Dimensions as _;
use alacritty_terminal::event::{EventListener, OnResize, WindowSize};
use alacritty_terminal::grid::Dimensions as TermDimensions;
use alacritty_terminal::index::{Column, Direction, Line, Point};
use alacritty_terminal::selection::{Selection, SelectionRange};
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::color::Rgb;
use alacritty_terminal::term::{
SizeInfo, Term, TermDamage, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES,
};
use alacritty_terminal::term::{Term, TermDamage, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES};
use crate::config::font::Font;
#[cfg(not(windows))]
@ -135,6 +134,166 @@ impl From<glutin::ContextError> for Error {
}
}
/// Terminal size info.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct SizeInfo<T = f32> {
/// Terminal window width.
width: T,
/// Terminal window height.
height: T,
/// Width of individual cell.
cell_width: T,
/// Height of individual cell.
cell_height: T,
/// Horizontal window padding.
padding_x: T,
/// Vertical window padding.
padding_y: T,
/// Number of lines in the viewport.
screen_lines: usize,
/// Number of columns in the viewport.
columns: usize,
}
impl From<SizeInfo<f32>> for SizeInfo<u32> {
fn from(size_info: SizeInfo<f32>) -> Self {
Self {
width: size_info.width as u32,
height: size_info.height as u32,
cell_width: size_info.cell_width as u32,
cell_height: size_info.cell_height as u32,
padding_x: size_info.padding_x as u32,
padding_y: size_info.padding_y as u32,
screen_lines: size_info.screen_lines,
columns: size_info.screen_lines,
}
}
}
impl From<SizeInfo<f32>> for WindowSize {
fn from(size_info: SizeInfo<f32>) -> Self {
Self {
num_cols: size_info.columns() as u16,
num_lines: size_info.screen_lines() as u16,
cell_width: size_info.cell_width() as u16,
cell_height: size_info.cell_width() as u16,
}
}
}
impl<T: Clone + Copy> SizeInfo<T> {
#[inline]
pub fn width(&self) -> T {
self.width
}
#[inline]
pub fn height(&self) -> T {
self.height
}
#[inline]
pub fn cell_width(&self) -> T {
self.cell_width
}
#[inline]
pub fn cell_height(&self) -> T {
self.cell_height
}
#[inline]
pub fn padding_x(&self) -> T {
self.padding_x
}
#[inline]
pub fn padding_y(&self) -> T {
self.padding_y
}
}
impl SizeInfo<f32> {
#[allow(clippy::too_many_arguments)]
pub fn new(
width: f32,
height: f32,
cell_width: f32,
cell_height: f32,
mut padding_x: f32,
mut padding_y: f32,
dynamic_padding: bool,
) -> SizeInfo {
if dynamic_padding {
padding_x = Self::dynamic_padding(padding_x.floor(), width, cell_width);
padding_y = Self::dynamic_padding(padding_y.floor(), height, cell_height);
}
let lines = (height - 2. * padding_y) / cell_height;
let screen_lines = cmp::max(lines as usize, MIN_SCREEN_LINES);
let columns = (width - 2. * padding_x) / cell_width;
let columns = cmp::max(columns as usize, MIN_COLUMNS);
SizeInfo {
width,
height,
cell_width,
cell_height,
padding_x: padding_x.floor(),
padding_y: padding_y.floor(),
screen_lines,
columns,
}
}
#[inline]
pub fn reserve_lines(&mut self, count: usize) {
self.screen_lines = cmp::max(self.screen_lines.saturating_sub(count), MIN_SCREEN_LINES);
}
/// Check if coordinates are inside the terminal grid.
///
/// The padding, message bar or search are not counted as part of the grid.
#[inline]
pub fn contains_point(&self, x: usize, y: usize) -> bool {
x <= (self.padding_x + self.columns as f32 * self.cell_width) as usize
&& x > self.padding_x as usize
&& y <= (self.padding_y + self.screen_lines as f32 * self.cell_height) as usize
&& y > self.padding_y as usize
}
/// Calculate padding to spread it evenly around the terminal content.
#[inline]
fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
padding + ((dimension - 2. * padding) % cell_dimension) / 2.
}
}
impl TermDimensions for SizeInfo {
#[inline]
fn columns(&self) -> usize {
self.columns
}
#[inline]
fn screen_lines(&self) -> usize {
self.screen_lines
}
#[inline]
fn total_lines(&self) -> usize {
self.screen_lines()
}
}
#[derive(Default, Clone, Debug, PartialEq)]
pub struct DisplayUpdate {
pub dirty: bool,
@ -456,7 +615,7 @@ impl Display {
self.size_info.reserve_lines(message_bar_lines + search_lines);
// Resize PTY.
pty_resize_handle.on_resize(&self.size_info);
pty_resize_handle.on_resize(self.size_info.into());
// Resize terminal.
terminal.resize(self.size_info);

View File

@ -50,10 +50,10 @@ use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use winapi::shared::minwindef::WORD;
use alacritty_terminal::index::Point;
use alacritty_terminal::term::SizeInfo;
use crate::config::window::{Decorations, Identity, WindowConfig};
use crate::config::UiConfig;
use crate::display::SizeInfo;
use crate::gl;
/// Window icon for `_NET_WM_ICON` property.

View File

@ -32,7 +32,7 @@ use alacritty_terminal::grid::{Dimensions, Scroll};
use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side};
use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::term::search::{Match, RegexSearch};
use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
use alacritty_terminal::term::{ClipboardType, Term, TermMode};
use crate::cli::{Options as CliOptions, WindowOptions};
use crate::clipboard::Clipboard;
@ -43,7 +43,7 @@ use crate::daemon::foreground_process_path;
use crate::daemon::spawn_daemon;
use crate::display::hint::HintMatch;
use crate::display::window::Window;
use crate::display::{self, Display};
use crate::display::{self, Display, SizeInfo};
use crate::input::{self, ActionContext as _, FONT_SIZE_STEP};
use crate::message_bar::{Message, MessageBuffer};
use crate::scheduler::{Scheduler, TimerId, Topic};
@ -1093,6 +1093,10 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
.unwrap_or(self.ctx.display.colors[index]);
self.ctx.write_to_pty(format(color).into_bytes());
},
TerminalEvent::TextAreaSizeRequest(format) => {
let text = format(self.ctx.size_info().into());
self.ctx.write_to_pty(text.into_bytes());
},
TerminalEvent::PtyWrite(text) => self.ctx.write_to_pty(text.into_bytes()),
TerminalEvent::MouseCursorDirty => self.reset_mouse_cursor(),
TerminalEvent::Exit => (),

View File

@ -27,14 +27,14 @@ use alacritty_terminal::grid::{Dimensions, Scroll};
use alacritty_terminal::index::{Boundary, Column, Direction, Point, Side};
use alacritty_terminal::selection::SelectionType;
use alacritty_terminal::term::search::Match;
use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
use alacritty_terminal::term::{ClipboardType, Term, TermMode};
use alacritty_terminal::vi_mode::ViMotion;
use crate::clipboard::Clipboard;
use crate::config::{Action, BindingMode, Key, MouseAction, SearchAction, UiConfig, ViAction};
use crate::display::hint::HintMatch;
use crate::display::window::Window;
use crate::display::Display;
use crate::display::{Display, SizeInfo};
use crate::event::{ClickState, Event, EventType, Mouse, TYPING_SEARCH_DELAY};
use crate::message_bar::{self, Message};
use crate::scheduler::{Scheduler, TimerId, Topic};
@ -1110,7 +1110,7 @@ mod tests {
false,
);
let mut terminal = Term::new(&cfg.terminal_config, size, MockEventProxy);
let mut terminal = Term::new(&cfg.terminal_config, &size, MockEventProxy);
let mut mouse = Mouse {
click_state: $initial_state,

View File

@ -3,7 +3,8 @@ use std::collections::VecDeque;
use unicode_width::UnicodeWidthChar;
use alacritty_terminal::grid::Dimensions;
use alacritty_terminal::term::SizeInfo;
use crate::display::SizeInfo;
pub const CLOSE_BUTTON_TEXT: &str = "[X]";
const CLOSE_BUTTON_PADDING: usize = 1;
@ -186,7 +187,7 @@ impl MessageBuffer {
mod tests {
use super::*;
use alacritty_terminal::term::SizeInfo;
use crate::display::SizeInfo;
#[test]
fn appends_close_button() {

View File

@ -7,9 +7,9 @@ use log::info;
use alacritty_terminal::index::Point;
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::color::Rgb;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::renderer::rects::{RectRenderer, RenderRect};
use crate::renderer::shader::ShaderError;

View File

@ -7,9 +7,9 @@ use alacritty_terminal::grid::Dimensions;
use alacritty_terminal::index::{Column, Point};
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::color::Rgb;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;
use crate::renderer::shader::{ShaderError, ShaderProgram, ShaderVersion};

View File

@ -5,9 +5,9 @@ use crossfont::RasterizedGlyph;
use log::info;
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;
use crate::renderer::shader::{ShaderProgram, ShaderVersion};

View File

@ -5,9 +5,9 @@ use crossfont::RasterizedGlyph;
use log::info;
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;
use crate::renderer::shader::{ShaderProgram, ShaderVersion};

View File

@ -2,9 +2,9 @@ use bitflags::bitflags;
use crossfont::{GlyphKey, RasterizedGlyph};
use alacritty_terminal::term::cell::Flags;
use alacritty_terminal::term::SizeInfo;
use crate::display::content::RenderableCell;
use crate::display::SizeInfo;
use crate::gl;
use crate::gl::types::*;

View File

@ -24,6 +24,7 @@ use alacritty_terminal::event_loop::{EventLoop as PtyEventLoop, Msg, Notifier};
use alacritty_terminal::grid::{Dimensions, Scroll};
use alacritty_terminal::index::Direction;
use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::test::TermSize;
use alacritty_terminal::term::{Term, TermMode};
use alacritty_terminal::tty;
@ -98,7 +99,7 @@ impl WindowContext {
// This object contains all of the state about what's being displayed. It's
// wrapped in a clonable mutex since both the I/O loop and display need to
// access it.
let terminal = Term::new(&config.terminal_config, display.size_info, event_proxy.clone());
let terminal = Term::new(&config.terminal_config, &display.size_info, event_proxy.clone());
let terminal = Arc::new(FairMutex::new(terminal));
// Create the PTY.
@ -106,7 +107,7 @@ impl WindowContext {
// The PTY forks a process to run the shell on the slave side of the
// pseudoterminal. A file descriptor for the master side is retained for
// reading/writing to the shell.
let pty = tty::new(&pty_config, &display.size_info, display.window.x11_window_id())?;
let pty = tty::new(&pty_config, display.size_info.into(), display.window.x11_window_id())?;
#[cfg(not(windows))]
let master_fd = pty.file().as_raw_fd();
@ -350,7 +351,9 @@ impl WindowContext {
let serialized_grid = json::to_string(&grid).expect("serialize grid");
let serialized_size = json::to_string(&self.display.size_info).expect("serialize size");
let size_info = &self.display.size_info;
let size = TermSize::new(size_info.columns(), size_info.screen_lines());
let serialized_size = json::to_string(&size).expect("serialize size");
let serialized_config = format!("{{\"history_size\":{}}}", grid.history_size());

View File

@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use crate::term::color::Rgb;
use crate::term::{ClipboardType, SizeInfo};
use crate::term::ClipboardType;
/// Terminal event.
///
@ -38,6 +38,9 @@ pub enum Event {
/// Write some text to the PTY.
PtyWrite(String),
/// Request to write the text area size.
TextAreaSizeRequest(Arc<dyn Fn(WindowSize) -> String + Sync + Send + 'static>),
/// Cursor blinking state has changed.
CursorBlinkingChange,
@ -56,6 +59,7 @@ impl Debug for Event {
match self {
Event::ClipboardStore(ty, text) => write!(f, "ClipboardStore({:?}, {})", ty, text),
Event::ClipboardLoad(ty, _) => write!(f, "ClipboardLoad({:?})", ty),
Event::TextAreaSizeRequest(_) => write!(f, "TextAreaSizeRequest"),
Event::ColorRequest(index, _) => write!(f, "ColorRequest({})", index),
Event::PtyWrite(text) => write!(f, "PtyWrite({})", text),
Event::Title(title) => write!(f, "Title({})", title),
@ -77,9 +81,17 @@ pub trait Notify {
fn notify<B: Into<Cow<'static, [u8]>>>(&self, _: B);
}
#[derive(Copy, Clone, Debug)]
pub struct WindowSize {
pub num_lines: u16,
pub num_cols: u16,
pub cell_width: u16,
pub cell_height: u16,
}
/// Types that are interested in when the display is resized.
pub trait OnResize {
fn on_resize(&mut self, size: &SizeInfo);
fn on_resize(&mut self, window_size: WindowSize);
}
/// Event Loop for notifying the renderer about terminal events.

View File

@ -15,9 +15,9 @@ use mio::unix::UnixReady;
use mio::{self, Events, PollOpt, Ready};
use mio_extras::channel::{self, Receiver, Sender};
use crate::event::{self, Event, EventListener};
use crate::event::{self, Event, EventListener, WindowSize};
use crate::sync::FairMutex;
use crate::term::{SizeInfo, Term};
use crate::term::Term;
use crate::{ansi, thread, tty};
/// Max bytes to read from the PTY before forced terminal synchronization.
@ -36,7 +36,7 @@ pub enum Msg {
Shutdown,
/// Instruction to resize the PTY.
Resize(SizeInfo),
Resize(WindowSize),
}
/// The main event!.. loop.
@ -78,8 +78,8 @@ impl event::Notify for Notifier {
}
impl event::OnResize for Notifier {
fn on_resize(&mut self, size: &SizeInfo) {
let _ = self.0.send(Msg::Resize(*size));
fn on_resize(&mut self, window_size: WindowSize) {
let _ = self.0.send(Msg::Resize(window_size));
}
}
@ -182,7 +182,7 @@ where
while let Ok(msg) = self.rx.try_recv() {
match msg {
Msg::Input(input) => state.write_list.push_back(input),
Msg::Resize(size) => self.pty.on_resize(&size),
Msg::Resize(window_size) => self.pty.on_resize(window_size),
Msg::Shutdown => return false,
}
}

View File

@ -397,11 +397,12 @@ mod tests {
use crate::config::Config;
use crate::index::{Column, Point, Side};
use crate::term::{SizeInfo, Term};
use crate::term::test::TermSize;
use crate::term::Term;
fn term(height: usize, width: usize) -> Term<()> {
let size = SizeInfo::new(width as f32, height as f32, 1.0, 1.0, 0.0, 0.0, false);
Term::new(&Config::default(), size, ())
let size = TermSize::new(width, height);
Term::new(&Config::default(), &size, ())
}
/// Test case of single cell selection.

View File

@ -6,7 +6,6 @@ use std::{cmp, mem, ptr, slice, str};
use bitflags::bitflags;
use log::{debug, trace};
use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
use crate::ansi::{
@ -74,155 +73,6 @@ impl Default for TermMode {
}
}
/// Terminal size info.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct SizeInfo<T = f32> {
/// Terminal window width.
width: T,
/// Terminal window height.
height: T,
/// Width of individual cell.
cell_width: T,
/// Height of individual cell.
cell_height: T,
/// Horizontal window padding.
padding_x: T,
/// Vertical window padding.
padding_y: T,
/// Number of lines in the viewport.
screen_lines: usize,
/// Number of columns in the viewport.
columns: usize,
}
impl From<SizeInfo<f32>> for SizeInfo<u32> {
fn from(size_info: SizeInfo<f32>) -> Self {
Self {
width: size_info.width as u32,
height: size_info.height as u32,
cell_width: size_info.cell_width as u32,
cell_height: size_info.cell_height as u32,
padding_x: size_info.padding_x as u32,
padding_y: size_info.padding_y as u32,
screen_lines: size_info.screen_lines,
columns: size_info.screen_lines,
}
}
}
impl<T: Clone + Copy> SizeInfo<T> {
#[inline]
pub fn width(&self) -> T {
self.width
}
#[inline]
pub fn height(&self) -> T {
self.height
}
#[inline]
pub fn cell_width(&self) -> T {
self.cell_width
}
#[inline]
pub fn cell_height(&self) -> T {
self.cell_height
}
#[inline]
pub fn padding_x(&self) -> T {
self.padding_x
}
#[inline]
pub fn padding_y(&self) -> T {
self.padding_y
}
}
impl SizeInfo<f32> {
#[allow(clippy::too_many_arguments)]
pub fn new(
width: f32,
height: f32,
cell_width: f32,
cell_height: f32,
mut padding_x: f32,
mut padding_y: f32,
dynamic_padding: bool,
) -> SizeInfo {
if dynamic_padding {
padding_x = Self::dynamic_padding(padding_x.floor(), width, cell_width);
padding_y = Self::dynamic_padding(padding_y.floor(), height, cell_height);
}
let lines = (height - 2. * padding_y) / cell_height;
let screen_lines = cmp::max(lines as usize, MIN_SCREEN_LINES);
let columns = (width - 2. * padding_x) / cell_width;
let columns = cmp::max(columns as usize, MIN_COLUMNS);
SizeInfo {
width,
height,
cell_width,
cell_height,
padding_x: padding_x.floor(),
padding_y: padding_y.floor(),
screen_lines,
columns,
}
}
#[inline]
pub fn reserve_lines(&mut self, count: usize) {
self.screen_lines = cmp::max(self.screen_lines.saturating_sub(count), MIN_SCREEN_LINES);
}
/// Check if coordinates are inside the terminal grid.
///
/// The padding, message bar or search are not counted as part of the grid.
#[inline]
pub fn contains_point(&self, x: usize, y: usize) -> bool {
x <= (self.padding_x + self.columns as f32 * self.cell_width) as usize
&& x > self.padding_x as usize
&& y <= (self.padding_y + self.screen_lines as f32 * self.cell_height) as usize
&& y > self.padding_y as usize
}
/// Calculate padding to spread it evenly around the terminal content.
#[inline]
fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
padding + ((dimension - 2. * padding) % cell_dimension) / 2.
}
}
impl Dimensions for SizeInfo {
#[inline]
fn columns(&self) -> usize {
self.columns
}
#[inline]
fn screen_lines(&self) -> usize {
self.screen_lines
}
#[inline]
fn total_lines(&self) -> usize {
self.screen_lines()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct LineDamageBounds {
/// Damaged line number.
@ -431,10 +281,6 @@ pub struct Term<T> {
/// term is set.
title_stack: Vec<Option<String>>,
/// Information about cell dimensions.
cell_width: usize,
cell_height: usize,
/// Information about damaged cells.
damage: TermDamageState,
}
@ -462,9 +308,9 @@ impl<T> Term<T> {
}
}
pub fn new(config: &Config, size: SizeInfo, event_proxy: T) -> Term<T> {
let num_cols = size.columns;
let num_lines = size.screen_lines;
pub fn new<D: Dimensions>(config: &Config, dimensions: &D, event_proxy: T) -> Term<T> {
let num_cols = dimensions.columns();
let num_lines = dimensions.screen_lines();
let history_size = config.scrolling.history() as usize;
let grid = Grid::new(num_lines, num_cols, history_size);
@ -495,8 +341,6 @@ impl<T> Term<T> {
title: None,
title_stack: Vec::new(),
selection: None,
cell_width: size.cell_width as usize,
cell_height: size.cell_height as usize,
damage,
}
}
@ -717,15 +561,12 @@ impl<T> Term<T> {
}
/// Resize terminal to new dimensions.
pub fn resize(&mut self, size: SizeInfo) {
self.cell_width = size.cell_width as usize;
self.cell_height = size.cell_height as usize;
pub fn resize<S: Dimensions>(&mut self, size: S) {
let old_cols = self.columns();
let old_lines = self.screen_lines();
let num_cols = size.columns;
let num_lines = size.screen_lines;
let num_cols = size.columns();
let num_lines = size.screen_lines();
if old_cols == num_cols && old_lines == num_lines {
debug!("Term::resize dimensions unchanged");
@ -2077,10 +1918,11 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn text_area_size_pixels(&mut self) {
let width = self.cell_width * self.columns();
let height = self.cell_height * self.screen_lines();
let text = format!("\x1b[4;{};{}t", height, width);
self.event_proxy.send_event(Event::PtyWrite(text));
self.event_proxy.send_event(Event::TextAreaSizeRequest(Arc::new(move |window_size| {
let height = window_size.num_lines * window_size.cell_height;
let width = window_size.num_cols * window_size.cell_width;
format!("\x1b[4;{};{}t", height, width)
})));
}
#[inline]
@ -2217,11 +2059,38 @@ impl<'a> RenderableContent<'a> {
pub mod test {
use super::*;
use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
use crate::config::Config;
use crate::index::Column;
#[derive(Serialize, Deserialize)]
pub struct TermSize {
pub columns: usize,
pub screen_lines: usize,
}
impl TermSize {
pub fn new(columns: usize, screen_lines: usize) -> Self {
Self { columns, screen_lines }
}
}
impl Dimensions for TermSize {
fn total_lines(&self) -> usize {
self.screen_lines()
}
fn screen_lines(&self) -> usize {
self.screen_lines
}
fn columns(&self) -> usize {
self.columns
}
}
/// Construct a terminal from its content as string.
///
/// A `\n` will break line and `\r\n` will break line without wrapping.
@ -2250,8 +2119,8 @@ pub mod test {
.unwrap_or(0);
// Create terminal with the appropriate dimensions.
let size = SizeInfo::new(num_cols as f32, lines.len() as f32, 1., 1., 0., 0., false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(num_cols, lines.len());
let mut term = Term::new(&Config::default(), &size, ());
// Fill terminal with content.
for (line, text) in lines.iter().enumerate() {
@ -2291,11 +2160,12 @@ mod tests {
use crate::index::{Column, Point, Side};
use crate::selection::{Selection, SelectionType};
use crate::term::cell::{Cell, Flags};
use crate::term::test::TermSize;
#[test]
fn scroll_display_page_up() {
let size = SizeInfo::new(5., 10., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 11 lines of scrollback.
for _ in 0..20 {
@ -2320,8 +2190,8 @@ mod tests {
#[test]
fn scroll_display_page_down() {
let size = SizeInfo::new(5., 10., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 11 lines of scrollback.
for _ in 0..20 {
@ -2350,8 +2220,8 @@ mod tests {
#[test]
fn simple_selection_works() {
let size = SizeInfo::new(5., 5., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 5);
let mut term = Term::new(&Config::default(), &size, ());
let grid = term.grid_mut();
for i in 0..4 {
if i == 1 {
@ -2396,8 +2266,8 @@ mod tests {
#[test]
fn semantic_selection_works() {
let size = SizeInfo::new(5., 3., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 3);
let mut term = Term::new(&Config::default(), &size, ());
let mut grid: Grid<Cell> = Grid::new(3, 5, 0);
for i in 0..5 {
for j in 0..2 {
@ -2444,8 +2314,8 @@ mod tests {
#[test]
fn line_selection_works() {
let size = SizeInfo::new(5., 1., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 1);
let mut term = Term::new(&Config::default(), &size, ());
let mut grid: Grid<Cell> = Grid::new(1, 5, 0);
for i in 0..5 {
grid[Line(0)][Column(i)].c = 'a';
@ -2465,8 +2335,8 @@ mod tests {
#[test]
fn block_selection_works() {
let size = SizeInfo::new(5., 5., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 5);
let mut term = Term::new(&Config::default(), &size, ());
let grid = term.grid_mut();
for i in 1..4 {
grid[Line(i)][Column(0)].c = '"';
@ -2521,8 +2391,8 @@ mod tests {
#[test]
fn input_line_drawing_character() {
let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(7, 17);
let mut term = Term::new(&Config::default(), &size, ());
let cursor = Point::new(Line(0), Column(0));
term.configure_charset(CharsetIndex::G0, StandardCharset::SpecialCharacterAndLineDrawing);
term.input('a');
@ -2532,8 +2402,8 @@ mod tests {
#[test]
fn clearing_viewport_keeps_history_position() {
let size = SizeInfo::new(10.0, 20.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 20);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..29 {
@ -2553,8 +2423,8 @@ mod tests {
#[test]
fn clearing_viewport_with_vi_mode_keeps_history_position() {
let size = SizeInfo::new(10.0, 20.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 20);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..29 {
@ -2579,8 +2449,8 @@ mod tests {
#[test]
fn clearing_scrollback_resets_display_offset() {
let size = SizeInfo::new(10.0, 20.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 20);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..29 {
@ -2600,8 +2470,8 @@ mod tests {
#[test]
fn clearing_scrollback_sets_vi_cursor_into_viewport() {
let size = SizeInfo::new(10.0, 20.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 20);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..29 {
@ -2626,8 +2496,8 @@ mod tests {
#[test]
fn clear_saved_lines() {
let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(7, 17);
let mut term = Term::new(&Config::default(), &size, ());
// Add one line of scrollback.
term.grid.scroll_up(&(Line(0)..Line(1)), 1);
@ -2648,8 +2518,8 @@ mod tests {
#[test]
fn vi_cursor_keep_pos_on_scrollback_buffer() {
let size = SizeInfo::new(5., 10., 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(5, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 11 lines of scrollback.
for _ in 0..20 {
@ -2668,8 +2538,8 @@ mod tests {
#[test]
fn grow_lines_updates_active_cursor_pos() {
let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let mut size = TermSize::new(100, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..19 {
@ -2688,8 +2558,8 @@ mod tests {
#[test]
fn grow_lines_updates_inactive_cursor_pos() {
let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let mut size = TermSize::new(100, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..19 {
@ -2714,8 +2584,8 @@ mod tests {
#[test]
fn shrink_lines_updates_active_cursor_pos() {
let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let mut size = TermSize::new(100, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..19 {
@ -2734,8 +2604,8 @@ mod tests {
#[test]
fn shrink_lines_updates_inactive_cursor_pos() {
let mut size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let mut size = TermSize::new(100, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Create 10 lines of scrollback.
for _ in 0..19 {
@ -2760,8 +2630,8 @@ mod tests {
#[test]
fn damage_public_usage() {
let size = SizeInfo::new(10.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 10);
let mut term = Term::new(&Config::default(), &size, ());
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
@ -2840,8 +2710,8 @@ mod tests {
#[test]
fn damage_cursor_movements() {
let size = SizeInfo::new(10.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 10);
let mut term = Term::new(&Config::default(), &size, ());
let num_cols = term.columns();
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
@ -2938,8 +2808,8 @@ mod tests {
#[test]
fn damage_vi_movements() {
let size = SizeInfo::new(10.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(10, 10);
let mut term = Term::new(&Config::default(), &size, ());
let num_cols = term.columns();
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
@ -2970,8 +2840,8 @@ mod tests {
#[test]
fn full_damage() {
let size = SizeInfo::new(100.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(100, 10);
let mut term = Term::new(&Config::default(), &size, ());
assert!(term.damage.is_fully_damaged);
for _ in 0..20 {
@ -3049,15 +2919,15 @@ mod tests {
assert!(term.damage.is_fully_damaged);
term.reset_damage();
let size = SizeInfo::new(10.0, 10.0, 1.0, 1.0, 0.0, 0.0, false);
let size = TermSize::new(10, 10);
term.resize(size);
assert!(term.damage.is_fully_damaged);
}
#[test]
fn window_title() {
let size = SizeInfo::new(21.0, 51.0, 3.0, 3.0, 0.0, 0.0, false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(7, 17);
let mut term = Term::new(&Config::default(), &size, ());
// Title None by default.
assert_eq!(term.title, None);

View File

@ -510,8 +510,7 @@ mod tests {
use crate::config::Config;
use crate::index::{Column, Line};
use crate::term::test::mock_term;
use crate::term::SizeInfo;
use crate::term::test::{mock_term, TermSize};
#[test]
fn regex_right() {
@ -810,8 +809,8 @@ mod tests {
#[test]
fn wide_without_spacer() {
let size = SizeInfo::new(2., 2., 1., 1., 0., 0., false);
let mut term = Term::new(&Config::default(), size, ());
let size = TermSize::new(2, 2);
let mut term = Term::new(&Config::default(), &size, ());
term.grid[Line(0)][Column(0)].c = 'x';
term.grid[Line(0)][Column(1)].c = '字';
term.grid[Line(0)][Column(1)].flags = Flags::WIDE_CHAR;

View File

@ -22,9 +22,7 @@ use signal_hook::consts as sigconsts;
use signal_hook_mio::v0_6::Signals;
use crate::config::{Program, PtyConfig};
use crate::event::OnResize;
use crate::grid::Dimensions;
use crate::term::SizeInfo;
use crate::event::{OnResize, WindowSize};
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
macro_rules! die {
@ -36,11 +34,11 @@ macro_rules! die {
/// Get raw fds for master/slave ends of a new PTY.
fn make_pty(size: winsize) -> (RawFd, RawFd) {
let mut win_size = size;
win_size.ws_xpixel = 0;
win_size.ws_ypixel = 0;
let mut window_size = size;
window_size.ws_xpixel = 0;
window_size.ws_ypixel = 0;
let ends = openpty(Some(&win_size), None).expect("openpty failed");
let ends = openpty(Some(&window_size), None).expect("openpty failed");
(ends.master, ends.slave)
}
@ -137,8 +135,8 @@ fn default_shell(pw: &Passwd<'_>) -> Program {
}
/// Create a new TTY and return a handle to interact with it.
pub fn new(config: &PtyConfig, size: &SizeInfo, window_id: Option<usize>) -> Result<Pty> {
let (master, slave) = make_pty(size.to_winsize());
pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: Option<usize>) -> Result<Pty> {
let (master, slave) = make_pty(window_size.to_winsize());
#[cfg(any(target_os = "linux", target_os = "macos"))]
if let Ok(mut termios) = termios::tcgetattr(master) {
@ -229,7 +227,7 @@ pub fn new(config: &PtyConfig, size: &SizeInfo, window_id: Option<usize>) -> Res
signals,
signals_token: mio::Token::from(0),
};
pty.on_resize(size);
pty.on_resize(window_size);
Ok(pty)
},
Err(err) => Err(Error::new(
@ -347,8 +345,8 @@ impl OnResize for Pty {
///
/// Tells the kernel that the window size changed with the new pixel
/// dimensions and line/column counts.
fn on_resize(&mut self, size: &SizeInfo) {
let win = size.to_winsize();
fn on_resize(&mut self, window_size: WindowSize) {
let win = window_size.to_winsize();
let res = unsafe { libc::ioctl(self.file.as_raw_fd(), libc::TIOCSWINSZ, &win as *const _) };
@ -361,17 +359,17 @@ impl OnResize for Pty {
/// Types that can produce a `libc::winsize`.
pub trait ToWinsize {
/// Get a `libc::winsize`.
fn to_winsize(&self) -> winsize;
fn to_winsize(self) -> winsize;
}
impl<'a> ToWinsize for &'a SizeInfo {
fn to_winsize(&self) -> winsize {
winsize {
ws_row: self.screen_lines() as libc::c_ushort,
ws_col: self.columns() as libc::c_ushort,
ws_xpixel: self.width() as libc::c_ushort,
ws_ypixel: self.height() as libc::c_ushort,
}
impl ToWinsize for WindowSize {
fn to_winsize(self) -> winsize {
let ws_row = self.num_lines as libc::c_ushort;
let ws_col = self.num_cols as libc::c_ushort;
let ws_xpixel = ws_col * self.cell_width as libc::c_ushort;
let ws_ypixel = ws_row * self.cell_height as libc::c_ushort;
winsize { ws_row, ws_col, ws_xpixel, ws_ypixel }
}
}

View File

@ -1,6 +1,6 @@
use std::io::Error;
use std::os::windows::io::IntoRawHandle;
use std::{i16, mem, ptr};
use std::{mem, ptr};
use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
use winapi::shared::basetsd::{PSIZE_T, SIZE_T};
@ -16,9 +16,7 @@ use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTF_USESTDHANDLES, ST
use winapi::um::wincontypes::{COORD, HPCON};
use crate::config::PtyConfig;
use crate::event::OnResize;
use crate::grid::Dimensions;
use crate::term::SizeInfo;
use crate::event::{OnResize, WindowSize};
use crate::tty::windows::child::ChildExitWatcher;
use crate::tty::windows::{cmdline, win32_string, Pty};
@ -40,7 +38,7 @@ impl Drop for Conpty {
// The ConPTY handle can be sent between threads.
unsafe impl Send for Conpty {}
pub fn new(config: &PtyConfig, size: &SizeInfo) -> Option<Pty> {
pub fn new(config: &PtyConfig, window_size: WindowSize) -> Option<Pty> {
let mut pty_handle = 0 as HPCON;
// Passing 0 as the size parameter allows the "system default" buffer
@ -50,13 +48,10 @@ pub fn new(config: &PtyConfig, size: &SizeInfo) -> Option<Pty> {
let (conout, conout_pty_handle) = miow::pipe::anonymous(0).unwrap();
let (conin_pty_handle, conin) = miow::pipe::anonymous(0).unwrap();
let coord =
coord_from_sizeinfo(size).expect("Overflow when creating initial size on pseudoconsole");
// Create the Pseudo Console, using the pipes.
let result = unsafe {
CreatePseudoConsole(
coord,
window_size.into(),
conin_pty_handle.into_raw_handle(),
conout_pty_handle.into_raw_handle(),
0,
@ -174,22 +169,16 @@ fn panic_shell_spawn() {
}
impl OnResize for Conpty {
fn on_resize(&mut self, sizeinfo: &SizeInfo) {
if let Some(coord) = coord_from_sizeinfo(sizeinfo) {
let result = unsafe { ResizePseudoConsole(self.handle, coord) };
assert_eq!(result, S_OK);
}
fn on_resize(&mut self, window_size: WindowSize) {
let result = unsafe { ResizePseudoConsole(self.handle, window_size.into()) };
assert_eq!(result, S_OK);
}
}
/// Helper to build a COORD from a SizeInfo, returning None in overflow cases.
fn coord_from_sizeinfo(size: &SizeInfo) -> Option<COORD> {
let lines = size.screen_lines();
let columns = size.columns();
if columns <= i16::MAX as usize && lines <= i16::MAX as usize {
Some(COORD { X: columns as i16, Y: lines as i16 })
} else {
None
impl From<WindowSize> for COORD {
fn from(window_size: WindowSize) -> Self {
let lines = window_size.num_lines;
let columns = window_size.num_cols;
COORD { X: columns as i16, Y: lines as i16 }
}
}

View File

@ -5,8 +5,7 @@ use std::os::windows::ffi::OsStrExt;
use std::sync::mpsc::TryRecvError;
use crate::config::{Program, PtyConfig};
use crate::event::OnResize;
use crate::term::SizeInfo;
use crate::event::{OnResize, WindowSize};
use crate::tty::windows::child::ChildExitWatcher;
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
@ -28,8 +27,9 @@ pub struct Pty {
child_watcher: ChildExitWatcher,
}
pub fn new(config: &PtyConfig, size: &SizeInfo, _window_id: Option<usize>) -> Result<Pty> {
conpty::new(config, size).ok_or_else(|| Error::new(ErrorKind::Other, "failed to spawn conpty"))
pub fn new(config: &PtyConfig, window_size: WindowSize, _window_id: Option<usize>) -> Result<Pty> {
conpty::new(config, window_size)
.ok_or_else(|| Error::new(ErrorKind::Other, "failed to spawn conpty"))
}
impl Pty {
@ -160,8 +160,8 @@ impl EventedPty for Pty {
}
impl OnResize for Pty {
fn on_resize(&mut self, size: &SizeInfo) {
self.backend.on_resize(size)
fn on_resize(&mut self, window_size: WindowSize) {
self.backend.on_resize(window_size)
}
}

View File

@ -381,11 +381,12 @@ mod tests {
use crate::ansi::Handler;
use crate::config::Config;
use crate::index::{Column, Line};
use crate::term::{SizeInfo, Term};
use crate::term::test::TermSize;
use crate::term::Term;
fn term() -> Term<()> {
let size = SizeInfo::new(20., 20., 1.0, 1.0, 0.0, 0.0, false);
Term::new(&Config::default(), size, ())
let size = TermSize::new(20, 20);
Term::new(&Config::default(), &size, ())
}
#[test]

View File

@ -11,7 +11,8 @@ use alacritty_terminal::event::{Event, EventListener};
use alacritty_terminal::grid::{Dimensions, Grid};
use alacritty_terminal::index::{Column, Line};
use alacritty_terminal::term::cell::Cell;
use alacritty_terminal::term::{SizeInfo, Term};
use alacritty_terminal::term::test::TermSize;
use alacritty_terminal::term::Term;
macro_rules! ref_tests {
($($name:ident)*) => {
@ -98,14 +99,14 @@ fn ref_test(dir: &Path) {
let serialized_grid = fs::read_to_string(dir.join("grid.json")).unwrap();
let serialized_cfg = fs::read_to_string(dir.join("config.json")).unwrap();
let size: SizeInfo = json::from_str(&serialized_size).unwrap();
let size: TermSize = json::from_str(&serialized_size).unwrap();
let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap();
let mut config = Config::default();
config.scrolling.set_history(ref_config.history_size);
let mut terminal = Term::new(&config, size, Mock);
let mut terminal = Term::new(&config, &size, Mock);
let mut parser = ansi::Processor::new();
for byte in recording {

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":662.0,"height":708.0,"cell_width":10.0,"cell_height":22.0,"padding_x":0.0,"padding_y":0.0,"columns":66,"screen_lines":32}
{"columns":66,"screen_lines":32}

View File

@ -1 +1 @@
{"width":939.0,"height":1020.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":6.0,"columns":116,"screen_lines":63}
{"columns":116,"screen_lines":63}

View File

@ -1 +1 @@
{"width":1262.0,"height":690.0,"cell_width":9.0,"cell_height":18.0,"padding_x":0.0,"padding_y":0.0,"screen_lines":38,"columns":140}
{"screen_lines":38,"columns":140}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":939.0,"height":503.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":3.0,"columns":116,"screen_lines":31}
{"columns":116,"screen_lines":31}

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1916.0,"height":1054.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":106,"screen_lines":30}
{"columns":106,"screen_lines":30}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":939.0,"height":503.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":3.0,"columns":116,"screen_lines":31}
{"columns":116,"screen_lines":31}

View File

@ -1 +1 @@
{"width":1900.0,"height":1040.0,"cell_width":11.0,"cell_height":22.0,"padding_x":0.0,"padding_y":0.0,"columns":172,"screen_lines":47}
{"columns":172,"screen_lines":47}

View File

@ -1 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"columns":139,"screen_lines":35}
{"columns":139,"screen_lines":35}

View File

@ -1 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"columns":139,"screen_lines":35}
{"columns":139,"screen_lines":35}

View File

@ -1 +1 @@
{"width":1840.0,"height":1040.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":102,"screen_lines":29}
{"columns":102,"screen_lines":29}

View File

@ -1 +1 @@
{"width":70.0,"height":63.0,"cell_width":7.0,"cell_height":21.0,"padding_x":0.0,"padding_y":0.0,"columns":10,"screen_lines":3}
{"columns":10,"screen_lines":3}

View File

@ -1 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"columns":139,"screen_lines":35}
{"columns":139,"screen_lines":35}

View File

@ -1 +1 @@
{"width":939.0,"height":1020.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":6.0,"columns":116,"screen_lines":63}
{"columns":116,"screen_lines":63}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":948.0,"height":1041.0,"cell_width":7.0,"cell_height":16.0,"padding_x":5.0,"padding_y":8.0,"screen_lines":64,"columns":134}
{"screen_lines":64,"columns":134}

View File

@ -1 +1 @@
{"width":1916.0,"height":2121.0,"cell_width":11.0,"cell_height":22.0,"padding_x":0.0,"padding_y":0.0,"columns":174,"screen_lines":96}
{"columns":174,"screen_lines":96}

View File

@ -1 +1 @@
{"width":1900.0,"height":1040.0,"cell_width":11.0,"cell_height":22.0,"padding_x":0.0,"padding_y":0.0,"columns":172,"screen_lines":47}
{"columns":172,"screen_lines":47}

View File

@ -1 +1 @@
{"width":644.0,"height":412.0,"cell_width":8.0,"cell_height":17.0,"padding_x":0.0,"padding_y":0.0,"columns":80,"screen_lines":24}
{"columns":80,"screen_lines":24}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}

View File

@ -1 +1 @@
{"width":939.0,"height":503.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":3.0,"columns":116,"screen_lines":31}
{"columns":116,"screen_lines":31}

View File

@ -1 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"columns":139,"screen_lines":35}
{"columns":139,"screen_lines":35}

View File

@ -1 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"screen_lines":35,"columns":139}
{"screen_lines":35,"columns":139}

View File

@ -1 +1 @@
{"width":1900.0,"height":1038.0,"cell_width":18.0,"cell_height":35.0,"padding_x":0.0,"padding_y":0.0,"columns":105,"screen_lines":29}
{"columns":105,"screen_lines":29}