mirror of
https://github.com/zellij-org/zellij.git
synced 2024-12-26 10:43:46 +03:00
fic(compatibility): htop scrolling issues (#77)
* fix(compatibility): scrolling inside scroll region with 'M' esc dispatch * style(format): make rustfmt happy * fix(tests): send proper data * fix(logs): do not crash if log file doesn't exist
This commit is contained in:
parent
ea549f151e
commit
c47fed927e
BIN
htop-debugging/currently-debugging.log
Normal file
BIN
htop-debugging/currently-debugging.log
Normal file
Binary file not shown.
BIN
htop-debugging/mosaic-3.log
Normal file
BIN
htop-debugging/mosaic-3.log
Normal file
Binary file not shown.
@ -450,10 +450,11 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
|
||||
}
|
||||
// cleanup();
|
||||
let reset_style = "\u{1b}[m";
|
||||
let show_cursor = "\u{1b}[?25h";
|
||||
let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1);
|
||||
let goodbye_message = format!(
|
||||
"{}\n{}Bye from Mosaic!",
|
||||
goto_start_of_last_line, reset_style
|
||||
"{}\n{}{}Bye from Mosaic!",
|
||||
goto_start_of_last_line, reset_style, show_cursor
|
||||
);
|
||||
|
||||
os_input.unset_raw_mode(0);
|
||||
|
@ -11,7 +11,7 @@ use std::path::PathBuf;
|
||||
|
||||
use crate::layout::Layout;
|
||||
use crate::os_input_output::OsApi;
|
||||
use crate::utils::logging::debug_to_file;
|
||||
use crate::utils::logging::{debug_log_to_file, debug_to_file};
|
||||
use crate::ScreenInstruction;
|
||||
|
||||
pub struct ReadFromPid {
|
||||
|
@ -135,6 +135,28 @@ impl CanonicalLine {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for CanonicalLine {
|
||||
@ -331,21 +353,18 @@ impl Scroll {
|
||||
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 {
|
||||
// the scroll region indices start at 1, so we need to adjust them
|
||||
if self.show_cursor {
|
||||
// scroll region should be ignored if the cursor is hidden
|
||||
let scroll_region_top_index = scroll_region_top - 1;
|
||||
let scroll_region_bottom_index = scroll_region_bottom - 1;
|
||||
if current_canonical_line_index == scroll_region_bottom_index + 1 {
|
||||
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_index);
|
||||
self.canonical_lines.remove(scroll_region_top);
|
||||
self.canonical_lines
|
||||
.insert(scroll_region_bottom_index + 1, CanonicalLine::new());
|
||||
.insert(scroll_region_bottom, CanonicalLine::new());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -473,6 +492,20 @@ impl Scroll {
|
||||
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;
|
||||
@ -592,6 +625,25 @@ impl Scroll {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn move_cursor_up_in_scroll_region(&mut self, count: usize) {
|
||||
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
||||
// the scroll region indices start at 1, so we need to adjust them
|
||||
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) {
|
||||
|
@ -687,8 +687,11 @@ impl vte::Perform for TerminalPane {
|
||||
if params[0] == 0 {
|
||||
self.scroll
|
||||
.clear_canonical_line_right_of_cursor(self.pending_styles);
|
||||
} else if params[0] == 1 {
|
||||
self.scroll
|
||||
.clear_canonical_line_left_of_cursor(self.pending_styles);
|
||||
}
|
||||
// TODO: implement 1 and 2
|
||||
// TODO: implement 2
|
||||
} else if c == 'J' {
|
||||
// clear all (0 => below, 1 => above, 2 => all, 3 => saved)
|
||||
if params[0] == 0 {
|
||||
@ -826,12 +829,21 @@ impl vte::Perform for TerminalPane {
|
||||
self.scroll.delete_lines_in_scroll_region(count);
|
||||
self.scroll.add_empty_lines_in_scroll_region(count);
|
||||
} else {
|
||||
debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params)).unwrap();
|
||||
panic!("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) {
|
||||
// TBD
|
||||
fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) {
|
||||
match (byte, intermediates.get(0)) {
|
||||
(b'M', None) => {
|
||||
self.scroll.move_cursor_up_in_scroll_region(1);
|
||||
}
|
||||
_ => {
|
||||
let _ = debug_log_to_file(format!(
|
||||
"Unhandled esc_dispatch: {}->{:?}",
|
||||
byte, intermediates
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
src/tests/fixtures/htop_scrolling
vendored
Normal file
BIN
src/tests/fixtures/htop_scrolling
vendored
Normal file
Binary file not shown.
@ -214,3 +214,26 @@ pub fn htop() {
|
||||
assert_snapshot!(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn htop_scrolling() {
|
||||
let fake_win_size = PositionAndSize {
|
||||
columns: 116,
|
||||
rows: 28,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
let fixture_name = "htop_scrolling";
|
||||
let mut fake_input_output = get_fake_os_input(&fake_win_size, fixture_name);
|
||||
fake_input_output.add_terminal_input(&[&COMMAND_TOGGLE, &COMMAND_TOGGLE, &QUIT]);
|
||||
start(Box::new(fake_input_output.clone()), Opt::default());
|
||||
let output_frames = fake_input_output
|
||||
.stdout_writer
|
||||
.output_frames
|
||||
.lock()
|
||||
.unwrap();
|
||||
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||
for snapshot in snapshots {
|
||||
assert_snapshot!(snapshot);
|
||||
}
|
||||
}
|
||||
|
@ -29,4 +29,4 @@ expression: snapshot
|
||||
99272 aram 20 0 8456 4348 3320 R 1.3 0.0 0:00.13 htop
|
||||
8611 aram 20 0 2944M 318M 130M S 1.3 2.0 8:17.90 /usr/lib/firefox/firefox -contentproc -childID 6 -i
|
||||
F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
|
||||
Bye from Mosaic!
|
||||
Bye from Mosaic!█
|
||||
|
@ -0,0 +1,32 @@
|
||||
---
|
||||
source: src/tests/integration/compatibility.rs
|
||||
expression: snapshot
|
||||
---
|
||||
1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
|
||||
2 [ 0.0%] Load average: 1.40 1.43 1.38
|
||||
3 [ 0.0%] Uptime: 2 days, 07:33:50
|
||||
4 [ 0.0%]
|
||||
Mem[|||||||||||||||||||||||||||||||||||||3.64G/15.3G]
|
||||
Swp[ 0K/16.0G]
|
||||
|
||||
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
|
||||
123934 aram 20 0 8444 4384 3364 R 66.7 0.0 0:00.05 htop --delay=100000000000
|
||||
1 root 20 0 171M 11616 8608 S 0.0 0.1 0:56.91 /sbin/init
|
||||
268 root 20 0 93324 34340 33072 S 0.0 0.2 0:01.05 /usr/lib/systemd/systemd-journald
|
||||
276 root 20 0 32648 10192 7240 S 0.0 0.1 0:01.13 /usr/lib/systemd/systemd-udevd
|
||||
286 root 20 0 78060 1132 996 S 0.0 0.0 0:00.00 /usr/bin/lvmetad -f
|
||||
343 dbus 20 0 6952 4384 3520 S 0.0 0.0 0:13.85 /usr/bin/dbus-daemon --system --address=systemd: --
|
||||
344 root 20 0 14588 7512 6176 S 0.0 0.0 0:03.21 /usr/bin/connmand -n --nodnsproxy
|
||||
345 root 20 0 17696 8372 7128 S 0.0 0.1 0:00.67 /usr/lib/systemd/systemd-logind
|
||||
395 root 20 0 1635M 83324 44976 S 0.0 0.5 0:32.43 /usr/bin/dockerd -H fd://
|
||||
396 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
|
||||
397 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
|
||||
398 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
399 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
412 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
441 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.35 /usr/bin/dockerd -H fd://
|
||||
442 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.61 /usr/bin/dockerd -H fd://
|
||||
444 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.13 /usr/bin/dockerd -H fd://
|
||||
449 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.39 /usr/bin/dockerd -H fd://
|
||||
F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
|
||||
Bye from Mosaic!█
|
@ -0,0 +1,32 @@
|
||||
---
|
||||
source: src/tests/integration/compatibility.rs
|
||||
expression: snapshot
|
||||
---
|
||||
1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
|
||||
2 [ 0.0%] Load average: 1.40 1.43 1.38
|
||||
3 [ 0.0%] Uptime: 2 days, 07:33:50
|
||||
4 [ 0.0%]
|
||||
Mem[|||||||||||||||||||||||||||||||||||||3.64G/15.3G]
|
||||
Swp[ 0K/16.0G]
|
||||
|
||||
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
|
||||
123934 aram 20 0 8444 4384 3364 R 66.7 0.0 0:00.05 htop --delay=100000000000
|
||||
1 root 20 0 171M 11616 8608 S 0.0 0.1 0:56.91 /sbin/init
|
||||
268 root 20 0 93324 34340 33072 S 0.0 0.2 0:01.05 /usr/lib/systemd/systemd-journald
|
||||
276 root 20 0 32648 10192 7240 S 0.0 0.1 0:01.13 /usr/lib/systemd/systemd-udevd
|
||||
286 root 20 0 78060 1132 996 S 0.0 0.0 0:00.00 /usr/bin/lvmetad -f
|
||||
343 dbus 20 0 6952 4384 3520 S 0.0 0.0 0:13.85 /usr/bin/dbus-daemon --system --address=systemd: --
|
||||
344 root 20 0 14588 7512 6176 S 0.0 0.0 0:03.21 /usr/bin/connmand -n --nodnsproxy
|
||||
345 root 20 0 17696 8372 7128 S 0.0 0.1 0:00.67 /usr/lib/systemd/systemd-logind
|
||||
395 root 20 0 1635M 83324 44976 S 0.0 0.5 0:32.43 /usr/bin/dockerd -H fd://
|
||||
396 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
|
||||
397 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
|
||||
398 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
399 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
412 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
|
||||
441 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.35 /usr/bin/dockerd -H fd://
|
||||
442 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.61 /usr/bin/dockerd -H fd://
|
||||
444 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.13 /usr/bin/dockerd -H fd://
|
||||
449 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.39 /usr/bin/dockerd -H fd://
|
||||
F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
|
||||
█
|
@ -29,4 +29,4 @@ expression: snapshot
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Press <SPACE> to pause. Use <TAB> to rearrange tables. (DNS queries hidden).
|
||||
Bye from Mosaic!
|
||||
Bye from Mosaic!█
|
||||
|
@ -33,6 +33,17 @@ pub fn debug_log_to_file(message: String) -> io::Result<()> {
|
||||
file.write_all(b"\n")
|
||||
}
|
||||
|
||||
pub fn debug_log_to_file_without_newline(message: String) -> io::Result<()> {
|
||||
atomic_create_file(MOSAIC_TMP_LOG_FILE);
|
||||
let mut file = fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(MOSAIC_TMP_LOG_FILE)?;
|
||||
file.write_all(message.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn debug_log_to_file_pid_0(message: String, pid: RawFd) -> io::Result<()> {
|
||||
if pid == 0 {
|
||||
debug_log_to_file(message)
|
||||
|
Loading…
Reference in New Issue
Block a user