diff options
| author | sigoden <sigoden@gmail.com> | 2023-10-31 18:34:38 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-31 18:34:38 +0800 |
| commit | 64202758ec8693dd18951c554728bb5c6b7e5eeb (patch) | |
| tree | 9adc7291e704b44bd39a8b0c42892806bd68cfa1 /src/render | |
| parent | bd3fc8e657777e58976aa06756ccc0a151bd0ea3 (diff) | |
| download | aichat-64202758ec8693dd18951c554728bb5c6b7e5eeb.tar.gz | |
chore: move split_line_* from repl/cmd.rs to utils/ (#190)
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/cmd.rs | 218 | ||||
| -rw-r--r-- | src/render/repl.rs | 3 |
2 files changed, 3 insertions, 218 deletions
diff --git a/src/render/cmd.rs b/src/render/cmd.rs index 57b6256..115170b 100644 --- a/src/render/cmd.rs +++ b/src/render/cmd.rs @@ -2,6 +2,7 @@ use super::MarkdownRender; use crate::print_now; use crate::repl::{ReplyStreamEvent, SharedAbortSignal}; +use crate::utils::{spaces, split_line_sematic, split_line_tail}; use anyhow::Result; use crossbeam::channel::Receiver; @@ -65,220 +66,3 @@ pub fn cmd_render_stream( } Ok(()) } - -fn split_line_sematic(text: &str) -> Option<(String, String)> { - let mut balance: Vec<Kind> = Vec::new(); - let chars: Vec<char> = text.chars().collect(); - let mut index = 0; - let len = chars.len(); - while index < len - 1 { - let ch = chars[index]; - if balance.is_empty() - && ((matches!(ch, ',' | '.' | ';') && chars[index + 1].is_whitespace()) - || matches!(ch, ',' | '。' | ';')) - { - let (output, remain) = chars.split_at(index + 1); - return Some((output.iter().collect(), remain.iter().collect())); - } - if index + 2 < len && do_balance(&mut balance, &chars[index..=index + 2]) { - index += 3; - continue; - } - if do_balance(&mut balance, &chars[index..=index + 1]) { - index += 2; - continue; - } - do_balance(&mut balance, &chars[index..=index]); - index += 1; - } - - None -} - -pub(crate) fn split_line_tail(text: &str) -> (&str, &str) { - if let Some((head, tail)) = text.rsplit_once('\n') { - (head, tail) - } else { - ("", text) - } -} - -fn spaces(n: usize) -> String { - " ".repeat(n) -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -enum Kind { - ParentheseStart, - ParentheseEnd, - BracketStart, - BracketEnd, - Asterisk, - Asterisk2, - SingleQuota, - DoubleQuota, - Tilde, - Tilde2, - Backtick, - Backtick3, -} - -impl Kind { - fn from_chars(chars: &[char]) -> Option<Self> { - let kind = match chars.len() { - 1 => match chars[0] { - '(' => Self::ParentheseStart, - ')' => Self::ParentheseEnd, - '[' => Self::BracketStart, - ']' => Self::BracketEnd, - '*' => Self::Asterisk, - '\'' => Self::SingleQuota, - '"' => Self::DoubleQuota, - '~' => Self::Tilde, - '`' => Self::Backtick, - _ => return None, - }, - 2 if chars[0] == chars[1] => match chars[0] { - '*' => Self::Asterisk2, - '~' => Self::Tilde2, - _ => return None, - }, - 3 => { - if chars == ['`', '`', '`'] { - Self::Backtick3 - } else { - return None; - } - } - _ => return None, - }; - Some(kind) - } -} - -fn do_balance(balance: &mut Vec<Kind>, chars: &[char]) -> bool { - Kind::from_chars(chars).map_or(false, |kind| { - let last = balance.last(); - match (kind, last) { - (Kind::ParentheseEnd, Some(&Kind::ParentheseStart)) - | (Kind::BracketEnd, Some(&Kind::BracketStart)) - | (Kind::Asterisk, Some(&Kind::Asterisk)) - | (Kind::Asterisk2, Some(&Kind::Asterisk2)) - | (Kind::SingleQuota, Some(&Kind::SingleQuota)) - | (Kind::DoubleQuota, Some(&Kind::DoubleQuota)) - | (Kind::Tilde, Some(&Kind::Tilde)) - | (Kind::Tilde2, Some(&Kind::Tilde2)) - | (Kind::Backtick, Some(&Kind::Backtick)) - | (Kind::Backtick3, Some(&Kind::Backtick3)) => { - balance.pop(); - true - } - ( - Kind::ParentheseStart - | Kind::BracketStart - | Kind::Asterisk - | Kind::Asterisk2 - | Kind::SingleQuota - | Kind::DoubleQuota - | Kind::Tilde - | Kind::Tilde2 - | Kind::Backtick - | Kind::Backtick3, - _, - ) => { - balance.push(kind); - true - } - _ => false, - } - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! assert_split_line { - ($a:literal, $b:literal, true) => { - assert_eq!( - split_line_sematic(&format!("{}{}", $a, $b)), - Some(($a.into(), $b.into())) - ); - }; - ($a:literal, $b:literal, false) => { - assert_eq!(split_line_sematic(&format!("{}{}", $a, $b)), None); - }; - } - - #[test] - fn test_split_line() { - assert_split_line!( - "Lorem ipsum dolor sit amet,", - " consectetur adipiscing elit.", - true - ); - assert_split_line!( - "Lorem ipsum dolor sit amet.", - " consectetur adipiscing elit.", - true - ); - assert_split_line!("黃更室幼許刀知,", "波食小午足田世根候法。", true); - assert_split_line!("黃更室幼許刀知。", "波食小午足田世根候法。", true); - assert_split_line!("黃更室幼許刀知;", "波食小午足田世根候法。", true); - assert_split_line!( - "Lorem ipsum (dolor sit amet).", - " consectetur adipiscing elit.", - true - ); - assert_split_line!( - "Lorem ipsum dolor sit `amet,", - " consectetur` adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit ```amet,", - " consectetur``` adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit *amet,", - " consectetur* adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit **amet,", - " consectetur** adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit ~amet,", - " consectetur~ adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit ~~amet,", - " consectetur~~ adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit ``amet,", - " consectetur`` adipiscing elit.", - true - ); - assert_split_line!( - "Lorem ipsum dolor sit \"amet,", - " consectetur\" adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit 'amet,", - " consectetur' adipiscing elit.", - false - ); - assert_split_line!( - "Lorem ipsum dolor sit amet.", - "consectetur adipiscing elit.", - false - ); - } -} diff --git a/src/render/repl.rs b/src/render/repl.rs index d55c1c1..845a5e3 100644 --- a/src/render/repl.rs +++ b/src/render/repl.rs @@ -1,6 +1,7 @@ -use super::{cmd::split_line_tail, MarkdownRender}; +use super::MarkdownRender; use crate::repl::{ReplyStreamEvent, SharedAbortSignal}; +use crate::utils::split_line_tail; use anyhow::Result; use crossbeam::channel::Receiver; |
