1use crossterm::{
74 QueueableCommand,
75 cursor::{self, position},
76 event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
77 style::Print,
78 terminal::{self, disable_raw_mode,},
79};
80use futures_util::{FutureExt, StreamExt, select};
81use grapheme_utils::*;
82use historybuffer::HistoryBuffer;
83use std::{
84 io::{self, Stdout, Write, stdout},
85 ops::DerefMut,
86 rc::Rc,
87 string::String,
88};
89use thingbuf::mpsc::{Receiver, Sender, errors::TrySendError};
90use unicode_segmentation::UnicodeSegmentation;
91
92mod error;
93pub use self::error::{Error, Result};
94
95const HISTORY_BUFFER_SIZE: usize = 300 * 160 * 4;
96
97#[derive(Debug)]
98pub enum EditorEvent {
99 CtrlC,
100 CtrlD,
101 CtrlQ,
102 CtrlN,
103 CtrlS,
104 CtrlX,
105}
106
107pub enum WriteHistoryType {
108 PageUp,
109 PageDown,
110 Quit,
111}
112
113pub struct AsyncEditor {
124 event_stream: EventStream, stdout_rx: Receiver<Vec<u8>>, editor: Editor, }
128
129impl AsyncEditor {
130 pub fn new(
133 initial_content: &str,
134 split_prompt: String,
135 print_height: f32,
136 tabstop: u8,
137 ) -> Result<(Self, SharedStdout)> {
138 let (stdout_tx, stdout_rx) = thingbuf::mpsc::channel(500);
139
140 let editor = Editor::new(initial_content, split_prompt, print_height, tabstop)?;
141
142 let mut async_editor = AsyncEditor {
143 event_stream: EventStream::new(),
144 stdout_rx,
145 editor,
146 };
147 async_editor.editor.term.queue(terminal::EnableLineWrap)?;
148 async_editor.editor.term.flush()?;
149 Ok((
150 async_editor,
151 SharedStdout {
152 buf: Vec::new(),
153 stdout_tx: stdout_tx,
154 },
155 ))
156 }
157
158 pub fn flush(&mut self) -> Result<()> {
159 while let Ok(buf) = self.stdout_rx.try_recv_ref() {
160 self.editor.writeout(&buf)?;
161 }
162 self.editor.term.flush()?;
163 Ok(())
164 }
165
166 pub async fn async_editor(&mut self) -> Result<EditorEvent> {
169 loop {
170 select! {
171 event = self.event_stream.next().fuse() => match event {
172 Some(Ok(event)) => {
173 match self.editor.handle_event(event) {
174 Ok(Some(event)) => {
175 self.editor.term.flush()?;
176 return Result::<_>::Ok(event) },
178 Err(e) => return Err(e),
179 Ok(None) => self.editor.term.flush()?,
180 }
181 }
182 Some(Err(e)) => return Err(e.into()),
183 None => {},
184 },
185 result = self.stdout_rx.recv_ref().fuse() => match result {
186 Some(buf) => {
187 self.editor.writeout(&buf)?;
188 self.editor.term.flush()?;
189 },
190 None => return Err(Error::SharedStdoutClosed),
191 },
192 }
193 }
194 }
195
196 pub fn text(&self) -> String {
197 self.editor.text()
198 }
199}
200
201fn string_to_hex(s: &str, maxlen: usize) -> String {
202 let mut new_hex_string = String::with_capacity(s.as_bytes().len() * 2);
203
204 for byte in s.as_bytes().iter() {
205 let s = format!("{:02x} ", byte);
206 new_hex_string.push_str(&s);
207 if new_hex_string.len() >= maxlen {
208 return new_hex_string[..maxlen].to_string();
209 }
210 }
211 new_hex_string
212}
213
214pub struct Editor {
215 curx: u16, cury: u16,
217 hb_active: bool,
218 hb_start_index: usize,
219 hb_end_index: usize,
220 histbuf: HistoryBuffer, lidx: usize,
222 lines: Vec<String>, lineidx: usize, lofs: usize,
225 loose_cursor: bool, printlines: u16, printx: u16, printy: u16,
229 scrollstart: usize,
230 sizex: u16, sizey: u16,
232 split_prompt: String,
233 tabstop: u8,
234 term: Stdout,
235 tmpbuf: Rc<String>,
236}
237
238impl Editor {
239 pub fn new(
240 initial_content: &str,
241 split_prompt: String,
242 print_height: f32,
243 tabstop: u8,
244 ) -> Result<Self> {
245 let term = stdout();
246 let (sizex, sizey) = terminal::size()?;
247 let (_curx, cury) = position()?;
248 let newprintlines = (sizey as f32 * print_height.max(0.1).min(0.9)) as u16;
249 terminal::enable_raw_mode()?;
250
251 Ok(Self {
252 curx: 0,
253 cury: newprintlines + 2,
254 hb_active: false,
255 hb_start_index: 0,
256 hb_end_index: 0,
257 histbuf: HistoryBuffer::new(HISTORY_BUFFER_SIZE), lidx: 0, lines: initial_content.split("\n").map(|s| s.to_string()).collect(), lineidx: 0,
261 lofs: 0, loose_cursor: false,
263 printlines: newprintlines,
264 printx: 0,
265 printy: cury + 1,
266 scrollstart: 0,
267 sizex: sizex,
268 sizey: sizey,
269 split_prompt: split_prompt,
270 tabstop: tabstop,
271 term: term,
272 tmpbuf: Rc::new(String::new()), })
274 }
275
276 fn ch(&self, idx: usize) -> char {
277 grapheme_at_idx(&self.lines[self.lineidx], idx)
278 .chars()
279 .next()
280 .unwrap_or('\0')
281 }
282
283 fn grapheme_idx_at_idx(&self, idx: usize) -> usize {
284 grapheme_idx_at_idx(&self.lines[self.lineidx], idx)
285 }
286
287 fn grapheme_width_lofs_to_lidx(&self) -> u16 {
288 let st = &self.lines[self.lineidx][self.lofs..self.lidx];
289 if !st.contains('\t') {
290 return string_width(&st) as u16;
291 }
292 let ofs = string_width(&self.lines[self.lineidx][..self.lofs]) % self.tabstop as usize;
293 let mut char_width;
294 let mut width = 0;
295 for (_, g) in st.grapheme_indices(true) {
296 if g == "\t" {
297 let ts = self.tabstop as usize;
298 char_width = ts - ((width + ofs) % ts);
299 } else {
300 char_width = string_width(g);
301 }
302 width += char_width;
303 }
304 return width as u16;
305 }
306
307 pub fn handle_event(&mut self, event: Event) -> Result<Option<EditorEvent>> {
308 match event {
309 Event::Key(KeyEvent {
312 code,
313 modifiers: KeyModifiers::CONTROL,
314 kind: KeyEventKind::Press,
315 ..
316 }) => match code {
317 KeyCode::Char('a') => {
319 self.lidx = 0;
320 self.lofs = 0;
321 self.setpos()?;
322 }
323 KeyCode::Char('c') => {
325 return Ok(Some(EditorEvent::CtrlC));
329 }
330 KeyCode::Char('d') => {
332 return Ok(Some(EditorEvent::CtrlD));
334 }
335 KeyCode::Char('e') => {
337 self.move_end()?;
338 }
339 KeyCode::Char('l') => {
340 self.printx = 0;
341 self.printy = 0;
342 self.redraw()?;
343 }
344 KeyCode::Char('n') => {
345 return Ok(Some(EditorEvent::CtrlS));
346 }
347 KeyCode::Char('q') => {
348 return Ok(Some(EditorEvent::CtrlQ));
349 }
350 KeyCode::Char('s') => {
351 return Ok(Some(EditorEvent::CtrlS));
352 }
353 KeyCode::Char('x') => {
354 return Ok(Some(EditorEvent::CtrlX));
355 }
356 KeyCode::Char('u') => {
357 self.lines[self.lineidx].drain(0..self.lidx);
358 self.redraw()?;
359 }
360 KeyCode::Down => {
361 self.resize(3)?;
362 }
363 KeyCode::End => {
364 self.lineidx = self.lines.len().saturating_sub(1);
365 self.scrollstart = self.lineidx; self.cury = self.printlines + 2; self.lidx = self.len();
368 self.setpos()?;
369 self.redraw()?;
370 }
371 KeyCode::Home => {
372 self.lineidx = 0;
373 self.scrollstart = 0;
374 self.cury = self.printlines + 2;
375 self.lidx = 0;
376 self.setpos()?;
377 self.redraw()?;
378 }
379 KeyCode::Left => {
381 if self.lidx == 0 {
382 self.move_up(1, true)?;
383 self.lidx = self.len();
384 }
385 while self.lidx > 0 && self.prev_char(self.lidx).is_whitespace() {
386 self.lidx = self.prev_grapheme_idx_from_idx(self.lidx);
387 }
388 while self.lidx > 0 && !self.prev_char(self.lidx).is_whitespace() {
389 self.lidx = self.prev_grapheme_idx_from_idx(self.lidx);
390 }
391 self.setpos()?;
392 }
393 KeyCode::PageDown => { self.writehistory(WriteHistoryType::PageDown)?;
396 }
397 KeyCode::PageUp => { if !self.hb_active {
399 self.hb_active = true;
400 self.hb_start_index = self.histbuf.get_last_index();
401 self.hb_end_index = self.hb_start_index;
402 } else {
403 if self.hb_start_index == 0 {
404 return Ok(None);
405 }
406 }
407 self.writehistory(WriteHistoryType::PageUp)?;
408 }
409 KeyCode::Right => {
411 while self.lidx < self.len() && !self.ch(self.lidx).is_whitespace() {
412 self.lidx = self.next_grapheme_idx_from_idx(self.lidx);
413 }
414 if self.lidx == self.len() {
415 self.move_down(1, true)?;
416 self.lidx = 0;
417 }
418 while self.lidx < self.len() && self.ch(self.lidx).is_whitespace() {
419 self.lidx = self.next_grapheme_idx_from_idx(self.lidx);
420 }
421 self.setpos()?;
422 }
423 KeyCode::Up => {
424 self.resize(-3)?;
425 }
426 _ => {}
427 },
428 Event::Key(KeyEvent {
431 code,
432 modifiers: _,
433 kind: KeyEventKind::Press,
434 ..
435 }) => match code {
436 KeyCode::Backspace => {
437 if self.lidx == 0 {
438 if self.lineidx == 0 {
439 return Ok(None);
440 }
441 self.lidx = self.lines[self.lineidx - 1].len();
442 let s = self.lines[self.lineidx].clone();
444 self.lines[self.lineidx - 1].push_str(&s);
445 self.lines.remove(self.lineidx);
446 self.move_up(1, false)?;
447 self.setpos()?;
448 self.redraw()?;
449 } else {
450 if self.lidx > self.len() {
451 self.lidx = self.len();
452 self.lofs = 0;
453 }
454 let start = self.prev_grapheme_idx_from_idx(self.lidx);
455 let mut gwid = self.grapheme_width_lofs_to_lidx(); self.lines[self.lineidx].replace_range(start..self.lidx, "");
457 self.lidx = start;
458 gwid = gwid.saturating_sub(self.grapheme_width_lofs_to_lidx());
459 self.curx = self.curx.saturating_sub(gwid);
460 self.redrawline()?;
461 }
462 }
463 KeyCode::Char(c) => {
464 self.insert_charstr(&c.to_string())?;
465 }
466 KeyCode::Delete => {
467 if self.lidx == self.len() {
468 if self.lineidx + 1 < self.lines.len() {
469 let s = self.lines[self.lineidx + 1].clone();
470 self.lines[self.lineidx].push_str(&s);
471 self.lines.remove(self.lineidx + 1);
472 self.redraw()?;
473 }
474 } else {
475 let end = self.next_grapheme_idx_from_idx(self.lidx);
476 self.lines[self.lineidx].replace_range(self.lidx..end, "");
477 self.redrawline()?;
478 }
479 }
480 KeyCode::Down => {
481 self.move_down(1, false)?;
482 self.redraw()?;
483 }
484 KeyCode::End => {
485 self.move_end()?;
486 }
487 KeyCode::Esc => {
488 self.writehistory(WriteHistoryType::Quit)?;
489 self.hb_active = false;
490 }
491 KeyCode::Enter => {
492 if self.lidx > self.len() {
493 self.lidx = self.len();
494 }
495 self.lines.insert(
496 self.lineidx + 1,
497 self.lines[self.lineidx][self.lidx..].to_string(),
498 );
499 self.lines[self.lineidx].drain(self.lidx..);
500 self.move_down(1, true)?;
501 self.redraw()?;
502 }
503 KeyCode::Home => {
504 self.lidx = 0;
505 self.lofs = 0;
506 self.setpos()?;
507 }
508 KeyCode::Left => {
509 if self.lidx == 0 {
510 if self.lineidx == 0 { return Ok(None) }
511 self.move_up(1, true)?;
512 self.lidx = self.len();
513 } else {
514 self.lidx = self.prev_grapheme_idx_from_idx(self.lidx);
515 }
516 self.setpos()?;
517 }
518 KeyCode::PageDown => {
519 let numlines = self.sizey - self.printlines - 2;
520 self.move_down(numlines, false)?;
521 }
522 KeyCode::PageUp => {
523 let numlines = self.sizey - self.printlines - 2;
524 self.move_up(numlines, false)?;
525 }
526 KeyCode::Right => {
527 if self.lidx >= self.len() {
528 if self.lineidx + 1 == self.lines.len() { return Ok(None) }
529 self.move_down(1, true)?;
530 self.lidx = 0;
531 } else {
532 self.lidx = self.next_grapheme_idx_from_idx(self.lidx);
533 }
534 self.setpos()?;
535 }
536 KeyCode::Tab => {
537 self.insert_charstr("\t")?;
538 }
539 KeyCode::Up => {
540 self.move_up(1, false)?;
541 }
542 _ => {}
543 },
544 Event::Resize(x, y) => {
545 let curp: f32 = (self.printlines as f32 / self.sizey as f32)
546 .max(0.9)
547 .min(0.1);
548 let delta: i16 = (curp * y as f32) as i16 - self.printlines as i16;
549
550 self.sizex = x;
551 self.sizey = y;
552 self.resize(delta)?;
553
554 self.sizey = y;
555 }
556 _ => {}
557 }
558 if false {
559 self.split_prompt = string_to_hex(&self.lines[self.lineidx], 40);
561 self.redraw()?;
562 }
563 self.term.queue(cursor::MoveTo(self.curx, self.cury))?;
564 self.term.flush()?;
565 Ok(None)
566 }
567
568 fn insert_charstr(&mut self, ch: &str) -> Result<()> {
569 if self.lidx > self.len() {
570 self.lidx = self.len();
571 self.lofs = 0;
572 }
573 self.lines[self.lineidx].insert_str(self.lidx, ch);
575 self.lidx = self.next_grapheme_idx_from_idx(self.lidx);
577 self.curx = self.grapheme_width_lofs_to_lidx();
578
579 self.redrawline()?;
580 Ok(())
581 }
582
583 fn len(&mut self) -> usize {
584 self.lines[self.lineidx].len()
585 }
586
587 fn matchpos(&mut self) -> Result<()> {
589 self.setpos()?;
593 Ok(())
594 }
595
596 fn move_down(&mut self, num: u16, move_to_beginning: bool) -> Result<()> {
597 self.loose_cursor = true;
598 if self.lineidx + 1 == self.lines.len() && self.scrollstart + 1 == self.lines.len() as usize {
599 self.lidx = self.len();
600 self.setpos()?;
601 self.redrawline()?;
602 return Ok(());
603 }
604
605 let virtidx;
612 if self.scrollstart <= (self.sizey as usize + 2).saturating_sub((self.cury + self.printlines) as usize) {
613 virtidx = (self.cury - self.printlines) as usize - 2;
614 } else {
615 virtidx = self.scrollstart + (self.sizey - self.printlines) as usize - 3;
616 }
617
618 self.cury += num;
619 self.lineidx = (self.lineidx + num as usize).min(self.lines.len().saturating_sub(1));
620 if self.cury > self.sizey - 1 || self.lineidx + 1 == self.lines.len() {
621 if num > 10 {
622 self.scrollstart = (self.scrollstart + num as usize).min(self.lineidx);
624 } else {
625 self.scrollstart = (virtidx + num as usize + self.printlines as usize + 3).saturating_sub(self.sizey as usize).min(self.lineidx);
627 }
628 }
629 self.cury = self.cury.min((self.lineidx - self.scrollstart) as u16 + self.printlines + 2).min(self.sizey - 1);
630
631 if move_to_beginning {
632 self.lidx = 0;
633 self.lofs = 0;
634 self.curx = 0;
635 } else {
636 self.matchpos()?;
637 }
638 self.redraw()?;
639 Ok(())
640 }
641
642 fn move_end(&mut self) -> Result<()> {
643 self.lidx = self.len();
644 self.setpos()?;
645 self.redrawline()?;
646 Ok(())
647 }
648
649 fn move_up(&mut self, num: u16, move_to_end: bool) -> Result<()> {
650 self.loose_cursor = true;
651
652 if self.lineidx == 0 && self.scrollstart == 0 {
653 self.lofs = 0;
654 self.lidx = 0;
655 self.curx = 0;
656 self.redrawline()?;
657 return Ok(())
658 }
659
660 self.lineidx = self.lineidx.saturating_sub(num as usize);
661 if self.cury == self.printlines+2 || self.lineidx < self.scrollstart {
662 self.scrollstart = self.scrollstart.saturating_sub(num as usize);
663 }
664 self.cury = (self.lineidx - self.scrollstart) as u16 + self.printlines + 2; if move_to_end {
666 self.lidx = self.len();
667 }
668 self.matchpos()?;
669 self.redraw()?;
670 Ok(())
671 }
672
673 fn next_grapheme_from_idx(&self, idx: usize) -> &str {
674 next_grapheme_from_idx(&self.lines[self.lineidx], idx)
675 }
676
677 fn next_grapheme_idx_from_idx(&self, idx: usize) -> usize {
678 next_grapheme_idx_from_idx(&self.lines[self.lineidx], idx)
679 }
680
681 fn prev_char(&self, idx: usize) -> char {
682 self.prev_grapheme_from_idx(idx)
683 .chars()
684 .next()
685 .unwrap_or('\0')
686 }
687
688 fn prev_grapheme_from_idx(&self, idx: usize) -> &str {
689 prev_grapheme_from_idx(&self.lines[self.lineidx], idx)
690 }
691
692 fn prev_grapheme_idx_from_idx(&self, idx: usize) -> usize {
693 prev_grapheme_idx_from_idx(&self.lines[self.lineidx], idx)
694 }
695
696 pub fn redraw(&mut self) -> Result<()> {
697 let tbuf = Rc::get_mut(&mut self.tmpbuf).ok_or(Error::RedrawRcError)?;
700 tbuf.clear();
702 let s = format!(
727 "===== AsyncEditor ========== {} == Ctrl ⬅️ / ⮕ / ⬆️/ / ⬇️ == Ctrl-PgUp/Ctrl-PgDn ",
728 self.split_prompt);
729 let extend_count = (self.sizex as usize).saturating_sub(string_width(&s));
730
731 self.term
732 .queue(cursor::MoveTo(0, self.printlines + 1 as u16))?;
733 self.term
734 .queue(terminal::Clear(terminal::ClearType::FromCursorDown))?;
735 self.term.queue(Print(&format!(
737 "{}{}\n",
738 s,
739 std::iter::repeat("=")
740 .take(extend_count)
741 .collect::<String>()
742 )))?;
743 self.term.queue(cursor::MoveToColumn(0))?;
744
745 let end_index = (self.scrollstart
746 + (self.sizey.saturating_sub(self.printlines + 2) as usize))
747 .min(self.lines.len());
748 for lidx in self.scrollstart..end_index {
749 if lidx == self.lineidx {
751 self.redrawline()?;
752 if lidx != end_index - 1 {
753 self.term.queue(cursor::MoveToNextLine(1))?;
754 }
755 continue;
756 }
757
758 let line = &self.lines[lidx];
759 let maxwidth = self.sizex as usize - 1;
760 let stwidth = string_width(line);
761 let mut width = 0usize;
762 let mut char_width;
763 let mut s = String::with_capacity(200);
764 let mut news = String::with_capacity(200);
765
766 match (stwidth > maxwidth, line.contains('\t')) {
767 (false, false) => {
768 self.term.queue(Print(&line))?;
770 }
771 (_, _) => {
772 s.clear();
774 for (_, g) in line.grapheme_indices(true) {
775 news.clear();
776 if g == "\t" {
777 let ts = self.tabstop as usize;
778 char_width = ts - (width % ts);
779 let tab_arrow_string: String =
780 std::iter::repeat("→").take(char_width as usize).collect();
781 news.push_str(&tab_arrow_string);
782 } else {
783 char_width = string_width(g);
784 news.push_str(g);
785 }
786 if width + char_width as usize > maxwidth {
787 break;
788 }
789 s.push_str(&news);
790 width += char_width;
791 }
792 self.term.queue(Print(&s))?;
793 if stwidth > maxwidth {
794 self.term.queue(cursor::MoveToColumn(self.sizex - 1))?;
795 self.term.queue(Print(&'>'))?;
796 }
797 }
798 }
799 if lidx != end_index - 1 {
800 self.term.queue(cursor::MoveToNextLine(1))?;
801 }
802 }
803 self.term.queue(cursor::MoveTo(self.curx, self.cury))?;
804 self.term.flush()?;
805 Ok(())
806 }
807
808 fn redrawline(&mut self) -> Result<()> {
809 self.term
810 .queue(terminal::Clear(terminal::ClearType::CurrentLine))?;
811 self.term.queue(cursor::MoveToColumn(0))?;
812 let start = if self.lofs > self.len() {
814 0
815 } else {
816 self.grapheme_idx_at_idx(self.lofs)
817 };
818
819 let line = &self.lines[self.lineidx][start..];
821 let maxwidth = self.sizex as usize - 2;
822 let stwidth = string_width(line);
823 let mut width = 0usize;
824 let mut char_width;
825 let mut s = String::with_capacity(200);
826 let mut news = String::with_capacity(200);
827
828 match (stwidth > maxwidth, line.contains('\t')) {
829 (false, false) => {
830 self.term.queue(Print(&line))?;
833 }
834 (_, _) => {
835 s.clear();
837 for (_, g) in line.grapheme_indices(true) {
838 news.clear();
839 if g == "\t" {
840 let ts = self.tabstop as usize;
841 char_width = ts - (width % ts);
842 let tab_arrow_string: String =
843 std::iter::repeat("→").take(char_width as usize).collect();
844 news.push_str(&tab_arrow_string);
845 } else {
846 char_width = string_width(g);
847 news.push_str(g);
848 }
849 if width + char_width as usize > maxwidth + 1 {
850 break;
851 }
852 s.push_str(&news);
853 width += char_width;
854 }
855 self.term.queue(Print(&s))?;
857 }
858 }
859 self.term.queue(cursor::MoveTo(self.curx, self.cury))?;
860 Ok(())
861 }
862
863 fn resize(&mut self, delta: i16) -> Result<()> {
864 self.term
865 .queue(cursor::MoveTo(self.printx, self.printy as u16))?;
866 self.term
867 .queue(terminal::Clear(terminal::ClearType::FromCursorDown))?;
868 let pre = self.printlines as i16;
869 self.printlines = (self.printlines as i16 + delta)
870 .max((self.sizey >> 3) as i16)
871 .min(self.sizey as i16 - 8) as u16;
872 let new_delta = self.printlines as i16 - pre;
873 self.cury = (self.cury as i16 + new_delta)
874 .max(self.printlines as i16 + 2) as u16;
875 while self.cury >= self.sizey {
876 self.cury -= 1;
877 self.lineidx -= 1;
878 }
879 self.setpos()?;
880 self.writebuf(&[])?;
881 Ok(())
882 }
883
884 fn setpos(&mut self) -> Result<()> {
886 let maxwidth = self.sizex - 1;
887 self.lidx = self.grapheme_idx_at_idx(self.lidx);
888
889 if self.loose_cursor {
893 if self.lidx < (self.lofs + (self.sizey << 2) as usize + 15) {
895 self.lofs = 0;
897 } else {
898 self.lofs = self.grapheme_idx_at_idx(self.lofs); }
901 }
902 if self.lidx < self.lofs {
903 self.lofs = 0;
905 }
906 self.loose_cursor = false;
907
908 let mut stwidth = self.grapheme_width_lofs_to_lidx();
909
910 loop {
911 if stwidth <= maxwidth {
912 self.curx = stwidth;
913 return Ok(());
914 }
915 self.lofs = self.next_grapheme_idx_from_idx(self.lofs);
918 stwidth = self.grapheme_width_lofs_to_lidx();
919 }
920 }
921
922 pub fn text(&self) -> String {
923 self.lines.join("\n")
924 }
925
926 fn writebuf(&mut self, buf: &[u8]) -> Result<()> {
927 for line in buf.split_inclusive(|b| *b == b'\n') {
933 self.term.write_all(line)?;
934 self.term.flush()?;
935 if line.ends_with(b"\n") {
936 self.term.queue(cursor::MoveToColumn(0))?;
937 self.printx = 0;
938 self.printy += 1;
939 } else {
940 let mut x = self.printx as usize + line.len(); while x > self.sizex as usize {
942 x -= self.sizex as usize;
943 self.printy += 1;
944 }
945 self.printx = x as u16;
946 }
947 }
948
949 self.printy = self.printy.min(self.sizey);
950 if self.printy > self.printlines {
951 self.term
952 .queue(terminal::ScrollUp(self.printy - self.printlines))?;
953 self.printy = self.printlines;
954 }
955
956 self.redraw()?;
957 Ok(())
958 }
959
960 fn writehistory(&mut self, write_history_type: WriteHistoryType) -> Result<()> {
961 self.term.queue(cursor::MoveTo(0, 0))?;
962 self.term.queue(terminal::Clear(terminal::ClearType::All))?;
963
964 self.printx = 0;
965 self.printy = 0;
966
967 let mut linecnt = self.sizex;
969 let mut num_lines = 0;
970 let mut buf = Vec::<u8>::with_capacity(self.printlines as usize * self.sizex as usize);
971 let mut revbuf: Vec::<u8> = vec![];
972
973 match write_history_type {
974 WriteHistoryType::PageDown => {
975 self.hb_start_index = self.hb_end_index;
976 while let Some(ch) = self.histbuf.get(self.hb_start_index + buf.len()) {
977 buf.push(ch);
978 linecnt -= 1;
979 if ch == b'\n' || linecnt == 0 {
980 linecnt = self.sizex - 1;
981 num_lines += 1;
982 if num_lines >= self.printlines {
983 break;
984 }
985 }
986 }
987 self.hb_end_index = self.hb_start_index + buf.len();
988 if num_lines < self.printlines { buf = self.histbuf.get_recent(self.printlines as usize * self.sizex as usize);
990 self.writebuf(&buf)?;
991 self.hb_active = false;
992 } else {
993 self.writebuf(&buf)?;
994 }
995 },
996 WriteHistoryType::PageUp => {
997 self.hb_end_index = self.hb_start_index;
998 while let Some(ch) = self.histbuf.get(self.hb_start_index) {
999 buf.push(ch);
1000 linecnt -= 1;
1001 if ch == b'\n' || linecnt == 0 {
1002 linecnt = self.sizex - 1;
1003 num_lines += 1;
1004 if num_lines >= self.printlines {
1005 break;
1006 }
1007 }
1008 if self.hb_start_index == 0 {
1009 break;
1010 }
1011 self.hb_start_index = self.hb_start_index.saturating_sub(1);
1012 }
1013 if self.hb_start_index == 0 { let mut linecnt = self.sizex;
1015 let mut num_lines = 0;
1016 revbuf = Vec::<u8>::with_capacity(self.printlines as usize * self.sizex as usize);
1017 while let Some(ch) = self.histbuf.get(self.hb_start_index + revbuf.len()) {
1018 revbuf.push(ch);
1019 linecnt -= 1;
1020 if ch == b'\n' || linecnt == 0 {
1021 linecnt = self.sizex - 1;
1022 num_lines += 1;
1023 if num_lines >= self.printlines {
1024 break;
1025 }
1026 }
1027 }
1028 self.hb_end_index = revbuf.len();
1029 } else {
1030 revbuf = buf.into_iter().rev().collect();
1031 }
1032 self.writebuf(&revbuf)?;
1033 },
1034 WriteHistoryType::Quit => {
1035 buf = self.histbuf.get_recent(self.printlines as usize * self.sizex as usize);
1036 self.writebuf(&buf)?;
1037 self.hb_active = false;
1038 }
1039 }
1040 Ok(())
1041 }
1042
1043 fn writeout(&mut self, buf: &[u8]) -> Result<()> {
1044 self.histbuf.add(buf);
1046 if !self.hb_active {
1047 self.term
1048 .queue(cursor::MoveTo(self.printx, self.printy as u16))?;
1049 self.term
1050 .queue(terminal::Clear(terminal::ClearType::FromCursorDown))?;
1051 self.writebuf(buf)?;
1052 }
1053 Ok(())
1054 }
1055}
1056
1057impl Drop for Editor {
1058 fn drop(&mut self) {
1059 let _ = disable_raw_mode();
1060 self.term
1061 .queue(cursor::MoveTo(0, self.sizey - 1))
1062 .unwrap();
1063 self.term.queue(cursor::MoveToNextLine(1)).unwrap();
1064 self.term.flush().unwrap();
1065 }
1066}
1067
1068#[pin_project::pin_project]
1069pub struct SharedStdout {
1070 #[pin]
1071 buf: Vec<u8>,
1072 stdout_tx: Sender<Vec<u8>>,
1073}
1074
1075impl io::Write for SharedStdout {
1076 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1077 self.buf.extend_from_slice(buf);
1078 if true {
1079 match self.stdout_tx.try_send_ref() {
1080 Ok(mut send_buf) => {
1081 std::mem::swap(send_buf.deref_mut(), &mut self.buf);
1082 self.buf.clear();
1083 }
1084 Err(TrySendError::Full(_)) => return Err(io::ErrorKind::WouldBlock.into()),
1085 _ => {
1086 return Err(io::Error::new(
1087 io::ErrorKind::Other,
1088 "io Error: ThingBuf Receiver Closed",
1089 ));
1090 }
1091 }
1092 }
1093 Ok(buf.len())
1094 }
1095 fn flush(&mut self) -> io::Result<()> {
1096 Ok(())
1097 }
1098}