@@ 17,6 17,7 @@ use {
Duration
},
collections::{
+ BTreeMap,
BTreeSet,
BinaryHeap
}
@@ 55,7 56,7 @@ use {
History
},
cache::{
- LineCache,
+ RangeCache,
CharCache
},
trie::{
@@ 88,13 89,13 @@ pub struct EditorView {
click: (Instant, u8),
// rendering
- lines: LineCache<String>,
- spans: LineCache<Vec<StyledIndexedSpan>>,
+ lines: BTreeMap<usize, String>,
+ spans: BTreeMap<usize, Vec<StyledIndexedSpan>>,
highlight_heap: BinaryHeap<LineHighlightState>,
lines_to_highlight: BTreeSet<usize>,
/// Draw this instead of `spans` if a cursor is on the line.
- spans_highlight: LineCache<Vec<StyledIndexedSpan>>,
+ spans_highlight: BTreeMap<usize, Vec<StyledIndexedSpan>>,
/// To draw the empty space after the line.
line_highlight: Style,
/// To borrow a `str` of only spaces for drawing behind the line.
@@ 264,8 265,8 @@ impl Builder {
view_width: 0,
click: (Instant::now(), 0),
- lines: LineCache::new(),
- spans: LineCache::new(),
+ lines: BTreeMap::new(),
+ spans: BTreeMap::new(),
highlight_heap: BinaryHeap::new(),
lines_to_highlight: BTreeSet::new(),
line_highlight: {
@@ 273,7 274,7 @@ impl Builder {
self.highlighting.cursor_line(&mut style);
style
},
- spans_highlight: LineCache::new(),
+ spans_highlight: BTreeMap::new(),
space: CharCache::new(' '),
selections: Vec::new(),
cursors: Vec::new(),
@@ 386,8 387,8 @@ impl View for EditorView {
// Cache the line strings.
for line_idx in line_idc.clone() {
- if let None = self.lines.get(line_idx) {
- self.lines.cache(line_idx,
+ if let None = self.lines.get(&line_idx) {
+ self.lines.insert(line_idx,
// allocate owned string
self.buf.text().line(line_idx).to_string()
);
@@ 397,7 398,7 @@ impl View for EditorView {
{ // Cache the line styles.
let mut current_highlight = None;
for line_idx in line_idc.clone() {
- if let None = self.spans.get(line_idx) {
+ if let None = self.spans.get(&line_idx) {
let mut highlight = current_highlight.take()
.unwrap_or_else(|| {
let (start_line_idx, mut highlight) = self.highlight_heap.peek()
@@ 406,15 407,15 @@ impl View for EditorView {
for line_idx in start_line_idx..line_idx {
highlight.parse(
- self.lines.get(line_idx).expect("line not allocated").as_str()
+ self.lines.get(&line_idx).expect("line not allocated").as_str()
);
}
highlight
});
- let line = self.lines.get(line_idx).expect("line not allocated").as_str();
- self.spans.cache(line_idx,
+ let line = self.lines.get(&line_idx).expect("line not allocated").as_str();
+ self.spans.insert(line_idx,
// highlight syntax
highlight.highlight(line)
);
@@ 465,8 466,8 @@ impl View for EditorView {
// highlight lines
for line_idx in self.lines_to_highlight.iter() {
- if let None = self.spans_highlight.get(*line_idx) {
- let spans = self.spans.get(*line_idx)
+ if let None = self.spans_highlight.get(line_idx) {
+ let spans = self.spans.get(line_idx)
.map(|spans| spans.iter()
.cloned()
.map(|mut span| {
@@ 477,7 478,7 @@ impl View for EditorView {
.collect())
.unwrap_or_else(|| vec![]);
- self.spans_highlight.cache(*line_idx, spans);
+ self.spans_highlight.insert(*line_idx, spans);
}
}
} else {
@@ 540,8 541,8 @@ impl View for EditorView {
let mut style: Style = ColorStyle::primary().into(); // fallback
// find style at span under cursor
- if let Some(spans) = self.spans.get(line_idx) {
- let line = self.lines.get(line_idx).expect("line not cached");
+ if let Some(spans) = self.spans.get(&line_idx) {
+ let line = self.lines.get(&line_idx).expect("line not cached");
let mut x_acc = 0;
for span in spans.iter() {
@@ 606,13 607,13 @@ impl View for EditorView {
* Since line highlighting always affects the whole line,
* we can also do that here before rendering other stuff … */
self.scrollbase.draw(printer, |printer, line_idx| {
- let line = self.lines.get(line_idx).expect("line not allocated in draw()").as_str();
+ let line = self.lines.get(&line_idx).expect("line not allocated in draw()").as_str();
let highlight_line = self.lines_to_highlight.contains(&line_idx);
let spans = if highlight_line {
- self.spans_highlight.get(line_idx).expect("line not highlighted in draw()")
+ self.spans_highlight.get(&line_idx).expect("line not highlighted in draw()")
} else {
- self.spans .get(line_idx).expect("line not styled in draw()")
+ self.spans .get(&line_idx).expect("line not styled in draw()")
};
let mut x = 0;
@@ 662,7 663,7 @@ impl View for EditorView {
// `span`: (x_range, line_idx)
let print_span_text = |printer: &Printer, span: (Range<usize>, usize)| {
let (x_range, line_idx) = span;
- let line = self.lines.get(line_idx)
+ let line = self.lines.get(&line_idx)
.map(|s| s.as_str())
.unwrap_or(" ");
@@ 742,14 743,14 @@ impl View for EditorView {
for event in tx.0.iter() {
self.buf.handle((**event).clone());
}
- self.cur.handle_cur(&self.buf, cursor::CursorEvent::Jump(tx.1.to_vec()));
+ self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
EventResult::Consumed(None)
}
Err(_) => EventResult::Ignored
}
HistoryCmd::Redo => match self.hist.redo() {
Ok(ref tx) => {
- self.cur.handle_cur(&self.buf, cursor::CursorEvent::Jump(tx.1.to_vec()));
+ self.cur.handle_cur(&self.buf, CursorEvent::Jump(tx.1.to_vec()));
for event in tx.0.iter() {
self.buf.handle((**event).clone());
}
@@ 902,9 903,9 @@ impl View for EditorView {
.min(self.buf.text().len_lines().saturating_sub(1))
)
.unwrap();
- self.lines .invalidate_lines_from(first_damage..);
- self.spans .invalidate_lines_from(first_damage..);
- self.spans_highlight.invalidate_lines_from(first_damage..);
+ self.lines .invalidate_from(first_damage..);
+ self.spans .invalidate_from(first_damage..);
+ self.spans_highlight.invalidate_from(first_damage..);
while self.highlight_heap.peek()
.map(|x| x.line_idx >= first_damage)
.unwrap_or(false)
@@ 1,46 1,24 @@
use std::ops::RangeFrom;
use std::collections::BTreeMap;
-pub struct LineCache<T> {
- lines: BTreeMap<usize, T>
+pub trait RangeCache {
+ /// Returns whether the index was cached.
+ fn invalidate(&mut self, idx: usize) -> bool;
+
+ /// Returns whether at least one index was cached.
+ // TODO name invalidate_range() instead with RangeArgument once stable
+ fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool;
}
-impl<T> LineCache<T> {
- pub fn new() -> Self {
- Self {
- lines: BTreeMap::new()
- }
- }
-
- #[allow(dead_code)]
- pub fn len(&self) -> usize {
- self.lines.len()
+impl<T> RangeCache for BTreeMap<usize, T> {
+ fn invalidate(&mut self, idx: usize) -> bool {
+ self.remove(&idx).is_some()
}
- #[allow(dead_code)]
- pub fn is_empty(&self) -> bool {
- self.lines.len() == 0
- }
-
- pub fn cache(&mut self, line_idx: usize, line: T) {
- self.lines.insert(line_idx, line);
- }
-
- pub fn get(&self, line_idx: usize) -> Option<&T> {
- self.lines.get(&line_idx)
- }
-
- /// Returns whether the line was cached.
- pub fn invalidate_line(&mut self, line_idx: usize) -> bool {
- self.lines.remove(&line_idx).is_some()
- }
-
- /// Returns whether at least one line was cached.
- // TODO name invalidate_lines() instead with RangeArgument once stable
- pub fn invalidate_lines_from(&mut self, line_idc: RangeFrom<usize>) -> bool {
+ fn invalidate_from(&mut self, idc: RangeFrom<usize>) -> bool {
let mut changed = false;
- for line_idx in line_idc.start..=*self.lines.keys().max().unwrap_or(&line_idc.start) {
- changed |= self.invalidate_line(line_idx);
+ for line_idx in idc.start..=*self.keys().max().unwrap_or(&idc.start) {
+ changed |= self.invalidate(line_idx);
}
changed
}