summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/cmd.rs64
-rw-r--r--src/render/markdown.rs40
-rw-r--r--src/render/mod.rs43
-rw-r--r--src/render/stream.rs (renamed from src/render/repl.rs)42
4 files changed, 58 insertions, 131 deletions
diff --git a/src/render/cmd.rs b/src/render/cmd.rs
deleted file mode 100644
index e942025..0000000
--- a/src/render/cmd.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use super::{MarkdownRender, ReplyEvent};
-
-use crate::utils::{split_line_sematic, split_line_tail, AbortSignal};
-
-use anyhow::Result;
-use crossbeam::channel::Receiver;
-use textwrap::core::display_width;
-
-pub fn cmd_render_stream(
- rx: &Receiver<ReplyEvent>,
- render: &mut MarkdownRender,
- abort: &AbortSignal,
-) -> Result<()> {
- let mut buffer = String::new();
- let mut indent = 0;
- loop {
- if abort.aborted() {
- return Ok(());
- }
- if let Ok(evt) = rx.try_recv() {
- match evt {
- ReplyEvent::Text(text) => {
- if text.contains('\n') {
- let text = format!("{buffer}{text}");
- let (head, tail) = split_line_tail(&text);
- buffer = tail.to_string();
- let output = render.render_with_indent(head, indent);
- println!("{}", output);
- indent = 0;
- } else {
- buffer = format!("{buffer}{text}");
- if !(render.is_code()
- || buffer.len() < 40
- || buffer.starts_with('#')
- || buffer.starts_with('>')
- || buffer.starts_with('|'))
- {
- if let Some((head, remain)) = split_line_sematic(&buffer) {
- buffer = remain;
- let output = render.render_with_indent(&head, indent);
- let (_, tail) = split_line_tail(&output);
- if let Some(width) = render.wrap_width() {
- if output.contains('\n') {
- indent = display_width(tail);
- } else {
- indent += display_width(&output);
- }
- indent %= width as usize;
- }
- print!("{}", output);
- }
- }
- }
- }
- ReplyEvent::Done => {
- let output = render.render_with_indent(&buffer, indent);
- println!("{}", output);
- break;
- }
- }
- }
- }
- Ok(())
-}
diff --git a/src/render/markdown.rs b/src/render/markdown.rs
index f300854..44e24b3 100644
--- a/src/render/markdown.rs
+++ b/src/render/markdown.rs
@@ -64,17 +64,6 @@ impl MarkdownRender {
})
}
- pub(crate) const fn is_code(&self) -> bool {
- matches!(
- self.prev_line_type,
- LineType::CodeBegin | LineType::CodeInner
- )
- }
-
- pub(crate) const fn wrap_width(&self) -> Option<u16> {
- self.wrap_width
- }
-
pub fn render(&mut self, text: &str) -> String {
text.split('\n')
.map(|line| self.render_line_mut(line))
@@ -82,16 +71,6 @@ impl MarkdownRender {
.join("\n")
}
- pub fn render_with_indent(&mut self, text: &str, indent: usize) -> String {
- let text = format!("{}{}", " ".repeat(indent), text);
- let output = self.render(&text);
- if output.starts_with('\n') {
- output
- } else {
- output.chars().skip(indent).collect()
- }
- }
-
pub fn render_line(&self, line: &str) -> String {
let (_, code_syntax, is_code) = self.check_line(line);
if is_code {
@@ -377,23 +356,4 @@ std::error::Error>> {
let output = render.render(TEXT);
assert_eq!(TEXT_WRAP_ALL, output);
}
-
- #[test]
- fn wrap_with_indent() {
- let options = RenderOptions::default();
- let mut render = MarkdownRender::init(options).unwrap();
- render.wrap_width = Some(80);
-
- let input = "To unzip a file in Rust, you can use the `zip` crate. Here's an example code";
- let output = render.render_with_indent(input, 40);
- let expect =
- "To unzip a file in Rust, you can use the\n`zip` crate. Here's an example code";
- assert_eq!(output, expect);
-
- let input = "Unzip a file";
- let output = render.render_with_indent(input, 76);
- let expect = "\nUnzip a file";
-
- assert_eq!(output, expect);
- }
}
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 2b97557..1e20ccc 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -1,10 +1,8 @@
-mod cmd;
mod markdown;
-mod repl;
+mod stream;
-use self::cmd::cmd_render_stream;
pub use self::markdown::{MarkdownRender, RenderOptions};
-use self::repl::repl_render_stream;
+use self::stream::{markdown_stream, raw_stream};
use crate::client::Client;
use crate::config::GlobalConfig;
@@ -13,17 +11,19 @@ use crate::utils::AbortSignal;
use anyhow::{Context, Result};
use crossbeam::channel::{unbounded, Sender};
use crossbeam::sync::WaitGroup;
+use is_terminal::IsTerminal;
use nu_ansi_term::{Color, Style};
+use std::io::stdout;
use std::thread::spawn;
pub fn render_stream(
input: &str,
client: &dyn Client,
config: &GlobalConfig,
- repl: bool,
abort: AbortSignal,
- wg: WaitGroup,
) -> Result<String> {
+ let wg = WaitGroup::new();
+ let wg_cloned = wg.clone();
let render_options = config.read().get_render_options()?;
let mut stream_handler = {
let (tx, rx) = unbounded();
@@ -31,33 +31,44 @@ pub fn render_stream(
let highlight = config.read().highlight;
spawn(move || {
let run = move || {
- if repl {
+ if stdout().is_terminal() {
let mut render = MarkdownRender::init(render_options)?;
- repl_render_stream(&rx, &mut render, &abort)
+ markdown_stream(&rx, &mut render, &abort)
} else {
- let mut render = MarkdownRender::init(render_options)?;
- cmd_render_stream(&rx, &mut render, &abort)
+ raw_stream(&rx, &abort)
}
};
if let Err(err) = run() {
render_error(err, highlight);
}
- drop(wg);
+ drop(wg_cloned);
});
ReplyHandler::new(tx, abort_clone)
};
- client.send_message_streaming(input, &mut stream_handler)?;
- let buffer = stream_handler.get_buffer();
- Ok(buffer.to_string())
+ let ret = client.send_message_streaming(input, &mut stream_handler);
+ wg.wait();
+ let output = stream_handler.get_buffer().to_string();
+ match ret {
+ Ok(_) => {
+ println!();
+ Ok(output)
+ }
+ Err(err) => {
+ if !output.is_empty() {
+ println!();
+ }
+ Err(err)
+ }
+ }
}
pub fn render_error(err: anyhow::Error, highlight: bool) {
let err = format!("{err:?}");
if highlight {
let style = Style::new().fg(Color::Red);
- println!("{}", style.paint(err.trim()));
+ eprintln!("{}", style.paint(err));
} else {
- println!("{}", err.trim());
+ eprintln!("{err}");
}
}
diff --git a/src/render/repl.rs b/src/render/stream.rs
index eeb5420..189862d 100644
--- a/src/render/repl.rs
+++ b/src/render/stream.rs
@@ -1,6 +1,6 @@
use super::{MarkdownRender, ReplyEvent};
-use crate::utils::{split_line_tail, AbortSignal};
+use crate::utils::AbortSignal;
use anyhow::Result;
use crossbeam::channel::Receiver;
@@ -16,7 +16,7 @@ use std::{
};
use textwrap::core::display_width;
-pub fn repl_render_stream(
+pub fn markdown_stream(
rx: &Receiver<ReplyEvent>,
render: &mut MarkdownRender,
abort: &AbortSignal,
@@ -24,14 +24,33 @@ pub fn repl_render_stream(
enable_raw_mode()?;
let mut stdout = io::stdout();
- let ret = repl_render_stream_inner(rx, render, abort, &mut stdout);
+ let ret = markdown_stream_inner(rx, render, abort, &mut stdout);
disable_raw_mode()?;
ret
}
-fn repl_render_stream_inner(
+pub fn raw_stream(rx: &Receiver<ReplyEvent>, abort: &AbortSignal) -> Result<()> {
+ loop {
+ if abort.aborted() {
+ return Ok(());
+ }
+ if let Ok(evt) = rx.try_recv() {
+ match evt {
+ ReplyEvent::Text(text) => {
+ print!("{}", text);
+ }
+ ReplyEvent::Done => {
+ break;
+ }
+ }
+ }
+ }
+ Ok(())
+}
+
+fn markdown_stream_inner(
rx: &Receiver<ReplyEvent>,
render: &mut MarkdownRender,
abort: &AbortSignal,
@@ -104,13 +123,6 @@ fn repl_render_stream_inner(
writer.flush()?;
}
ReplyEvent::Done => {
- #[cfg(target_os = "windows")]
- let eol = "\n\n";
- #[cfg(not(target_os = "windows"))]
- let eol = "\n";
- queue!(writer, style::Print(eol))?;
- writer.flush()?;
-
break;
}
}
@@ -157,6 +169,14 @@ fn print_block(writer: &mut Stdout, text: &str, columns: u16) -> Result<u16> {
Ok(num)
}
+fn split_line_tail(text: &str) -> (&str, &str) {
+ if let Some((head, tail)) = text.rsplit_once('\n') {
+ (head, tail)
+ } else {
+ ("", text)
+ }
+}
+
fn need_rows(text: &str, columns: u16) -> u16 {
let buffer_width = display_width(text).max(1) as u16;
(buffer_width + columns - 1) / columns