Skip to content

Commit 830c06a

Browse files
authored
fix: spinner not being cleaned up properly (#3282)
1 parent b315782 commit 830c06a

File tree

2 files changed

+70
-81
lines changed

2 files changed

+70
-81
lines changed

crates/chat-cli/src/cli/chat/custom_spinner.rs

Lines changed: 0 additions & 67 deletions
This file was deleted.

crates/chat-cli/src/cli/chat/mod.rs

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use spinners::{
2+
Spinner,
3+
Spinners,
4+
};
5+
16
use crate::theme::StyledText;
27
use crate::util::ui::should_send_structured_message;
38
pub mod cli;
49
mod consts;
510
pub mod context;
611
mod conversation;
7-
mod custom_spinner;
812
mod input_source;
913
mod message;
1014
mod parse;
@@ -83,7 +87,6 @@ use crossterm::{
8387
style,
8488
terminal,
8589
};
86-
use custom_spinner::Spinners;
8790
use eyre::{
8891
Report,
8992
Result,
@@ -576,7 +579,7 @@ pub struct ChatSession {
576579
input_source: InputSource,
577580
/// Width of the terminal, required for [ParseState].
578581
terminal_width_provider: fn() -> Option<usize>,
579-
spinner: Option<Spinners>,
582+
spinner: Option<Spinner>,
580583
/// [ConversationState].
581584
conversation: ConversationState,
582585
/// Tool uses requested by the model that are actively being handled.
@@ -829,6 +832,11 @@ impl ChatSession {
829832

830833
if self.spinner.is_some() {
831834
drop(self.spinner.take());
835+
queue!(
836+
self.stderr,
837+
terminal::Clear(terminal::ClearType::CurrentLine),
838+
cursor::MoveToColumn(0),
839+
)?;
832840
}
833841

834842
let (context, report, display_err_message) = match err {
@@ -1138,6 +1146,10 @@ impl ChatSession {
11381146

11391147
impl Drop for ChatSession {
11401148
fn drop(&mut self) {
1149+
if let Some(spinner) = &mut self.spinner {
1150+
spinner.stop();
1151+
}
1152+
11411153
execute!(
11421154
self.stderr,
11431155
cursor::MoveToColumn(0),
@@ -1435,7 +1447,7 @@ impl ChatSession {
14351447
.await?;
14361448

14371449
if self.interactive {
1438-
self.spinner = Some(Spinners::new("Creating summary...".to_string()));
1450+
self.spinner = Some(Spinner::new(Spinners::Dots, "Creating summary...".to_string()));
14391451
}
14401452

14411453
let mut response = match self
@@ -1451,6 +1463,12 @@ impl ChatSession {
14511463
Err(err) => {
14521464
if self.interactive {
14531465
self.spinner.take();
1466+
execute!(
1467+
self.stderr,
1468+
terminal::Clear(terminal::ClearType::CurrentLine),
1469+
cursor::MoveToColumn(0),
1470+
StyledText::reset_attributes()
1471+
)?;
14541472
}
14551473

14561474
// If the request fails due to context window overflow, then we'll see if it's
@@ -1548,6 +1566,11 @@ impl ChatSession {
15481566

15491567
if self.spinner.is_some() {
15501568
drop(self.spinner.take());
1569+
queue!(
1570+
self.stderr,
1571+
terminal::Clear(terminal::ClearType::CurrentLine),
1572+
cursor::MoveToColumn(0),
1573+
)?;
15511574
}
15521575

15531576
self.conversation
@@ -1718,10 +1741,10 @@ impl ChatSession {
17181741

17191742
if self.interactive {
17201743
execute!(self.stderr, cursor::Hide, style::Print("\n"))?;
1721-
self.spinner = Some(Spinners::new(format!(
1722-
"Generating agent config for '{}'...",
1723-
agent_name
1724-
)));
1744+
self.spinner = Some(Spinner::new(
1745+
Spinners::Dots,
1746+
format!("Generating agent config for '{}'...", agent_name),
1747+
));
17251748
}
17261749

17271750
let mut response = match self
@@ -1737,6 +1760,12 @@ impl ChatSession {
17371760
Err(err) => {
17381761
if self.interactive {
17391762
self.spinner.take();
1763+
execute!(
1764+
self.stderr,
1765+
terminal::Clear(terminal::ClearType::CurrentLine),
1766+
cursor::MoveToColumn(0),
1767+
StyledText::reset_attributes()
1768+
)?;
17401769
}
17411770
return Err(err);
17421771
},
@@ -1783,6 +1812,11 @@ impl ChatSession {
17831812

17841813
if self.spinner.is_some() {
17851814
drop(self.spinner.take());
1815+
queue!(
1816+
self.stderr,
1817+
terminal::Clear(terminal::ClearType::CurrentLine),
1818+
cursor::MoveToColumn(0),
1819+
)?;
17861820
}
17871821
// Parse and validate the initial generated config
17881822
let initial_agent_config = match serde_json::from_str::<Agent>(&agent_config_json) {
@@ -2174,7 +2208,7 @@ impl ChatSession {
21742208
queue!(self.stderr, cursor::Hide)?;
21752209

21762210
if self.interactive {
2177-
self.spinner = Some(Spinners::new("Thinking...".to_owned()));
2211+
self.spinner = Some(Spinner::new(Spinners::Dots, "Thinking...".to_owned()));
21782212
}
21792213

21802214
Ok(ChatState::HandleResponseStream(conv_state))
@@ -2326,6 +2360,12 @@ impl ChatSession {
23262360

23272361
if let Some(spinner) = self.spinner.take() {
23282362
drop(spinner);
2363+
queue!(
2364+
self.stderr,
2365+
terminal::Clear(terminal::ClearType::CurrentLine),
2366+
cursor::MoveToColumn(0),
2367+
cursor::Show
2368+
)?;
23292369
}
23302370

23312371
// Handle checkpoint after tool execution - store tag for later display
@@ -2601,7 +2641,7 @@ impl ChatSession {
26012641
execute!(self.stderr, cursor::Hide)?;
26022642
execute!(self.stderr, style::Print("\n"), StyledText::reset_attributes())?;
26032643
if self.interactive {
2604-
self.spinner = Some(Spinners::new("Thinking...".to_string()));
2644+
self.spinner = Some(Spinner::new(Spinners::Dots, "Thinking...".to_string()));
26052645
}
26062646

26072647
self.send_chat_telemetry(os, TelemetryResult::Succeeded, None, None, None, false)
@@ -2657,6 +2697,11 @@ impl ChatSession {
26572697

26582698
if self.spinner.is_some() {
26592699
drop(self.spinner.take());
2700+
queue!(
2701+
self.stderr,
2702+
terminal::Clear(terminal::ClearType::CurrentLine),
2703+
cursor::MoveToColumn(0),
2704+
)?;
26602705
}
26612706

26622707
loop {
@@ -2699,6 +2744,11 @@ impl ChatSession {
26992744
parser::ResponseEvent::ToolUse(tool_use) => {
27002745
if self.spinner.is_some() {
27012746
drop(self.spinner.take());
2747+
queue!(
2748+
self.stderr,
2749+
terminal::Clear(terminal::ClearType::CurrentLine),
2750+
cursor::MoveToColumn(0),
2751+
)?;
27022752
}
27032753
tool_uses.push(tool_use);
27042754
tool_name_being_recvd = None;
@@ -2748,7 +2798,7 @@ impl ChatSession {
27482798
);
27492799

27502800
execute!(self.stderr, cursor::Hide)?;
2751-
self.spinner = Some(Spinners::new("Dividing up the work...".to_string()));
2801+
self.spinner = Some(Spinner::new(Spinners::Dots, "Dividing up the work...".to_string()));
27522802

27532803
// For stream timeouts, we'll tell the model to try and split its response into
27542804
// smaller chunks.
@@ -2887,6 +2937,12 @@ impl ChatSession {
28872937

28882938
if tool_name_being_recvd.is_none() && !buf.is_empty() && self.spinner.is_some() {
28892939
drop(self.spinner.take());
2940+
queue!(
2941+
self.stderr,
2942+
terminal::Clear(terminal::ClearType::CurrentLine),
2943+
cursor::MoveToColumn(0),
2944+
cursor::Show
2945+
)?;
28902946
}
28912947

28922948
info!("## control end: buf: {:?}", buf);
@@ -2940,7 +2996,7 @@ impl ChatSession {
29402996
if tool_name_being_recvd.is_some() {
29412997
queue!(self.stderr, cursor::Hide)?;
29422998
if self.interactive {
2943-
self.spinner = Some(Spinners::new("Thinking...".to_string()));
2999+
self.spinner = Some(Spinner::new(Spinners::Dots, "Thinking...".to_string()));
29443000
}
29453001
}
29463002

@@ -3263,7 +3319,7 @@ impl ChatSession {
32633319
}
32643320

32653321
if self.interactive {
3266-
self.spinner = Some(Spinners::new("Thinking...".to_owned()));
3322+
self.spinner = Some(Spinner::new(Spinners::Dots, "Thinking...".to_owned()));
32673323
}
32683324

32693325
Ok(ChatState::HandleResponseStream(
@@ -3708,7 +3764,7 @@ where
37083764
Fut: std::future::Future<Output = Result<T, E>>,
37093765
{
37103766
queue!(output, cursor::Hide,).ok();
3711-
let spinner = Spinners::new(spinner_text.to_owned());
3767+
let spinner = Spinner::new(Spinners::Dots, spinner_text.to_owned());
37123768

37133769
let result = f().await;
37143770

0 commit comments

Comments
 (0)