Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compatibility): implement device reports #500

Merged
merged 2 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Fix propagation of plugin ui request (https://github.com/zellij-org/zellij/pull/495)
* Handle pasted text properly (https://github.com/zellij-org/zellij/pull/494)
* Fix default keybinds for tab -> resize mode (https://github.com/zellij-org/zellij/pull/497)
* Terminal compatibility: device reports (https://github.com/zellij-org/zellij/pull/500)

## [0.9.0] - 2021-05-11
* Add more functionality to unbinding the default keybindings (https://github.com/zellij-org/zellij/pull/468)
Expand Down
67 changes: 67 additions & 0 deletions src/client/panes/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use vte::{Params, Perform};
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
const SCROLL_BACK: usize = 10_000;

use crate::utils::consts::VERSION;
use crate::utils::logging::debug_log_to_file;
use crate::utils::shared::version_number;

use crate::panes::terminal_character::{
CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter,
Expand Down Expand Up @@ -186,6 +188,7 @@ pub struct Grid {
pub clear_viewport_before_rendering: bool,
pub width: usize,
pub height: usize,
pub pending_messages_to_pty: Vec<Vec<u8>>,
}

impl Debug for Grid {
Expand Down Expand Up @@ -222,6 +225,7 @@ impl Grid {
alternative_lines_above_viewport_and_cursor: None,
clear_viewport_before_rendering: false,
active_charset: Default::default(),
pending_messages_to_pty: vec![],
}
}
pub fn contains_widechar(&self) -> bool {
Expand Down Expand Up @@ -1283,6 +1287,64 @@ impl Perform for Grid {
for _ in 0..next_param_or(1) {
self.move_to_previous_tabstop();
}
} else if c == 'c' {
// identify terminal
// https://vt100.net/docs/vt510-rm/DA1.html
match intermediates.get(0) {
None | Some(0) => {
// primary device attributes
let terminal_capabilities = "\u{1b}[?6c";
self.pending_messages_to_pty
.push(terminal_capabilities.as_bytes().to_vec());
}
Some(b'>') => {
// secondary device attributes
let version = version_number(VERSION);
let text = format!("\u{1b}[>0;{};1c", version);
self.pending_messages_to_pty.push(text.as_bytes().to_vec());
}
_ => {}
}
} else if c == 'n' {
// DSR - device status report
// https://vt100.net/docs/vt510-rm/DSR.html
match next_param_or(0) {
5 => {
// report terminal status
let all_good = "\u{1b}[0n";
self.pending_messages_to_pty
.push(all_good.as_bytes().to_vec());
}
6 => {
// CPR - cursor position report
let position_report =
format!("\x1b[{};{}R", self.cursor.y + 1, self.cursor.x + 1);
self.pending_messages_to_pty
.push(position_report.as_bytes().to_vec());
}
_ => {}
}
} else if c == 't' {
match next_param_or(1) as usize {
14 => {
// TODO: report text area size in pixels, currently unimplemented
// to solve this we probably need to query the user's terminal for the cursor
// size and then use it as a multiplier
}
18 => {
// report text area
let text_area_report = format!("\x1b[8;{};{}t", self.height, self.width);
self.pending_messages_to_pty
.push(text_area_report.as_bytes().to_vec());
}
22 => {
// TODO: push title
}
23 => {
// TODO: pop title
}
_ => {}
}
} else {
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
#[cfg(not(test))]
Expand Down Expand Up @@ -1341,6 +1403,11 @@ impl Perform for Grid {
(b'7', None) => {
self.save_cursor_position();
}
(b'Z', None) => {
let terminal_capabilities = "\u{1b}[?6c";
self.pending_messages_to_pty
.push(terminal_capabilities.as_bytes().to_vec());
}
(b'8', None) => {
self.restore_cursor_position();
}
Expand Down
3 changes: 3 additions & 0 deletions src/client/panes/terminal_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ impl Pane for TerminalPane {
CursorShape::BlinkingBeam => "\u{1b}[5 q".to_string(),
}
}
fn drain_messages_to_pty(&mut self) -> Vec<Vec<u8>> {
self.grid.pending_messages_to_pty.drain(..).collect()
}
}

impl TerminalPane {
Expand Down
12 changes: 12 additions & 0 deletions src/client/panes/unit/grid_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,15 @@ fn csi_capital_z() {
}
assert_snapshot!(format!("{:?}", grid));
}

#[test]
fn terminal_reports() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(51, 97);
let fixture_name = "terminal_reports";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid.pending_messages_to_pty));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: src/client/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid . pending_messages_to_pty)"

---
[[27, 91, 63, 54, 99], [27, 91, 56, 59, 53, 49, 59, 57, 55, 116], [27, 91, 63, 54, 99], [27, 91, 48, 110], [27, 91, 49, 59, 49, 82]]
9 changes: 9 additions & 0 deletions src/client/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ pub trait Pane {
fn invisible_borders(&self) -> bool {
false
}
fn drain_messages_to_pty(&mut self) -> Vec<Vec<u8>> {
// TODO: this is only relevant to terminal panes
// we should probably refactor away from this trait at some point
vec![]
}
}

impl Tab {
Expand Down Expand Up @@ -601,6 +606,10 @@ impl Tab {
// the reason
if let Some(terminal_output) = self.panes.get_mut(&PaneId::Terminal(pid)) {
terminal_output.handle_pty_bytes(bytes);
let messages_to_pty = terminal_output.drain_messages_to_pty();
for message in messages_to_pty {
self.write_to_pane_id(message, PaneId::Terminal(pid));
}
}
}
pub fn write_to_terminals_on_current_tab(&mut self, input_bytes: Vec<u8>) {
Expand Down
21 changes: 21 additions & 0 deletions src/common/utils/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,24 @@ pub fn _detect_theme(bg: PaletteColor) -> Theme {
_ => Theme::Dark,
}
}

// (this was shamelessly copied from alacritty)
//
// This returns the current terminal version as a unique number based on the
// semver version. The different versions are padded to ensure that a higher semver version will
// always report a higher version number.
pub fn version_number(mut version: &str) -> usize {
if let Some(separator) = version.rfind('-') {
version = &version[..separator];
}

let mut version_number = 0;

let semver_versions = version.split('.');
for (i, semver_version) in semver_versions.rev().enumerate() {
let semver_number = semver_version.parse::<usize>().unwrap_or(0);
version_number += usize::pow(100, i as u32) * semver_number;
}

version_number
}
1 change: 1 addition & 0 deletions src/tests/fixtures/terminal_reports
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Z