summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsigoden <sigoden@gmail.com>2023-10-29 12:52:04 +0800
committerGitHub <noreply@github.com>2023-10-29 12:52:04 +0800
commit10b1d4b4de521a48747c73d29e9fe3f06db48a32 (patch)
tree5ed5364501eceef197e12d1377b24c61b2b0d18f
parent33a9aacf39ea105e311f032e5d15c62cbeaa93e0 (diff)
downloadaichat-10b1d4b4de521a48747c73d29e9fe3f06db48a32.tar.gz
fix: unexpcted duplicate lines in kitty (#167)
-rw-r--r--src/main.rs2
-rw-r--r--src/render/cmd.rs6
-rw-r--r--src/render/markdown.rs11
-rw-r--r--src/render/repl.rs61
4 files changed, 38 insertions, 42 deletions
diff --git a/src/main.rs b/src/main.rs
index d73d4c1..de798ec 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -116,7 +116,7 @@ fn start_directive(
let output = client.send_message(input)?;
if highlight {
let mut markdown_render = MarkdownRender::new(light_theme);
- println!("{}", markdown_render.render(&output).trim());
+ println!("{}", markdown_render.render_block(&output).trim());
} else {
println!("{}", output.trim());
}
diff --git a/src/render/cmd.rs b/src/render/cmd.rs
index bf7a006..527c194 100644
--- a/src/render/cmd.rs
+++ b/src/render/cmd.rs
@@ -26,7 +26,7 @@ pub fn cmd_render_stream(
let mut lines: Vec<&str> = text.split('\n').collect();
buffer = lines.pop().unwrap_or_default().to_string();
let output = lines.join("\n");
- print_now!("{}\n", markdown_render.render(&output));
+ print_now!("{}\n", markdown_render.render_block(&output));
} else {
buffer = format!("{buffer}{text}");
if !(markdown_render.is_code_block()
@@ -36,14 +36,14 @@ pub fn cmd_render_stream(
|| buffer.starts_with('|'))
{
if let Some((output, remain)) = split_line(&buffer) {
- print_now!("{}", markdown_render.render_line_stateless(&output));
+ print_now!("{}", markdown_render.render_line(&output));
buffer = remain;
}
}
}
}
ReplyStreamEvent::Done => {
- let output = markdown_render.render(&buffer);
+ let output = markdown_render.render_block(&buffer);
print_now!("{}\n", output.trim_end());
break;
}
diff --git a/src/render/markdown.rs b/src/render/markdown.rs
index 75904af..66bb601 100644
--- a/src/render/markdown.rs
+++ b/src/render/markdown.rs
@@ -53,14 +53,17 @@ impl MarkdownRender {
}
}
- pub fn render(&mut self, src: &str) -> String {
+ pub fn render_block(&mut self, src: &str) -> String {
src.split('\n')
- .map(|line| self.render_line(line).unwrap_or_else(|| line.to_string()))
+ .map(|line| {
+ self.render_line_impl(line)
+ .unwrap_or_else(|| line.to_string())
+ })
.collect::<Vec<String>>()
.join("\n")
}
- pub fn render_line_stateless(&self, line: &str) -> String {
+ pub fn render_line(&self, line: &str) -> String {
let output = if self.is_code_block() && detect_code_block(line).is_none() {
self.render_code_line(line)
} else {
@@ -76,7 +79,7 @@ impl MarkdownRender {
)
}
- fn render_line(&mut self, line: &str) -> Option<String> {
+ fn render_line_impl(&mut self, line: &str) -> Option<String> {
if let Some(lang) = detect_code_block(line) {
match self.prev_line_type {
LineType::Normal | LineType::CodeEnd => {
diff --git a/src/render/repl.rs b/src/render/repl.rs
index 2bdf3b2..eb50750 100644
--- a/src/render/repl.rs
+++ b/src/render/repl.rs
@@ -39,51 +39,62 @@ fn repl_render_stream_inner(
writer: &mut Stdout,
) -> Result<()> {
let mut last_tick = Instant::now();
- let tick_rate = Duration::from_millis(100);
+ let tick_rate = Duration::from_millis(50);
let mut buffer = String::new();
let mut markdown_render = MarkdownRender::new(light_theme);
- let terminal_columns = terminal::size()?.0;
+ let columns = terminal::size()?.0;
loop {
if abort.aborted() {
return Ok(());
}
if let Ok(evt) = rx.try_recv() {
- recover_cursor(writer, terminal_columns, &buffer)?;
-
match evt {
ReplyStreamEvent::Text(text) => {
+ if !buffer.is_empty() {
+ let buffer_width = buffer.width() as u16;
+ let need_rows = (buffer_width + columns - 1) / columns;
+ let (col, row) = cursor::position()?;
+
+ if row + 1 >= need_rows {
+ if col == 0 {
+ queue!(writer, cursor::MoveTo(0, row - need_rows))?;
+ } else {
+ queue!(writer, cursor::MoveTo(0, row + 1 - need_rows))?;
+ }
+ } else {
+ queue!(
+ writer,
+ terminal::ScrollUp(need_rows - 1 - row),
+ cursor::MoveTo(0, 0)
+ )?;
+ }
+ }
+
if text.contains('\n') {
let text = format!("{buffer}{text}");
let mut lines: Vec<&str> = text.split('\n').collect();
buffer = lines.pop().unwrap_or_default().to_string();
- let output = markdown_render.render(&lines.join("\n"));
+ let output = markdown_render.render_block(&lines.join("\n"));
for line in output.split('\n') {
queue!(
writer,
style::Print(line),
style::Print("\n"),
- cursor::MoveLeft(terminal_columns),
+ cursor::MoveLeft(columns),
)?;
}
queue!(writer, style::Print(&buffer),)?;
} else {
buffer = format!("{buffer}{text}");
- let output = markdown_render.render_line_stateless(&buffer);
+ let output = markdown_render.render_line(&buffer);
queue!(writer, style::Print(&output))?;
}
+
writer.flush()?;
}
ReplyStreamEvent::Done => {
- let output = markdown_render.render_line_stateless(&buffer);
- let trimed_output = output.trim_end();
- if !trimed_output.is_empty() {
- queue!(writer, style::Print(output.trim_end()))?;
- writer.flush()?;
- }
-
- let (_, row) = cursor::position()?;
- queue!(writer, cursor::MoveTo(0, row), style::Print("\n\n"))?;
+ queue!(writer, style::Print("\n"))?;
writer.flush()?;
break;
@@ -117,21 +128,3 @@ fn repl_render_stream_inner(
}
Ok(())
}
-
-fn recover_cursor(writer: &mut Stdout, terminal_columns: u16, buffer: &str) -> Result<()> {
- let buffer_rows = (u16::try_from(buffer.width()).unwrap_or(u16::MAX) + terminal_columns - 1)
- / terminal_columns;
- let (_, row) = cursor::position()?;
- if buffer_rows == 0 {
- queue!(writer, cursor::MoveTo(0, row))?;
- } else if row + 1 >= buffer_rows {
- queue!(writer, cursor::MoveTo(0, row + 1 - buffer_rows))?;
- } else {
- queue!(
- writer,
- terminal::ScrollUp(buffer_rows - 1 - row),
- cursor::MoveTo(0, 0)
- )?;
- }
- Ok(())
-}