A file-based task manager
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

WIP: add reworked parser

+80 -63
+16
Cargo.lock
··· 296 296 ] 297 297 298 298 [[package]] 299 + name = "smallstr" 300 + version = "0.3.0" 301 + source = "registry+https://github.com/rust-lang/crates.io-index" 302 + checksum = "63b1aefdf380735ff8ded0b15f31aab05daf1f70216c01c02a12926badd1df9d" 303 + dependencies = [ 304 + "smallvec", 305 + ] 306 + 307 + [[package]] 308 + name = "smallvec" 309 + version = "1.13.2" 310 + source = "registry+https://github.com/rust-lang/crates.io-index" 311 + checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 312 + 313 + [[package]] 299 314 name = "strsim" 300 315 version = "0.11.1" 301 316 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 370 385 "colored", 371 386 "edit", 372 387 "nix", 388 + "smallstr", 373 389 "thiserror", 374 390 "url", 375 391 "xattr",
+1
Cargo.toml
··· 12 12 url = "2.5.2" 13 13 xattr = "1.3.1" 14 14 colored = "2.1.0" 15 + smallstr = "0.3.0" 15 16 16 17 [build-dependencies] 17 18 clap_mangen = "0.2.23"
+63 -63
src/task.rs
··· 4 4 use crate::{errors::Error, workspace::Id}; 5 5 use colored::Colorize; 6 6 7 - #[derive(Debug, Eq, PartialEq)] 7 + #[derive(Debug, Eq, PartialEq, Clone, Copy)] 8 8 enum ParserOpcode { 9 9 // Started by ` =`, terminated by `= 10 10 Highlight(usize), ··· 46 46 links: Vec<Url>, 47 47 } 48 48 49 + #[derive(Default)] 50 + struct ParseState { 51 + highlight: Option<usize>, 52 + link: Option<usize>, 53 + internal: Option<usize>, 54 + italics: Option<usize>, 55 + bold: Option<usize>, 56 + underline: Option<usize>, 57 + strikethrough: Option<usize>, 58 + block: bool, 59 + inline: Option<usize>, 60 + quote: Option<(usize, u8)>, 61 + } 62 + 49 63 pub(crate) fn parse(s: &str) -> Option<ParsedTask> { 50 - let mut out = String::with_capacity(s.len()); 51 - let mut ops: Vec<ParserOpcode> = Vec::new(); 64 + let mut state = ParseState::default(); 65 + let mut out = s.to_string(); 52 66 let mut stream = s.char_indices().peekable(); 53 67 let outgoing_internal_links = Vec::new(); 54 - let mut links = Vec::new(); 68 + let links = Vec::new(); 69 + let mut last = '\0'; 55 70 loop { 56 - use ParserOpcode::*; 57 71 match stream.next() { 58 72 // there will always be an op code in the stack 59 - Some((pos, c)) => match dbg!((ops.last(), c)) { 60 - // Highlight terminal 61 - (Some(Highlight(start)), '=') => { 62 - out.push_str(&s[start + 1..=pos - 1].reversed().to_string()); 63 - // reduce 64 - ops.pop(); 65 - } 66 - // Highlight start 67 - (op, '=') => { 68 - ops.push(Highlight(pos)); 69 - } 70 - (Some(Linktext(start)), ']') => match stream.peek() { 71 - Some((_, '(')) => { 72 - out.push_str(&s[start + 1..=pos - 1].bright_blue().underline().to_string()); 73 - ops.pop(); 74 - ops.push(LinkJoin) 73 + Some((pos, c)) => { 74 + match (last, c, &state) { 75 + ( 76 + ' ', 77 + '=', 78 + ParseState { 79 + highlight: Some(hl), 80 + .. 81 + }, 82 + ) 83 + | ( 84 + '=', 85 + ' ', 86 + ParseState { 87 + highlight: Some(hl), 88 + .. 89 + }, 90 + ) 91 + | ( 92 + '=', 93 + '\n', 94 + ParseState { 95 + highlight: Some(hl), 96 + .. 97 + }, 98 + ) => { 99 + out.replace_range( 100 + *hl..pos, 101 + &out.get(*hl + 1..pos - 1)?.reversed().to_string(), 102 + ); 75 103 } 76 - // Terminal for internal link 77 - Some((_, ']')) => { 78 - out.push_str(&s[start + 1..=pos - 1].green().bold().to_string()); 79 - ops.pop(); 104 + ( 105 + ' ', 106 + '=', 107 + ParseState { 108 + highlight: None, .. 109 + }, 110 + ) => { 111 + state.highlight = Some(pos); 80 112 } 113 + 81 114 _ => (), 82 - }, 83 - (Some(Link(start)), ')') => { 84 - if let Ok(uri) = Url::parse(&s[start + 1..=pos - 1]) { 85 - links.push(uri); 86 - } 87 115 } 88 - (op, '[') => { 89 - if let Some(op) = op { 90 - ops.push(op); 91 - } 92 - ops.push(Linktext(pos)); 93 - } 94 - (Some(LinkJoin), '(') => { 95 - ops.push(Link(pos)); 96 - } 97 - (None | Some(_), c) => out.push(c), 98 - }, 99 - None => match ops.pop() { 100 - Some( 101 - Plain(start) | Highlight(start) | Linktext(start) | Link(start) 102 - | InternalLink(start) | Italics(start) | Bold(start) | Underline(start) 103 - | Strikethrough(start), 104 - ) => { 105 - // We have an 106 - return None; 107 - } 108 - None => { 109 - break; 110 - } 111 - Some(LinkJoin) => unreachable!(), 112 - Some(UnorderedList(_, _)) => todo!(), 113 - Some(OrderedList(_, _)) => todo!(), 114 - Some(BlockStart(_)) => todo!(), 115 - Some(BlockEnd(_)) => todo!(), 116 - Some(InlineBlock(_)) => todo!(), 117 - Some(Blockquote(_)) => todo!(), 118 - }, 116 + last = c; 117 + } 118 + None => break, 119 119 } 120 120 } 121 121 Some(ParsedTask { ··· 130 130 use super::*; 131 131 #[test] 132 132 fn test_highlight() { 133 - let input = "hello =world="; 133 + let input = "hello =world=\n"; 134 134 let output = parse(input).expect("parse to work"); 135 - assert_eq!("hello \u{1b}[7mworld\u{1b}[0m", output.content); 135 + assert_eq!("hello \u{1b}[7mworld\u{1b}[0m\n", output.content); 136 136 } 137 137 138 138 #[test]