diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/render/stream.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/render/stream.rs b/src/render/stream.rs index 189862d..2e05c3a 100644 --- a/src/render/stream.rs +++ b/src/render/stream.rs @@ -64,14 +64,21 @@ fn markdown_stream_inner( let columns = terminal::size()?.0; + let mut spinner = Spinner::new(" Generating"); + loop { if abort.aborted() { return Ok(()); } + spinner.step(writer)?; if let Ok(evt) = rx.try_recv() { match evt { ReplyEvent::Text(text) => { + if spinner.is_running() { + spinner.stop(writer)?; + } + let (col, mut row) = cursor::position()?; // Fix unexpected duplicate lines on kitty, see https://github.com/sigoden/aichat/issues/105 @@ -155,6 +162,59 @@ fn markdown_stream_inner( Ok(()) } +struct Spinner { + index: usize, + message: String, + stopped: bool, +} + +impl Spinner { + const DATA: [&str; 10] = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + + fn new(message: &str) -> Self { + Spinner { + index: 0, + message: message.to_string(), + stopped: false, + } + } + + fn is_running(&self) -> bool { + !self.stopped + } + + fn step(&mut self, writer: &mut Stdout) -> Result<()> { + if self.stopped { + return Ok(()); + } + let frame = Self::DATA[self.index % Self::DATA.len()]; + let dots = ".".repeat((self.index / 8) % 4); + let line = format!("{frame}{}{dots}", self.message); + queue!(writer, cursor::MoveToColumn(0), style::Print(line),)?; + if self.index == 0 { + queue!(writer, cursor::Hide)?; + } + writer.flush()?; + self.index += 1; + Ok(()) + } + + fn stop(&mut self, writer: &mut Stdout) -> Result<()> { + if self.stopped { + return Ok(()); + } + self.stopped = true; + queue!( + writer, + cursor::MoveToColumn(0), + terminal::Clear(terminal::ClearType::FromCursorDown), + cursor::Show + )?; + writer.flush()?; + Ok(()) + } +} + fn print_block(writer: &mut Stdout, text: &str, columns: u16) -> Result<u16> { let mut num = 0; for line in text.split('\n') { |
