1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
//! The text storage structures

use std::cell::{Cell, RefCell};
use std::rc::Rc;

use std::fmt::Debug;

use crate::{Result, EdError};

use crate::history::Snapshot;

pub mod iters;
use iters::*;

/// Text data and metadata for a single line of text
///
/// Note the [`Rc<Cell>`]s placed around internal variables we wish to share
/// between points in history while allowing modification, both in that Rc and
/// without [`&mut`] access to the line. This is to let [`History`] enforce use
/// of [`History::current_mut`] to edit the text, while allowing changes to
/// other data using [`History::current`] (which doesn't create undo snapshots).

// We don't derive Clone, since it usually isn't what library users expect.
// Instead we write a manual clone for Buffer, so History can do its thing.
#[derive(Debug, PartialEq, Eq)]
pub struct Line {
  // Tracks if the line has been matched in a 'g' or similar command in a shared
  // instance throughout the line's lifetime (to save on allocations)
  // (A change to BitVec would be good, TODO.)
  //
  // To support nested invocations we have a vector, where index 0 is the
  // outermost invocation and nested invocation have incrementing indices.
  //
  // Note that this has one main gotchas that must be handled where this is
  // used:
  //   There mustn't be any old data on an index when an invocation uses it,
  //   not even outside the selection acted upon.
  //   (Handled by src/cmd/regex_commands.rs : mark_matching, which resizes
  //   Vec to the correct length and overwrites the soon to be relevant index
  //   across all lines. Since mark_matching is called for each nested
  //   invocation this should be run on every relevant index before it's used.)
  //
  // Also note that this will be empty on newly created lines, but get_matching
  // handles this by defaulting to false and mark_matching explicitly resizes to
  // the size it needs.
  pub(crate) matched: Rc<RefCell<Vec<bool>>>,
  /// The tag set on the given line
  ///
  /// It is stored in an Rc<Cell> to have a shared overwriteable tag for all
  /// historical instances of the line.
  pub tag: Rc<Cell<char>>,
  /// The text data for a given line
  ///
  /// It is stored in an Rc as a CoW mechanism, since it allows a shared
  /// allocation for historical states with the same text data while
  /// preventing modification of that shared state. To modify, create a new
  /// String with the data you want and put it in a new Rc in this field.
  pub text: Rc<String>,
}
impl Line {
  pub (crate) fn new<T: Into<String>>(text: T, tag: char) -> Self {
    Self{
      matched: Rc::new(RefCell::new(Vec::new())),
      tag: Rc::new(Cell::new(tag)),
      text: Rc::new(text.into()),
    }
  }
}
impl Snapshot for Line {
  fn create_snapshot(&self) -> Self {
    Line{
      tag: self.tag.clone(),
      matched: self.matched.clone(),
      text: self.text.clone(),
    }
  }
}

/// A fully public version of the [`Line`] struct above
///
/// Intended for API interaction, since it cannot represent the metadata in Line
/// which could cause trouble if invalid.
///
/// [`From`] is implemented both ways, to make it easy to convert into and from
/// [`Line`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PubLine {
  /// The tag set on the line
  ///
  /// See [`Line.tag`], but note that we disconnect the shared tag state through
  /// history by converting into this.
  pub tag: char,
  /// The text data for the line
  ///
  /// See [`Line.text`].
  pub text: Rc<String>,
}

/// Declare a type over Vec<PubLine>, to be able to add some utility methods
///
/// Needed due to orphan rules.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Clipboard {
  inner: Vec<PubLine>,
}
impl Clipboard {
  pub fn new() -> Self {
    Self{ inner: Vec::new() }
  }
}

impl std::ops::Deref for Clipboard {
  type Target = Vec<PubLine>;
  fn deref(&self) -> &Self::Target {
    &self.inner
  }
}
impl std::ops::DerefMut for Clipboard {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.inner
  }
}
impl From<&str> for PubLine {
  fn from(l: &str) -> Self {
    Self{tag: '\0', text: Rc::new(l.to_owned())}
  }
}
impl From<(char, &str)> for PubLine {
  fn from(l: (char, &str)) -> Self {
    Self{tag: l.0, text: Rc::new(l.1.to_owned())}
  }
}
impl From<&Line> for PubLine {
  fn from(l: &Line) -> Self {
    Self{tag: l.tag.get(), text: l.text.clone()}
  }
}
impl<'a, T> From<&'a [T]> for Clipboard
where
  &'a T: Into<PubLine>,
{
  fn from(l: &'a [T]) -> Self {
    let mut tmp = Vec::new();
    for line in l {
      tmp.push(line.into());
    }
    Self{
      inner: tmp,
    }
  }
}
impl From<&PubLine> for Line {
  fn from(l: &PubLine) -> Self {
    Self{
      tag: Rc::new(Cell::new(l.tag)),
      text: l.text.clone(),
      matched: Rc::new(RefCell::new(Vec::new())),
    }
  }
}
impl From<&str> for Line {
  fn from(l: &str) -> Self {
    Self{
      tag: Rc::new(Cell::new('\0')),
      text: Rc::new(l.to_owned()),
      matched: Rc::new(RefCell::new(Vec::new())),
    }
  }
}
impl Into<Vec<Line>> for &Clipboard {
  fn into(self) -> Vec<Line> {
    let mut tmp = Vec::new();
    for line in &self.inner {
      tmp.push(line.into());
    }
    tmp
  }
}

/// Declare a type over Vec<Line>, to be able to add some utility methods
#[derive(Debug, PartialEq)]
pub struct Buffer {
  pub inner: Vec<Line>,
}
impl std::ops::Deref for Buffer {
  type Target = Vec<Line>;
  fn deref(&self) -> &Self::Target {
    &self.inner
  }
}
impl std::ops::DerefMut for Buffer {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.inner
  }
}
// Manually implement a special clone for History
impl Snapshot for Buffer {
  fn create_snapshot(&self) -> Self {
    let mut new_inner = Vec::new();
    for line in self.inner.iter() {
      new_inner.push(line.create_snapshot());
    }
    Self{ inner: new_inner }
  }
}
impl Default for Buffer {
  fn default() -> Self{ Self{ inner: Vec::new() } }
}
impl Buffer {
  /// Verify that an index is valid to operate on
  ///
  /// Doesn't mean that there exists a line at the index.
  /// Note the related [`Ed::verify_line`] and [`Ed::verify_selection`].
  pub fn verify_index(
    &self,
    index: usize,
  ) -> Result<()> {
    let buffer_len = self.len();
    if index > buffer_len {
      Err(EdError::IndexTooBig{index, buffer_len})
    } else {
      Ok(())
    }
  }
  /// Verfy that a line exists at given index
  ///
  /// Note the related [`Ed::verify_index`] and  [`Ed::verify_selection`].
  pub fn verify_line(
    &self,
    index: usize,
  ) -> Result<()> {
    if index == 0 { Err(EdError::Line0Invalid) }
    else { self.verify_index(index) }
  }
  /// Verify that all the lines in selection exist
  ///
  /// Note the related [`Ed::verify_index`] [`Ed::verify_line`].
  pub fn verify_selection(
    &self,
    selection: (usize, usize),
  ) -> Result<()> {
    self.verify_line(selection.0)?;
    self.verify_line(selection.1)?;
    if selection.0 > selection.1 {
      Err(EdError::SelectionEmpty(selection))
    } else {
      Ok(())
    }
  }

  /// Get the lines in the given selection
  ///
  /// Returns an iterator over &str to save on allocations.
  pub fn get_lines(
    &self,
    selection: (usize, usize),
  ) -> Result<LinesIter> {
    self.verify_selection(selection)?;
    Ok(self[selection.0 - 1 .. selection.1]
      .iter()
      .map(get_lines_helper as fn(&Line) -> &str)
      .into()
    )
  }
  /// Get the lines in the given selection with their tags
  ///
  /// Returns an iterator of (char, &str) to save on allocations.
  pub fn get_tagged_lines(
    &self,
    selection: (usize, usize),
  ) -> Result<TaggedLinesIter> {
    self.verify_selection(selection)?;
    Ok(self[selection.0 - 1 .. selection.1]
      .iter()
      .map(get_tagged_lines_helper as fn(&Line) -> (char, &str))
      .into()
    )
  }
}

// These functions need to be declared, because the map iterator over a closure
// has an un-name-able type (and we don't wish to use generics towards IO for 
// performance and being able to make dyn IO).
fn get_lines_helper(line: &Line) -> &str {
  &line.text[..]
}
fn get_tagged_lines_helper(line: &Line) -> (char, &str) {
  (line.tag.get(), &line.text[..])
}