* work * work * work * work * work * more work * work * work * work * hack around stdin repeater * refactor(sixel): rename sixel structs * feat(sixel): render text above images * fix(sixel): reap images once they're past the end of the scrollbuffer * fix(sixel): display images in the middle of the line * fix(sixel): render crash * fix(sixel): react to SIGWINCH * fix(sixel): behave properly in alternate screen mode * fix(sixel): reap images on terminal reset * feat(sixel): handle DECSDM * fix(terminal): properly respond to XTSMGRAPHICS and device attributes with Sixel * Add comment * fix(sixel): hack for unknown event overflow until we fix the api * feat(input): query terminal for all OSC 4 colors and respond to them in a buggy way * fix(sixel): do not render corrupted image * feat(input): improve STDIN queries * fix(client): mistake in clear terminal attributes string * fix(ansi): report correct number of supported color registers * fix(sixel): reap images that are completely covered * style(comment): fix name * test(sixel): infra * test(sixel): cases and fixes * fix(sixel): forward dcs bytes to sixel parser * refactor(client): ansi stdin parser * refactor(output): cleanup * some refactorings * fix test * refactor(grid): sixel-grid / sixel-image-store * refactor(grid): grid debug method * refactor(grid): move various logic to sixel.rs * refactor(grid): remove unused methods * fix(sixel): work with multiple users * refactor(pane): remove unused z_index * style(fmt): prepend unused variable * style(fmt): rustfmt * fix(tests): various apis * chore(dependencies): use published version of sixel crates * style(fmt): rustfmt * style(fmt): rustfmt * style(lint): make clippy happy * style(lint): make clippy happy... again * style(lint): make clippy happy... again (chapter 2) * style(comment): remove unused * fix(colors): export COLORTERM and respond to XTVERSION * fix(test): color register count * fix(stdin): adjust STDIN sleep times
93 lines
3.4 KiB
Rust
93 lines
3.4 KiB
Rust
use crate::os_input_output::ClientOsApi;
|
|
use crate::stdin_ansi_parser::StdinAnsiParser;
|
|
use crate::InputInstruction;
|
|
use std::sync::{Arc, Mutex};
|
|
use zellij_utils::channels::SenderWithContext;
|
|
use zellij_utils::termwiz::input::{InputEvent, InputParser, MouseButtons};
|
|
|
|
pub(crate) fn stdin_loop(
|
|
mut os_input: Box<dyn ClientOsApi>,
|
|
send_input_instructions: SenderWithContext<InputInstruction>,
|
|
stdin_ansi_parser: Arc<Mutex<StdinAnsiParser>>,
|
|
) {
|
|
let mut holding_mouse = false;
|
|
let mut input_parser = InputParser::new();
|
|
let mut current_buffer = vec![];
|
|
// on startup we send a query to the terminal emulator for stuff like the pixel size and colors
|
|
// we get a response through STDIN, so it makes sense to do this here
|
|
let terminal_emulator_query_string = stdin_ansi_parser
|
|
.lock()
|
|
.unwrap()
|
|
.terminal_emulator_query_string();
|
|
let _ = os_input
|
|
.get_stdout_writer()
|
|
.write(terminal_emulator_query_string.as_bytes())
|
|
.unwrap();
|
|
loop {
|
|
let buf = os_input.read_from_stdin();
|
|
{
|
|
// here we check if we need to parse specialized ANSI instructions sent over STDIN
|
|
// this happens either on startup (see above) or on SIGWINCH
|
|
//
|
|
// if we need to parse them, we do so with an internal timeout - anything else we
|
|
// receive on STDIN during that timeout is unceremoniously dropped
|
|
let mut stdin_ansi_parser = stdin_ansi_parser.lock().unwrap();
|
|
if stdin_ansi_parser.should_parse() {
|
|
let events = stdin_ansi_parser.parse(buf);
|
|
if !events.is_empty() {
|
|
let _ = send_input_instructions
|
|
.send(InputInstruction::AnsiStdinInstructions(events));
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
current_buffer.append(&mut buf.to_vec());
|
|
let maybe_more = false; // read_from_stdin should (hopefully) always empty the STDIN buffer completely
|
|
let mut events = vec![];
|
|
input_parser.parse(
|
|
&buf,
|
|
|input_event: InputEvent| {
|
|
events.push(input_event);
|
|
},
|
|
maybe_more,
|
|
);
|
|
|
|
let event_count = events.len();
|
|
for (i, input_event) in events.into_iter().enumerate() {
|
|
if holding_mouse && is_mouse_press_or_hold(&input_event) && i == event_count - 1 {
|
|
let mut poller = os_input.stdin_poller();
|
|
loop {
|
|
if poller.ready() {
|
|
break;
|
|
}
|
|
send_input_instructions
|
|
.send(InputInstruction::KeyEvent(
|
|
input_event.clone(),
|
|
current_buffer.clone(),
|
|
))
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
holding_mouse = is_mouse_press_or_hold(&input_event);
|
|
|
|
send_input_instructions
|
|
.send(InputInstruction::KeyEvent(
|
|
input_event,
|
|
current_buffer.drain(..).collect(),
|
|
))
|
|
.unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn is_mouse_press_or_hold(input_event: &InputEvent) -> bool {
|
|
if let InputEvent::Mouse(mouse_event) = input_event {
|
|
if mouse_event.mouse_buttons.contains(MouseButtons::LEFT)
|
|
|| mouse_event.mouse_buttons.contains(MouseButtons::RIGHT)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|