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