Skip to content

Commit a8097f1

Browse files
committed
perf: use Vec<T> instead of HashMap<usize, T>
1 parent 22f9571 commit a8097f1

File tree

2 files changed

+51
-24
lines changed

2 files changed

+51
-24
lines changed

helix-term/src/ui/editor.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use helix_view::{
3131
keyboard::{KeyCode, KeyModifiers},
3232
Document, Editor, Theme, View,
3333
};
34-
use std::{collections::HashMap, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc};
34+
use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc};
3535

3636
use tui::{buffer::Buffer as Surface, text::Span};
3737

@@ -214,37 +214,44 @@ impl EditorView {
214214
{
215215
decorations.add_decoration(InlineBlame::new(
216216
theme,
217-
HashMap::from([(cursor_line_idx, line_blame)]),
217+
text_decorations::blame::LineBlame::OneLine((cursor_line_idx, line_blame)),
218218
));
219219
};
220220
}
221221
} else if config.inline_blame.behaviour == InlineBlameBehaviour::AllLines {
222222
let text = doc.text();
223-
let len_lines = text.len_lines();
223+
let text_line_count = text.len_lines();
224224
let view_height = view.inner_height();
225225
let first_visible_line =
226226
text.char_to_line(doc.view_offset(view.id).anchor.min(text.len_chars()));
227227
let first_line = first_visible_line.saturating_sub(view_height);
228228
let last_line = first_visible_line
229229
.saturating_add(view_height.saturating_mul(2))
230-
.min(len_lines);
230+
.min(text_line_count);
231+
232+
let mut blame_lines = vec![None; text_line_count];
231233

232234
// Compute ~3 times the current view height of inline blame, that way some scrolling
233235
// will not show half the view with inline blame and half without while still being faster
234236
// than rendering inline blame for the full file.
235-
let blame_for_all_lines = (first_line..last_line)
236-
.filter_map(|line_idx| {
237-
// do not render inline blame for empty lines to reduce visual noise
238-
if text.line(line_idx) != doc.line_ending.as_str() {
239-
doc.line_blame(line_idx as u32, &config.inline_blame.format)
240-
.ok()
241-
.map(|blame| (line_idx, blame))
242-
} else {
243-
None
244-
}
245-
})
246-
.collect();
247-
decorations.add_decoration(InlineBlame::new(theme, blame_for_all_lines));
237+
let blame_for_all_lines = (first_line..last_line).filter_map(|line_idx| {
238+
// do not render inline blame for empty lines to reduce visual noise
239+
if text.line(line_idx) != doc.line_ending.as_str() {
240+
doc.line_blame(line_idx as u32, &config.inline_blame.format)
241+
.ok()
242+
.map(|blame| (line_idx, blame))
243+
} else {
244+
None
245+
}
246+
});
247+
248+
for (line_idx, blame) in blame_for_all_lines {
249+
blame_lines[line_idx] = Some(blame);
250+
}
251+
decorations.add_decoration(InlineBlame::new(
252+
theme,
253+
text_decorations::blame::LineBlame::ManyLines(blame_lines),
254+
));
248255
}
249256

250257
render_document(

helix-term/src/ui/text_decorations/blame.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::collections::HashMap;
2-
31
use helix_core::Position;
42

53
use helix_view::theme::Style;
@@ -8,13 +6,21 @@ use helix_view::Theme;
86
use crate::ui::document::{LinePos, TextRenderer};
97
use crate::ui::text_decorations::Decoration;
108

9+
pub enum LineBlame {
10+
OneLine((usize, String)),
11+
// Optimization: Use `Vec<T>` insted of `HashMap<usize, T>`
12+
// because we know that the amount of lines visible in the viewport X3 cannot be a very large number,
13+
// most likely up to a few hundred. In the absolute extreme case, maybe 5,000.
14+
ManyLines(Vec<Option<String>>),
15+
}
16+
1117
pub struct InlineBlame {
12-
lines: HashMap<usize, String>,
18+
lines: LineBlame,
1319
style: Style,
1420
}
1521

1622
impl InlineBlame {
17-
pub fn new(theme: &Theme, lines: HashMap<usize, String>) -> Self {
23+
pub fn new(theme: &Theme, lines: LineBlame) -> Self {
1824
InlineBlame {
1925
style: theme.get("ui.virtual.inline-blame"),
2026
lines,
@@ -29,9 +35,23 @@ impl Decoration for InlineBlame {
2935
pos: LinePos,
3036
virt_off: Position,
3137
) -> Position {
32-
let Some(blame) = self.lines.get(&pos.doc_line) else {
33-
// do not draw inline blame for lines that have no content in them
34-
return Position::new(0, 0);
38+
let blame = match &self.lines {
39+
LineBlame::OneLine((line, blame)) => {
40+
if line != &pos.doc_line {
41+
// do not draw inline blame for lines that have no content in them
42+
blame
43+
} else {
44+
return Position::new(0, 0);
45+
}
46+
}
47+
LineBlame::ManyLines(lines) => {
48+
if let Some(Some(blame)) = lines.get(pos.doc_line) {
49+
blame
50+
} else {
51+
// do not draw inline blame for lines that have no content in them
52+
return Position::new(0, 0);
53+
}
54+
}
3555
};
3656

3757
// where the line in the document ends

0 commit comments

Comments
 (0)