perf: use Vec<T>
instead of HashMap<usize, T>
This commit is contained in:
parent
22f9571687
commit
a8097f1cdc
2 changed files with 51 additions and 24 deletions
|
@ -31,7 +31,7 @@ use helix_view::{
|
|||
keyboard::{KeyCode, KeyModifiers},
|
||||
Document, Editor, Theme, View,
|
||||
};
|
||||
use std::{collections::HashMap, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc};
|
||||
use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc};
|
||||
|
||||
use tui::{buffer::Buffer as Surface, text::Span};
|
||||
|
||||
|
@ -214,37 +214,44 @@ impl EditorView {
|
|||
{
|
||||
decorations.add_decoration(InlineBlame::new(
|
||||
theme,
|
||||
HashMap::from([(cursor_line_idx, line_blame)]),
|
||||
text_decorations::blame::LineBlame::OneLine((cursor_line_idx, line_blame)),
|
||||
));
|
||||
};
|
||||
}
|
||||
} else if config.inline_blame.behaviour == InlineBlameBehaviour::AllLines {
|
||||
let text = doc.text();
|
||||
let len_lines = text.len_lines();
|
||||
let text_line_count = text.len_lines();
|
||||
let view_height = view.inner_height();
|
||||
let first_visible_line =
|
||||
text.char_to_line(doc.view_offset(view.id).anchor.min(text.len_chars()));
|
||||
let first_line = first_visible_line.saturating_sub(view_height);
|
||||
let last_line = first_visible_line
|
||||
.saturating_add(view_height.saturating_mul(2))
|
||||
.min(len_lines);
|
||||
.min(text_line_count);
|
||||
|
||||
let mut blame_lines = vec![None; text_line_count];
|
||||
|
||||
// Compute ~3 times the current view height of inline blame, that way some scrolling
|
||||
// will not show half the view with inline blame and half without while still being faster
|
||||
// than rendering inline blame for the full file.
|
||||
let blame_for_all_lines = (first_line..last_line)
|
||||
.filter_map(|line_idx| {
|
||||
// do not render inline blame for empty lines to reduce visual noise
|
||||
if text.line(line_idx) != doc.line_ending.as_str() {
|
||||
doc.line_blame(line_idx as u32, &config.inline_blame.format)
|
||||
.ok()
|
||||
.map(|blame| (line_idx, blame))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
decorations.add_decoration(InlineBlame::new(theme, blame_for_all_lines));
|
||||
let blame_for_all_lines = (first_line..last_line).filter_map(|line_idx| {
|
||||
// do not render inline blame for empty lines to reduce visual noise
|
||||
if text.line(line_idx) != doc.line_ending.as_str() {
|
||||
doc.line_blame(line_idx as u32, &config.inline_blame.format)
|
||||
.ok()
|
||||
.map(|blame| (line_idx, blame))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
for (line_idx, blame) in blame_for_all_lines {
|
||||
blame_lines[line_idx] = Some(blame);
|
||||
}
|
||||
decorations.add_decoration(InlineBlame::new(
|
||||
theme,
|
||||
text_decorations::blame::LineBlame::ManyLines(blame_lines),
|
||||
));
|
||||
}
|
||||
|
||||
render_document(
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use helix_core::Position;
|
||||
|
||||
use helix_view::theme::Style;
|
||||
|
@ -8,13 +6,21 @@ use helix_view::Theme;
|
|||
use crate::ui::document::{LinePos, TextRenderer};
|
||||
use crate::ui::text_decorations::Decoration;
|
||||
|
||||
pub enum LineBlame {
|
||||
OneLine((usize, String)),
|
||||
// Optimization: Use `Vec<T>` insted of `HashMap<usize, T>`
|
||||
// because we know that the amount of lines visible in the viewport X3 cannot be a very large number,
|
||||
// most likely up to a few hundred. In the absolute extreme case, maybe 5,000.
|
||||
ManyLines(Vec<Option<String>>),
|
||||
}
|
||||
|
||||
pub struct InlineBlame {
|
||||
lines: HashMap<usize, String>,
|
||||
lines: LineBlame,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl InlineBlame {
|
||||
pub fn new(theme: &Theme, lines: HashMap<usize, String>) -> Self {
|
||||
pub fn new(theme: &Theme, lines: LineBlame) -> Self {
|
||||
InlineBlame {
|
||||
style: theme.get("ui.virtual.inline-blame"),
|
||||
lines,
|
||||
|
@ -29,9 +35,23 @@ impl Decoration for InlineBlame {
|
|||
pos: LinePos,
|
||||
virt_off: Position,
|
||||
) -> Position {
|
||||
let Some(blame) = self.lines.get(&pos.doc_line) else {
|
||||
// do not draw inline blame for lines that have no content in them
|
||||
return Position::new(0, 0);
|
||||
let blame = match &self.lines {
|
||||
LineBlame::OneLine((line, blame)) => {
|
||||
if line != &pos.doc_line {
|
||||
// do not draw inline blame for lines that have no content in them
|
||||
blame
|
||||
} else {
|
||||
return Position::new(0, 0);
|
||||
}
|
||||
}
|
||||
LineBlame::ManyLines(lines) => {
|
||||
if let Some(Some(blame)) = lines.get(pos.doc_line) {
|
||||
blame
|
||||
} else {
|
||||
// do not draw inline blame for lines that have no content in them
|
||||
return Position::new(0, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// where the line in the document ends
|
||||
|
|
Loading…
Add table
Reference in a new issue