@@ -44,124 +44,6 @@ impl Default for EditorView {
4444 }
4545}
4646
47−struct Merge<I> {
48− iter: I,
49− spans: Box<dyn Iterator<Item = (usize, std::ops::Range<usize>)>>,
50−
51− next_event: Option<HighlightEvent>,
52− next_span: Option<(usize, std::ops::Range<usize>)>,
53−
54− queue: Vec<HighlightEvent>,
55−}
56−
57−fn merge<I: Iterator<Item = HighlightEvent>>(
58− iter: I,
59− spans: Vec<(usize, std::ops::Range<usize>)>,
60−) -> impl Iterator<Item = HighlightEvent> {
61− let spans = Box::new(spans.into_iter());
62− let mut merge = Merge {
63− iter,
64− spans,
65− next_event: None,
66− next_span: None,
67− queue: Vec::new(),
68− };
69− merge.next_event = merge.iter.next();
70− merge.next_span = merge.spans.next();
71− merge
72−}
73−
74−impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
75− type Item = HighlightEvent;
76− fn next(&mut self) -> Option<Self::Item> {
77− use HighlightEvent::*;
78− if let Some(event) = self.queue.pop() {
79− return Some(event);
80− }
81−
82− loop {
83− match (self.next_event, &self.next_span) {
84− // this happens when range is partially or fully offscreen
85− (Some(Source { start, end }), Some((span, range))) if start > range.start => {
86− if start > range.end {
87− self.next_span = self.spans.next();
88− } else {
89− self.next_span = Some((*span, start..range.end));
90− };
91− }
92− _ => break,
93− }
94− }
95−
96− match (self.next_event, &self.next_span) {
97− (Some(HighlightStart(i)), _) => {
98− self.next_event = self.iter.next();
99− Some(HighlightStart(i))
100− }
101− (Some(HighlightEnd), _) => {
102− self.next_event = self.iter.next();
103− Some(HighlightEnd)
104− }
105− (Some(Source { start, end }), Some((span, range))) if start < range.start => {
106− let intersect = range.start.min(end);
107− let event = Source {
108− start,
109− end: intersect,
110− };
111−
112− if end == intersect {
113− // the event is complete
114− self.next_event = self.iter.next();
115− } else {
116− // subslice the event
117− self.next_event = Some(Source {
118− start: intersect,
119− end,
120− });
121− };
122−
123− Some(event)
124− }
125− (Some(Source { start, end }), Some((span, range))) if start == range.start => {
126− let intersect = range.end.min(end);
127− let event = HighlightStart(Highlight(*span));
128−
129− // enqueue in reverse order
130− self.queue.push(HighlightEnd);
131− self.queue.push(Source {
132− start,
133− end: intersect,
134− });
135−
136− if end == intersect {
137− // the event is complete
138− self.next_event = self.iter.next();
139− } else {
140− // subslice the event
141− self.next_event = Some(Source {
142− start: intersect,
143− end,
144− });
145− };
146−
147− if intersect == range.end {
148− self.next_span = self.spans.next();
149− } else {
150− self.next_span = Some((*span, intersect..range.end));
151− }
152−
153− Some(event)
154− }
155− (Some(event), None) => {
156− self.next_event = self.iter.next();
157− Some(event)
158− }
159− (None, None) => None,
160− e => unreachable!("{:?}", e),
161− }
162− }
163−}
164−
16547impl EditorView {
16648 pub fn new(keymaps: Keymaps) -> Self {
16749 Self {
@@ -290,27 +172,16 @@ impl EditorView {
290172 .find_scope_index("ui.selection.primary")
291173 .unwrap_or(selection_scope);
292174
293− // TODO: primary + insert mode patching
294− // let primary_cursor_style = theme
295− // .try_get("ui.cursor.primary")
296− // .map(|style| {
297− // if mode != Mode::Normal {
298− // // we want to make sure that the insert and select highlights
299− // // also affect the primary cursor if set
300− // style.patch(cursor_style)
301− // } else {
302− // style
303− // }
304− // })
305− // .unwrap_or(cursor_style);
306−
307− let primary_cursor_scope = theme
308− .find_scope_index("ui.cursor.primary")
309− .unwrap_or(cursor_scope);
310−
311175 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
312176 // inject selections as highlight scopes
313− let mut spans_: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
177+ let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
178+
179+ // TODO: primary + insert mode patching:
180+ // (ui.cursor.primary).patch(mode).unwrap_or(cursor)
181+
182+ let primary_cursor_scope = theme
183+ .find_scope_index("ui.cursor.primary")
184+ .unwrap_or(cursor_scope);
314185
315186 for (i, range) in selections.iter().enumerate() {
316187 let (cursor_scope, selection_scope) = if i == primary_idx {
@@ -320,39 +191,40 @@ impl EditorView {
320191 };
321192
322193 if range.head == range.anchor {
323− spans_.push((cursor_scope, range.head..range.head + 1));
194+ spans.push((cursor_scope, range.head..range.head + 1));
324195 continue;
325196 }
326197
327198 let reverse = range.head < range.anchor;
328199
329200 if reverse {
330− spans_.push((cursor_scope, range.head..range.head + 1));
331− spans_.push((selection_scope, range.head + 1..range.anchor + 1));
201+ spans.push((cursor_scope, range.head..range.head + 1));
202+ spans.push((selection_scope, range.head + 1..range.anchor + 1));
332203 } else {
333− spans_.push((selection_scope, range.anchor..range.head));
334− spans_.push((cursor_scope, range.head..range.head + 1));
204+ spans.push((selection_scope, range.anchor..range.head));
205+ spans.push((cursor_scope, range.head..range.head + 1));
335206 }
336207 }
337208
338− Box::new(merge(highlights, spans_))
209+ Box::new(syntax::merge(highlights, spans))
339210 } else {
340211 Box::new(highlights)
341212 };
342213
343214 // diagnostic injection
344215 let diagnostic_scope = theme.find_scope_index("diagnostic").unwrap_or(cursor_scope);
345− let spans_ = doc
346− .diagnostics()
347− .iter()
348− .map(|diagnostic| {
349− (
350− diagnostic_scope,
351− diagnostic.range.start..diagnostic.range.end,
352− )
353− })
354− .collect();
355− let highlights = Box::new(merge(highlights, spans_));
216+ let highlights = Box::new(syntax::merge(
217+ highlights,
218+ doc.diagnostics()
219+ .iter()
220+ .map(|diagnostic| {
221+ (
222+ diagnostic_scope,
223+ diagnostic.range.start..diagnostic.range.end,
224+ )
225+ })
226+ .collect(),
227+ ));
356228
357229 'outer: for event in highlights {
358230 match event {
@@ -403,16 +275,20 @@ impl EditorView {
403275 break 'outer;
404276 }
405277 } else if grapheme == "\t" {
406− if !out_of_bounds {
407− // we still want to render an empty cell with the style
408− surface.set_string(
409− viewport.x + visual_x - view.first_col as u16,
410− viewport.y + line,
411− " ".repeat(tab_width),
412− style,
413− );
278+ if out_of_bounds {
279+ // if we're offscreen just keep going until we hit a new line
280+ visual_x = visual_x.saturating_add(tab_width as u16);
281+ continue;
414282 }
415283
284+ // we still want to render an empty cell with the style
285+ surface.set_string(
286+ viewport.x + visual_x - view.first_col as u16,
287+ viewport.y + line,
288+ " ".repeat(tab_width),
289+ style,
290+ );
291+
416292 visual_x = visual_x.saturating_add(tab_width as u16);
417293 } else {
418294 // Cow will prevent allocations if span contained in a single slice