Skip to content

Commit 23f9672

Browse files
Squashed commit of the following:
commit e5f837f Merge: 1c0b99d 99cea8c Author: nik rev <pm@nikrev.com> Date: Sun Aug 31 11:07:18 2025 +0100 Merge branch 'master' into gix-blame commit 1c0b99d Author: Nik Revenco <pm@nikrev.com> Date: Sun Jul 27 10:51:12 2025 +0100 refactor: Do not use `unwrap_or_default` on simple integer See rust-lang/rust-clippy#15037 commit 7a83e9e Author: Nik Revenco <pm@nikrev.com> Date: Sun Jul 27 10:43:39 2025 +0100 feat: horizontal scroll of the current document into account when drawing the blame Co-authored-by: Taylor Plewe <tplewe@outlook.com> commit 5e21b7f Author: Nik Revenco <pm@nikrev.com> Date: Tue Jun 17 11:40:21 2025 +0100 fix: Cargo.lock commit 14d4163 Merge: a476d6d fed3edc Author: Nik Revenco <pm@nikrev.com> Date: Tue Jun 17 11:37:05 2025 +0100 Merge branch 'master' into gix-blame commit a476d6d Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat Jun 7 14:06:25 2025 +0100 Revert "feat: if you are the author, use "You" instead of name" This reverts commit 41cb919. I don't think it's worth to have this feature for the additional complexity of allowing users to opt-out, plus considering the fact that it might be inaccurate and cause confusion Similar discussion: zed-industries/zed#10557 commit 41cb919 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat Jun 7 11:57:55 2025 +0100 feat: if you are the author, use "You" instead of name commit 100ad75 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat Jun 7 11:35:46 2025 +0100 chore: clarify comment commit d00ff25 Merge: 08c6650 f4b488e Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat Jun 7 11:34:29 2025 +0100 Merge branch 'master' into gix-blame commit 08c6650 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 13:54:00 2025 +0100 docs: Add line breaks to paragraph + improve wording commit e64b4fa Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon May 19 13:47:34 2025 +0100 docs: improve wording Co-authored-by: uncenter <uncenter@uncenter.dev> commit 92dc3ca Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon May 19 13:44:00 2025 +0100 docs: improve wording Co-authored-by: uncenter <uncenter@uncenter.dev> commit eb559cf Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon May 19 13:43:28 2025 +0100 docs: remove hard to understand sentence Co-authored-by: uncenter <uncenter@uncenter.dev> commit dd1f31d Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon May 19 12:21:05 2025 +0100 docs: improve wording Co-authored-by: uncenter <uncenter@uncenter.dev> commit 9d27551 Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon May 19 12:20:48 2025 +0100 docs: improve wording Co-authored-by: uncenter <uncenter@uncenter.dev> commit 01e9dc1 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 10:27:10 2025 +0100 test: use correct variable name commit 00117f8 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:49:15 2025 +0100 fix: use correct variable name `title` instead of `message` commit 4eebdec Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:47:47 2025 +0100 test: use renamed `commit_message` commit a859cb2 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:44:17 2025 +0100 docs: change sentence commit f1a29ee Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:41:01 2025 +0100 feat: rename the `message` variable to `title` commit 0123bac Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:31:18 2025 +0100 docs: remove confusing instructions These instructions are confusing and hard to interpret. The details won't matter for almost all people, so there's no need to provide this information commit 1ca7ee8 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:27:54 2025 +0100 feat: rename config options Based off uncenter's review commit b8bd060 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:11:34 2025 +0100 chore: fix merge conflicts commit deb5897 Merge: 7effac9 3ceae88 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon May 19 09:11:20 2025 +0100 Merge branch 'master' into gix-blame commit 7effac9 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue May 6 18:22:25 2025 +0100 fix: only render inline blame once per line at most Renders inline blame for the last visual line commit be5fbff Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue May 6 17:38:04 2025 +0100 chore: resolve merge conflicts commit b31f1c7 Merge: 03f0883 e53462c Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue May 6 17:10:02 2025 +0100 Merge branch 'master' into gix-blame commit 03f0883 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Wed Apr 16 23:34:56 2025 +0100 chore: fix merge conflicts commit 5d83e93 Merge: 616758e 37b5d8b Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Wed Apr 16 23:09:49 2025 +0100 Merge branch 'master' into gix-blame commit 616758e Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Fri Apr 4 08:19:40 2025 +0100 refactor: rename macro _ commit c74fec4 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Wed Apr 2 00:12:38 2025 +0100 fix?: do not block on the main thread when acquiring diff handle not sure if this will work as I can't reproduce this but let's see! commit e8d7e76 Author: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Tue Apr 1 12:17:48 2025 +0100 fix: spelling error Co-authored-by: Sebastian Klähn <39526136+Septias@users.noreply.github.com> commit 1a0dad3 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sun Mar 30 11:42:43 2025 +0100 perf: only render inline blame for visible lines when `all-lines` is set Previously, we rendereded the inline blame for lines in 3X the range of the viewport This is not necessary because when we scroll down, the rendering will occur before we see the new content commit 95344a9 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat Mar 29 23:59:06 2025 +0000 perf: use string preallocations for string concatenation commit af3b670 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:35:45 2025 +0000 refactor: move expression _ commit b3b1c88 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:34:06 2025 +0000 refactor: pass the `Style` instead of `Theme` commit c101f37 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:31:08 2025 +0000 style: fmt commit 082ba4d Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:27:14 2025 +0000 refactor: `match` over `if` commit ab56638 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:24:33 2025 +0000 refactor: render inline blame in a separate Editor function commit 00d168a Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 21:14:02 2025 +0000 fix: funny boolean inversion commit a8097f1 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 20:02:05 2025 +0000 perf: use `Vec<T>` instead of `HashMap<usize, T>` commit 22f9571 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 19:01:12 2025 +0000 feat: split `inline-blame.behaviour` into two options _ _ commit b9f8226 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 13:03:20 2025 +0000 refactor: remove `new_config` from EditorConfigDidChange event There is no need for it because we have access to `Editor::config()` commit d34074a Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 12:51:47 2025 +0000 perf: do not render inline blame on invisible lines commit ac0e677 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 12:34:01 2025 +0000 chore: appease clippy commit 76a92af Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 12:25:12 2025 +0000 feat: `all-lines` option for inline blame commit 7478d9e Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 11:55:05 2025 +0000 refactor: extract as variable commit f54fdef Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 25 11:46:36 2025 +0000 refactor: remove extra layer of sync commit 8f0721f Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon Mar 24 16:07:19 2025 +0000 use format! instead of preallocating this is more efficient apparently commit 07c69c1 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon Mar 24 04:00:02 2025 +0000 fix: update blame when editing config commit 647615d Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon Mar 24 01:31:01 2025 +0000 perf: optimize obtaining blame for the same line _ fix: blame_line_impl _ _ _ _ _ commit 29f4428 Author: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue Mar 18 01:11:57 2025 +0000 feat: Inline Git Blame fix: use relative path when finding file style: cargo fmt _ chore: better error message refactor: rename to `blame_line` fix: use line of primary cursor for git blame feat: basic implementation of blocking Blame handler feat: implement basic virtual text (end of line blame) feat: figure out how to draw stuff at the end of lines feat: implement end of line virtual text for the current line feat: implement inline git blame chore: clean up chore: remove unused import _ chore: set `blame` to `false` by default docs: document `[editor.vcs.blame]` chore: add progress perf: use background task for worker _ chore: remove unnecessary panic!s chore: remove commented code refactor: remove some layers of abstraction refactor: remove nesting feat: [editor.vcs] -> [editor.version-control] fix: account for inserted and deleted lines _ refactor: extract into a `blame` module feat: allow using custom commit format feat: allow more customizability for inline blame test: add tests for custom inline commit parsser refactor: rename `blame` -> `blame_line` _ _ test: create helper macros for tests test: make test syntax more expressive. Allow specifying line numbers that just got added test: with interspersed lines feat: add `line_blame` static command _ test: add an extra test case test: add ability to have `delete`d lines test: fix on windows (?) test: `delete` test case test: add extra step to test case test: add documentation for macro refactor: use `hashmap!` macro refactor: collapse match arm fix: remove panic perf: update inline git blame every 150 milliseconds instead of on each command test: add attributes on blocks style: move function earlier in the file perf: cache blame results in a hashma chore: remove log statements chore: clean up. ALSO: removes checking for inline blame every N seconds. _ perf: use mspc instead of busy-wait docs: add information why we don't optimize the repo _ test: add back the commented out tests chore: comment out cfg(not(windows)) test: add extra history to blame test docs: remove incorrect static command _ test: disable test on windows feat: send inline blame event update when reloading or saving the document feat: rename `version-control` -> `inline-blame` feat: update theme key used for inline-blame chore: remove unused #![allow] chore: style: remove accidental formatting docs: remove incorrect key perf: Use a single `ThreadSafeRepository` instead of re-constructing it each time feat: add `inline_blame` static command bound to `space + B` style: revert formatting in keymap.md chore: do not compute blame for document when changing config option This isn't needed anymore because the inline-blame will be computed regardless if `inline_blame.enable` is set or not style: remove newline refactor: use `fold` instead of loop chore: clean up feat: log error forl line blame when it happens feat: improve message when we don't have the blame We know that we don't have it because we're still calculating it. feat: do not render inline blame for empty lines _ feat: do not show blame output when we are on a hunk that was added refactor: remove additional wrapper methods fix _ feat: more readable time for git blame chr feat: feat: improved error handling fix: path separator on Windows test: disable on windows refactor: move pretty date function formatter into `helix-stdx` perf: do not use a syscall on each render chore: add TODO comment to update gix version chore: use `gix::path` conversion from Path -> BString _ _ chore: do not update file blame on document save This is not needed because when we write the file, we don't make a new commit so the blame will not change. refactor: use statics to get time elapsed instead of editor state refactor: do not use custom event, use handler instead fix: do not spawn a new handler docs: correct examples for `editor.inline-blame.format` docs: correct static command name refactor: add comments, and improve variable names I didn't really understand this function when I made it. Was just copy-pasted from end of line diagnostics I wanted to know what this is actually doing, so I investigated and while doing this also added comments and improved names of variables so others can understand too fix: time in future is accounted for perf: inline some functions that are called in only 1 place, during a render loop perf: add option to disable requesting inline blame in the background fix: request blame again when document is reloaded chore: inline blame is disabled with request on demand feat: when requesting line blame with "blame on demand", show blame in status perf: use less allocations perf: less allocations in `format_relative_time` _ _ _ _ docs: correct name of command _ feat: improve error message _ feat: rename enum variants for inline blame behaviour docs: improve description of behaviour field
1 parent d7d8c2d commit 23f9672

File tree

30 files changed

+1341
-18
lines changed

30 files changed

+1341
-18
lines changed

Cargo.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

book/src/editor.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- [`[editor.clipboard-provider]` Section](#editorclipboard-provider-section)
55
- [`[editor.statusline]` Section](#editorstatusline-section)
66
- [`[editor.lsp]` Section](#editorlsp-section)
7+
- [`[editor.inline-blame]` Section](#editorinlineblame-section)
78
- [`[editor.cursor-shape]` Section](#editorcursor-shape-section)
89
- [`[editor.file-picker]` Section](#editorfile-picker-section)
910
- [`[editor.auto-pairs]` Section](#editorauto-pairs-section)
@@ -173,6 +174,39 @@ The following statusline elements can be configured:
173174

174175
[^2]: You may also have to activate them in the language server config for them to appear, not just in Helix. Inlay hints in Helix are still being improved on and may be a little bit laggy/janky under some circumstances. Please report any bugs you see so we can fix them!
175176

177+
### `[editor.inline-blame]` Section
178+
179+
Inline blame is virtual text that appears at the end of a line, displaying information about the most recent commit that affected this line.
180+
181+
| Key | Description | Default |
182+
| ------- | ------------------------------------------ | ------- |
183+
| `show` | When to show inline blame | `"never"` |
184+
| `auto-fetch` | Automatically fetch blame information in the background | `false` |
185+
| `format` | Inline blame message format | `"{author}, {time-ago} • {title} • {commit}"` |
186+
187+
`show` can be one of the following:
188+
- `"all-lines"`: Inline blame is on every line.
189+
- `"cursor-line"`: Inline blame is only on the line of the primary cursor.
190+
- `"hidden"`: Inline blame is hidden.
191+
192+
With `auto-fetch` set to `false`, blame for the current file is fetched only when explicitly requested, such as when using `space + B` to display the blame for the line of the cursor. There may be a little delay when loading the blame.
193+
194+
When `auto-fetch` is set to `true`, blame for the file is fetched in the background; this will have no effect on performance, but will use a little bit extra resources in the background. Directly requesting the blame with `space + B` will be instant. Inline blame will show as soon as the blame is available when loading new files.
195+
196+
When opening new files, even with `show` set 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 with `space + B`.
197+
198+
#### `format`
199+
200+
Change the `format` string to customize the blame message displayed. Variables are text placeholders wrapped in curly braces: `{variable}`. The following variables are available:
201+
202+
- `author`: The author of the commit
203+
- `date`: When the commit was made
204+
- `time-ago`: How long ago the commit was made
205+
- `title`: The title of the commit
206+
- `body`: The body of the commit
207+
- `commit`: The short hex SHA1 hash of the commit
208+
- `email`: The email of the author of the commit
209+
176210
### `[editor.cursor-shape]` Section
177211

178212
Defines the shape of cursor in each mode.

book/src/generated/static-cmd.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,5 +311,6 @@
311311
| `extend_to_word` | Extend to a two-character label | select: `` gw `` |
312312
| `goto_next_tabstop` | Goto next snippet placeholder | |
313313
| `goto_prev_tabstop` | Goto next snippet placeholder | |
314+
| `blame_line` | Show blame for the current line | normal: `` <space>B ``, select: `` <space>B `` |
314315
| `rotate_selections_first` | Make the first selection your primary one | |
315316
| `rotate_selections_last` | Make the last selection your primary one | |

book/src/keymap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ This layer is a kludge of mappings, mostly pickers.
314314
| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
315315
| `/` | Global search in workspace folder | `global_search` |
316316
| `?` | Open command palette | `command_palette` |
317+
| `B` | Show blame for the current line | `blame_line` |
317318

318319
> 💡 Global search displays results in a fuzzy picker, use `Space + '` to bring it back up after opening a file.
319320

book/src/themes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ These scopes are used for theming the editor interface:
338338
| `ui.virtual.inlay-hint.type` | Style for inlay hints of kind `type` (language servers are not required to set a kind) |
339339
| `ui.virtual.wrap` | Soft-wrap indicator (see the [`editor.soft-wrap` config][editor-section]) |
340340
| `ui.virtual.jump-label` | Style for virtual jump labels |
341+
| `ui.virtual.inline-blame` | Inline blame indicator (see the [`editor.inline-blame` config][editor-section]) |
341342
| `ui.menu` | Code and command completion menus |
342343
| `ui.menu.selected` | Selected autocomplete item |
343344
| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar |

helix-stdx/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ pub mod faccess;
66
pub mod path;
77
pub mod range;
88
pub mod rope;
9+
pub mod str;
10+
pub mod time;
911

1012
pub use range::Range;

helix-stdx/src/str.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// Concatenates strings together.
2+
///
3+
/// `str_concat!(a, " ", b, " ", c)` is:
4+
/// - more performant than `format!("{a} {b} {c}")`
5+
/// - more ergonomic than using `String::with_capacity` followed by a series of `String::push_str`
6+
#[macro_export]
7+
macro_rules! str_concat {
8+
($($value:expr),*) => {{
9+
// Rust does not allow using `+` as separator between value
10+
// so we must add that at the end of everything. The `0` is necessary
11+
// at the end so it does not end with "+ " (which would be invalid syntax)
12+
let mut buf = String::with_capacity($($value.len() + )* 0);
13+
$(
14+
buf.push_str(&$value);
15+
)*
16+
buf
17+
}}
18+
}

helix-stdx/src/time.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::time::{Instant, SystemTime};
2+
3+
use once_cell::sync::Lazy;
4+
5+
const SECOND: i64 = 1;
6+
const MINUTE: i64 = 60 * SECOND;
7+
const HOUR: i64 = 60 * MINUTE;
8+
const DAY: i64 = 24 * HOUR;
9+
const MONTH: i64 = 30 * DAY;
10+
const YEAR: i64 = 365 * DAY;
11+
12+
/// Like `std::time::SystemTime::now()` but does not cause a syscall on every invocation.
13+
///
14+
/// There is just one syscall at the start of the program, subsequent invocations are
15+
/// much cheaper and use the monotonic clock instead of trigerring a syscall.
16+
#[inline]
17+
fn now() -> SystemTime {
18+
static START_INSTANT: Lazy<Instant> = Lazy::new(Instant::now);
19+
static START_SYSTEM_TIME: Lazy<SystemTime> = Lazy::new(SystemTime::now);
20+
21+
*START_SYSTEM_TIME + START_INSTANT.elapsed()
22+
}
23+
24+
/// Formats a timestamp into a human-readable relative time string.
25+
///
26+
/// # Arguments
27+
///
28+
/// * `timestamp` - A point in history. Seconds since UNIX epoch (UTC)
29+
/// * `timezone_offset` - Timezone offset in seconds
30+
///
31+
/// # Returns
32+
///
33+
/// A String representing the relative time (e.g., "4 years ago", "11 months from now")
34+
#[inline]
35+
pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String {
36+
let timestamp = timestamp + timezone_offset as i64;
37+
let now = now()
38+
.duration_since(std::time::UNIX_EPOCH)
39+
.unwrap_or_default()
40+
.as_secs() as i64
41+
+ timezone_offset as i64;
42+
43+
let time_passed = now - timestamp;
44+
45+
let time_difference = time_passed.abs();
46+
47+
let (value, unit) = if time_difference >= YEAR {
48+
let years = time_difference / YEAR;
49+
(years, if years == 1 { "year" } else { "years" })
50+
} else if time_difference >= MONTH {
51+
let months = time_difference / MONTH;
52+
(months, if months == 1 { "month" } else { "months" })
53+
} else if time_difference >= DAY {
54+
let days = time_difference / DAY;
55+
(days, if days == 1 { "day" } else { "days" })
56+
} else if time_difference >= HOUR {
57+
let hours = time_difference / HOUR;
58+
(hours, if hours == 1 { "hour" } else { "hours" })
59+
} else if time_difference >= MINUTE {
60+
let minutes = time_difference / MINUTE;
61+
(minutes, if minutes == 1 { "minute" } else { "minutes" })
62+
} else {
63+
let seconds = time_difference / SECOND;
64+
(seconds, if seconds == 1 { "second" } else { "seconds" })
65+
};
66+
let value = value.to_string();
67+
68+
let label = if time_passed.is_positive() {
69+
"ago"
70+
} else {
71+
"from now"
72+
};
73+
74+
crate::str_concat!(value, " ", unit, " ", label)
75+
}

helix-term/src/application.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use helix_view::{
1111
align_view,
1212
document::{DocumentOpenError, DocumentSavedEventResult},
1313
editor::{ConfigEvent, EditorEvent},
14+
events::EditorConfigDidChange,
1415
graphics::Rect,
1516
theme,
1617
tree::Layout,
@@ -387,6 +388,10 @@ impl Application {
387388
// the Application can apply it.
388389
ConfigEvent::Update(editor_config) => {
389390
let mut app_config = (*self.config.load().clone()).clone();
391+
helix_event::dispatch(EditorConfigDidChange {
392+
old_config: &app_config.editor,
393+
editor: &mut self.editor,
394+
});
390395
app_config.editor = *editor_config;
391396
if let Err(err) = self.terminal.reconfigure((&app_config.editor).into()) {
392397
self.editor.set_error(err.to_string());

helix-term/src/commands.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use helix_stdx::{
1111
rope::{self, RopeSliceExt},
1212
};
1313
use helix_vcs::{FileChange, Hunk};
14+
use helix_view::document::LineBlameError;
1415
pub use lsp::*;
1516
pub use syntax::*;
1617
use tui::{
@@ -613,6 +614,7 @@ impl MappableCommand {
613614
extend_to_word, "Extend to a two-character label",
614615
goto_next_tabstop, "Goto next snippet placeholder",
615616
goto_prev_tabstop, "Goto next snippet placeholder",
617+
blame_line, "Show blame for the current line",
616618
rotate_selections_first, "Make the first selection your primary one",
617619
rotate_selections_last, "Make the last selection your primary one",
618620
);
@@ -3512,6 +3514,55 @@ fn insert_at_line_start(cx: &mut Context) {
35123514
insert_with_indent(cx, IndentFallbackPos::LineStart);
35133515
}
35143516

3517+
pub(crate) fn blame_line_impl(editor: &mut Editor, doc_id: DocumentId, cursor_line: u32) {
3518+
let inline_blame_config = &editor.config().inline_blame;
3519+
let Some(doc) = editor.document(doc_id) else {
3520+
return;
3521+
};
3522+
let line_blame = match doc.line_blame(cursor_line, &inline_blame_config.format) {
3523+
result
3524+
if (result.is_ok() && doc.is_blame_potentially_out_of_date)
3525+
|| matches!(result, Err(LineBlameError::NotReadyYet) if !inline_blame_config.auto_fetch) =>
3526+
{
3527+
if let Some(path) = doc.path() {
3528+
let tx = editor.handlers.blame.clone();
3529+
helix_event::send_blocking(
3530+
&tx,
3531+
helix_view::handlers::BlameEvent {
3532+
path: path.to_path_buf(),
3533+
doc_id: doc.id(),
3534+
line: Some(cursor_line),
3535+
},
3536+
);
3537+
editor.set_status(format!("Requested blame for {}...", path.display()));
3538+
let doc = editor
3539+
.document_mut(doc_id)
3540+
.expect("exists since we return from the function earlier if it does not");
3541+
doc.is_blame_potentially_out_of_date = false;
3542+
} else {
3543+
editor.set_error("Could not get path of document");
3544+
};
3545+
return;
3546+
}
3547+
Ok(line_blame) => line_blame,
3548+
Err(err @ (LineBlameError::NotCommittedYet | LineBlameError::NotReadyYet)) => {
3549+
editor.set_status(err.to_string());
3550+
return;
3551+
}
3552+
Err(err @ LineBlameError::NoFileBlame(_, _)) => {
3553+
editor.set_error(err.to_string());
3554+
return;
3555+
}
3556+
};
3557+
3558+
editor.set_status(line_blame);
3559+
}
3560+
3561+
fn blame_line(cx: &mut Context) {
3562+
let (view, doc) = current_ref!(cx.editor);
3563+
blame_line_impl(cx.editor, doc.id(), doc.cursor_line(view.id) as u32);
3564+
}
3565+
35153566
// `A` inserts at the end of each line with a selection.
35163567
// If the line is empty, automatically indent.
35173568
fn insert_at_line_end(cx: &mut Context) {

0 commit comments

Comments
 (0)