helix
helix copied to clipboard
feat: Inline Git Blame
This PR adds Inline Git Blame.
While moving around in the editor, virtual text will appear to the right showing the latest commit information for this line. Showcase:
- The git blame output is very customizable. See below.
- There is a keybinding
space + Bto show blame for the current line in the status line. Useful if you don't haveinline-blame.enableand just want to blame a single line
Closes #3035
Documentation
[editor.inline-blame] Section
Inline blame is virtual text that appears at the end of a line, displaying information about the most recent commit that affected this line.
| Key | Description | Default |
|---|---|---|
show |
Choose when to show inline blame | "never" |
auto-fetch |
Choose when inline blame should be computed | false |
format |
The format in which to show the inline blame | "{author}, {time-ago} • {title} • {commit}" |
show can be one of the following:
"all-lines": Inline blame is on every line."cursor-line": Inline blame is only on the line of the primary cursor."hidden": Inline blame is hidden.
Inline blame will only show if the blame for the file has already been fetched.
The auto-fetch key determines under which circumstances the blame is fetched, and can be one of the following:
-
false: Blame for the file is fetched only when explicitly requested, such as when usingspace + Bto blame the line of the cursor. There may be a little delay when loading the blame.When opening new files, even with
showset to"all-lines"or"cursor-line", the inline blame won't show. It needs to be fetched first in order to become available, which can be triggered manually withspace + B. -
true: Blame for the file is fetched in the background.This will have zero effect on performance of the Editor, but will use a little bit extra resources.
Directly requesting the blame with
space + Bwill be instant. Inline blame will show as soon as the blame is available when loading new files.
Set a format string for format to customize the blame message displayed. Variables are text placeholders wrapped in curly braces: {variable}.
The following variables are available:
author: The author of the commitdate: When the commit was madetime-ago: How long ago the commit was madetitle: The title of the commitbody: The body of the commitcommit: The short hex SHA1 hash of the commitemail: The email of the author of the commit
Notes for the reviewer
helix-term/src/handlers/blame.rs: I created a newBlameHandlerthat requests that a document'sblamefield is updated. This field has the information on which line numbers represent a specific commithelix-term/src/ui/text_decrations/blame.rs: This module hosts aDecorationimpl that is responsible for drawing a string (the blame output) at the end of a given linehelix-vcs/src/git/blame.rs: Holds theFileBlamestruct that contains the logic on how blame is retrieved for a file and a specific line in the document, as well as how this blame is formatted into a string.
Run this PR using --release mode otherwise you may run into a panic caused by a failing debug_assert! in gix_blame. This was tested to not have any user impact. The issue for this is known: https://github.com/GitoxideLabs/gitoxide/issues/1847
that's really neat! good job :3
Awesome work, I've been wanting this for a long time, and tried looking into it two weeks ago, but my rust skills just weren't up for it!
I wonder if opening the repo is the slow step here, which could mean that the following isn't necessary, see my comment below.
Could it would make sense to get the blame for the whole file at once instead of doing it on-demand for every line? That would be much faster, as you could just look up the stored info of what the blame is for a given line. But then we would ideally need to keep count of added/deleted lines in order to "keep count" when querying for the currently selected line.
The current behavior of this PR is basically that though - if I type something on a new line, the blame mentions the previous author, not me/"Not comitted yet" (not even after save, which is interesting, but beside my point) and the count is off, I think.
I notice that the blame info is computed on moving left and right. That isn't necessary.
Stuff like not updating when moving left and right, or get the diff for the files are definitely optimizations we can look into
But the biggest one is figuring out how to compute the blame off the main thread. Even if you compute it just once per file, it can take 10 seconds for that to happen and the UI will be frozen in that time which isn't acceptable
if I type something on a new line, the blame mentions the previous author, not me/"Not comitted yet"
Yeah this shouldn't be difficult to fix, once I figure out how to stop the freezes I'll also implement this
Hey this looks great thank you ! Would it be possible to map it on a key press to show ? We'd avoid performing the computation every time the cursor change line, and it would reduced the visual pollution
Hey this looks great thank you ! Would it be possible to map it on a key press to show ? We'd avoid performing the computation every time the cursor change line, and it would reduced the visual pollution
Yes, that is possible to do however the UI would still freeze for e.g. 10 seconds which isn't really good
edit: this message doesn't apply anymore, the problem was fixed. I implemented the keybinding to get the git blame for the current line
YES! I finally figured it out. Now we're not doing the git blame on the main thread anymore :)
The solution is basically that we have a worker and we check it every 0.05 seconds if its done. If not, then try again later. If it is, then get its result.
The reason why this works now is that I am not doing any computation while having a &mut Editor. All work is done when I don't have it
Hey this looks great thank you ! Would it be possible to map it on a key press to show ? We'd avoid performing the computation every time the cursor change line, and it would reduced the visual pollution
I think having a default keybinding to trigger this once is a good idea. Will add that to the TODO
edit: implemented
It looks like this with Inlay Hints, and end of line diagnostics
Update:
- Now the PR takes uncommitted lines into account.
- Added several tests.
- You can now customize the inline git blame using a string with variables.
- Added a static command
line_blamebound for key<space>B. This shows the blame for the current line using your config.
Customizing the inline git blame
[editor.version-control] Section
| Key | Description | Default |
|---|---|---|
inline-blame |
Show git blame output for the current line | false |
inline-blame-format |
The format in which to show the inline blame | "{author}, {date} • {message} • {commit}" |
For inline-blame-format, you can use specific variables like so: {variable}.
These are the available variables:
author: The author of the commitdate: When the commit was mademessage: The message of the commit, excluding the bodybody: The body of the commitcommit: The short hex SHA1 hash of the commitemail: The email of the author of the commit
Any of the variables can potentially be empty. In this case, the content before the variable will not be included in the string. If the variable is at the beginning of the string, the content after the variable will not be included.
Some examples, using the default value inline-blame-format value:
- If
authoris empty:"{date} • {message} • {commit}" - If
dateis empty:"{author} • {message} • {commit}" - If
messageis empty:"{author}, {date} • {commit}" - If
commitis empty:"{author}, {date} • {message}" - If
dateandmessageis empty:"{author} • {commit}" - If
authorandmessageis empty:"{date} • {commit}"
Tests
side note: For the tests, probably wrote my most complicated declarative macro ever, but at least we can have easily readable test syntax for git blame:
Test Syntax for Git Blame
#[test]
pub fn blamed_lines() {
assert_line_blame_progress! {
1 =>
"fn main() {" 1,
"" 1,
"}" 1;
// modifying a line works
2 =>
"fn main() {" 1,
" one" 2,
"}" 1;
// inserting a line works
3 =>
"fn main() {" 1,
" one" 2,
" two" 3,
"}" 1;
// deleting a line works
4 =>
"fn main() {" 1,
" two" 3,
"}" 1;
// when a line is inserted in-between the blame order is preserved
5 no_commit =>
"fn main() {" 1,
" hello world" insert,
" two" 3,
"}" 1;
// Having a bunch of random lines interspersed should not change which lines
// have blame for which commits
6 no_commit =>
" six" insert,
" three" insert,
"fn main() {" 1,
" five" insert,
" four" insert,
" two" 3,
" five" insert,
" four" insert,
"}" 1,
" five" insert,
" four" insert;
};
}
Would it be possible to open the git blame into a scratch buffer with git diff language style applied?
Would it be possible to open the git blame into a scratch buffer with git diff language style applied?
it should be doable, but it would be out of scope for this PR. Something like Lazygit would be more suited for seeing the git blame for the entire file
I think the following could be desirable, but don't worry if you feel it is out of scope:
- yank the blame commit
- yank the formatted blame string
- yank the blame commit url (this is harder, and can be repo-provider-dependent. I wrote a bash script last week for this, see my comment here and bash script here.
- if getting the url is possible, add an option for adding a link to the blame formatted output.
- maaaybe
open-blame-urlthat directly opens in the browser. Not sure if there is any precedent in the helix project for opening urls programmatically (e.g.xdg-open).
I think the following could be desirable, but don't worry if you feel it is out of scope:
* yank the blame commit * yank the formatted blame string * yank the blame commit url (this is harder, and can be repo-provider-dependent. I wrote a bash script last week for this, see my comment [here](https://github.com/helix-editor/helix/discussions/6421#discussioncomment-12502299) and [bash script here](https://gist.github.com/thomasaarholt/2659407306e83edde4262a398aaf9f43#file-blame-L125). * if getting the url is possible, add an option for adding a link to the blame formatted output. * maaaybe `open-blame-url` that directly opens in the browser. Not sure if there is any precedent in the helix project for opening urls programmatically (e.g. `xdg-open`).
for 5., there is gf which can open links iirc so Helix can definitely do that
That being said, these items would be good to add but I don't want to put everything into 1 PR as that just means it could take a very long time to get reviewed. I would rather just have the core functionality for now and then make a new PR to add the niceties
I got this panic when using the latest commit, on doing :log-open and moving the cursor one line down:
❯ hx .
thread 'main' panicked at helix-term/src/handlers/blame.rs:96:39:
called `Option::unwrap()` on a `None` value
stack backtrace:
0: 0x5610edff724b - std::backtrace_rs::backtrace::libunwind::trace::hbee8a7973eeb6c93
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/../../backtrace/src/backtrace/libunwind.rs:104:5
1: 0x5610edff724b - std::backtrace_rs::backtrace::trace_unsynchronized::hc8ac75eea3aa6899
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x5610edff724b - std::sys_common::backtrace::_print_fmt::hc7f3e3b5298b1083
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:68:5
3: 0x5610edff724b - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hbb235daedd7c6190
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:44:22
4: 0x5610ed0d95a0 - core::fmt::rt::Argument::fmt::h76c38a80d925a410
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/fmt/rt.rs:142:9
5: 0x5610ed0d95a0 - core::fmt::write::h3ed6aeaa977c8e45
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/fmt/mod.rs:1120:17
6: 0x5610edff2fd3 - std::io::Write::write_fmt::h78b18af5775fedb5
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/io/mod.rs:1810:15
7: 0x5610edff6fe4 - std::sys_common::backtrace::_print::h5d645a07e0fcfdbb
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:47:5
8: 0x5610edff6fe4 - std::sys_common::backtrace::print::h85035a511aafe7a8
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:34:9
9: 0x5610edff9560 - std::panicking::default_hook::{{closure}}::hcce8cea212785a25
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:272:22
10: 0x5610edff927f - std::panicking::default_hook::hf5fcb0f213fe709a
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:292:9
11: 0x5610edff9c2f - <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call::hbc5ccf4eb663e1e5
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/alloc/src/boxed.rs:2029:9
12: 0x5610edff9c2f - std::panicking::rust_panic_with_hook::h095fccf1dc9379ee
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:783:13
13: 0x5610edff9949 - std::panicking::begin_panic_handler::{{closure}}::h032ba12139b353db
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:649:13
14: 0x5610edff7746 - std::sys_common::backtrace::__rust_end_short_backtrace::h9259bc2ff8fd0f76
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:171:18
15: 0x5610edff96f0 - rust_begin_unwind
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
16: 0x5610ecfc3855 - core::panicking::panic_fmt::h784f20a50eaab275
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
17: 0x5610ecfc3913 - core::panicking::panic::hb837a5ebbbe5b188
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:144:5
18: 0x5610ed98486a - helix_event::hook::ErasedHook::new::call::h11ad64f2206d9be2
19: 0x5610edad813b - helix_event::registry::with::hd723a5bf64ad0323
20: 0x5610ed727b0e - helix_term::ui::editor::EditorView::handle_keymap_event::{{closure}}::h0acda43659dfd283
21: 0x5610ed727a15 - helix_term::ui::editor::EditorView::handle_keymap_event::hfea1af47727d2306
22: 0x5610ed729492 - <helix_term::ui::editor::EditorView as helix_term::compositor::Component>::handle_event::h108e44023d161bfe
23: 0x5610ed7682a5 - helix_term::compositor::Compositor::handle_event::h49983d2fd645b11b
24: 0x5610edd773f7 - hx::main_impl::{{closure}}::h05533ca0f2469032
25: 0x5610edd75588 - tokio::runtime::park::CachedParkThread::block_on::h7f045a3adc92d673
26: 0x5610edddda09 - tokio::runtime::context::runtime::enter_runtime::h7417e5403934ecd3
27: 0x5610ede0574f - tokio::runtime::runtime::Runtime::block_on::h55b4bf63cf9912d5
28: 0x5610eddbbd42 - hx::main::ha7b9158d45812ad4
29: 0x5610eddec8a3 - std::sys_common::backtrace::__rust_begin_short_backtrace::h3fa1501b4bd3efc7
30: 0x5610eddec9dd - std::rt::lang_start::{{closure}}::h6bfd917f3e71d59c
31: 0x5610edfe9955 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h37600b1e5eea4ecd
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:284:13
32: 0x5610edfe9955 - std::panicking::try::do_call::hb4bda49fa13a0c2b
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:552:40
33: 0x5610edfe9955 - std::panicking::try::h8bbf75149211aaaa
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:516:19
34: 0x5610edfe9955 - std::panic::catch_unwind::h8c78ec68ebea34cb
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panic.rs:142:14
35: 0x5610edfe9955 - std::rt::lang_start_internal::{{closure}}::hffdf44a19fd9e220
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/rt.rs:148:48
36: 0x5610edfe9955 - std::panicking::try::do_call::hcb3194972c74716d
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:552:40
37: 0x5610edfe9955 - std::panicking::try::hcdc6892c5f0dba4c
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:516:19
38: 0x5610edfe9955 - std::panic::catch_unwind::h4910beb4573f4776
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panic.rs:142:14
39: 0x5610edfe9955 - std::rt::lang_start_internal::h6939038e2873596b
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/rt.rs:148:20
40: 0x5610eddbbe35 - main
41: 0x7fdaacb951ca - <unknown>
42: 0x7fdaacb9528b - __libc_start_main
43: 0x5610ed050625 - _start
44: 0x0 - <unknown>
I got this panic when using the latest commit, on doing
:log-openand moving the cursor one line down:❯ hx . thread 'main' panicked at helix-term/src/handlers/blame.rs:96:39: called `Option::unwrap()` on a `None` value stack backtrace: 0: 0x5610edff724b - std::backtrace_rs::backtrace::libunwind::trace::hbee8a7973eeb6c93 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/../../backtrace/src/backtrace/libunwind.rs:104:5 1: 0x5610edff724b - std::backtrace_rs::backtrace::trace_unsynchronized::hc8ac75eea3aa6899 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 2: 0x5610edff724b - std::sys_common::backtrace::_print_fmt::hc7f3e3b5298b1083 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:68:5 3: 0x5610edff724b - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hbb235daedd7c6190 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:44:22 4: 0x5610ed0d95a0 - core::fmt::rt::Argument::fmt::h76c38a80d925a410 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/fmt/rt.rs:142:9 5: 0x5610ed0d95a0 - core::fmt::write::h3ed6aeaa977c8e45 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/fmt/mod.rs:1120:17 6: 0x5610edff2fd3 - std::io::Write::write_fmt::h78b18af5775fedb5 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/io/mod.rs:1810:15 7: 0x5610edff6fe4 - std::sys_common::backtrace::_print::h5d645a07e0fcfdbb at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:47:5 8: 0x5610edff6fe4 - std::sys_common::backtrace::print::h85035a511aafe7a8 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:34:9 9: 0x5610edff9560 - std::panicking::default_hook::{{closure}}::hcce8cea212785a25 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:272:22 10: 0x5610edff927f - std::panicking::default_hook::hf5fcb0f213fe709a at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:292:9 11: 0x5610edff9c2f - <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call::hbc5ccf4eb663e1e5 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/alloc/src/boxed.rs:2029:9 12: 0x5610edff9c2f - std::panicking::rust_panic_with_hook::h095fccf1dc9379ee at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:783:13 13: 0x5610edff9949 - std::panicking::begin_panic_handler::{{closure}}::h032ba12139b353db at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:649:13 14: 0x5610edff7746 - std::sys_common::backtrace::__rust_end_short_backtrace::h9259bc2ff8fd0f76 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/sys_common/backtrace.rs:171:18 15: 0x5610edff96f0 - rust_begin_unwind at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5 16: 0x5610ecfc3855 - core::panicking::panic_fmt::h784f20a50eaab275 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14 17: 0x5610ecfc3913 - core::panicking::panic::hb837a5ebbbe5b188 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:144:5 18: 0x5610ed98486a - helix_event::hook::ErasedHook::new::call::h11ad64f2206d9be2 19: 0x5610edad813b - helix_event::registry::with::hd723a5bf64ad0323 20: 0x5610ed727b0e - helix_term::ui::editor::EditorView::handle_keymap_event::{{closure}}::h0acda43659dfd283 21: 0x5610ed727a15 - helix_term::ui::editor::EditorView::handle_keymap_event::hfea1af47727d2306 22: 0x5610ed729492 - <helix_term::ui::editor::EditorView as helix_term::compositor::Component>::handle_event::h108e44023d161bfe 23: 0x5610ed7682a5 - helix_term::compositor::Compositor::handle_event::h49983d2fd645b11b 24: 0x5610edd773f7 - hx::main_impl::{{closure}}::h05533ca0f2469032 25: 0x5610edd75588 - tokio::runtime::park::CachedParkThread::block_on::h7f045a3adc92d673 26: 0x5610edddda09 - tokio::runtime::context::runtime::enter_runtime::h7417e5403934ecd3 27: 0x5610ede0574f - tokio::runtime::runtime::Runtime::block_on::h55b4bf63cf9912d5 28: 0x5610eddbbd42 - hx::main::ha7b9158d45812ad4 29: 0x5610eddec8a3 - std::sys_common::backtrace::__rust_begin_short_backtrace::h3fa1501b4bd3efc7 30: 0x5610eddec9dd - std::rt::lang_start::{{closure}}::h6bfd917f3e71d59c 31: 0x5610edfe9955 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h37600b1e5eea4ecd at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:284:13 32: 0x5610edfe9955 - std::panicking::try::do_call::hb4bda49fa13a0c2b at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:552:40 33: 0x5610edfe9955 - std::panicking::try::h8bbf75149211aaaa at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:516:19 34: 0x5610edfe9955 - std::panic::catch_unwind::h8c78ec68ebea34cb at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panic.rs:142:14 35: 0x5610edfe9955 - std::rt::lang_start_internal::{{closure}}::hffdf44a19fd9e220 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/rt.rs:148:48 36: 0x5610edfe9955 - std::panicking::try::do_call::hcb3194972c74716d at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:552:40 37: 0x5610edfe9955 - std::panicking::try::hcdc6892c5f0dba4c at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:516:19 38: 0x5610edfe9955 - std::panic::catch_unwind::h4910beb4573f4776 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panic.rs:142:14 39: 0x5610edfe9955 - std::rt::lang_start_internal::h6939038e2873596b at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/rt.rs:148:20 40: 0x5610eddbbe35 - main 41: 0x7fdaacb951ca - <unknown> 42: 0x7fdaacb9528b - __libc_start_main 43: 0x5610ed050625 - _start 44: 0x0 - <unknown>
Ah yes, I just fixed it
I only see the commits and comments, but even if it doesn't affect the main thread, the performance is still a critical point, helix should stay light. Is a update every 150milliseconds necessary ?
I only see the commits and comments, but even if it doesn't affect the main thread, the performance is still a critical point, helix should stay light. Is a update every 150milliseconds necessary ?
Update: We don't do updates every N seconds anymore
Git blame for every line whenever you move is expensive especially on a large repo, so it's guaranteed Helix will consume more resources
I'll try my best to improve performance. I hope to at the very least achieve the performance that Zed has for its inline git blame implementation. It should be doable because from what I can tell Zed spawns a process for git blame while here we are using gix_blame crate which claims to be significantly faster
So far, I've done some experimentation on the Helix repo itself which has around 6,000 commits. Specifically these are the steps that run in the background every time we request the git blame
getting repo dir: 992ns
opening repo: 450.24µs
getting suspect: 119.356µs
creating commit traversal: 212.905224ms
diff resource cache for tree diff: 410.095µs
blame_line: 339.222459ms
Originally I was going to focus on caching the opening repo step however this is negligible in comparison to the time it takes to:
create commit traversal (0.21s)(which we should be able to cache for huge performance increase)blame_line (0.34s). This step is out of our control, it is implemented bygix_blamecrate. So we could think about how we can efficiently re-use git blame for lines when it was already computed
Update: gix_blame can actually return all the blamed regions, great! I am now confident this can be extremely fast (100x what we have right now)
The solution is basically that we have a worker and we check it every 0.05 seconds if its done. If not, then try again later. If it is, then get its result.
Can this busy-wait loop replaced by a Notify?
Update:
gix_blamecan actually return all the blamed regions, great! I am now confident this can be extremely fast (100x what we have right now)
New performance update! I have followed through on my comment. Once the blame for the file loads, there is zero delay between getting new blame lines
https://github.com/user-attachments/assets/b44197e8-c272-4ca2-b6b4-9ebf0f890138
The solution is basically that we have a worker and we check it every 0.05 seconds if its done. If not, then try again later. If it is, then get its result.
Can this busy-wait loop replaced by a Notify?
If you something like mspc then yes, I just did it
Now that the blame is being loaded for the full file. Does this open the door for displaying the blame for the full file near the line numbers? Similar to how GitHub does?
Now that the blame is being loaded for the full file. Does this open the door for displaying the blame for the full file near the line numbers? Similar to how GitHub does?
Yes, it does! There are lots of other interesting things you could do based off this PR
While testing in debug mode I ran into the following panic from gix-blame
thread 'tokio-runtime-worker' panicked at /home/e/.cargo/registry/src/index.crates.io-6f17d22bba15001f/gix-blame-0.0.0/src/file/function.rs:243:25:
#[
UnblamedHunk {
range_in_blamed_file: 0..1,
suspects: {
Sha1(bc0084d071ac53fa460370667cdd8740e7499c76): 0..1,
Sha1(e216e9621e73cda1968632cd20595231af5e07be): 0..1,
},
},
I did research and bug is known (https://github.com/GitoxideLabs/gitoxide/issues/1847)
This is a failing debug_assert! in gix::blame. From my extensive testing in --release mode this is not a problem that is user-facing so we should not worry about it.
I would say this PR is ready now!
I don't know if I'm missing some configurations, but I am getting an error trying to turn on the blaming.
I'm working on C++, under your branch at commit f7e83323e29a07b21f349363f7fbd8a3edd2b397
Built with cargo build --release
The workspace folder is a git repo properly initialized and with commit history
The file contains valid blames when running
git blame {path}
I don't know if I'm missing some configurations, but I am getting an error trying to turn on the blaming. I'm working on C++, under your branch at commit f7e8332 Built with
cargo build --releaseThe workspace folder is a git repo properly initialized and with commit historyThe file contains valid blames when running
git blame {path}
I updated the PR so it will print the error returned by gix_blame as well as into the :log-open helix file. (in case it is too long)
Could you try to get this error again and then post the logs here?
I don't know if I'm missing some configurations, but I am getting an error trying to turn on the blaming. I'm working on C++, under your branch at commit f7e8332 Built with
cargo build --releaseThe workspace folder is a git repo properly initialized and with commit historyThe file contains valid blames when running
git blame {path}I updated the PR so it will print the error returned by
gix_blameas well as into the:log-openhelix file. (in case it is too long)Could you try to get this error again and then post the logs here?
It seems gix-blame is looking for the file in the entire git history and can't find it on the first commit, which makes sense because the file was not present there.
In order to facilitate the bug's reproduction, here's the repository I'm trying to get blame on https://github.com/Hush-Engine/Hush-Engine I also tried it on the helix repo itself, and the same issue seems to be hapenning
I don't know if I'm missing some configurations, but I am getting an error trying to turn on the blaming. I'm working on C++, under your branch at commit f7e8332 Built with
cargo build --releaseThe workspace folder is a git repo properly initialized and with commit historyThe file contains valid blames when running
git blame {path}I updated the PR so it will print the error returned by
gix_blameas well as into the:log-openhelix file. (in case it is too long) Could you try to get this error again and then post the logs here?It seems
gix-blameis looking for the file in the entire git history and can't find it on the first commit, which makes sense because the file was not present there.In order to facilitate the bug's reproduction, here's the repository I'm trying to get blame on https://github.com/Hush-Engine/Hush-Engine I also tried it on the helix repo itself, and the same issue seems to be hapenning
i can't reproduce this, I am getting git blame:
I don't know if I'm missing some configurations, but I am getting an error trying to turn on the blaming. I'm working on C++, under your branch at commit f7e8332 Built with
cargo build --releaseThe workspace folder is a git repo properly initialized and with commit historyThe file contains valid blames when running
git blame {path}I updated the PR so it will print the error returned by
gix_blameas well as into the:log-openhelix file. (in case it is too long) Could you try to get this error again and then post the logs here?It seems
gix-blameis looking for the file in the entire git history and can't find it on the first commit, which makes sense because the file was not present there.In order to facilitate the bug's reproduction, here's the repository I'm trying to get blame on https://github.com/Hush-Engine/Hush-Engine I also tried it on the helix repo itself, and the same issue seems to be hapenning
i can't reproduce this, I am getting git blame:
Hmm, in that case it's probably an issue with my environment, I'll be troubleshooting this then, thanks for the quick responses, and keep it up, this PR makes Helix 100 times better, kudos for that!
The file contains valid blames when running 

