A sheep speaks.
0
fork

Configure Feed

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

add --think mode, move message tail rendering

Kevin cbf7abcc 57a9c1d4

+44 -21
-1
README.md
··· 47 47 ## TODO 48 48 49 49 - Add Dolly moods! 50 - - Add `--think` mode 51 50 - add `--deepthink` mode?
-2
dolly.txt
··· 1 - \ 2 - \ 3 1 .~``~,,```-. 4 2 ( -~~- ) 5 3 ( // OO \\ )
-2
dollys.txt
··· 1 - \ \ 2 - \ \ 3 1 .~``~,,```-. .~``~,,```-. 4 2 ( -~~- ) ( -~~- ) 5 3 ( // OO \\ ) ( // OO \\ )
+9 -13
src/bubble.rs
··· 2 2 3 3 // Builds the speech bubble (without trailing newline) and returns 4 4 // it as one String. 5 - pub fn render(text: &str, max_width: usize, min_width: usize) -> String { 5 + pub fn render(text: &str, max_width: usize, min_width: usize, think: bool) -> String { 6 6 let wrapped_text: Vec<String> = textwrap::wrap(text, max_width) 7 7 .into_iter() 8 8 .map(|cow| cow.into_owned()) ··· 27 27 out.push('\n'); 28 28 29 29 if wrapped_text.len() == 1 { 30 - // Single-line: 31 - // _______________________ 32 - // < this is a single line > 33 - // ----------------------- 34 - push_bubble_line(&mut out, &wrapped_text[0], inner, '<', '>'); 30 + // Single-line: < text > for speech, ( text ) for thought. 31 + let (l, r) = if think { ('(', ')') } else { ('<', '>') }; 32 + push_bubble_line(&mut out, &wrapped_text[0], inner, l, r); 35 33 } else { 36 - // Multi-line: 37 - // ___________________________________________________________ 38 - // / this is a multi line text that will require rounding the \ 39 - // | speech bubble corners. since it is more than two lines it | 40 - // \ will need to be extended with walls. / 41 - // ----------------------------------------------------------- 34 + // Multi-line: rounded speech corners + | walls, 35 + // or all parens for thought (cowthink convention). 42 36 let last = wrapped_text.len() - 1; 43 37 for (i, line) in wrapped_text.iter().enumerate() { 44 - let (l, r) = if i == 0 { 38 + let (l, r) = if think { 39 + ('(', ')') 40 + } else if i == 0 { 45 41 ('/', '\\') 46 42 } else if i == last { 47 43 ('\\', '/')
+35 -3
src/main.rs
··· 12 12 const MIN_BUBBLE_SIZE: usize = 20; 13 13 const MAX_BUBBLE_SIZE: usize = 60; 14 14 const MIN_CLONE_INNER: usize = 22; 15 + const DOLLY_MESSAGE_TAIL_POS: &[usize] = &[3]; 16 + const DOLLYS_MESSAGE_TAIL_POS: &[usize] = &[3, 22]; 15 17 16 18 const MUSINGS: &[&str] = &[ 17 19 "I push, therefore I baa.", ··· 36 38 /// Have Dolly share what's on her mind. 37 39 #[arg(long)] 38 40 muse: bool, 41 + 42 + /// Use a thought bubble instead of speech. 43 + #[arg(long)] 44 + think: bool, 39 45 } 40 46 41 47 fn main() -> ExitCode { ··· 50 56 }; 51 57 52 58 let min_inner = if cli.clone { MIN_CLONE_INNER } else { 0 }; 53 - let bubble: String = bubble::render(&message, message_width(), min_inner); 59 + let bubble: String = bubble::render(&message, message_width(), min_inner, cli.think); 60 + 61 + let (art, tail_pos) = if cli.clone { 62 + (DOLLYS, DOLLYS_MESSAGE_TAIL_POS) 63 + } else { 64 + (DOLLY, DOLLY_MESSAGE_TAIL_POS) 65 + }; 66 + let tail = render_message_tail(tail_pos, cli.think); 54 67 55 68 // Lock stdout and use BufWriter to group writes to one syscall only. 56 69 let stdout = io::stdout(); 57 70 let mut out = BufWriter::new(stdout.lock()); 58 71 59 - let art = if cli.clone { DOLLYS } else { DOLLY }; 60 - 61 72 let _ = writeln!(out, "{bubble}"); 73 + let _ = out.write_all(tail.as_bytes()); 62 74 let _ = out.write_all(art.as_bytes()); 63 75 64 76 match out.flush() { ··· 111 123 .map(|d| d.as_millis()) 112 124 .unwrap_or(0); 113 125 MUSINGS[(nanos as usize) % MUSINGS.len()] 126 + } 127 + 128 + // Renders the two-line tail connecting bubble to Dolly's head. Each anchor 129 + // in `positions` starts a tail char at that column on line 1 and at col+1 on line 2. 130 + fn render_message_tail(positions: &[usize], think: bool) -> String { 131 + let ch = if think { 'o' } else { '\\' }; 132 + let mut out = String::new(); 133 + for offset in 0..2 { 134 + let mut col = 0; 135 + for &pos in positions { 136 + let target = pos + offset; 137 + for _ in col..target { 138 + out.push(' '); 139 + } 140 + out.push(ch); 141 + col = target + 1; 142 + } 143 + out.push('\n'); 144 + } 145 + out 114 146 } 115 147 116 148 // Computes the wrap width for the message inside the bubble.