fix(compatibility): implement device reports (#500)

* fix(compatibility): implement device reports

* docs(changelog): update change
This commit is contained in:
Aram Drevekenin 2021-05-13 16:09:07 +02:00 committed by GitHub
parent a24c7f79f1
commit b93e51cf88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 120 additions and 0 deletions

View file

@ -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)

View file

@ -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,
@ -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 {
@ -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 {
@ -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))]
@ -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();
}

View file

@ -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 {

View file

@ -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));
}

View file

@ -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]]

View file

@ -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 {
@ -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>) {

View file

@ -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
src/tests/fixtures/terminal_reports vendored Normal file
View file

@ -0,0 +1 @@
Z