feat(ux): show loading screen (#1997)
* feat(ux): show loading prompt * style(fmt): rustfmt
This commit is contained in:
parent
81287a276f
commit
f8a078c1a9
5 changed files with 85 additions and 3 deletions
|
|
@ -147,6 +147,20 @@ impl InputHandler {
|
||||||
self.handle_stdin_ansi_instruction(ansi_instruction);
|
self.handle_stdin_ansi_instruction(ansi_instruction);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Ok((InputInstruction::StartedParsing, _error_context)) => {
|
||||||
|
log::info!("sending done loading");
|
||||||
|
self.send_client_instructions
|
||||||
|
.send(ClientInstruction::StartedParsingStdinQuery)
|
||||||
|
.unwrap();
|
||||||
|
log::info!("done sent done loading");
|
||||||
|
},
|
||||||
|
Ok((InputInstruction::DoneParsing, _error_context)) => {
|
||||||
|
log::info!("sending done loading");
|
||||||
|
self.send_client_instructions
|
||||||
|
.send(ClientInstruction::DoneParsingStdinQuery)
|
||||||
|
.unwrap();
|
||||||
|
log::info!("done sent done loading");
|
||||||
|
},
|
||||||
Err(err) => panic!("Encountered read error: {:?}", err),
|
Err(err) => panic!("Encountered read error: {:?}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ pub(crate) enum ClientInstruction {
|
||||||
SwitchToMode(InputMode),
|
SwitchToMode(InputMode),
|
||||||
Connected,
|
Connected,
|
||||||
ActiveClients(Vec<ClientId>),
|
ActiveClients(Vec<ClientId>),
|
||||||
|
StartedParsingStdinQuery,
|
||||||
|
DoneParsingStdinQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerToClientMsg> for ClientInstruction {
|
impl From<ServerToClientMsg> for ClientInstruction {
|
||||||
|
|
@ -70,6 +72,8 @@ impl From<&ClientInstruction> for ClientContext {
|
||||||
ClientInstruction::SwitchToMode(_) => ClientContext::SwitchToMode,
|
ClientInstruction::SwitchToMode(_) => ClientContext::SwitchToMode,
|
||||||
ClientInstruction::Connected => ClientContext::Connected,
|
ClientInstruction::Connected => ClientContext::Connected,
|
||||||
ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients,
|
ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients,
|
||||||
|
ClientInstruction::StartedParsingStdinQuery => ClientContext::StartedParsingStdinQuery,
|
||||||
|
ClientInstruction::DoneParsingStdinQuery => ClientContext::DoneParsingStdinQuery,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +125,8 @@ pub(crate) enum InputInstruction {
|
||||||
KeyEvent(InputEvent, Vec<u8>),
|
KeyEvent(InputEvent, Vec<u8>),
|
||||||
SwitchToMode(InputMode),
|
SwitchToMode(InputMode),
|
||||||
AnsiStdinInstructions(Vec<AnsiStdinInstruction>),
|
AnsiStdinInstructions(Vec<AnsiStdinInstruction>),
|
||||||
|
StartedParsing,
|
||||||
|
DoneParsing,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_client(
|
pub fn start_client(
|
||||||
|
|
@ -337,13 +343,51 @@ pub fn start_client(
|
||||||
};
|
};
|
||||||
|
|
||||||
let exit_msg: String;
|
let exit_msg: String;
|
||||||
|
let mut loading = true;
|
||||||
|
let mut pending_instructions = vec![];
|
||||||
|
|
||||||
|
let mut stdout = os_input.get_stdout_writer();
|
||||||
|
stdout
|
||||||
|
.write_all("\u{1b}[1mLoading Zellij\u{1b}[m".as_bytes())
|
||||||
|
.expect("cannot write to stdout");
|
||||||
|
stdout.flush().expect("could not flush");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (client_instruction, mut err_ctx) = receive_client_instructions
|
let (client_instruction, mut err_ctx) = if !loading && !pending_instructions.is_empty() {
|
||||||
.recv()
|
// there are buffered instructions, we need to go through them before processing the
|
||||||
.expect("failed to receive app instruction on channel");
|
// new ones
|
||||||
|
pending_instructions.remove(0)
|
||||||
|
} else {
|
||||||
|
receive_client_instructions
|
||||||
|
.recv()
|
||||||
|
.expect("failed to receive app instruction on channel")
|
||||||
|
};
|
||||||
|
|
||||||
|
if loading {
|
||||||
|
// when the app is still loading, we buffer instructions and show a loading screen
|
||||||
|
match client_instruction {
|
||||||
|
ClientInstruction::StartedParsingStdinQuery => {
|
||||||
|
stdout
|
||||||
|
.write_all("\n\rQuerying terminal emulator for \u{1b}[32;1mdefault colors\u{1b}[m and \u{1b}[32;1mpixel/cell\u{1b}[m ratio...".as_bytes())
|
||||||
|
.expect("cannot write to stdout");
|
||||||
|
stdout.flush().expect("could not flush");
|
||||||
|
},
|
||||||
|
ClientInstruction::DoneParsingStdinQuery => {
|
||||||
|
stdout
|
||||||
|
.write_all("done".as_bytes())
|
||||||
|
.expect("cannot write to stdout");
|
||||||
|
stdout.flush().expect("could not flush");
|
||||||
|
loading = false;
|
||||||
|
},
|
||||||
|
instruction => {
|
||||||
|
pending_instructions.push((instruction, err_ctx));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
err_ctx.add_call(ContextType::Client((&client_instruction).into()));
|
err_ctx.add_call(ContextType::Client((&client_instruction).into()));
|
||||||
|
|
||||||
match client_instruction {
|
match client_instruction {
|
||||||
ClientInstruction::Exit(reason) => {
|
ClientInstruction::Exit(reason) => {
|
||||||
os_input.send_to_server(ClientToServerMsg::ClientExited);
|
os_input.send_to_server(ClientToServerMsg::ClientExited);
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,9 @@ impl StdinAnsiParser {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
pub fn startup_query_duration(&self) -> u64 {
|
||||||
|
STARTUP_PARSE_DEADLINE_MS
|
||||||
|
}
|
||||||
pub fn parse(&mut self, mut raw_bytes: Vec<u8>) -> Vec<AnsiStdinInstruction> {
|
pub fn parse(&mut self, mut raw_bytes: Vec<u8>) -> Vec<AnsiStdinInstruction> {
|
||||||
for byte in raw_bytes.drain(..) {
|
for byte in raw_bytes.drain(..) {
|
||||||
self.parse_byte(byte);
|
self.parse_byte(byte);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,20 @@ use std::sync::{Arc, Mutex};
|
||||||
use zellij_utils::channels::SenderWithContext;
|
use zellij_utils::channels::SenderWithContext;
|
||||||
use zellij_utils::termwiz::input::{InputEvent, InputParser, MouseButtons};
|
use zellij_utils::termwiz::input::{InputEvent, InputParser, MouseButtons};
|
||||||
|
|
||||||
|
fn send_done_parsing_after_query_timeout(
|
||||||
|
send_input_instructions: SenderWithContext<InputInstruction>,
|
||||||
|
query_duration: u64,
|
||||||
|
) {
|
||||||
|
std::thread::spawn({
|
||||||
|
move || {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(query_duration));
|
||||||
|
send_input_instructions
|
||||||
|
.send(InputInstruction::DoneParsing)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn stdin_loop(
|
pub(crate) fn stdin_loop(
|
||||||
mut os_input: Box<dyn ClientOsApi>,
|
mut os_input: Box<dyn ClientOsApi>,
|
||||||
send_input_instructions: SenderWithContext<InputInstruction>,
|
send_input_instructions: SenderWithContext<InputInstruction>,
|
||||||
|
|
@ -15,6 +29,9 @@ pub(crate) fn stdin_loop(
|
||||||
let mut current_buffer = vec![];
|
let mut current_buffer = vec![];
|
||||||
// on startup we send a query to the terminal emulator for stuff like the pixel size and colors
|
// 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
|
// we get a response through STDIN, so it makes sense to do this here
|
||||||
|
send_input_instructions
|
||||||
|
.send(InputInstruction::StartedParsing)
|
||||||
|
.unwrap();
|
||||||
let terminal_emulator_query_string = stdin_ansi_parser
|
let terminal_emulator_query_string = stdin_ansi_parser
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -23,6 +40,8 @@ pub(crate) fn stdin_loop(
|
||||||
.get_stdout_writer()
|
.get_stdout_writer()
|
||||||
.write(terminal_emulator_query_string.as_bytes())
|
.write(terminal_emulator_query_string.as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let query_duration = stdin_ansi_parser.lock().unwrap().startup_query_duration();
|
||||||
|
send_done_parsing_after_query_timeout(send_input_instructions.clone(), query_duration);
|
||||||
loop {
|
loop {
|
||||||
let buf = os_input.read_from_stdin();
|
let buf = os_input.read_from_stdin();
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,8 @@ pub enum ClientContext {
|
||||||
Connected,
|
Connected,
|
||||||
ActiveClients,
|
ActiveClients,
|
||||||
OwnClientId,
|
OwnClientId,
|
||||||
|
StartedParsingStdinQuery,
|
||||||
|
DoneParsingStdinQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
|
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue