ad_editor/exec/
cached_stdin.rs1use crate::{
2 buffer::GapBuffer,
3 dot::Dot,
4 exec::{addr::Address, Edit},
5};
6use std::{
7 cell::RefCell,
8 io::{stdin, Stdin},
9};
10
11const LINE_BUF_LEN: usize = 100;
13
14#[derive(Debug)]
17pub struct CachedStdin {
18 inner: RefCell<CachedStdinInner>,
19 buf: RefCell<String>,
20 gb: RefCell<GapBuffer>,
21}
22
23#[derive(Debug)]
24struct CachedStdinInner {
25 stdin: Stdin,
26 closed: bool,
27}
28
29impl Default for CachedStdin {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl CachedStdin {
36 pub fn new() -> Self {
38 Self {
39 inner: RefCell::new(CachedStdinInner {
40 stdin: stdin(),
41 closed: false,
42 }),
43 buf: RefCell::new(String::with_capacity(LINE_BUF_LEN)),
44 gb: RefCell::new(GapBuffer::from("")),
45 }
46 }
47
48 fn is_closed(&self) -> bool {
49 self.inner.borrow().closed
50 }
51
52 fn get_char(&self, ix: usize) -> Option<char> {
53 self.gb.borrow().get_char(ix)
54 }
55
56 fn try_read_next_line(&self) {
57 let mut inner = self.inner.borrow_mut();
58 let mut buf = self.buf.borrow_mut();
59 buf.clear();
60
61 match inner.stdin.read_line(&mut buf) {
62 Ok(n) => {
63 let len = self.gb.borrow().len_chars();
64 self.gb.borrow_mut().insert_str(len, &buf);
65 inner.closed = n == 0;
66 }
67 Err(_) => inner.closed = true,
68 };
69 }
70}
71
72impl Address for CachedStdin {
73 fn current_dot(&self) -> Dot {
74 Dot::from_char_indices(0, usize::MAX)
75 }
76
77 fn len_chars(&self) -> usize {
78 self.gb.borrow().len_chars()
79 }
80
81 fn max_iter(&self) -> usize {
82 if self.is_closed() {
83 self.gb.borrow().len_chars()
84 } else {
85 usize::MAX
86 }
87 }
88
89 fn line_to_char(&self, line_idx: usize) -> Option<usize> {
90 let cur_len = self.gb.borrow().len_lines();
91
92 if line_idx > cur_len {
93 for _ in cur_len..=line_idx {
94 self.try_read_next_line();
95 if self.is_closed() {
96 break;
97 }
98 }
99 }
100
101 self.gb.borrow().try_line_to_char(line_idx)
102 }
103
104 fn char_to_line(&self, char_idx: usize) -> Option<usize> {
105 self.gb.borrow().try_char_to_line(char_idx)
106 }
107
108 fn char_to_line_end(&self, char_idx: usize) -> Option<usize> {
109 let gb = self.gb.borrow();
110 let line_idx = gb.try_char_to_line(char_idx)?;
111 match gb.try_line_to_char(line_idx + 1) {
112 None => Some(gb.len_chars() - 1),
113 Some(idx) => Some(idx),
114 }
115 }
116
117 fn char_to_line_start(&self, char_idx: usize) -> Option<usize> {
118 let gb = self.gb.borrow();
119 let line_idx = gb.try_char_to_line(char_idx)?;
120 Some(gb.line_to_char(line_idx))
121 }
122}
123
124impl Edit for CachedStdin {
125 fn insert(&mut self, ix: usize, s: &str) {
126 self.gb.borrow_mut().insert_str(ix, s)
127 }
128
129 fn remove(&mut self, from: usize, to: usize) {
130 self.gb.borrow_mut().remove_range(from, to)
131 }
132}
133
134#[derive(Debug)]
135pub struct CachedStdinIter<'a> {
136 pub(super) inner: &'a CachedStdin,
137 pub(super) from: usize,
138 pub(super) to: usize,
139}
140
141impl Iterator for CachedStdinIter<'_> {
142 type Item = (usize, char);
143
144 fn next(&mut self) -> Option<Self::Item> {
145 if self.from >= self.to {
148 return None;
149 }
150
151 loop {
152 match self.inner.get_char(self.from) {
153 Some(ch) => {
154 let res = (self.from, ch);
155 self.from += 1;
156 return Some(res);
157 }
158 None if self.inner.is_closed() => return None,
159 None => self.inner.try_read_next_line(),
160 }
161 }
162 }
163}