From 29f442887a62c49524ac8b2b34d3ec154d4a4f6e Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 18 Mar 2025 01:11:57 +0000 Subject: [PATCH 01/55] 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 --- Cargo.lock | 52 +- book/src/editor.md | 36 ++ book/src/generated/static-cmd.md | 1 + book/src/keymap.md | 1 + book/src/themes.md | 1 + helix-stdx/src/lib.rs | 1 + helix-stdx/src/time.rs | 81 +++ helix-term/src/commands.rs | 50 ++ helix-term/src/commands/typed.rs | 34 ++ helix-term/src/handlers.rs | 5 + helix-term/src/handlers/blame.rs | 94 +++ helix-term/src/keymap/default.rs | 1 + helix-term/src/ui/editor.rs | 22 +- helix-term/src/ui/text_decorations.rs | 1 + helix-term/src/ui/text_decorations/blame.rs | 67 +++ helix-vcs/Cargo.toml | 3 +- helix-vcs/src/git.rs | 4 +- helix-vcs/src/git/blame.rs | 632 ++++++++++++++++++++ helix-vcs/src/git/test.rs | 26 +- helix-vcs/src/lib.rs | 5 +- helix-view/src/document.rs | 50 ++ helix-view/src/editor.rs | 43 ++ helix-view/src/events.rs | 3 +- helix-view/src/handlers.rs | 12 + 24 files changed, 1196 insertions(+), 29 deletions(-) create mode 100644 helix-stdx/src/time.rs create mode 100644 helix-term/src/handlers/blame.rs create mode 100644 helix-term/src/ui/text_decorations/blame.rs create mode 100644 helix-vcs/src/git/blame.rs diff --git a/Cargo.lock b/Cargo.lock index b0e34b3f5271..6964b4bacc32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,6 +211,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -509,6 +518,7 @@ checksum = "736f14636705f3a56ea52b553e67282519418d9a35bb1e90b3a9637a00296b68" dependencies = [ "gix-actor", "gix-attributes", + "gix-blame", "gix-command", "gix-commitgraph", "gix-config", @@ -591,6 +601,21 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "gix-blame" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc795e239a2347eb50ed18b8c529382dd8b62439c57277f79af3d8f8928a986" +dependencies = [ + "gix-diff", + "gix-hash", + "gix-object", + "gix-trace", + "gix-traverse", + "gix-worktree", + "thiserror 2.0.12", +] + [[package]] name = "gix-chunk" version = "0.4.11" @@ -739,12 +764,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bfdd4838a8d42bd482c9f0cb526411d003ee94cc7c7b08afe5007329c71d554" dependencies = [ "crc32fast", + "crossbeam-channel", "flate2", "gix-hash", "gix-trace", "gix-utils", "libc", "once_cell", + "parking_lot", "prodash", "sha1_smol", "thiserror 2.0.12", @@ -1526,6 +1553,7 @@ dependencies = [ "gix", "helix-core", "helix-event", + "helix-stdx", "imara-diff", "log", "parking_lot", @@ -1823,15 +1851,15 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91335e575850c5c4c673b9bd467b0e025f164ca59d0564f69d0c2ee0ffad4653" +checksum = "962e1dfe9b2d75a84536cf5bf5eaaa4319aa7906c7160134a22883ac316d5f31" [[package]] name = "jiff-tzdb-platform" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9835f0060a626fe59f160437bc725491a6af23133ea906500027d1bd2f8f4329" +checksum = "a63c62e404e7b92979d2792352d885a7f8f83fd1d0d31eea582d77b2ceca697e" dependencies = [ "jiff-tzdb", ] @@ -2087,15 +2115,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -2132,9 +2160,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -2463,9 +2491,9 @@ checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", diff --git a/book/src/editor.md b/book/src/editor.md index 1e5c2a507749..9958798ebd0d 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -4,6 +4,7 @@ - [`[editor.clipboard-provider]` Section](#editorclipboard-provider-section) - [`[editor.statusline]` Section](#editorstatusline-section) - [`[editor.lsp]` Section](#editorlsp-section) +- [`[editor.inline-blame]` Section](#editorinlineblame-section) - [`[editor.cursor-shape]` Section](#editorcursor-shape-section) - [`[editor.file-picker]` Section](#editorfile-picker-section) - [`[editor.auto-pairs]` Section](#editorauto-pairs-section) @@ -161,6 +162,41 @@ The following statusline elements can be configured: [^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! +### `[editor.inline-blame]` Section + +| Key | Description | Default | +| ------- | ------------------------------------------ | ------- | +| `behaviour` | Choose the behaviour of inline blame | `"disabled"` | +| `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {message} • {commit}"` | + +The `behaviour` can be one of the following: +- `"visible"`: Inline blame is turned on. Virtual text will appear at the end of each non-empty line, showing information about the latest commit for that line. +- `"background"`: Inline blame is turned off, but the blame is still requested in the background when opening and reloading files. This will have zero impact on performance, but will use slightly more resources in the background. This allows blame for line (`space + B`) to be retrieved instantaneously with zero delay. +- `"disabled"`: Inline blame is turned off, with no requests happening in the background. When you run `space + B` for the first time in a file, it will load the blame for this file. You may have to wait a little bit for the blame to become available, depending on the size of your repository. After it becomes available, for this file `space + B` will retrieve the blame for any line in this file with zero delay. If the file is reloaded, the process will repeat as the blame is potentially out of date and needs to be refreshed. + +`inline-blame-format` allows customization of the blame message, and can be set to any string. Variables can be used like so: `{variable}`. These are the available variables: + +- `author`: The author of the commit +- `date`: When the commit was made +- `time-ago`: How long ago the commit was made +- `message`: The message of the commit, excluding the body +- `body`: The body of the commit +- `commit`: The short hex SHA1 hash of the commit +- `email`: 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 `format` value: + +- If `author` is empty: `"{time-ago} • {message} • {commit}"` +- If `time-ago` is empty: `"{author} • {message} • {commit}"` +- If `message` is empty: `"{author}, {time-ago} • {commit}"` +- If `commit` is empty: `"{author}, {time-ago} • {message}"` +- If `time-ago` and `message` is empty: `"{author} • {commit}"` +- If `author` and `message` is empty: `"{time-ago} • {commit}"` + ### `[editor.cursor-shape]` Section Defines the shape of cursor in each mode. diff --git a/book/src/generated/static-cmd.md b/book/src/generated/static-cmd.md index af7515b8e824..3efba2a66b41 100644 --- a/book/src/generated/static-cmd.md +++ b/book/src/generated/static-cmd.md @@ -298,3 +298,4 @@ | `extend_to_word` | Extend to a two-character label | select: `` gw `` | | `goto_next_tabstop` | goto next snippet placeholder | | | `goto_prev_tabstop` | goto next snippet placeholder | | +| `blame_line` | Show blame for the current line | normal: `` B ``, select: `` B `` | diff --git a/book/src/keymap.md b/book/src/keymap.md index 2797eaee2908..86ad51363215 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -309,6 +309,7 @@ This layer is a kludge of mappings, mostly pickers. | `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` | | `/` | Global search in workspace folder | `global_search` | | `?` | Open command palette | `command_palette` | +| `B` | Show blame for the current line | `blame_line` | > 💡 Global search displays results in a fuzzy picker, use `Space + '` to bring it back up after opening a file. diff --git a/book/src/themes.md b/book/src/themes.md index 412d17efc237..4201720e6240 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -314,6 +314,7 @@ These scopes are used for theming the editor interface: | `ui.virtual.inlay-hint.type` | Style for inlay hints of kind `type` (language servers are not required to set a kind) | | `ui.virtual.wrap` | Soft-wrap indicator (see the [`editor.soft-wrap` config][editor-section]) | | `ui.virtual.jump-label` | Style for virtual jump labels | +| `ui.virtual.inline-blame` | Inline blame indicator (see the [`editor.inline-blame` config][editor-section]) | | `ui.menu` | Code and command completion menus | | `ui.menu.selected` | Selected autocomplete item | | `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar | diff --git a/helix-stdx/src/lib.rs b/helix-stdx/src/lib.rs index d09df587a63d..eeaba0d81b21 100644 --- a/helix-stdx/src/lib.rs +++ b/helix-stdx/src/lib.rs @@ -3,5 +3,6 @@ pub mod faccess; pub mod path; pub mod range; pub mod rope; +pub mod time; pub use range::Range; diff --git a/helix-stdx/src/time.rs b/helix-stdx/src/time.rs new file mode 100644 index 000000000000..a7bb1a040ab8 --- /dev/null +++ b/helix-stdx/src/time.rs @@ -0,0 +1,81 @@ +use std::time::{Instant, SystemTime}; + +use once_cell::sync::Lazy; + +const SECOND: i64 = 1; +const MINUTE: i64 = 60 * SECOND; +const HOUR: i64 = 60 * MINUTE; +const DAY: i64 = 24 * HOUR; +const MONTH: i64 = 30 * DAY; +const YEAR: i64 = 365 * DAY; + +/// Like `std::time::SystemTime::now()` but does not cause a syscall on every invocation. +/// +/// There is just one syscall at the start of the program, subsequent invocations are +/// much cheaper and use the monotonic clock instead of trigerring a syscall. +#[inline] +fn now() -> SystemTime { + static START_INSTANT: Lazy = Lazy::new(Instant::now); + static START_SYSTEM_TIME: Lazy = Lazy::new(SystemTime::now); + + *START_SYSTEM_TIME + START_INSTANT.elapsed() +} + +/// Formats a timestamp into a human-readable relative time string. +/// +/// # Arguments +/// +/// * `timestamp` - A point in history. Seconds since UNIX epoch (UTC) +/// * `timezone_offset` - Timezone offset in seconds +/// +/// # Returns +/// +/// A String representing the relative time (e.g., "4 years ago", "11 months from now") +#[inline] +pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String { + let timestamp = timestamp + timezone_offset as i64; + let now = now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_secs() as i64 + + timezone_offset as i64; + + let time_passed = now - timestamp; + + let time_difference = time_passed.abs(); + + let (value, unit) = if time_difference >= YEAR { + let years = time_difference / YEAR; + (years, if years == 1 { "year" } else { "years" }) + } else if time_difference >= MONTH { + let months = time_difference / MONTH; + (months, if months == 1 { "month" } else { "months" }) + } else if time_difference >= DAY { + let days = time_difference / DAY; + (days, if days == 1 { "day" } else { "days" }) + } else if time_difference >= HOUR { + let hours = time_difference / HOUR; + (hours, if hours == 1 { "hour" } else { "hours" }) + } else if time_difference >= MINUTE { + let minutes = time_difference / MINUTE; + (minutes, if minutes == 1 { "minute" } else { "minutes" }) + } else { + let seconds = time_difference / SECOND; + (seconds, if seconds == 1 { "second" } else { "seconds" }) + }; + let value = value.to_string(); + + let label = if time_passed.is_positive() { + "ago" + } else { + "from now" + }; + + let mut relative_time = String::with_capacity(value.len() + 1 + unit.len() + 1 + label.len()); + relative_time.push_str(&value); + relative_time.push(' '); + relative_time.push_str(unit); + relative_time.push(' '); + relative_time.push_str(label); + relative_time +} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2e15dcdcc77c..c1d1a46af952 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -10,6 +10,7 @@ use helix_stdx::{ rope::{self, RopeSliceExt}, }; use helix_vcs::{FileChange, Hunk}; +use helix_view::document::LineBlameError; pub use lsp::*; use tui::{ text::{Span, Spans}, @@ -596,6 +597,7 @@ impl MappableCommand { extend_to_word, "Extend to a two-character label", goto_next_tabstop, "goto next snippet placeholder", goto_prev_tabstop, "goto next snippet placeholder", + blame_line, "Show blame for the current line", ); } @@ -3470,6 +3472,54 @@ fn insert_at_line_start(cx: &mut Context) { insert_with_indent(cx, IndentFallbackPos::LineStart); } +pub(crate) fn blame_line_impl(editor: &mut Editor, doc: DocumentId, cursor_line: u32) { + let inline_blame_config = &editor.config().inline_blame; + let Some(doc) = editor.document(doc) else { + return; + }; + let line_blame = match doc.line_blame(cursor_line, &inline_blame_config.format) { + result + if (result.is_ok() && doc.is_blame_potentially_out_of_date) + || matches!(result, Err(LineBlameError::NotReadyYet) if inline_blame_config.behaviour + == helix_view::editor::InlineBlameBehaviour::Disabled) => + { + if let Some(path) = doc.path() { + let tx = editor.handlers.blame.clone(); + helix_event::send_blocking( + &tx, + helix_view::handlers::BlameEvent { + path: path.to_path_buf(), + doc_id: doc.id(), + line: Some(cursor_line), + }, + ); + editor.set_status(format!("Requested blame for {}...", path.display())); + let doc = doc_mut!(editor); + doc.is_blame_potentially_out_of_date = false; + } else { + editor.set_error("Could not get path of document"); + }; + return; + } + Ok(line_blame) => line_blame, + Err(err @ (LineBlameError::NotCommittedYet | LineBlameError::NotReadyYet)) => { + editor.set_status(err.to_string()); + return; + } + Err(err @ LineBlameError::NoFileBlame(_, _)) => { + editor.set_error(err.to_string()); + return; + } + }; + + editor.set_status(line_blame); +} + +fn blame_line(cx: &mut Context) { + let (view, doc) = current_ref!(cx.editor); + blame_line_impl(cx.editor, doc.id(), doc.cursor_line(view.id) as u32); +} + // `A` inserts at the end of each line with a selection. // If the line is empty, automatically indent. fn insert_at_line_end(cx: &mut Context) { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index e1c09a04dfc9..15792bc6628f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -14,6 +14,7 @@ use helix_stdx::path::home_dir; use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME}; use helix_view::editor::{CloseError, ConfigEvent}; use helix_view::expansion; +use helix_view::handlers::BlameEvent; use serde_json::Value; use ui::completers::{self, Completer}; @@ -1326,16 +1327,33 @@ fn reload(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyh } let scrolloff = cx.editor.config().scrolloff; + let inline_blame_behaviour = cx.editor.config().inline_blame.behaviour; let (view, doc) = current!(cx.editor); doc.reload(view, &cx.editor.diff_providers).map(|_| { view.ensure_cursor_in_view(doc, scrolloff); })?; + let doc_id = doc.id(); if let Some(path) = doc.path() { cx.editor .language_servers .file_event_handler .file_changed(path.clone()); } + + if doc.should_request_full_file_blame(inline_blame_behaviour) { + if let Some(path) = doc.path() { + helix_event::send_blocking( + &cx.editor.handlers.blame, + BlameEvent { + path: path.to_path_buf(), + doc_id, + line: None, + }, + ); + } + } + doc.is_blame_potentially_out_of_date = true; + Ok(()) } @@ -1362,6 +1380,8 @@ fn reload_all(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> }) .collect(); + let blame_behaviour = cx.editor.config().inline_blame.behaviour; + for (doc_id, view_ids) in docs_view_ids { let doc = doc_mut!(cx.editor, &doc_id); @@ -1389,6 +1409,20 @@ fn reload_all(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> view.ensure_cursor_in_view(doc, scrolloff); } } + + if doc.should_request_full_file_blame(blame_behaviour) { + if let Some(path) = doc.path() { + helix_event::send_blocking( + &cx.editor.handlers.blame, + BlameEvent { + path: path.to_path_buf(), + doc_id, + line: None, + }, + ); + } + } + doc.is_blame_potentially_out_of_date = true; } Ok(()) diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs index c7d71526c802..4686e6e71e48 100644 --- a/helix-term/src/handlers.rs +++ b/helix-term/src/handlers.rs @@ -10,9 +10,11 @@ use crate::handlers::signature_help::SignatureHelpHandler; pub use helix_view::handlers::Handlers; +use self::blame::BlameHandler; use self::document_colors::DocumentColorsHandler; mod auto_save; +pub mod blame; pub mod completion; mod diagnostics; mod document_colors; @@ -26,12 +28,14 @@ pub fn setup(config: Arc>) -> Handlers { let signature_hints = SignatureHelpHandler::new().spawn(); let auto_save = AutoSaveHandler::new().spawn(); let document_colors = DocumentColorsHandler::default().spawn(); + let blame = BlameHandler::default().spawn(); let handlers = Handlers { completions: helix_view::handlers::completion::CompletionHandler::new(event_tx), signature_hints, auto_save, document_colors, + blame, }; helix_view::handlers::register_hooks(&handlers); @@ -41,5 +45,6 @@ pub fn setup(config: Arc>) -> Handlers { diagnostics::register_hooks(&handlers); snippet::register_hooks(&handlers); document_colors::register_hooks(&handlers); + blame::register_hooks(&handlers); handlers } diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs new file mode 100644 index 000000000000..6a35859f834c --- /dev/null +++ b/helix-term/src/handlers/blame.rs @@ -0,0 +1,94 @@ +use std::time::Duration; + +use helix_event::register_hook; +use helix_vcs::FileBlame; +use helix_view::{ + editor::InlineBlameBehaviour, + events::DocumentDidOpen, + handlers::{BlameEvent, Handlers}, + DocumentId, +}; +use tokio::{sync::oneshot, time::Instant}; + +use crate::job; + +#[derive(Default)] +pub struct BlameHandler { + worker: Option>>, + doc_id: DocumentId, + show_blame_for_line_in_statusline: Option, +} + +impl helix_event::AsyncHook for BlameHandler { + type Event = BlameEvent; + + fn handle_event( + &mut self, + event: Self::Event, + _timeout: Option, + ) -> Option { + if let Some(worker) = &mut self.worker { + if worker.try_recv().is_ok() { + self.finish_debounce(); + return None; + } + } + + self.doc_id = event.doc_id; + self.show_blame_for_line_in_statusline = event.line; + let (tx, rx) = oneshot::channel(); + + tokio::spawn(async move { + let result = FileBlame::try_new(event.path); + let _ = tx.send(result); + }); + + self.worker = Some(rx); + + Some(Instant::now() + Duration::from_millis(50)) + } + + fn finish_debounce(&mut self) { + let doc_id = self.doc_id; + let line_blame = self.show_blame_for_line_in_statusline; + if let Some(worker) = self.worker.take() { + tokio::spawn(async move { + let Ok(result) = worker.await else { + return; + }; + + job::dispatch(move |editor, _| { + let Some(doc) = editor.document_mut(doc_id) else { + return; + }; + doc.file_blame = Some(result); + if editor.config().inline_blame.behaviour == InlineBlameBehaviour::Disabled { + if let Some(line) = line_blame { + crate::commands::blame_line_impl(editor, doc_id, line); + } else { + editor.set_status("Blame for this file is now available") + } + } + }) + .await; + }); + } + } +} + +pub(super) fn register_hooks(handlers: &Handlers) { + let tx = handlers.blame.clone(); + register_hook!(move |event: &mut DocumentDidOpen<'_>| { + if event.editor.config().inline_blame.behaviour != InlineBlameBehaviour::Disabled { + helix_event::send_blocking( + &tx, + BlameEvent { + path: event.path.to_path_buf(), + doc_id: event.doc, + line: None, + }, + ); + } + Ok(()) + }); +} diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index e160b2246b1e..63d09ffbdf9d 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -289,6 +289,7 @@ pub fn default() -> HashMap { "C" => toggle_block_comments, "A-c" => toggle_line_comments, "?" => command_palette, + "B" => blame_line, }, "z" => { "View" "z" | "c" => align_view_center, diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 6be5657477bc..739f109c8f7a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -25,7 +25,7 @@ use helix_core::{ use helix_view::{ annotations::diagnostics::DiagnosticFilter, document::{Mode, SCRATCH_BUFFER_NAME}, - editor::{CompleteAction, CursorShapeConfig}, + editor::{CompleteAction, CursorShapeConfig, InlineBlameBehaviour}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, @@ -35,6 +35,8 @@ use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc}; use tui::{buffer::Buffer as Surface, text::Span}; +use super::text_decorations::blame::InlineBlame; + pub struct EditorView { pub keymaps: Keymaps, on_next_key: Option<(OnKeyCallback, OnKeyCallbackKind)>, @@ -201,6 +203,24 @@ impl EditorView { inline_diagnostic_config, config.end_of_line_diagnostics, )); + + if config.inline_blame.behaviour == InlineBlameBehaviour::Visible { + let cursor_line_idx = doc.cursor_line(view.id); + + // do not render inline blame for empty lines to reduce visual noise + if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { + if let Ok(line_blame) = + doc.line_blame(cursor_line_idx as u32, &config.inline_blame.format) + { + decorations.add_decoration(InlineBlame::new( + theme, + cursor_line_idx, + line_blame, + )); + }; + } + } + render_document( surface, inner, diff --git a/helix-term/src/ui/text_decorations.rs b/helix-term/src/ui/text_decorations.rs index 931ea431178c..f9d757ad8ce0 100644 --- a/helix-term/src/ui/text_decorations.rs +++ b/helix-term/src/ui/text_decorations.rs @@ -8,6 +8,7 @@ use crate::ui::document::{LinePos, TextRenderer}; pub use diagnostics::InlineDiagnostics; +pub mod blame; mod diagnostics; /// Decorations are the primary mechanism for extending the text rendering. diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs new file mode 100644 index 000000000000..49b0a31d7295 --- /dev/null +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -0,0 +1,67 @@ +use helix_core::Position; + +use helix_view::theme::Style; +use helix_view::Theme; + +use crate::ui::document::{LinePos, TextRenderer}; +use crate::ui::text_decorations::Decoration; + +pub struct InlineBlame { + message: String, + cursor: usize, + style: Style, +} + +impl InlineBlame { + pub fn new(theme: &Theme, cursor: usize, message: String) -> Self { + InlineBlame { + style: theme.get("ui.virtual.inline-blame"), + message, + cursor, + } + } +} + +impl Decoration for InlineBlame { + fn render_virt_lines( + &mut self, + renderer: &mut TextRenderer, + pos: LinePos, + virt_off: Position, + ) -> Position { + // do not draw inline blame for lines other than the cursor line + if self.cursor != pos.doc_line { + return Position::new(0, 0); + } + + // where the line in the document ends + let end_of_line = virt_off.col as u16; + // length of line in the document + // draw the git blame 6 spaces after the end of the line + let start_drawing_at = end_of_line + 6; + + let amount_of_characters_drawn = renderer + .column_in_bounds(start_drawing_at as usize, 1) + .then(|| { + // the column where we stop drawing the blame + let stopped_drawing_at = renderer + .set_string_truncated( + renderer.viewport.x + start_drawing_at, + pos.visual_line, + &self.message, + renderer.viewport.width.saturating_sub(start_drawing_at) as usize, + |_| self.style, + true, + false, + ) + .0; + + let line_length = end_of_line - renderer.offset.col as u16; + + stopped_drawing_at - line_length + }) + .unwrap_or_default(); + + Position::new(0, amount_of_characters_drawn as usize) + } +} diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index c0812242125a..6624cb94c58a 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -14,12 +14,13 @@ homepage.workspace = true [dependencies] helix-core = { path = "../helix-core" } helix-event = { path = "../helix-event" } +helix-stdx = { path = "../helix-stdx" } tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] } parking_lot.workspace = true arc-swap = { version = "1.7.1" } -gix = { version = "0.70.0", features = ["attributes", "status"], default-features = false, optional = true } +gix = { version = "0.70.0", features = ["attributes", "status", "blame", "parallel"], default-features = false, optional = true } imara-diff = "0.1.8" anyhow = "1" diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index b8ddd79fa921..7e76ab7cf724 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -1,11 +1,11 @@ use anyhow::{bail, Context, Result}; use arc_swap::ArcSwap; +use gix::bstr::ByteSlice as _; use gix::filter::plumbing::driver::apply::Delay; use std::io::Read; use std::path::Path; use std::sync::Arc; -use gix::bstr::ByteSlice; use gix::diff::Rewrites; use gix::dir::entry::Status; use gix::objs::tree::EntryKind; @@ -22,6 +22,8 @@ use crate::FileChange; #[cfg(test)] mod test; +pub mod blame; + #[inline] fn get_repo_dir(file: &Path) -> Result<&Path> { file.parent().context("file has no parent directory") diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs new file mode 100644 index 000000000000..70e630bcc6ee --- /dev/null +++ b/helix-vcs/src/git/blame.rs @@ -0,0 +1,632 @@ +use anyhow::Context as _; +use anyhow::Result; +use std::collections::HashMap; +use std::path::PathBuf; + +use crate::DiffHandle; + +use super::{get_repo_dir, open_repo}; + +/// Stores information about the blame for a file +#[derive(Debug)] +pub struct FileBlame { + /// A map from line numbers to commit IDs + blame: HashMap, + /// The owning repository for this file's `ObjectId`s + repo: gix::ThreadSafeRepository, +} + +impl FileBlame { + /// Get the blame information corresponing to a line in file and diff for that line + /// + /// returns `None` if the line is part of an insertion, as the blame for that line would not + /// be meaningful + #[inline] + pub fn blame_for_line(&self, line: u32, diff_handle: Option<&DiffHandle>) -> Option { + let (inserted_lines, removed_lines) = diff_handle.map_or( + // in theory there can be situations where we don't have the diff for a file + // but we have the blame. In this case, we can just act like there is no diff + Some((0, 0)), + |diff_handle| { + // Compute the amount of lines inserted and deleted before the `line` + // This information is needed to accurately transform the state of the + // file in the file system into what gix::blame knows about (gix::blame only + // knows about commit history, it does not know about uncommitted changes) + diff_handle + .load() + .hunks_intersecting_line_ranges(std::iter::once((0, line as usize))) + .try_fold( + (0, 0), + |(total_inserted_lines, total_deleted_lines), hunk| { + // check if the line intersects the hunk's `after` (which represents + // inserted lines) + (hunk.after.start > line || hunk.after.end <= line).then_some(( + total_inserted_lines + (hunk.after.end - hunk.after.start), + total_deleted_lines + (hunk.before.end - hunk.before.start), + )) + }, + ) + }, + )?; + + Some(self.blame_for_line_inserted_removed(line, inserted_lines, removed_lines)) + } + + // this is a separate function for use in Tests + #[inline] + fn blame_for_line_inserted_removed( + &self, + line: u32, + inserted_lines: u32, + removed_lines: u32, + ) -> LineBlame { + // Because gix_blame doesn't care about stuff that is not commited, we have to "normalize" the + // line number to account for uncommited code. + // + // You'll notice that blame_line can be 0 when, for instance we have: + // - removed 0 lines + // - added 10 lines + // - cursor_line is 8 + // + // So when our cursor is on the 10th added line or earlier, blame_line will be 0. This means + // the blame will be incorrect. But that's fine, because when the cursor_line is on some hunk, + // we can show to the user nothing at all. This is detected in the editor + let blame_line = line.saturating_sub(inserted_lines) + removed_lines; + let repo = self.repo.to_thread_local(); + + let commit = self + .blame + .get(&blame_line) + .and_then(|obj| repo.find_commit(*obj).ok()); + let message = commit.as_ref().and_then(|c| c.message().ok()); + let author = commit.as_ref().and_then(|c| c.author().ok()); + + LineBlame { + commit_hash: commit + .as_ref() + .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), + author_name: author.map(|a| a.name.to_string()), + author_email: author.map(|a| a.email.to_string()), + commit_date: author.map(|a| a.time.format(gix::date::time::format::SHORT)), + commit_message: message.as_ref().map(|msg| msg.title.to_string()), + commit_body: message + .as_ref() + .and_then(|msg| msg.body.map(|body| body.to_string())), + time_ago: author + .map(|a| helix_stdx::time::format_relative_time(a.time.seconds, a.time.offset)), + } + } + + /// Compute blame for this file + pub fn try_new(file: PathBuf) -> Result { + let thread_safe_repo = + open_repo(get_repo_dir(&file)?).context("Failed to open git repo")?; + let repo = thread_safe_repo.to_thread_local(); + let head = repo.head()?.peel_to_commit_in_place()?.id; + + // TODO: this iterator has a performane issue for large repos + // It was replaced in a new (yet unreleased) version of `gix`. + // + // Update to the new version once it releases. + // + // More info: https://github.com/helix-editor/helix/pull/13133#discussion_r2008611830 + let traverse = gix::traverse::commit::topo::Builder::from_iters( + &repo.objects, + [head], + None::>, + ) + .build()?; + + let mut resource_cache = repo.diff_resource_cache_for_tree_diff()?; + let file_blame = gix::blame::file( + &repo.objects, + traverse.into_iter(), + &mut resource_cache, + // bstr always uses unix separators + &gix::path::to_unix_separators_on_windows(gix::path::try_into_bstr( + file.strip_prefix( + repo.path() + .parent() + .context("Could not get the parent path of the repo")?, + )?, + )?), + None, + )? + .entries; + + Ok(Self { + blame: file_blame + .into_iter() + .flat_map(|blame| { + (blame.start_in_blamed_file..blame.start_in_blamed_file + blame.len.get()) + .map(move |i| (i, blame.commit_id)) + }) + .collect(), + repo: thread_safe_repo, + }) + } +} + +#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug)] +pub struct LineBlame { + commit_hash: Option, + author_name: Option, + author_email: Option, + commit_date: Option, + commit_message: Option, + commit_body: Option, + time_ago: Option, +} + +impl LineBlame { + /// Longest variable is: `time-ago` (and `message`) + const LONGEST_VARIABLE_LENGTH: usize = 7; + /// # Returns + /// + /// None => Invalid variable + /// Some(None) => Valid variable, but is empty + #[inline] + fn get_variable(&self, var: &str) -> Option> { + Some( + // if adding new variables, update `Self::LONGEST_VARIABLE_LENGTH` + match var { + "commit" => &self.commit_hash, + "author" => &self.author_name, + "date" => &self.commit_date, + "message" => &self.commit_message, + "email" => &self.author_email, + "body" => &self.commit_body, + "time-ago" => &self.time_ago, + _ => return None, + } + .as_deref(), + ) + } + + /// Parse the user's blame format + #[inline] + pub fn parse_format(&self, format: &str) -> String { + let mut line_blame = String::new(); + let mut content_before_variable = String::with_capacity(format.len()); + + let mut chars = format.char_indices().peekable(); + // in all cases, when any of the variables is empty we exclude the content before the variable + // However, if the variable is the first and it is empty - then exclude the content after the variable + let mut exclude_content_after_variable = false; + while let Some((ch_idx, ch)) = chars.next() { + if ch == '{' { + let mut variable = String::with_capacity(Self::LONGEST_VARIABLE_LENGTH); + // eat all characters until the end + while let Some((_, ch)) = chars.next_if(|(_, ch)| *ch != '}') { + variable.push(ch); + } + // eat the '}' if it was found + let has_closing = chars.next().is_some(); + + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum Variable<'a> { + Valid(&'a str), + Invalid(&'a str), + Empty, + } + + let variable_value = self.get_variable(&variable).map_or_else( + || { + // Invalid variable. So just add whatever we parsed before. + // The length of the variable, including opening and optionally + // closing curly braces + let variable_len = 1 + variable.len() + has_closing as usize; + + Variable::Invalid(&format[ch_idx..ch_idx + variable_len]) + }, + |s| s.map(Variable::Valid).unwrap_or(Variable::Empty), + ); + + match variable_value { + Variable::Invalid(value) | Variable::Valid(value) => { + if exclude_content_after_variable { + // don't push anything. + exclude_content_after_variable = false; + } else { + line_blame.push_str(&content_before_variable); + } + line_blame.push_str(value); + } + Variable::Empty => { + if line_blame.is_empty() { + // exclude content AFTER this variable (at next iteration of the loop, + // we'll exclude the content before a valid variable) + exclude_content_after_variable = true; + } else { + // exclude content BEFORE this variable + // also just don't add anything. + } + } + } + + // we've consumed the content before the variable so just get rid of it and + // make space for new + content_before_variable.drain(..); + } else { + content_before_variable.push(ch); + } + } + + line_blame + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::git::test::create_commit_with_message; + use crate::git::test::empty_git_repo; + use std::fs::File; + + /// describes how a line was modified + #[derive(PartialEq, PartialOrd, Ord, Eq)] + enum LineDiff { + /// this line is added + Insert, + /// this line is deleted + Delete, + /// no changes for this line + None, + } + + /// checks if the first argument is `no_commit` or not + macro_rules! no_commit_flag { + (no_commit, $commit_msg:literal) => { + false + }; + (, $commit_msg:literal) => { + true + }; + ($any:tt, $commit_msg:literal) => { + compile_error!(concat!( + "expected `no_commit` or nothing for commit ", + $commit_msg + )) + }; + } + + /// checks if the first argument is `insert` or `delete` + macro_rules! line_diff_flag { + (insert, $commit_msg:literal, $line:expr) => { + LineDiff::Insert + }; + (delete, $commit_msg:literal, $line:expr) => { + LineDiff::Delete + }; + (, $commit_msg:literal, $line:expr) => { + LineDiff::None + }; + ($any:tt, $commit_msg:literal, $line:expr) => { + compile_error!(concat!( + "expected `insert`, `delete` or nothing for commit ", + $commit_msg, + " line ", + $line + )) + }; + } + + /// This macro exists because we can't pass a `match` statement into `concat!` + /// we would like to exclude any lines that are `delete` + macro_rules! line_diff_flag_str { + (insert, $commit_msg:literal, $line:expr) => { + concat!($line, newline_literal!()) + }; + (delete, $commit_msg:literal, $line:expr) => { + "" + }; + (, $commit_msg:literal, $line:expr) => { + concat!($line, newline_literal!()) + }; + ($any:tt, $commit_msg:literal, $line:expr) => { + compile_error!(concat!( + "expected `insert`, `delete` or nothing for commit ", + $commit_msg, + " line ", + $line + )) + }; + } + + #[cfg(windows)] + macro_rules! newline_literal { + () => { + "\r\n" + }; + } + #[cfg(not(windows))] + macro_rules! newline_literal { + () => { + "\n" + }; + } + + /// Helper macro to create a history of the same file being modified. + macro_rules! assert_line_blame_progress { + ( + $( + // a unique identifier for the commit, other commits must not use this + // If `no_commit` option is used, use the identifier of the previous commit + $commit_msg:literal + // must be `no_commit` if exists. + // If exists, this block won't be committed + $($no_commit:ident)? => + $( + // contents of a line in the file + $line:literal + // what commit identifier we are expecting for this line + $($expected:literal)? + // must be `insert` or `delete` if exists + // if exists, must be used with `no_commit` + // - `insert`: this line is added + // - `delete`: this line is deleted + $($line_diff:ident)? + ),+ + );+ + $(;)? + ) => {{ + use std::fs::OpenOptions; + use std::io::Write; + + let repo = empty_git_repo(); + let file = repo.path().join("file.txt"); + File::create(&file).expect("could not create file"); + + $( + let file_content = concat!( + $( + line_diff_flag_str!($($line_diff)?, $commit_msg, $line), + )* + ); + eprintln!("at commit {}:\n\n{file_content}", stringify!($commit_msg)); + + let mut f = OpenOptions::new() + .write(true) + .truncate(true) + .open(&file) + .unwrap(); + + f.write_all(file_content.as_bytes()).unwrap(); + + let should_commit = no_commit_flag!($($no_commit)?, $commit_msg); + if should_commit { + create_commit_with_message(repo.path(), true, stringify!($commit_msg)); + } + + let mut line_number = 0; + let mut added_lines = 0; + let mut removed_lines = 0; + + $( + let line_diff_flag = line_diff_flag!($($line_diff)?, $commit_msg, $line); + #[allow(unused_assignments)] + match line_diff_flag { + LineDiff::Insert => added_lines += 1, + LineDiff::Delete => removed_lines += 1, + LineDiff::None => () + } + // completely skip lines that are marked as `delete` + if line_diff_flag != LineDiff::Delete { + // if there is no $expected, then we don't care what blame_line returns + // because we won't show it to the user. + $( + let blame_result = + FileBlame::try_new(file.clone()) + .unwrap() + .blame_for_line_inserted_removed(line_number, added_lines, removed_lines) + .commit_message; + + assert_eq!( + blame_result, + Some(concat!(stringify!($expected), newline_literal!()).to_owned()), + "Blame mismatch\nat commit: {}\nat line: {}\nline contents: {}\nexpected commit: {}\nbut got commit: {}", + $commit_msg, + line_number, + file_content + .lines() + .nth(line_number.try_into().unwrap()) + .unwrap(), + stringify!($expected), + blame_result + .as_ref() + .map(|blame| blame.trim_end()) + .unwrap_or("") + ); + )? + #[allow(unused_assignments)] + { + line_number += 1; + } + } + )* + )* + }}; + } + + // For some reasons the CI is failing on windows with the message "Commits not found". + // The created temporary repository has no commits... But this is not an issue on unix. + // There is nothing platform-specific in this implementation. This is a problem only + // for tests on Windows. + // As such it should be fine to disable this test in Windows. + // As long as these tests pass on other platforms, on Windows it will work too. + #[cfg(not(windows))] + #[test] + pub fn blamed_lines() { + assert_line_blame_progress! { + // initialize + 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 + 4 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 + 4 no_commit => + " six" insert, + " three" insert, + "fn main() {" 1, + " five" insert, + " four" insert, + " two" 3, + " five" insert, + " four" insert, + "}" 1, + " five" insert, + " four" insert; + // committing all of those insertions should recognize that they are + // from the current commit, while still keeping the information about + // previous commits + 5 => + " six" 5, + " three" 5, + "fn main() {" 1, + " five" 5, + " four" 5, + " two" 3, + " five" 5, + " four" 5, + "}" 1, + " five" 5, + " four" 5; + // several lines deleted + 5 no_commit => + " six" 5, + " three" 5, + "fn main() {" delete, + " five" delete, + " four" delete, + " two" delete, + " five" delete, + " four" 5, + "}" 1, + " five" 5, + " four" 5; + // committing the deleted changes + 6 => + " six" 5, + " three" 5, + " four" 5, + "}" 1, + " five" 5, + " four" 5; + // mixing inserts with deletes + 6 no_commit => + " six" delete, + " 2" insert, + " three" delete, + " four" 5, + " 1" insert, + "}" 1, + "]" insert, + " five" delete, + " four" 5; + // committing inserts and deletes + 7 => + " 2" 7, + " four" 5, + " 1" 7, + "}" 1, + "]" 7, + " four" 5; + }; + } + + fn bob() -> LineBlame { + LineBlame { + commit_hash: Some("f14ab1cf".to_owned()), + author_name: Some("Bob TheBuilder".to_owned()), + author_email: Some("bob@bob.com".to_owned()), + commit_date: Some("2028-01-10".to_owned()), + commit_message: Some("feat!: extend house".to_owned()), + commit_body: Some("BREAKING CHANGE: Removed door".to_owned()), + time_ago: None, + } + } + + #[test] + pub fn inline_blame_format_parser() { + let format = "{author}, {date} • {message} • {commit}"; + + assert_eq!( + bob().parse_format(format), + "Bob TheBuilder, 2028-01-10 • feat!: extend house • f14ab1cf".to_owned() + ); + assert_eq!( + LineBlame { + author_name: None, + ..bob() + } + .parse_format(format), + "2028-01-10 • feat!: extend house • f14ab1cf".to_owned() + ); + assert_eq!( + LineBlame { + commit_date: None, + ..bob() + } + .parse_format(format), + "Bob TheBuilder • feat!: extend house • f14ab1cf".to_owned() + ); + assert_eq!( + LineBlame { + commit_message: None, + author_email: None, + ..bob() + } + .parse_format(format), + "Bob TheBuilder, 2028-01-10 • f14ab1cf".to_owned() + ); + assert_eq!( + LineBlame { + commit_hash: None, + ..bob() + } + .parse_format(format), + "Bob TheBuilder, 2028-01-10 • feat!: extend house".to_owned() + ); + assert_eq!( + LineBlame { + commit_date: None, + author_name: None, + ..bob() + } + .parse_format(format), + "feat!: extend house • f14ab1cf".to_owned() + ); + assert_eq!( + LineBlame { + author_name: None, + commit_message: None, + ..bob() + } + .parse_format(format), + "2028-01-10 • f14ab1cf".to_owned() + ); + } +} diff --git a/helix-vcs/src/git/test.rs b/helix-vcs/src/git/test.rs index 164040f50cd7..c758c80b03ff 100644 --- a/helix-vcs/src/git/test.rs +++ b/helix-vcs/src/git/test.rs @@ -4,11 +4,11 @@ use tempfile::TempDir; use crate::git; -fn exec_git_cmd(args: &str, git_dir: &Path) { +pub fn exec_git_cmd(args: &[&str], git_dir: &Path) { let res = Command::new("git") .arg("-C") .arg(git_dir) // execute the git command in this directory - .args(args.split_whitespace()) + .args(args) .env_remove("GIT_DIR") .env_remove("GIT_ASKPASS") .env_remove("SSH_ASKPASS") @@ -25,26 +25,30 @@ fn exec_git_cmd(args: &str, git_dir: &Path) { .env("GIT_CONFIG_KEY_1", "init.defaultBranch") .env("GIT_CONFIG_VALUE_1", "main") .output() - .unwrap_or_else(|_| panic!("`git {args}` failed")); + .unwrap_or_else(|_| panic!("`git {args:?}` failed")); if !res.status.success() { println!("{}", String::from_utf8_lossy(&res.stdout)); eprintln!("{}", String::from_utf8_lossy(&res.stderr)); - panic!("`git {args}` failed (see output above)") + panic!("`git {args:?}` failed (see output above)") } } -fn create_commit(repo: &Path, add_modified: bool) { +pub fn create_commit(repo: &Path, add_modified: bool) { + create_commit_with_message(repo, add_modified, "commit") +} + +pub fn create_commit_with_message(repo: &Path, add_modified: bool, message: &str) { if add_modified { - exec_git_cmd("add -A", repo); + exec_git_cmd(&["add", "-A"], repo); } - exec_git_cmd("commit -m message", repo); + exec_git_cmd(&["commit", "-m", message], repo); } -fn empty_git_repo() -> TempDir { +pub fn empty_git_repo() -> TempDir { let tmp = tempfile::tempdir().expect("create temp dir for git testing"); - exec_git_cmd("init", tmp.path()); - exec_git_cmd("config user.email test@helix.org", tmp.path()); - exec_git_cmd("config user.name helix-test", tmp.path()); + exec_git_cmd(&["init"], tmp.path()); + exec_git_cmd(&["config", "user.email", "test@helix.org"], tmp.path()); + exec_git_cmd(&["config", "user.name", "helix-test"], tmp.path()); tmp } diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs index 539be779a900..33078147ecf6 100644 --- a/helix-vcs/src/lib.rs +++ b/helix-vcs/src/lib.rs @@ -7,6 +7,7 @@ use std::{ #[cfg(feature = "git")] mod git; +pub use git::blame::FileBlame; mod diff; @@ -16,7 +17,7 @@ mod status; pub use status::FileChange; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct DiffProviderRegistry { providers: Vec, } @@ -84,7 +85,7 @@ impl Default for DiffProviderRegistry { /// cloning [DiffProviderRegistry] as `Clone` cannot be used in trait objects. /// /// `Copy` is simply to ensure the `clone()` call is the simplest it can be. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum DiffProvider { #[cfg(feature = "git")] Git, diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 41c9ee1ef6e4..2c2e57fdafe7 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -42,6 +42,7 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction, }; +use crate::editor::InlineBlameBehaviour; use crate::{ editor::Config, events::{DocumentDidChange, SelectionDidChange}, @@ -196,6 +197,10 @@ pub struct Document { diff_handle: Option, version_control_head: Option>>>, + /// Contains blame information for each line in the file + /// We store the Result because when we access the blame directly we want to log the error + /// But if it is in the background we are just going to ignore the error + pub file_blame: Option>, // when document was used for most-recent-used buffer picker pub focused_at: std::time::Instant, @@ -207,6 +212,8 @@ pub struct Document { // NOTE: ideally this would live on the handler for color swatches. This is blocked on a // large refactor that would make `&mut Editor` available on the `DocumentDidChange` event. pub color_swatch_controller: TaskController, + // when fetching blame on-demand, if this field is `true` we request the blame for this document again + pub is_blame_potentially_out_of_date: bool, } #[derive(Debug, Clone, Default)] @@ -283,6 +290,16 @@ pub struct DocumentInlayHintsId { pub last_line: usize, } +#[derive(Debug, thiserror::Error)] +pub enum LineBlameError<'a> { + #[error("Not committed yet")] + NotCommittedYet, + #[error("Unable to get blame for line {0}: {1}")] + NoFileBlame(u32, &'a anyhow::Error), + #[error("The blame for this file is not ready yet. Try again in a few seconds")] + NotReadyYet, +} + use std::{fmt, mem}; impl fmt::Debug for Document { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -719,6 +736,19 @@ impl Document { jump_labels: HashMap::new(), color_swatches: None, color_swatch_controller: TaskController::new(), + file_blame: None, + is_blame_potentially_out_of_date: false, + } + } + + pub fn should_request_full_file_blame( + &mut self, + blame_behaviour: InlineBlameBehaviour, + ) -> bool { + if blame_behaviour == InlineBlameBehaviour::Disabled { + self.is_blame_potentially_out_of_date + } else { + true } } @@ -1310,6 +1340,13 @@ impl Document { Range::new(0, 1).grapheme_aligned(self.text().slice(..)) } + /// Get the line of cursor for the primary selection + pub fn cursor_line(&self, view_id: ViewId) -> usize { + let text = self.text(); + let selection = self.selection(view_id); + text.char_to_line(selection.primary().cursor(text.slice(..))) + } + /// Reset the view's selection on this document to the /// [origin](Document::origin) cursor. pub fn reset_selection(&mut self, view_id: ViewId) { @@ -1541,6 +1578,19 @@ impl Document { self.apply_inner(transaction, view_id, true) } + /// Get the line blame for this view + pub fn line_blame(&self, cursor_line: u32, format: &str) -> Result { + Ok(self + .file_blame + .as_ref() + .ok_or(LineBlameError::NotReadyYet)? + .as_ref() + .map_err(|err| LineBlameError::NoFileBlame(cursor_line.saturating_add(1), err))? + .blame_for_line(cursor_line, self.diff_handle()) + .ok_or(LineBlameError::NotCommittedYet)? + .parse_format(format)) + } + /// Apply a [`Transaction`] to the [`Document`] to change its text /// without notifying the language servers. This is useful for temporary transactions /// that must not influence the server. diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 27a985ac3d31..c82eba5368d5 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -172,6 +172,44 @@ impl Default for GutterLineNumbersConfig { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum InlineBlameBehaviour { + /// Do not show inline blame + /// + /// Loads blame for the file in the background when the document is + /// opened and request it again when it is `:reload`ed. + /// + /// This allows instantaneous access to line blame with `space + B` and when + /// `:toggle inline-blame.enable` but for the cost of consuming more + /// resources in the background + Background, + /// Do not show inline blame, and do not request it in the background + /// + /// When manually requesting the inline blame, it may take several seconds to appear. + Disabled, + /// Show the inline blame + Visible, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case", default, deny_unknown_fields)] +pub struct InlineBlameConfig { + /// Show inline blame for a line when cursor is on that line + pub behaviour: InlineBlameBehaviour, + /// How the inline blame should look like and the information it includes + pub format: String, +} + +impl Default for InlineBlameConfig { + fn default() -> Self { + Self { + behaviour: InlineBlameBehaviour::Disabled, + format: "{author}, {time-ago} • {message} • {commit}".to_owned(), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct FilePickerConfig { @@ -370,6 +408,8 @@ pub struct Config { /// Whether to read settings from [EditorConfig](https://editorconfig.org) files. Defaults to /// `true`. pub editor_config: bool, + /// Inline blame allows showing the latest commit that affected the line the cursor is on as virtual text + pub inline_blame: InlineBlameConfig, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -1016,6 +1056,7 @@ impl Default for Config { inline_diagnostics: InlineDiagnosticsConfig::default(), end_of_line_diagnostics: DiagnosticFilter::Disable, clipboard_provider: ClipboardProvider::default(), + inline_blame: InlineBlameConfig::default(), editor_config: true, } } @@ -1784,11 +1825,13 @@ impl Editor { doc.set_version_control_head(self.diff_providers.get_current_head_name(&path)); let id = self.new_document(doc); + self.launch_language_servers(id); helix_event::dispatch(DocumentDidOpen { editor: self, doc: id, + path: &path, }); id diff --git a/helix-view/src/events.rs b/helix-view/src/events.rs index 4a44beb3540c..89969642b311 100644 --- a/helix-view/src/events.rs +++ b/helix-view/src/events.rs @@ -7,7 +7,8 @@ use crate::{Document, DocumentId, Editor, ViewId}; events! { DocumentDidOpen<'a> { editor: &'a mut Editor, - doc: DocumentId + doc: DocumentId, + path: &'a std::path::PathBuf } DocumentDidChange<'a> { doc: &'a mut Document, diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs index 258ed89e5cec..e6a303c68cf8 100644 --- a/helix-view/src/handlers.rs +++ b/helix-view/src/handlers.rs @@ -16,12 +16,24 @@ pub enum AutoSaveEvent { LeftInsertMode, } +#[derive(Debug)] +pub struct BlameEvent { + /// The path for which we request blame + pub path: std::path::PathBuf, + /// Document for which the blame is requested + pub doc_id: DocumentId, + /// If this field is set, when we obtain the blame for the file we will + /// show blame for this line in the status line + pub line: Option, +} + pub struct Handlers { // only public because most of the actual implementation is in helix-term right now :/ pub completions: CompletionHandler, pub signature_hints: Sender, pub auto_save: Sender, pub document_colors: Sender, + pub blame: Sender, } impl Handlers { From 647615ddecccad396be9136c3bb0913c4d0890d3 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:31:01 +0000 Subject: [PATCH 02/55] perf: optimize obtaining blame for the same line _ fix: blame_line_impl _ _ _ _ _ --- helix-term/src/commands.rs | 8 ++- helix-vcs/src/git/blame.rs | 134 +++++++++++++++++++------------------ helix-view/src/document.rs | 61 ++++++++++++++--- 3 files changed, 125 insertions(+), 78 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c1d1a46af952..f8a29e1c339e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3472,9 +3472,9 @@ fn insert_at_line_start(cx: &mut Context) { insert_with_indent(cx, IndentFallbackPos::LineStart); } -pub(crate) fn blame_line_impl(editor: &mut Editor, doc: DocumentId, cursor_line: u32) { +pub(crate) fn blame_line_impl(editor: &mut Editor, doc_id: DocumentId, cursor_line: u32) { let inline_blame_config = &editor.config().inline_blame; - let Some(doc) = editor.document(doc) else { + let Some(doc) = editor.document(doc_id) else { return; }; let line_blame = match doc.line_blame(cursor_line, &inline_blame_config.format) { @@ -3494,7 +3494,9 @@ pub(crate) fn blame_line_impl(editor: &mut Editor, doc: DocumentId, cursor_line: }, ); editor.set_status(format!("Requested blame for {}...", path.display())); - let doc = doc_mut!(editor); + let doc = editor + .document_mut(doc_id) + .expect("exists since we return from the function earlier if it does not"); doc.is_blame_potentially_out_of_date = false; } else { editor.set_error("Could not get path of document"); diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 70e630bcc6ee..27887716dd09 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -1,65 +1,38 @@ use anyhow::Context as _; use anyhow::Result; +use std::cell::RefCell; use std::collections::HashMap; use std::path::PathBuf; -use crate::DiffHandle; - use super::{get_repo_dir, open_repo}; +/// Allows us to save compute resources when requesting blame for the same line +/// To go from an `ObjectId` (which represents a commit) to `LineBLame`, we have to perform some work. +/// +/// With this struct, we only do this work once. Getting `LineBlame` for the same line for the 2nd and subsequent +/// times is going to be free. This is important because we do this step on every render, in the main thread. +#[derive(Debug)] +enum LineBlameUnit { + /// The raw object id of the commit for a line. + /// It will take a bit of compute in order to obtain the `LineBlame` for it. + Unprocessed(gix::ObjectId), + /// Fully processed line blame information. + Processed(LineBlame), +} + /// Stores information about the blame for a file #[derive(Debug)] pub struct FileBlame { - /// A map from line numbers to commit IDs - blame: HashMap, + /// A map from line numbers to blame for that line + blame: RefCell>, /// The owning repository for this file's `ObjectId`s repo: gix::ThreadSafeRepository, } impl FileBlame { /// Get the blame information corresponing to a line in file and diff for that line - /// - /// returns `None` if the line is part of an insertion, as the blame for that line would not - /// be meaningful #[inline] - pub fn blame_for_line(&self, line: u32, diff_handle: Option<&DiffHandle>) -> Option { - let (inserted_lines, removed_lines) = diff_handle.map_or( - // in theory there can be situations where we don't have the diff for a file - // but we have the blame. In this case, we can just act like there is no diff - Some((0, 0)), - |diff_handle| { - // Compute the amount of lines inserted and deleted before the `line` - // This information is needed to accurately transform the state of the - // file in the file system into what gix::blame knows about (gix::blame only - // knows about commit history, it does not know about uncommitted changes) - diff_handle - .load() - .hunks_intersecting_line_ranges(std::iter::once((0, line as usize))) - .try_fold( - (0, 0), - |(total_inserted_lines, total_deleted_lines), hunk| { - // check if the line intersects the hunk's `after` (which represents - // inserted lines) - (hunk.after.start > line || hunk.after.end <= line).then_some(( - total_inserted_lines + (hunk.after.end - hunk.after.start), - total_deleted_lines + (hunk.before.end - hunk.before.start), - )) - }, - ) - }, - )?; - - Some(self.blame_for_line_inserted_removed(line, inserted_lines, removed_lines)) - } - - // this is a separate function for use in Tests - #[inline] - fn blame_for_line_inserted_removed( - &self, - line: u32, - inserted_lines: u32, - removed_lines: u32, - ) -> LineBlame { + pub fn blame_for_line(&self, line: u32, inserted_lines: u32, removed_lines: u32) -> LineBlame { // Because gix_blame doesn't care about stuff that is not commited, we have to "normalize" the // line number to account for uncommited code. // @@ -74,14 +47,19 @@ impl FileBlame { let blame_line = line.saturating_sub(inserted_lines) + removed_lines; let repo = self.repo.to_thread_local(); - let commit = self - .blame - .get(&blame_line) - .and_then(|obj| repo.find_commit(*obj).ok()); + let mut blame = self.blame.borrow_mut(); + let line_blame_unit = blame.get_mut(&blame_line); + + let commit = match line_blame_unit { + Some(LineBlameUnit::Unprocessed(object_id)) => repo.find_commit(*object_id).ok(), + Some(LineBlameUnit::Processed(line_blame)) => return line_blame.clone(), + None => None, + }; + let message = commit.as_ref().and_then(|c| c.message().ok()); let author = commit.as_ref().and_then(|c| c.author().ok()); - LineBlame { + let line_blame = LineBlame { commit_hash: commit .as_ref() .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), @@ -92,12 +70,19 @@ impl FileBlame { commit_body: message .as_ref() .and_then(|msg| msg.body.map(|body| body.to_string())), - time_ago: author - .map(|a| helix_stdx::time::format_relative_time(a.time.seconds, a.time.offset)), - } + time_stamp: author.map(|a| (a.time.seconds, a.time.offset)), + time_ago: None, + }; + + // we know that `line_blame_unit` here is not processed + if let Some(line_blame_unit) = line_blame_unit { + *line_blame_unit = LineBlameUnit::Processed(line_blame.clone()); + }; + + line_blame } - /// Compute blame for this file + /// Compute blame for this file (expensive) pub fn try_new(file: PathBuf) -> Result { let thread_safe_repo = open_repo(get_repo_dir(&file)?).context("Failed to open git repo")?; @@ -135,13 +120,15 @@ impl FileBlame { .entries; Ok(Self { - blame: file_blame - .into_iter() - .flat_map(|blame| { - (blame.start_in_blamed_file..blame.start_in_blamed_file + blame.len.get()) - .map(move |i| (i, blame.commit_id)) - }) - .collect(), + blame: RefCell::new( + file_blame + .into_iter() + .flat_map(|blame| { + (blame.start_in_blamed_file..blame.start_in_blamed_file + blame.len.get()) + .map(move |i| (i, LineBlameUnit::Unprocessed(blame.commit_id))) + }) + .collect(), + ), repo: thread_safe_repo, }) } @@ -155,18 +142,28 @@ pub struct LineBlame { commit_date: Option, commit_message: Option, commit_body: Option, + /// Used to compute `time-ago` + time_stamp: Option<(i64, i32)>, + /// This field is the only one that needs to be re-computed every time + /// we request the `LineBlame`. It exists here for lifetime purposes, so we can return + /// `&str` from `Self::get_variable`. + /// + /// This should only be set from within and never initialized. time_ago: Option, } impl LineBlame { /// Longest variable is: `time-ago` (and `message`) + // this is just to reduce allocation by a little bit by specifying the max size we would expect a + // variable to be up-front. This function is called every render. const LONGEST_VARIABLE_LENGTH: usize = 7; + /// # Returns /// /// None => Invalid variable /// Some(None) => Valid variable, but is empty #[inline] - fn get_variable(&self, var: &str) -> Option> { + fn get_variable(&mut self, var: &str) -> Option> { Some( // if adding new variables, update `Self::LONGEST_VARIABLE_LENGTH` match var { @@ -176,7 +173,13 @@ impl LineBlame { "message" => &self.commit_message, "email" => &self.author_email, "body" => &self.commit_body, - "time-ago" => &self.time_ago, + "time-ago" => { + let time_ago = self.time_stamp.map(|(utc_seconds, timezone_offset)| { + helix_stdx::time::format_relative_time(utc_seconds, timezone_offset) + }); + self.time_ago = time_ago; + &self.time_ago + } _ => return None, } .as_deref(), @@ -185,7 +188,7 @@ impl LineBlame { /// Parse the user's blame format #[inline] - pub fn parse_format(&self, format: &str) -> String { + pub fn parse_format(&mut self, format: &str) -> String { let mut line_blame = String::new(); let mut content_before_variable = String::with_capacity(format.len()); @@ -418,7 +421,7 @@ mod test { let blame_result = FileBlame::try_new(file.clone()) .unwrap() - .blame_for_line_inserted_removed(line_number, added_lines, removed_lines) + .blame_for_line(line_number, added_lines, removed_lines) .commit_message; assert_eq!( @@ -565,6 +568,7 @@ mod test { commit_date: Some("2028-01-10".to_owned()), commit_message: Some("feat!: extend house".to_owned()), commit_body: Some("BREAKING CHANGE: Removed door".to_owned()), + time_stamp: None, time_ago: None, } } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 2c2e57fdafe7..9c5437bcab89 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -198,7 +198,7 @@ pub struct Document { diff_handle: Option, version_control_head: Option>>>, /// Contains blame information for each line in the file - /// We store the Result because when we access the blame directly we want to log the error + /// We store the Result because when we access the blame manually we want to log the error /// But if it is in the background we are just going to ignore the error pub file_blame: Option>, @@ -1580,15 +1580,56 @@ impl Document { /// Get the line blame for this view pub fn line_blame(&self, cursor_line: u32, format: &str) -> Result { - Ok(self - .file_blame - .as_ref() - .ok_or(LineBlameError::NotReadyYet)? - .as_ref() - .map_err(|err| LineBlameError::NoFileBlame(cursor_line.saturating_add(1), err))? - .blame_for_line(cursor_line, self.diff_handle()) - .ok_or(LineBlameError::NotCommittedYet)? - .parse_format(format)) + // how many lines were inserted and deleted before the cursor line + let (inserted_lines, deleted_lines) = self + .diff_handle() + .map_or( + // in theory there can be situations where we don't have the diff for a file + // but we have the blame. In this case, we can just act like there is no diff + Some((0, 0)), + |diff_handle| { + // Compute the amount of lines inserted and deleted before the `line` + // This information is needed to accurately transform the state of the + // file in the file system into what gix::blame knows about (gix::blame only + // knows about commit history, it does not know about uncommitted changes) + diff_handle + .load() + .hunks_intersecting_line_ranges(std::iter::once((0, cursor_line as usize))) + .try_fold( + (0, 0), + |(total_inserted_lines, total_deleted_lines), hunk| { + // check if the line intersects the hunk's `after` (which represents + // inserted lines) + (hunk.after.start > cursor_line || hunk.after.end <= cursor_line) + .then_some(( + total_inserted_lines + (hunk.after.end - hunk.after.start), + total_deleted_lines + (hunk.before.end - hunk.before.start), + )) + }, + ) + }, + ) + .ok_or(LineBlameError::NotCommittedYet)?; + + let file_blame = match &self.file_blame { + None => return Err(LineBlameError::NotReadyYet), + Some(result) => match result { + Err(err) => { + return Err(LineBlameError::NoFileBlame( + // convert 0-based line into 1-based line + cursor_line.saturating_add(1), + err, + )); + } + Ok(file_blame) => file_blame, + }, + }; + + let line_blame = file_blame + .blame_for_line(cursor_line, inserted_lines, deleted_lines) + .parse_format(format); + + Ok(line_blame) } /// Apply a [`Transaction`] to the [`Document`] to change its text From 07c69c1e742caa8139ee115f9027ab3ef13b15df Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 24 Mar 2025 04:00:02 +0000 Subject: [PATCH 03/55] fix: update blame when editing config --- helix-term/src/application.rs | 6 ++++++ helix-term/src/events.rs | 3 ++- helix-term/src/handlers/blame.rs | 24 +++++++++++++++++++++++- helix-view/src/events.rs | 7 ++++++- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3bc32439565d..b97cb29e40e2 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -11,6 +11,7 @@ use helix_view::{ align_view, document::{DocumentOpenError, DocumentSavedEventResult}, editor::{ConfigEvent, EditorEvent}, + events::EditorConfigDidChange, graphics::Rect, theme, tree::Layout, @@ -364,6 +365,11 @@ impl Application { // the Application can apply it. ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); + helix_event::dispatch(EditorConfigDidChange { + old_config: &app_config.editor, + new_config: &editor_config, + editor: &mut self.editor, + }); app_config.editor = *editor_config; if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) { self.editor.set_error(err.to_string()); diff --git a/helix-term/src/events.rs b/helix-term/src/events.rs index 80f045cd7773..4e1161d14488 100644 --- a/helix-term/src/events.rs +++ b/helix-term/src/events.rs @@ -2,7 +2,7 @@ use helix_event::{events, register_event}; use helix_view::document::Mode; use helix_view::events::{ DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, DocumentDidOpen, DocumentFocusLost, - LanguageServerExited, LanguageServerInitialized, SelectionDidChange, + EditorConfigDidChange, LanguageServerExited, LanguageServerInitialized, SelectionDidChange, }; use crate::commands; @@ -20,6 +20,7 @@ pub fn register() { register_event::(); register_event::(); register_event::(); + register_event::(); register_event::(); register_event::(); register_event::(); diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index 6a35859f834c..93fdf4e3db11 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -4,7 +4,7 @@ use helix_event::register_hook; use helix_vcs::FileBlame; use helix_view::{ editor::InlineBlameBehaviour, - events::DocumentDidOpen, + events::{DocumentDidOpen, EditorConfigDidChange}, handlers::{BlameEvent, Handlers}, DocumentId, }; @@ -91,4 +91,26 @@ pub(super) fn register_hooks(handlers: &Handlers) { } Ok(()) }); + let tx = handlers.blame.clone(); + register_hook!(move |event: &mut EditorConfigDidChange<'_>| { + if event.old_config.inline_blame.behaviour == InlineBlameBehaviour::Disabled + && event.new_config.inline_blame.behaviour != InlineBlameBehaviour::Disabled + { + // request blame for all documents, since any of them could have + // outdated blame + for doc in event.editor.documents() { + if let Some(path) = doc.path() { + helix_event::send_blocking( + &tx, + BlameEvent { + path: path.to_path_buf(), + doc_id: doc.id(), + line: None, + }, + ); + } + } + } + Ok(()) + }); } diff --git a/helix-view/src/events.rs b/helix-view/src/events.rs index 89969642b311..58881d9effca 100644 --- a/helix-view/src/events.rs +++ b/helix-view/src/events.rs @@ -2,7 +2,7 @@ use helix_core::{ChangeSet, Rope}; use helix_event::events; use helix_lsp::LanguageServerId; -use crate::{Document, DocumentId, Editor, ViewId}; +use crate::{editor::Config, Document, DocumentId, Editor, ViewId}; events! { DocumentDidOpen<'a> { @@ -17,6 +17,11 @@ events! { changes: &'a ChangeSet, ghost_transaction: bool } + EditorConfigDidChange<'a> { + old_config: &'a Config, + new_config: &'a Config, + editor: &'a mut Editor + } DocumentDidClose<'a> { editor: &'a mut Editor, doc: Document From 8f0721f00aca257809a52af8c4bf8876053b6bbe Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 24 Mar 2025 16:07:19 +0000 Subject: [PATCH 04/55] use format! instead of preallocating this is more efficient apparently --- helix-stdx/src/time.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/helix-stdx/src/time.rs b/helix-stdx/src/time.rs index a7bb1a040ab8..cb72a9386093 100644 --- a/helix-stdx/src/time.rs +++ b/helix-stdx/src/time.rs @@ -71,11 +71,5 @@ pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String { "from now" }; - let mut relative_time = String::with_capacity(value.len() + 1 + unit.len() + 1 + label.len()); - relative_time.push_str(&value); - relative_time.push(' '); - relative_time.push_str(unit); - relative_time.push(' '); - relative_time.push_str(label); - relative_time + format!("{value} {unit} {label}") } From f54fdef099c5e7ae8094579dfc70489d20620835 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:46:36 +0000 Subject: [PATCH 05/55] refactor: remove extra layer of sync --- helix-term/src/handlers/blame.rs | 30 ++++++------------------------ helix-vcs/src/git/blame.rs | 8 ++++---- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index 93fdf4e3db11..218db731edcf 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -1,4 +1,4 @@ -use std::time::Duration; +use std::{mem, time::Duration}; use helix_event::register_hook; use helix_vcs::FileBlame; @@ -8,13 +8,13 @@ use helix_view::{ handlers::{BlameEvent, Handlers}, DocumentId, }; -use tokio::{sync::oneshot, time::Instant}; +use tokio::time::Instant; use crate::job; #[derive(Default)] pub struct BlameHandler { - worker: Option>>, + file_blame: Option>, doc_id: DocumentId, show_blame_for_line_in_statusline: Option, } @@ -27,36 +27,18 @@ impl helix_event::AsyncHook for BlameHandler { event: Self::Event, _timeout: Option, ) -> Option { - if let Some(worker) = &mut self.worker { - if worker.try_recv().is_ok() { - self.finish_debounce(); - return None; - } - } - self.doc_id = event.doc_id; self.show_blame_for_line_in_statusline = event.line; - let (tx, rx) = oneshot::channel(); - - tokio::spawn(async move { - let result = FileBlame::try_new(event.path); - let _ = tx.send(result); - }); - - self.worker = Some(rx); - + self.file_blame = Some(FileBlame::try_new(event.path)); Some(Instant::now() + Duration::from_millis(50)) } fn finish_debounce(&mut self) { let doc_id = self.doc_id; let line_blame = self.show_blame_for_line_in_statusline; - if let Some(worker) = self.worker.take() { + let result = mem::take(&mut self.file_blame); + if let Some(result) = result { tokio::spawn(async move { - let Ok(result) = worker.await else { - return; - }; - job::dispatch(move |editor, _| { let Some(doc) = editor.document_mut(doc_id) else { return; diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 27887716dd09..0b83bd1d8b21 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -1,6 +1,6 @@ use anyhow::Context as _; use anyhow::Result; -use std::cell::RefCell; +use parking_lot::Mutex; use std::collections::HashMap; use std::path::PathBuf; @@ -24,7 +24,7 @@ enum LineBlameUnit { #[derive(Debug)] pub struct FileBlame { /// A map from line numbers to blame for that line - blame: RefCell>, + blame: Mutex>, /// The owning repository for this file's `ObjectId`s repo: gix::ThreadSafeRepository, } @@ -47,7 +47,7 @@ impl FileBlame { let blame_line = line.saturating_sub(inserted_lines) + removed_lines; let repo = self.repo.to_thread_local(); - let mut blame = self.blame.borrow_mut(); + let mut blame = self.blame.lock(); let line_blame_unit = blame.get_mut(&blame_line); let commit = match line_blame_unit { @@ -120,7 +120,7 @@ impl FileBlame { .entries; Ok(Self { - blame: RefCell::new( + blame: Mutex::new( file_blame .into_iter() .flat_map(|blame| { From 7478d9e688e32cb24b38c558307ab88c78cc0472 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:55:05 +0000 Subject: [PATCH 06/55] refactor: extract as variable --- helix-term/src/handlers/blame.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index 218db731edcf..fdf53b8cc58b 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -75,9 +75,11 @@ pub(super) fn register_hooks(handlers: &Handlers) { }); let tx = handlers.blame.clone(); register_hook!(move |event: &mut EditorConfigDidChange<'_>| { - if event.old_config.inline_blame.behaviour == InlineBlameBehaviour::Disabled - && event.new_config.inline_blame.behaviour != InlineBlameBehaviour::Disabled - { + let has_enabled_inline_blame = event.old_config.inline_blame.behaviour + == InlineBlameBehaviour::Disabled + && event.new_config.inline_blame.behaviour != InlineBlameBehaviour::Disabled; + + if has_enabled_inline_blame { // request blame for all documents, since any of them could have // outdated blame for doc in event.editor.documents() { From 76a92aff2ff1873c0db0446c1568e3409e86be23 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:25:12 +0000 Subject: [PATCH 07/55] feat: `all-lines` option for inline blame --- book/src/editor.md | 3 ++- helix-term/src/ui/editor.rs | 20 ++++++++++++++++---- helix-term/src/ui/text_decorations/blame.rs | 18 +++++++++--------- helix-view/src/editor.rs | 6 ++++-- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 9958798ebd0d..29e1ac563990 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -170,7 +170,8 @@ The following statusline elements can be configured: | `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {message} • {commit}"` | The `behaviour` can be one of the following: -- `"visible"`: Inline blame is turned on. Virtual text will appear at the end of each non-empty line, showing information about the latest commit for that line. +- `"all-lines"`: Inline blame is turned on. Virtual text will appear at the end of each non-empty line, showing information about the latest commit for that line. +- `"cursor-line"`: Inline blame is turned on. Virtual text will appear at the end of the current cursor line, showing information about the latest commit for that line. - `"background"`: Inline blame is turned off, but the blame is still requested in the background when opening and reloading files. This will have zero impact on performance, but will use slightly more resources in the background. This allows blame for line (`space + B`) to be retrieved instantaneously with zero delay. - `"disabled"`: Inline blame is turned off, with no requests happening in the background. When you run `space + B` for the first time in a file, it will load the blame for this file. You may have to wait a little bit for the blame to become available, depending on the size of your repository. After it becomes available, for this file `space + B` will retrieve the blame for any line in this file with zero delay. If the file is reloaded, the process will repeat as the blame is potentially out of date and needs to be refreshed. diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 739f109c8f7a..faf85344cfd4 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -31,7 +31,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc}; +use std::{collections::HashMap, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc}; use tui::{buffer::Buffer as Surface, text::Span}; @@ -204,7 +204,7 @@ impl EditorView { config.end_of_line_diagnostics, )); - if config.inline_blame.behaviour == InlineBlameBehaviour::Visible { + if config.inline_blame.behaviour == InlineBlameBehaviour::CursorLine { let cursor_line_idx = doc.cursor_line(view.id); // do not render inline blame for empty lines to reduce visual noise @@ -214,11 +214,23 @@ impl EditorView { { decorations.add_decoration(InlineBlame::new( theme, - cursor_line_idx, - line_blame, + HashMap::from([(cursor_line_idx, line_blame)]), )); }; } + } else if config.inline_blame.behaviour == InlineBlameBehaviour::AllLines { + let blame_for_all_lines = (0..doc.text().len_lines()) + .filter_map(|line_idx| { + (doc.text().line(line_idx) != doc.line_ending.as_str()) + .then(|| { + doc.line_blame(line_idx as u32, &config.inline_blame.format) + .ok() + .map(|blame| (line_idx, blame)) + }) + .flatten() + }) + .collect(); + decorations.add_decoration(InlineBlame::new(theme, blame_for_all_lines)); } render_document( diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 49b0a31d7295..df2669c36330 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use helix_core::Position; use helix_view::theme::Style; @@ -7,17 +9,15 @@ use crate::ui::document::{LinePos, TextRenderer}; use crate::ui::text_decorations::Decoration; pub struct InlineBlame { - message: String, - cursor: usize, + lines: HashMap, style: Style, } impl InlineBlame { - pub fn new(theme: &Theme, cursor: usize, message: String) -> Self { + pub fn new(theme: &Theme, lines: HashMap) -> Self { InlineBlame { style: theme.get("ui.virtual.inline-blame"), - message, - cursor, + lines, } } } @@ -29,10 +29,10 @@ impl Decoration for InlineBlame { pos: LinePos, virt_off: Position, ) -> Position { - // do not draw inline blame for lines other than the cursor line - if self.cursor != pos.doc_line { + 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); - } + }; // where the line in the document ends let end_of_line = virt_off.col as u16; @@ -48,7 +48,7 @@ impl Decoration for InlineBlame { .set_string_truncated( renderer.viewport.x + start_drawing_at, pos.visual_line, - &self.message, + &blame, renderer.viewport.width.saturating_sub(start_drawing_at) as usize, |_| self.style, true, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c82eba5368d5..5d930c113abf 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -188,8 +188,10 @@ pub enum InlineBlameBehaviour { /// /// When manually requesting the inline blame, it may take several seconds to appear. Disabled, - /// Show the inline blame - Visible, + /// Show the inline blame on the cursor line + CursorLine, + /// Show the inline blame on every other line + AllLines, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] From ac0e677fae088ef4ccf252411857346c649656cd Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:34:01 +0000 Subject: [PATCH 08/55] chore: appease clippy --- helix-term/src/ui/text_decorations/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index df2669c36330..69a1d2ac60fc 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -48,7 +48,7 @@ impl Decoration for InlineBlame { .set_string_truncated( renderer.viewport.x + start_drawing_at, pos.visual_line, - &blame, + blame, renderer.viewport.width.saturating_sub(start_drawing_at) as usize, |_| self.style, true, From d34074af1b552858d1fe6fdfec270ed725311a5b Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 12:51:47 +0000 Subject: [PATCH 09/55] perf: do not render inline blame on invisible lines --- helix-term/src/ui/editor.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index faf85344cfd4..c99b6ad6ca46 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -219,15 +219,29 @@ impl EditorView { }; } } else if config.inline_blame.behaviour == InlineBlameBehaviour::AllLines { - let blame_for_all_lines = (0..doc.text().len_lines()) + let text = doc.text(); + let len_lines = 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); + + // 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| { - (doc.text().line(line_idx) != doc.line_ending.as_str()) - .then(|| { - doc.line_blame(line_idx as u32, &config.inline_blame.format) - .ok() - .map(|blame| (line_idx, blame)) - }) - .flatten() + // 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)); From b9f82262084174efc2250394c2bc85d6139c335a Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:03:20 +0000 Subject: [PATCH 10/55] refactor: remove `new_config` from EditorConfigDidChange event There is no need for it because we have access to `Editor::config()` --- helix-term/src/application.rs | 1 - helix-term/src/handlers/blame.rs | 2 +- helix-view/src/events.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index b97cb29e40e2..c9cdd650708c 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -367,7 +367,6 @@ impl Application { let mut app_config = (*self.config.load().clone()).clone(); helix_event::dispatch(EditorConfigDidChange { old_config: &app_config.editor, - new_config: &editor_config, editor: &mut self.editor, }); app_config.editor = *editor_config; diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index fdf53b8cc58b..9f6fe9201e48 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -77,7 +77,7 @@ pub(super) fn register_hooks(handlers: &Handlers) { register_hook!(move |event: &mut EditorConfigDidChange<'_>| { let has_enabled_inline_blame = event.old_config.inline_blame.behaviour == InlineBlameBehaviour::Disabled - && event.new_config.inline_blame.behaviour != InlineBlameBehaviour::Disabled; + && event.editor.config().inline_blame.behaviour != InlineBlameBehaviour::Disabled; if has_enabled_inline_blame { // request blame for all documents, since any of them could have diff --git a/helix-view/src/events.rs b/helix-view/src/events.rs index 58881d9effca..a54ec8186680 100644 --- a/helix-view/src/events.rs +++ b/helix-view/src/events.rs @@ -19,7 +19,6 @@ events! { } EditorConfigDidChange<'a> { old_config: &'a Config, - new_config: &'a Config, editor: &'a mut Editor } DocumentDidClose<'a> { From 22f9571687bb73c8758e65e9c52b3516ef1be414 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 19:01:12 +0000 Subject: [PATCH 11/55] feat: split `inline-blame.behaviour` into two options _ _ --- book/src/editor.md | 18 +++++++++++++----- helix-term/src/commands.rs | 5 +++-- helix-term/src/commands/typed.rs | 8 ++++---- helix-term/src/handlers/blame.rs | 12 ++++++------ helix-view/src/document.rs | 9 +++------ helix-view/src/editor.rs | 27 +++++++++++++++------------ 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 29e1ac563990..25d98b84b945 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -164,16 +164,24 @@ The following statusline elements can be configured: ### `[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 | | ------- | ------------------------------------------ | ------- | -| `behaviour` | Choose the behaviour of inline blame | `"disabled"` | +| `behaviour` | Choose when to show inline blame | `"hidden"` | +| `compute` | Choose when inline blame should be computed | `"on-demand"` | | `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {message} • {commit}"` | The `behaviour` can be one of the following: -- `"all-lines"`: Inline blame is turned on. Virtual text will appear at the end of each non-empty line, showing information about the latest commit for that line. -- `"cursor-line"`: Inline blame is turned on. Virtual text will appear at the end of the current cursor line, showing information about the latest commit for that line. -- `"background"`: Inline blame is turned off, but the blame is still requested in the background when opening and reloading files. This will have zero impact on performance, but will use slightly more resources in the background. This allows blame for line (`space + B`) to be retrieved instantaneously with zero delay. -- `"disabled"`: Inline blame is turned off, with no requests happening in the background. When you run `space + B` for the first time in a file, it will load the blame for this file. You may have to wait a little bit for the blame to become available, depending on the size of your repository. After it becomes available, for this file `space + B` will retrieve the blame for any line in this file with zero delay. If the file is reloaded, the process will repeat as the blame is potentially out of date and needs to be refreshed. +- `"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 not shown. + +Inline blame will only show if the blame for the file has already been computed. + +The `compute` key determines under which circumstances the blame is computed, and can be one of the following: +- `"on-demand"`: Blame for the file is computed only when explicitly requested, such as when using `space + B` to blame the line of the cursor. There may be a little delay when loading the blame. When opening new files, even with `behaviour` not set to `"hidden"`, the inline blame won't show. It needs to be computed first in order to become available. This computation can be manually triggered by requesting it with `space + B`. +- `"background"`: Blame for the file is loaded 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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. `inline-blame-format` allows customization of the blame message, and can be set to any string. Variables can be used like so: `{variable}`. These are the available variables: diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f8a29e1c339e..df46b381d39c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3480,8 +3480,9 @@ pub(crate) fn blame_line_impl(editor: &mut Editor, doc_id: DocumentId, cursor_li let line_blame = match doc.line_blame(cursor_line, &inline_blame_config.format) { result if (result.is_ok() && doc.is_blame_potentially_out_of_date) - || matches!(result, Err(LineBlameError::NotReadyYet) if inline_blame_config.behaviour - == helix_view::editor::InlineBlameBehaviour::Disabled) => + || matches!(result, Err(LineBlameError::NotReadyYet) if inline_blame_config.compute + == helix_view::editor::InlineBlameCompute::OnDemand + ) => { if let Some(path) = doc.path() { let tx = editor.handlers.blame.clone(); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 15792bc6628f..8960093ab44a 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1327,7 +1327,7 @@ fn reload(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyh } let scrolloff = cx.editor.config().scrolloff; - let inline_blame_behaviour = cx.editor.config().inline_blame.behaviour; + let inline_compute = cx.editor.config().inline_blame.compute; let (view, doc) = current!(cx.editor); doc.reload(view, &cx.editor.diff_providers).map(|_| { view.ensure_cursor_in_view(doc, scrolloff); @@ -1340,7 +1340,7 @@ fn reload(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyh .file_changed(path.clone()); } - if doc.should_request_full_file_blame(inline_blame_behaviour) { + if doc.should_request_full_file_blame(inline_compute) { if let Some(path) = doc.path() { helix_event::send_blocking( &cx.editor.handlers.blame, @@ -1380,7 +1380,7 @@ fn reload_all(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> }) .collect(); - let blame_behaviour = cx.editor.config().inline_blame.behaviour; + let blame_compute = cx.editor.config().inline_blame.compute; for (doc_id, view_ids) in docs_view_ids { let doc = doc_mut!(cx.editor, &doc_id); @@ -1410,7 +1410,7 @@ fn reload_all(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> } } - if doc.should_request_full_file_blame(blame_behaviour) { + if doc.should_request_full_file_blame(blame_compute) { if let Some(path) = doc.path() { helix_event::send_blocking( &cx.editor.handlers.blame, diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index 9f6fe9201e48..cf8410897fe0 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -3,7 +3,7 @@ use std::{mem, time::Duration}; use helix_event::register_hook; use helix_vcs::FileBlame; use helix_view::{ - editor::InlineBlameBehaviour, + editor::InlineBlameCompute, events::{DocumentDidOpen, EditorConfigDidChange}, handlers::{BlameEvent, Handlers}, DocumentId, @@ -44,7 +44,7 @@ impl helix_event::AsyncHook for BlameHandler { return; }; doc.file_blame = Some(result); - if editor.config().inline_blame.behaviour == InlineBlameBehaviour::Disabled { + if editor.config().inline_blame.compute == InlineBlameCompute::OnDemand { if let Some(line) = line_blame { crate::commands::blame_line_impl(editor, doc_id, line); } else { @@ -61,7 +61,7 @@ impl helix_event::AsyncHook for BlameHandler { pub(super) fn register_hooks(handlers: &Handlers) { let tx = handlers.blame.clone(); register_hook!(move |event: &mut DocumentDidOpen<'_>| { - if event.editor.config().inline_blame.behaviour != InlineBlameBehaviour::Disabled { + if event.editor.config().inline_blame.compute != InlineBlameCompute::OnDemand { helix_event::send_blocking( &tx, BlameEvent { @@ -75,9 +75,9 @@ pub(super) fn register_hooks(handlers: &Handlers) { }); let tx = handlers.blame.clone(); register_hook!(move |event: &mut EditorConfigDidChange<'_>| { - let has_enabled_inline_blame = event.old_config.inline_blame.behaviour - == InlineBlameBehaviour::Disabled - && event.editor.config().inline_blame.behaviour != InlineBlameBehaviour::Disabled; + let has_enabled_inline_blame = event.old_config.inline_blame.compute + == InlineBlameCompute::OnDemand + && event.editor.config().inline_blame.compute == InlineBlameCompute::Background; if has_enabled_inline_blame { // request blame for all documents, since any of them could have diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 9c5437bcab89..d0007a1fd2cd 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -42,7 +42,7 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction, }; -use crate::editor::InlineBlameBehaviour; +use crate::editor::InlineBlameCompute; use crate::{ editor::Config, events::{DocumentDidChange, SelectionDidChange}, @@ -741,11 +741,8 @@ impl Document { } } - pub fn should_request_full_file_blame( - &mut self, - blame_behaviour: InlineBlameBehaviour, - ) -> bool { - if blame_behaviour == InlineBlameBehaviour::Disabled { + pub fn should_request_full_file_blame(&mut self, blame_fetch: InlineBlameCompute) -> bool { + if blame_fetch == InlineBlameCompute::OnDemand { self.is_blame_potentially_out_of_date } else { true diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 5d930c113abf..408efb72a028 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -175,30 +175,32 @@ impl Default for GutterLineNumbersConfig { #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum InlineBlameBehaviour { - /// Do not show inline blame - /// - /// Loads blame for the file in the background when the document is - /// opened and request it again when it is `:reload`ed. - /// - /// This allows instantaneous access to line blame with `space + B` and when - /// `:toggle inline-blame.enable` but for the cost of consuming more - /// resources in the background - Background, /// Do not show inline blame, and do not request it in the background /// /// When manually requesting the inline blame, it may take several seconds to appear. - Disabled, + Hidden, /// Show the inline blame on the cursor line CursorLine, /// Show the inline blame on every other line AllLines, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum InlineBlameCompute { + /// Inline blame for a file will be fetched when a document is opened or reloaded, for example + Background, + /// Inline blame for a file will be fetched when explicitly requested, e.g. when using `space + B` + OnDemand, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct InlineBlameConfig { - /// Show inline blame for a line when cursor is on that line + /// How to show the inline blame pub behaviour: InlineBlameBehaviour, + /// Whether the inline blame should be fetched in the background + pub compute: InlineBlameCompute, /// How the inline blame should look like and the information it includes pub format: String, } @@ -206,8 +208,9 @@ pub struct InlineBlameConfig { impl Default for InlineBlameConfig { fn default() -> Self { Self { - behaviour: InlineBlameBehaviour::Disabled, + behaviour: InlineBlameBehaviour::Hidden, format: "{author}, {time-ago} • {message} • {commit}".to_owned(), + compute: InlineBlameCompute::OnDemand, } } } From a8097f1cdc1df111035c56abe6f41095b7ce1536 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 20:02:05 +0000 Subject: [PATCH 12/55] perf: use `Vec` instead of `HashMap` --- helix-term/src/ui/editor.rs | 41 ++++++++++++--------- helix-term/src/ui/text_decorations/blame.rs | 34 +++++++++++++---- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index c99b6ad6ca46..56df7c44aa09 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -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( diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 69a1d2ac60fc..9b996f6dfa6b 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -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` insted of `HashMap` + // 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>), +} + pub struct InlineBlame { - lines: HashMap, + lines: LineBlame, style: Style, } impl InlineBlame { - pub fn new(theme: &Theme, lines: HashMap) -> 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 From 00d168a78d4e6756101d352124f8f6e1f9b2db50 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:14:02 +0000 Subject: [PATCH 13/55] fix: funny boolean inversion --- helix-term/src/ui/text_decorations/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 9b996f6dfa6b..ada2b261f393 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -37,7 +37,7 @@ impl Decoration for InlineBlame { ) -> Position { let blame = match &self.lines { LineBlame::OneLine((line, blame)) => { - if line != &pos.doc_line { + if line == &pos.doc_line { // do not draw inline blame for lines that have no content in them blame } else { From ab5663891c1a26eaed3c31cf7e7a9ce3ea7cdfb4 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:24:33 +0000 Subject: [PATCH 14/55] refactor: render inline blame in a separate Editor function --- helix-term/src/ui/editor.rs | 101 ++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 56df7c44aa09..56fd0424151d 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -25,7 +25,7 @@ use helix_core::{ use helix_view::{ annotations::diagnostics::DiagnosticFilter, document::{Mode, SCRATCH_BUFFER_NAME}, - editor::{CompleteAction, CursorShapeConfig, InlineBlameBehaviour}, + editor::{CompleteAction, CursorShapeConfig, InlineBlameBehaviour, InlineBlameConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, @@ -204,13 +204,62 @@ impl EditorView { config.end_of_line_diagnostics, )); - if config.inline_blame.behaviour == InlineBlameBehaviour::CursorLine { + Self::render_inline_blame(&config.inline_blame, doc, view, &mut decorations, theme); + + render_document( + surface, + inner, + doc, + view_offset, + &text_annotations, + syntax_highlights, + overlay_highlights, + theme, + decorations, + ); + + // if we're not at the edge of the screen, draw a right border + if viewport.right() != view.area.right() { + let x = area.right(); + let border_style = theme.get("ui.window"); + for y in area.top()..area.bottom() { + surface[(x, y)] + .set_symbol(tui::symbols::line::VERTICAL) + //.set_symbol(" ") + .set_style(border_style); + } + } + + if config.inline_diagnostics.disabled() + && config.end_of_line_diagnostics == DiagnosticFilter::Disable + { + Self::render_diagnostics(doc, view, inner, surface, theme); + } + + let statusline_area = view + .area + .clip_top(view.area.height.saturating_sub(1)) + .clip_bottom(1); // -1 from bottom to remove commandline + + let mut context = + statusline::RenderContext::new(editor, doc, view, is_focused, &self.spinners); + + statusline::render(&mut context, statusline_area, surface); + } + + fn render_inline_blame( + inline_blame: &InlineBlameConfig, + doc: &Document, + view: &View, + decorations: &mut DecorationManager, + theme: &Theme, + ) { + if inline_blame.behaviour == InlineBlameBehaviour::CursorLine { let cursor_line_idx = doc.cursor_line(view.id); // do not render inline blame for empty lines to reduce visual noise if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { - if let Ok(line_blame) = - doc.line_blame(cursor_line_idx as u32, &config.inline_blame.format) + if let Ok(line_blame) = doc.line_blame(cursor_line_idx as u32, &inline_blame.format) { decorations.add_decoration(InlineBlame::new( theme, @@ -218,7 +267,7 @@ impl EditorView { )); }; } - } else if config.inline_blame.behaviour == InlineBlameBehaviour::AllLines { + } else if inline_blame.behaviour == InlineBlameBehaviour::AllLines { let text = doc.text(); let text_line_count = text.len_lines(); let view_height = view.inner_height(); @@ -237,7 +286,7 @@ impl EditorView { 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) + doc.line_blame(line_idx as u32, &inline_blame.format) .ok() .map(|blame| (line_idx, blame)) } else { @@ -253,46 +302,6 @@ impl EditorView { text_decorations::blame::LineBlame::ManyLines(blame_lines), )); } - - render_document( - surface, - inner, - doc, - view_offset, - &text_annotations, - syntax_highlights, - overlay_highlights, - theme, - decorations, - ); - - // if we're not at the edge of the screen, draw a right border - if viewport.right() != view.area.right() { - let x = area.right(); - let border_style = theme.get("ui.window"); - for y in area.top()..area.bottom() { - surface[(x, y)] - .set_symbol(tui::symbols::line::VERTICAL) - //.set_symbol(" ") - .set_style(border_style); - } - } - - if config.inline_diagnostics.disabled() - && config.end_of_line_diagnostics == DiagnosticFilter::Disable - { - Self::render_diagnostics(doc, view, inner, surface, theme); - } - - let statusline_area = view - .area - .clip_top(view.area.height.saturating_sub(1)) - .clip_bottom(1); // -1 from bottom to remove commandline - - let mut context = - statusline::RenderContext::new(editor, doc, view, is_focused, &self.spinners); - - statusline::render(&mut context, statusline_area, surface); } pub fn render_rulers( From 082ba4d741896499388f4592e897165675819a7e Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:27:14 +0000 Subject: [PATCH 15/55] refactor: `match` over `if` --- helix-term/src/ui/editor.rs | 90 +++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 56fd0424151d..585107e153b9 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -254,53 +254,57 @@ impl EditorView { decorations: &mut DecorationManager, theme: &Theme, ) { - if inline_blame.behaviour == InlineBlameBehaviour::CursorLine { - let cursor_line_idx = doc.cursor_line(view.id); + match inline_blame.behaviour { + InlineBlameBehaviour::Hidden => (), + InlineBlameBehaviour::CursorLine => { + let cursor_line_idx = doc.cursor_line(view.id); - // do not render inline blame for empty lines to reduce visual noise - if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { - if let Ok(line_blame) = doc.line_blame(cursor_line_idx as u32, &inline_blame.format) - { - decorations.add_decoration(InlineBlame::new( - theme, - text_decorations::blame::LineBlame::OneLine((cursor_line_idx, line_blame)), - )); - }; - } - } else if inline_blame.behaviour == InlineBlameBehaviour::AllLines { - let text = doc.text(); - 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(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, &inline_blame.format) - .ok() - .map(|blame| (line_idx, blame)) - } else { - None + if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { + if let Ok(line_blame) = doc.line_blame(cursor_line_idx as u32, &inline_blame.format) + { + decorations.add_decoration(InlineBlame::new( + theme, + text_decorations::blame::LineBlame::OneLine((cursor_line_idx, line_blame)), + )); + }; } - }); + }, + InlineBlameBehaviour::AllLines => { + let text = doc.text(); + 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(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, &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), - )); + 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), + )); + }, } } From c101f372988e91756959c75960294a2340a4acef Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:31:08 +0000 Subject: [PATCH 16/55] style: fmt --- helix-term/src/ui/editor.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 585107e153b9..16f7d06356f6 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -261,15 +261,19 @@ impl EditorView { // do not render inline blame for empty lines to reduce visual noise if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { - if let Ok(line_blame) = doc.line_blame(cursor_line_idx as u32, &inline_blame.format) + if let Ok(line_blame) = + doc.line_blame(cursor_line_idx as u32, &inline_blame.format) { decorations.add_decoration(InlineBlame::new( theme, - text_decorations::blame::LineBlame::OneLine((cursor_line_idx, line_blame)), + text_decorations::blame::LineBlame::OneLine(( + cursor_line_idx, + line_blame, + )), )); }; } - }, + } InlineBlameBehaviour::AllLines => { let text = doc.text(); let text_line_count = text.len_lines(); @@ -300,11 +304,12 @@ impl EditorView { 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), )); - }, + } } } From b3b1c88d27a634ea8423f02b71658adbdea9bdad Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:34:06 +0000 Subject: [PATCH 17/55] refactor: pass the `Style` instead of `Theme` --- helix-term/src/ui/editor.rs | 5 +++-- helix-term/src/ui/text_decorations/blame.rs | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 16f7d06356f6..32a2a8a0f1ce 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -254,6 +254,7 @@ impl EditorView { decorations: &mut DecorationManager, theme: &Theme, ) { + const INLINE_BLAME_SCOPE: &str = "ui.virtual.inline-blame"; match inline_blame.behaviour { InlineBlameBehaviour::Hidden => (), InlineBlameBehaviour::CursorLine => { @@ -265,7 +266,7 @@ impl EditorView { doc.line_blame(cursor_line_idx as u32, &inline_blame.format) { decorations.add_decoration(InlineBlame::new( - theme, + theme.get(INLINE_BLAME_SCOPE), text_decorations::blame::LineBlame::OneLine(( cursor_line_idx, line_blame, @@ -306,7 +307,7 @@ impl EditorView { } decorations.add_decoration(InlineBlame::new( - theme, + theme.get(INLINE_BLAME_SCOPE), text_decorations::blame::LineBlame::ManyLines(blame_lines), )); } diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index ada2b261f393..372666597f49 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -1,7 +1,6 @@ use helix_core::Position; use helix_view::theme::Style; -use helix_view::Theme; use crate::ui::document::{LinePos, TextRenderer}; use crate::ui::text_decorations::Decoration; @@ -20,9 +19,9 @@ pub struct InlineBlame { } impl InlineBlame { - pub fn new(theme: &Theme, lines: LineBlame) -> Self { + pub fn new(style: Style, lines: LineBlame) -> Self { InlineBlame { - style: theme.get("ui.virtual.inline-blame"), + style, lines, } } From af3b670de6c92475a07390b0d4d1a38fdb2274f4 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:35:45 +0000 Subject: [PATCH 18/55] refactor: move expression _ --- helix-term/src/ui/editor.rs | 3 +-- helix-term/src/ui/text_decorations/blame.rs | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 32a2a8a0f1ce..e23ccb3f50d8 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -179,6 +179,7 @@ impl EditorView { } Self::render_rulers(editor, doc, view, inner, surface, theme); + Self::render_inline_blame(&config.inline_blame, doc, view, &mut decorations, theme); let primary_cursor = doc .selection(view.id) @@ -204,8 +205,6 @@ impl EditorView { config.end_of_line_diagnostics, )); - Self::render_inline_blame(&config.inline_blame, doc, view, &mut decorations, theme); - render_document( surface, inner, diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 372666597f49..645a0462c027 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -20,10 +20,7 @@ pub struct InlineBlame { impl InlineBlame { pub fn new(style: Style, lines: LineBlame) -> Self { - InlineBlame { - style, - lines, - } + InlineBlame { style, lines } } } From 95344a958506069af6b05f8142f20eb245574189 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat, 29 Mar 2025 23:59:06 +0000 Subject: [PATCH 19/55] perf: use string preallocations for string concatenation --- helix-stdx/src/lib.rs | 1 + helix-stdx/src/str.rs | 18 ++++++++++++++++++ helix-stdx/src/time.rs | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 helix-stdx/src/str.rs diff --git a/helix-stdx/src/lib.rs b/helix-stdx/src/lib.rs index eeaba0d81b21..7c0f25cf029e 100644 --- a/helix-stdx/src/lib.rs +++ b/helix-stdx/src/lib.rs @@ -3,6 +3,7 @@ pub mod faccess; pub mod path; pub mod range; pub mod rope; +pub mod str; pub mod time; pub use range::Range; diff --git a/helix-stdx/src/str.rs b/helix-stdx/src/str.rs new file mode 100644 index 000000000000..e79cbccccbc8 --- /dev/null +++ b/helix-stdx/src/str.rs @@ -0,0 +1,18 @@ +/// Concatenates strings together. +/// +/// `concat!(a, " ", b, " ", c)` is: +/// - more performant than `format!("{a} {b} {c}")` +/// - more ergonomic than using `String::with_capacity` followed by a series of `String::push_str` +#[macro_export] +macro_rules! concat { + ($($value:expr),*) => {{ + // Rust does not allow using `+` as separator between value + // so we must add that at the end of everything. The `0` is necessary + // at the end so it does not end with "+ " (which would be invalid syntax) + let mut buf = String::with_capacity($($value.len() + )* 0); + $( + buf.push_str(&$value); + )* + buf + }} +} diff --git a/helix-stdx/src/time.rs b/helix-stdx/src/time.rs index cb72a9386093..4df88c45cef4 100644 --- a/helix-stdx/src/time.rs +++ b/helix-stdx/src/time.rs @@ -71,5 +71,5 @@ pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String { "from now" }; - format!("{value} {unit} {label}") + crate::concat!(value, " ", unit, " ", label) } From 1a0dad36b75e95e1b264536c5a5696186efece17 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sun, 30 Mar 2025 11:42:43 +0100 Subject: [PATCH 20/55] 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 --- helix-term/src/ui/editor.rs | 22 +++++----------------- helix-view/src/view.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index e23ccb3f50d8..0e40775e1c28 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -254,13 +254,14 @@ impl EditorView { theme: &Theme, ) { const INLINE_BLAME_SCOPE: &str = "ui.virtual.inline-blame"; + let text = doc.text(); match inline_blame.behaviour { InlineBlameBehaviour::Hidden => (), InlineBlameBehaviour::CursorLine => { let cursor_line_idx = doc.cursor_line(view.id); // do not render inline blame for empty lines to reduce visual noise - if doc.text().line(cursor_line_idx) != doc.line_ending.as_str() { + if text.line(cursor_line_idx) != doc.line_ending.as_str() { if let Ok(line_blame) = doc.line_blame(cursor_line_idx as u32, &inline_blame.format) { @@ -275,22 +276,9 @@ impl EditorView { } } InlineBlameBehaviour::AllLines => { - let text = doc.text(); - 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(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| { + let mut blame_lines = vec![None; text.len_lines()]; + + let blame_for_all_lines = view.line_range(doc).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, &inline_blame.format) diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index d6f10753a135..b4863700d374 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -190,6 +190,18 @@ impl View { self.docs_access_history.push(id); } + /// The range of lines in the document that the view sees + pub fn line_range(&self, doc: &Document) -> std::ops::Range { + let text = doc.text(); + let text_line_count = text.len_lines(); + let first_line = text.char_to_line(doc.view_offset(self.id).anchor.min(text.len_chars())); + let last_line = first_line + .saturating_add(self.inner_height()) + .min(text_line_count); + + first_line..last_line + } + pub fn inner_area(&self, doc: &Document) -> Rect { self.area.clip_left(self.gutter_offset(doc)).clip_bottom(1) // -1 for statusline } From e8d7e76c737396d002abc0eafcda5f8449a0db95 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Tue, 1 Apr 2025 12:17:48 +0100 Subject: [PATCH 21/55] fix: spelling error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastian Klähn <39526136+Septias@users.noreply.github.com> --- helix-vcs/src/git/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 0b83bd1d8b21..c670b21ee3b0 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -30,7 +30,7 @@ pub struct FileBlame { } impl FileBlame { - /// Get the blame information corresponing to a line in file and diff for that line + /// Get the blame information corresponding to a line in the file and diff for that line #[inline] pub fn blame_for_line(&self, line: u32, inserted_lines: u32, removed_lines: u32) -> LineBlame { // Because gix_blame doesn't care about stuff that is not commited, we have to "normalize" the From c74fec4c6e77972da36e1c929bada17d3a643f34 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Wed, 2 Apr 2025 00:12:38 +0100 Subject: [PATCH 22/55] 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! --- helix-vcs/src/diff.rs | 7 +++++++ helix-view/src/document.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/helix-vcs/src/diff.rs b/helix-vcs/src/diff.rs index e49e171ddf4e..95e13b594cf2 100644 --- a/helix-vcs/src/diff.rs +++ b/helix-vcs/src/diff.rs @@ -75,6 +75,13 @@ impl DiffHandle { } } + pub fn try_load(&self) -> Option { + Some(Diff { + diff: self.diff.try_read()?, + inverted: self.inverted, + }) + } + /// Updates the document associated with this redraw handle /// This function is only intended to be called from within the rendering loop /// if called from elsewhere it may fail to acquire the render lock and panic diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index d0007a1fd2cd..c99a4e75f2d1 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1590,7 +1590,7 @@ impl Document { // file in the file system into what gix::blame knows about (gix::blame only // knows about commit history, it does not know about uncommitted changes) diff_handle - .load() + .try_load()? .hunks_intersecting_line_ranges(std::iter::once((0, cursor_line as usize))) .try_fold( (0, 0), From 616758ee81565d16fdc69a061c20ef1774a2a62d Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Fri, 4 Apr 2025 08:19:40 +0100 Subject: [PATCH 23/55] refactor: rename macro _ --- helix-stdx/src/str.rs | 4 ++-- helix-stdx/src/time.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-stdx/src/str.rs b/helix-stdx/src/str.rs index e79cbccccbc8..942acea9570b 100644 --- a/helix-stdx/src/str.rs +++ b/helix-stdx/src/str.rs @@ -1,10 +1,10 @@ /// Concatenates strings together. /// -/// `concat!(a, " ", b, " ", c)` is: +/// `str_concat!(a, " ", b, " ", c)` is: /// - more performant than `format!("{a} {b} {c}")` /// - more ergonomic than using `String::with_capacity` followed by a series of `String::push_str` #[macro_export] -macro_rules! concat { +macro_rules! str_concat { ($($value:expr),*) => {{ // Rust does not allow using `+` as separator between value // so we must add that at the end of everything. The `0` is necessary diff --git a/helix-stdx/src/time.rs b/helix-stdx/src/time.rs index 4df88c45cef4..08a45988ca76 100644 --- a/helix-stdx/src/time.rs +++ b/helix-stdx/src/time.rs @@ -71,5 +71,5 @@ pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String { "from now" }; - crate::concat!(value, " ", unit, " ", label) + crate::str_concat!(value, " ", unit, " ", label) } From 03f0883e7e11a4f7e6bc60418a22df0815dde429 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Wed, 16 Apr 2025 23:34:56 +0100 Subject: [PATCH 24/55] chore: fix merge conflicts --- Cargo.lock | 353 +++++++++++++++++++++++-------------- helix-vcs/src/git/blame.rs | 18 +- 2 files changed, 226 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6964b4bacc32..589c758f8c03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.10.0" @@ -202,6 +211,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -273,6 +291,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "dashmap" version = "6.1.0" @@ -287,6 +315,16 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -416,12 +454,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide 0.8.8", ] [[package]] @@ -481,6 +519,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -512,9 +560,9 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gix" -version = "0.70.0" +version = "0.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736f14636705f3a56ea52b553e67282519418d9a35bb1e90b3a9637a00296b68" +checksum = "a61e71ec6817fc3c9f12f812682cfe51ee6ea0d2e27e02fc3849c35524617435" dependencies = [ "gix-actor", "gix-attributes", @@ -563,23 +611,23 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.33.2" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20018a1a6332e065f1fcc8305c1c932c6b8c9985edea2284b3c79dc6fa3ee4b2" +checksum = "f438c87d4028aca4b82f82ba8d8ab1569823cfb3e5bc5fa8456a71678b2a20e7" dependencies = [ "bstr", "gix-date", "gix-utils", "itoa", "thiserror 2.0.12", - "winnow 0.6.18", + "winnow", ] [[package]] name = "gix-attributes" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f151000bf662ef5f641eca6102d942ee31ace80f271a3ef642e99776ce6ddb38" +checksum = "e4e25825e0430aa11096f8b65ced6780d4a96a133f81904edceebb5344c8dd7f" dependencies = [ "bstr", "gix-glob", @@ -603,16 +651,20 @@ dependencies = [ [[package]] name = "gix-blame" -version = "0.0.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc795e239a2347eb50ed18b8c529382dd8b62439c57277f79af3d8f8928a986" +checksum = "b25d5aa111ce9cb6d087c2d1153b96553a3dc491163398e96622b0bd7b40c7c6" dependencies = [ + "gix-commitgraph", + "gix-date", "gix-diff", "gix-hash", "gix-object", + "gix-revwalk", "gix-trace", "gix-traverse", "gix-worktree", + "smallvec", "thiserror 2.0.12", ] @@ -627,25 +679,25 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb410b84d6575db45e62025a9118bdbf4d4b099ce7575a76161e898d9ca98df1" +checksum = "c0378995847773a697f8e157fe2963ecf3462fe64be05b7b3da000b3b472def8" dependencies = [ "bstr", "gix-path", + "gix-quote", "gix-trace", "shell-words", ] [[package]] name = "gix-commitgraph" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e23a8ec2d8a16026a10dafdb6ed51bcfd08f5d97f20fa52e200bc50cb72e4877" +checksum = "043cbe49b7a7505150db975f3cb7c15833335ac1e26781f615454d9d640a28fe" dependencies = [ "bstr", "gix-chunk", - "gix-features", "gix-hash", "memmap2", "thiserror 2.0.12", @@ -653,9 +705,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.43.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377c1efd2014d5d469e0b3cd2952c8097bce9828f634e04d5665383249f1d9e9" +checksum = "9c6f830bf746604940261b49abf7f655d2c19cadc9f4142ae9379e3a316e8cfa" dependencies = [ "bstr", "gix-config-value", @@ -669,14 +721,14 @@ dependencies = [ "smallvec", "thiserror 2.0.12", "unicode-bom", - "winnow 0.6.18", + "winnow", ] [[package]] name = "gix-config-value" -version = "0.14.11" +version = "0.14.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11365144ef93082f3403471dbaa94cfe4b5e72743bdb9560719a251d439f4cee" +checksum = "8dc2c844c4cf141884678cabef736fd91dd73068b9146e6f004ba1a0457944b6" dependencies = [ "bitflags", "bstr", @@ -687,9 +739,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c57c477b645ee248b173bb1176b52dd528872f12c50375801a58aaf5ae91113f" +checksum = "daa30058ec7d3511fbc229e4f9e696a35abd07ec5b82e635eff864a2726217e4" dependencies = [ "bstr", "itoa", @@ -699,9 +751,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.50.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62afb7f4ca0acdf4e9dad92065b2eb1bf2993bcc5014b57bc796e3a365b17c4d" +checksum = "a2c975dad2afc85e4e233f444d1efbe436c3cdcf3a07173984509c436d00a3f8" dependencies = [ "bstr", "gix-attributes", @@ -723,9 +775,9 @@ dependencies = [ [[package]] name = "gix-dir" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d78db3927a12f7d1b788047b84efacaab03ef25738bd1c77856ad8966bd57b" +checksum = "5879497bd3815d8277ed864ec8975290a70de5b62bb92d2d666a4cefc5d4793b" dependencies = [ "bstr", "gix-discover", @@ -743,9 +795,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c2414bdf04064e0f5a5aa029dfda1e663cf9a6c4bfc8759f2d369299bb65d8" +checksum = "f7fb8a4349b854506a3915de18d3341e5f1daa6b489c8affc9ca0d69efe86781" dependencies = [ "bstr", "dunce", @@ -759,30 +811,29 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.40.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfdd4838a8d42bd482c9f0cb526411d003ee94cc7c7b08afe5007329c71d554" +checksum = "016d6050219458d14520fe22bdfdeb9cb71631dec9bc2724767c983f60109634" dependencies = [ "crc32fast", "crossbeam-channel", "flate2", - "gix-hash", + "gix-path", "gix-trace", "gix-utils", "libc", "once_cell", "parking_lot", "prodash", - "sha1_smol", "thiserror 2.0.12", "walkdir", ] [[package]] name = "gix-filter" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdcc36cd7dbc63ed0ec3558645886553d1afd3cd09daa5efb9cba9cceb942bbb" +checksum = "cb2b2bbffdc5cc9b2b82fc82da1b98163c9b423ac2b45348baa83a947ac9ab89" dependencies = [ "bstr", "encoding_rs", @@ -801,20 +852,23 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "182e7fa7bfdf44ffb7cfe7451b373cdf1e00870ac9a488a49587a110c562063d" +checksum = "951e886120dc5fa8cac053e5e5c89443f12368ca36811b2e43d1539081f9c111" dependencies = [ + "bstr", "fastrand", "gix-features", + "gix-path", "gix-utils", + "thiserror 2.0.12", ] [[package]] name = "gix-glob" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9c7249fa0a78f9b363aa58323db71e0a6161fd69860ed6f48dedf0ef3a314e" +checksum = "20972499c03473e773a2099e5fd0c695b9b72465837797a51a43391a1635a030" dependencies = [ "bitflags", "bstr", @@ -824,19 +878,21 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e81c5ec48649b1821b3ed066a44efb95f1a268b35c1d91295e61252539fbe9f8" +checksum = "834e79722063958b03342edaa1e17595cd2939bb2b3306b3225d0815566dcb49" dependencies = [ "faster-hex", + "gix-features", + "sha1-checked", "thiserror 2.0.12", ] [[package]] name = "gix-hashtable" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189130bc372accd02e0520dc5ab1cef318dcc2bc829b76ab8d84bbe90ac212d1" +checksum = "f06066d8702a9186dc1fdc1ed751ff2d7e924ceca21cb5d51b8f990c9c2e014a" dependencies = [ "gix-hash", "hashbrown 0.14.5", @@ -845,9 +901,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f529dcb80bf9855c0a7c49f0ac588df6d6952d63a63fefc254b9c869d2cdf6f" +checksum = "9a27c8380f493a10d1457f756a3f81924d578fc08d6535e304dfcafbf0261d18" dependencies = [ "bstr", "gix-glob", @@ -858,9 +914,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd12e3626879369310fffe2ac61acc828613ef656b50c4ea984dd59d7dc85d8" +checksum = "855bece2d4153453aa5d0a80d51deea1ce8cd6a3b4cf213da85ac344ccb908a7" dependencies = [ "bitflags", "bstr", @@ -886,9 +942,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9739815270ff6940968441824d162df9433db19211ca9ba8c3fc1b50b849c642" +checksum = "df47b8f11c34520db5541bc5fc9fbc8e4b0bdfcec3736af89ccb1a5728a0126f" dependencies = [ "gix-tempfile", "gix-utils", @@ -897,9 +953,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc4b3a0044244f0fe22347fb7a79cca165e37829d668b41b85ff46a43e5fd68" +checksum = "4943fcdae6ffc135920c9ea71e0362ed539182924ab7a85dd9dac8d89b0dd69a" dependencies = [ "bstr", "gix-actor", @@ -913,14 +969,14 @@ dependencies = [ "itoa", "smallvec", "thiserror 2.0.12", - "winnow 0.6.18", + "winnow", ] [[package]] name = "gix-odb" -version = "0.67.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e93457df69cd09573608ce9fa4f443fbd84bc8d15d8d83adecd471058459c1b" +checksum = "50306d40dcc982eb6b7593103f066ea6289c7b094cb9db14f3cd2be0b9f5e610" dependencies = [ "arc-swap", "gix-date", @@ -939,9 +995,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc13a475b3db735617017fb35f816079bf503765312d4b1913b18cf96f3fa515" +checksum = "9b65fffb09393c26624ca408d32cfe8776fb94cd0a5cdf984905e1d2f39779cb" dependencies = [ "clru", "gix-chunk", @@ -957,9 +1013,9 @@ dependencies = [ [[package]] name = "gix-packetline" -version = "0.18.3" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e5ae6bc3ac160a6bf44a55f5537813ca3ddb08549c0fd3e7ef699c73c439cd" +checksum = "123844a70cf4d5352441dc06bab0da8aef61be94ec239cb631e0ba01dc6d3a04" dependencies = [ "bstr", "faster-hex", @@ -969,9 +1025,9 @@ dependencies = [ [[package]] name = "gix-packetline-blocking" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cbf8767c6abd5a6779f586702b5bcd8702380f4208219449cf1c9d0cd1e17c" +checksum = "1ecf3ea2e105c7e45587bac04099824301262a6c43357fad5205da36dbb233b3" dependencies = [ "bstr", "faster-hex", @@ -981,9 +1037,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.14" +version = "0.10.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40f12bb65a8299be0cfb90fe718e3be236b7a94b434877012980863a883a99f" +checksum = "f910668e2f6b2a55ff35a1f04df88a1a049f7b868507f4cbeeaa220eaba7be87" dependencies = [ "bstr", "gix-trace", @@ -994,9 +1050,9 @@ dependencies = [ [[package]] name = "gix-pathspec" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6430d3a686c08e9d59019806faa78c17315fe22ae73151a452195857ca02f86c" +checksum = "fef8422c3c9066d649074b24025125963f85232bfad32d6d16aea9453b82ec14" dependencies = [ "bitflags", "bstr", @@ -1009,9 +1065,9 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.48.0" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c61bd61afc6b67d213241e2100394c164be421e3f7228d3521b04f48ca5ba90" +checksum = "5678ddae1d62880bc30e2200be1b9387af3372e0e88e21f81b4e7f8367355b5a" dependencies = [ "bstr", "gix-date", @@ -1023,14 +1079,14 @@ dependencies = [ "gix-utils", "maybe-async", "thiserror 2.0.12", - "winnow 0.6.18", + "winnow", ] [[package]] name = "gix-quote" -version = "0.4.15" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e49357fccdb0c85c0d3a3292a9f6db32d9b3535959b5471bb9624908f4a066c6" +checksum = "1b005c550bf84de3b24aa5e540a23e6146a1c01c7d30470e35d75a12f827f969" dependencies = [ "bstr", "gix-utils", @@ -1039,9 +1095,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.50.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47adf4c5f933429f8554e95d0d92eee583cfe4b95d2bf665cd6fd4a1531ee20c" +checksum = "b2e1f7eb6b7ce82d2d19961f74bd637bab3ea79b1bc7bfb23dbefc67b0415d8b" dependencies = [ "gix-actor", "gix-features", @@ -1055,14 +1111,14 @@ dependencies = [ "gix-validate", "memmap2", "thiserror 2.0.12", - "winnow 0.6.18", + "winnow", ] [[package]] name = "gix-refspec" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59650228d8f612f68e7f7a25f517fcf386c5d0d39826085492e94766858b0a90" +checksum = "1d8587b21e2264a6e8938d940c5c99662779c13a10741a5737b15fc85c252ffc" dependencies = [ "bstr", "gix-hash", @@ -1074,9 +1130,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe28bbccca55da6d66e6c6efc6bb4003c29d407afd8178380293729733e6b53" +checksum = "342caa4e158df3020cadf62f656307c3948fe4eacfdf67171d7212811860c3e9" dependencies = [ "bstr", "gix-commitgraph", @@ -1089,9 +1145,9 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ecb80c235b1e9ef2b99b23a81ea50dd569a88a9eb767179793269e0e616247" +checksum = "2dc7c3d7e5cdc1ab8d35130106e4af0a4f9f9eca0c81f4312b690780e92bde0d" dependencies = [ "gix-commitgraph", "gix-date", @@ -1104,9 +1160,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84dae13271f4313f8d60a166bf27e54c968c7c33e2ffd31c48cafe5da649875" +checksum = "47aeb0f13de9ef2f3033f5ff218de30f44db827ac9f1286f9ef050aacddd5888" dependencies = [ "bitflags", "gix-path", @@ -1116,9 +1172,9 @@ dependencies = [ [[package]] name = "gix-shallow" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab72543011e303e52733c85bef784603ef39632ddf47f69723def52825e35066" +checksum = "cc0598aacfe1d52575a21c9492fee086edbb21e228ec36c819c42ab923f434c3" dependencies = [ "bstr", "gix-hash", @@ -1128,9 +1184,9 @@ dependencies = [ [[package]] name = "gix-status" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cc1d85079d7ca32c3ab4a6479bf7e174cd251c74a82339c6cc393da3f4883" +checksum = "605a6d0eb5891680c46e24b2ee7a63ef7bd39cb136dc7c7e55172960cf68b2f5" dependencies = [ "bstr", "filetime", @@ -1151,9 +1207,9 @@ dependencies = [ [[package]] name = "gix-submodule" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74972fe8d46ac8a09490ae1e843b4caf221c5b157c5ac17057e8e1c38417a3ac" +checksum = "78c7390c2059505c365e9548016d4edc9f35749c6a9112b7b1214400bbc68da2" dependencies = [ "bstr", "gix-config", @@ -1166,9 +1222,9 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2558f423945ef24a8328c55d1fd6db06b8376b0e7013b1bb476cc4ffdf678501" +checksum = "3d6de439bbb9a5d3550c9c7fab0e16d2d637d120fcbe0dfbc538772a187f099b" dependencies = [ "dashmap", "gix-fs", @@ -1186,9 +1242,9 @@ checksum = "7c396a2036920c69695f760a65e7f2677267ccf483f25046977d87e4cb2665f7" [[package]] name = "gix-transport" -version = "0.45.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11187418489477b1b5b862ae1aedbbac77e582f2c4b0ef54280f20cfe5b964d9" +checksum = "b3f68c2870bfca8278389d2484a7f2215b67d0b0cc5277d3c72ad72acf41787e" dependencies = [ "bstr", "gix-command", @@ -1202,9 +1258,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.44.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bec70e53896586ef32a3efa7e4427b67308531ed186bb6120fb3eca0f0d61b4" +checksum = "36c0b049f8bdb61b20016694102f7b507f2e1727e83e9c5e6dad4f7d84ff7384" dependencies = [ "bitflags", "gix-commitgraph", @@ -1219,9 +1275,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29218c768b53dd8f116045d87fec05b294c731a4b2bdd257eeca2084cc150b13" +checksum = "48dfe23f93f1ddb84977d80bb0dd7aa09d1bf5d5afc0c9b6820cccacc25ae860" dependencies = [ "bstr", "gix-features", @@ -1233,9 +1289,9 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.14" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f24e03ac8916c478c8419d7d3c33393da9bb41fa4c24455d5406aeefd35f" +checksum = "189f8724cf903e7fd57cfe0b7bc209db255cacdcb22c781a022f52c3a774f8d0" dependencies = [ "bstr", "fastrand", @@ -1244,9 +1300,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eaa01c3337d885617c0a42e92823922a2aea71f4caeace6fe87002bdcadbd90" +checksum = "34b5f1253109da6c79ed7cf6e1e38437080bb6d704c76af14c93e2f255234084" dependencies = [ "bstr", "thiserror 2.0.12", @@ -1254,9 +1310,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6673512f7eaa57a6876adceca6978a501d6c6569a4f177767dc405f8b9778958" +checksum = "f7760dbc4b79aa274fed30adc0d41dca6b917641f26e7867c4071b1fb4dc727b" dependencies = [ "bstr", "gix-attributes", @@ -1800,9 +1856,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1841,25 +1897,41 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiff" -version = "0.1.13" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" +checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0" dependencies = [ + "jiff-static", "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", "windows-sys 0.59.0", ] +[[package]] +name = "jiff-static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "jiff-tzdb" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962e1dfe9b2d75a84536cf5bf5eaaa4319aa7906c7160134a22883ac316d5f31" +checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" [[package]] name = "jiff-tzdb-platform" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a63c62e404e7b92979d2792352d885a7f8f83fd1d0d31eea582d77b2ceca697e" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ "jiff-tzdb", ] @@ -1980,9 +2052,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -2119,6 +2191,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -2130,9 +2211,9 @@ dependencies = [ [[package]] name = "prodash" -version = "29.0.0" +version = "29.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a266d8d6020c61a437be704c5e618037588e1985c7dbb7bf8d265db84cffe325" +checksum = "f04bb108f648884c23b98a0e940ebc2c93c0c3b89f04dbaf7eb8256ce617d1bc" dependencies = [ "log", "parking_lot", @@ -2361,10 +2442,25 @@ dependencies = [ ] [[package]] -name = "sha1_smol" -version = "1.0.1" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest", + "sha1", +] [[package]] name = "shell-words" @@ -2440,9 +2536,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "smartstring" @@ -2513,9 +2609,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ "fastrand", "getrandom 0.3.1", @@ -2689,7 +2785,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.2", + "winnow", ] [[package]] @@ -2702,6 +2798,12 @@ dependencies = [ "regex", ] +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicase" version = "2.7.0" @@ -3012,15 +3114,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.2" diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index c670b21ee3b0..a003ad30c33d 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -89,23 +89,11 @@ impl FileBlame { let repo = thread_safe_repo.to_thread_local(); let head = repo.head()?.peel_to_commit_in_place()?.id; - // TODO: this iterator has a performane issue for large repos - // It was replaced in a new (yet unreleased) version of `gix`. - // - // Update to the new version once it releases. - // - // More info: https://github.com/helix-editor/helix/pull/13133#discussion_r2008611830 - let traverse = gix::traverse::commit::topo::Builder::from_iters( - &repo.objects, - [head], - None::>, - ) - .build()?; - let mut resource_cache = repo.diff_resource_cache_for_tree_diff()?; let file_blame = gix::blame::file( &repo.objects, - traverse.into_iter(), + head, + None, &mut resource_cache, // bstr always uses unix separators &gix::path::to_unix_separators_on_windows(gix::path::try_into_bstr( @@ -115,7 +103,7 @@ impl FileBlame { .context("Could not get the parent path of the repo")?, )?, )?), - None, + gix::blame::Options::default(), )? .entries; From be5fbff319651646f61c30aef92eb9435104a517 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 6 May 2025 17:38:04 +0100 Subject: [PATCH 25/55] chore: resolve merge conflicts --- Cargo.lock | 270 +++++++++++++++++++++---------------- helix-vcs/src/git/blame.rs | 5 +- 2 files changed, 160 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 589c758f8c03..c6a23eeba6ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -131,6 +131,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.7.1" @@ -231,9 +237,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -407,10 +413,11 @@ dependencies = [ [[package]] name = "faster-hex" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" +checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" dependencies = [ + "heapless", "serde", ] @@ -459,6 +466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide 0.8.8", ] @@ -560,9 +568,9 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gix" -version = "0.71.0" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61e71ec6817fc3c9f12f812682cfe51ee6ea0d2e27e02fc3849c35524617435" +checksum = "01237e8d3d78581f71642be8b0c2ae8c0b2b5c251c9c5d9ebbea3c1ea280dce8" dependencies = [ "gix-actor", "gix-attributes", @@ -611,9 +619,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.34.0" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f438c87d4028aca4b82f82ba8d8ab1569823cfb3e5bc5fa8456a71678b2a20e7" +checksum = "6b300e6e4f31f3f6bd2de5e2b0caab192ced00dc0fcd0f7cc56e28c575c8e1ff" dependencies = [ "bstr", "gix-date", @@ -625,9 +633,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e25825e0430aa11096f8b65ced6780d4a96a133f81904edceebb5344c8dd7f" +checksum = "e7e26b3ac280ddb25bb6980d34f4a82ee326f78bf2c6d4ea45eef2d940048b8e" dependencies = [ "bstr", "gix-glob", @@ -651,9 +659,9 @@ dependencies = [ [[package]] name = "gix-blame" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b25d5aa111ce9cb6d087c2d1153b96553a3dc491163398e96622b0bd7b40c7c6" +checksum = "a6807d2660ea9e15752a5d5867a9b05594ed27395ee18d51df7ebcb84a4809e9" dependencies = [ "gix-commitgraph", "gix-date", @@ -679,9 +687,9 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0378995847773a697f8e157fe2963ecf3462fe64be05b7b3da000b3b472def8" +checksum = "d2f47f3fb4ba33644061e8e0e1030ef2a937d42dc969553118c320a205a9fb28" dependencies = [ "bstr", "gix-path", @@ -692,9 +700,9 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043cbe49b7a7505150db975f3cb7c15833335ac1e26781f615454d9d640a28fe" +checksum = "e05050fd6caa6c731fe3bd7f9485b3b520be062d3d139cb2626e052d6c127951" dependencies = [ "bstr", "gix-chunk", @@ -705,9 +713,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.44.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6f830bf746604940261b49abf7f655d2c19cadc9f4142ae9379e3a316e8cfa" +checksum = "48f3c8f357ae049bfb77493c2ec9010f58cfc924ae485e1116c3718fc0f0d881" dependencies = [ "bstr", "gix-config-value", @@ -726,9 +734,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.14.12" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc2c844c4cf141884678cabef736fd91dd73068b9146e6f004ba1a0457944b6" +checksum = "439d62e241dae2dffd55bfeeabe551275cf9d9f084c5ebc6b48bad49d03285b7" dependencies = [ "bitflags", "bstr", @@ -739,21 +747,22 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa30058ec7d3511fbc229e4f9e696a35abd07ec5b82e635eff864a2726217e4" +checksum = "3a98593f1f1e14b9fa15c5b921b2c465e904d698b9463e21bb377be8376c3c1a" dependencies = [ "bstr", "itoa", "jiff", + "smallvec", "thiserror 2.0.12", ] [[package]] name = "gix-diff" -version = "0.51.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2c975dad2afc85e4e233f444d1efbe436c3cdcf3a07173984509c436d00a3f8" +checksum = "5e9b43e95fe352da82a969f0c84ff860c2de3e724d93f6681fedbcd6c917f252" dependencies = [ "bstr", "gix-attributes", @@ -775,9 +784,9 @@ dependencies = [ [[package]] name = "gix-dir" -version = "0.13.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5879497bd3815d8277ed864ec8975290a70de5b62bb92d2d666a4cefc5d4793b" +checksum = "01e6e2dc5b8917142d0ffe272209d1671e45b771e433f90186bc71c016792e87" dependencies = [ "bstr", "gix-discover", @@ -795,9 +804,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.39.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fb8a4349b854506a3915de18d3341e5f1daa6b489c8affc9ca0d69efe86781" +checksum = "dccfe3e25b4ea46083916c56db3ba9d1e6ef6dce54da485f0463f9fc0fe1837c" dependencies = [ "bstr", "dunce", @@ -811,9 +820,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.41.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016d6050219458d14520fe22bdfdeb9cb71631dec9bc2724767c983f60109634" +checksum = "56f4399af6ec4fd9db84dd4cf9656c5c785ab492ab40a7c27ea92b4241923fed" dependencies = [ "crc32fast", "crossbeam-channel", @@ -831,9 +840,9 @@ dependencies = [ [[package]] name = "gix-filter" -version = "0.18.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb2b2bbffdc5cc9b2b82fc82da1b98163c9b423ac2b45348baa83a947ac9ab89" +checksum = "f90c21f0d61778f518bbb7c431b00247bf4534b2153c3e85bcf383876c55ca6c" dependencies = [ "bstr", "encoding_rs", @@ -852,9 +861,9 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951e886120dc5fa8cac053e5e5c89443f12368ca36811b2e43d1539081f9c111" +checksum = "67a0637149b4ef24d3ea55f81f77231401c8463fae6da27331c987957eb597c7" dependencies = [ "bstr", "fastrand", @@ -866,9 +875,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20972499c03473e773a2099e5fd0c695b9b72465837797a51a43391a1635a030" +checksum = "2926b03666e83b8d01c10cf06e5733521aacbd2d97179a4c9b1fdddabb9e937d" dependencies = [ "bitflags", "bstr", @@ -878,9 +887,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834e79722063958b03342edaa1e17595cd2939bb2b3306b3225d0815566dcb49" +checksum = "8d4900562c662852a6b42e2ef03442eccebf24f047d8eab4f23bc12ef0d785d8" dependencies = [ "faster-hex", "gix-features", @@ -890,9 +899,9 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f06066d8702a9186dc1fdc1ed751ff2d7e924ceca21cb5d51b8f990c9c2e014a" +checksum = "b5b5cb3c308b4144f2612ff64e32130e641279fcf1a84d8d40dad843b4f64904" dependencies = [ "gix-hash", "hashbrown 0.14.5", @@ -901,9 +910,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a27c8380f493a10d1457f756a3f81924d578fc08d6535e304dfcafbf0261d18" +checksum = "ae358c3c96660b10abc7da63c06788dfded603e717edbd19e38c6477911b71c8" dependencies = [ "bstr", "gix-glob", @@ -914,9 +923,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855bece2d4153453aa5d0a80d51deea1ce8cd6a3b4cf213da85ac344ccb908a7" +checksum = "e6d505aea7d7c4267a3153cb90c712a89970b4dd02a2cb3205be322891f530b5" dependencies = [ "bitflags", "bstr", @@ -935,16 +944,16 @@ dependencies = [ "itoa", "libc", "memmap2", - "rustix 0.38.44", + "rustix 1.0.7", "smallvec", "thiserror 2.0.12", ] [[package]] name = "gix-lock" -version = "17.0.0" +version = "17.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df47b8f11c34520db5541bc5fc9fbc8e4b0bdfcec3736af89ccb1a5728a0126f" +checksum = "570f8b034659f256366dc90f1a24924902f20acccd6a15be96d44d1269e7a796" dependencies = [ "gix-tempfile", "gix-utils", @@ -953,9 +962,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.48.0" +version = "0.49.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4943fcdae6ffc135920c9ea71e0362ed539182924ab7a85dd9dac8d89b0dd69a" +checksum = "d957ca3640c555d48bb27f8278c67169fa1380ed94f6452c5590742524c40fbb" dependencies = [ "bstr", "gix-actor", @@ -974,9 +983,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.68.0" +version = "0.69.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50306d40dcc982eb6b7593103f066ea6289c7b094cb9db14f3cd2be0b9f5e610" +checksum = "868f703905fdbcfc1bd750942f82419903ecb7039f5288adb5206d6de405e0c9" dependencies = [ "arc-swap", "gix-date", @@ -995,9 +1004,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.58.0" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b65fffb09393c26624ca408d32cfe8776fb94cd0a5cdf984905e1d2f39779cb" +checksum = "9d49c55d69c8449f2a0a5a77eb9cbacfebb6b0e2f1215f0fc23a4cb60528a450" dependencies = [ "clru", "gix-chunk", @@ -1013,9 +1022,9 @@ dependencies = [ [[package]] name = "gix-packetline" -version = "0.18.4" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123844a70cf4d5352441dc06bab0da8aef61be94ec239cb631e0ba01dc6d3a04" +checksum = "8ddc034bc67c848e4ef7596ab5528cd8fd439d310858dbe1ce8b324f25deb91c" dependencies = [ "bstr", "faster-hex", @@ -1025,9 +1034,9 @@ dependencies = [ [[package]] name = "gix-packetline-blocking" -version = "0.18.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecf3ea2e105c7e45587bac04099824301262a6c43357fad5205da36dbb233b3" +checksum = "c44880f028ba46d6cf37a66d27a300310c6b51b8ed0e44918f93df061168e2f3" dependencies = [ "bstr", "faster-hex", @@ -1037,12 +1046,13 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.15" +version = "0.10.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f910668e2f6b2a55ff35a1f04df88a1a049f7b868507f4cbeeaa220eaba7be87" +checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642" dependencies = [ "bstr", "gix-trace", + "gix-validate", "home", "once_cell", "thiserror 2.0.12", @@ -1050,9 +1060,9 @@ dependencies = [ [[package]] name = "gix-pathspec" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8422c3c9066d649074b24025125963f85232bfad32d6d16aea9453b82ec14" +checksum = "ce061c50e5f8f7c830cacb3da3e999ae935e283ce8522249f0ce2256d110979d" dependencies = [ "bitflags", "bstr", @@ -1065,9 +1075,9 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.49.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5678ddae1d62880bc30e2200be1b9387af3372e0e88e21f81b4e7f8367355b5a" +checksum = "f5c17d78bb0414f8d60b5f952196dc2e47ec320dca885de9128ecdb4a0e38401" dependencies = [ "bstr", "gix-date", @@ -1084,9 +1094,9 @@ dependencies = [ [[package]] name = "gix-quote" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b005c550bf84de3b24aa5e540a23e6146a1c01c7d30470e35d75a12f827f969" +checksum = "4a375a75b4d663e8bafe3bf4940a18a23755644c13582fa326e99f8f987d83fd" dependencies = [ "bstr", "gix-utils", @@ -1095,9 +1105,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.51.0" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e1f7eb6b7ce82d2d19961f74bd637bab3ea79b1bc7bfb23dbefc67b0415d8b" +checksum = "d1b7985657029684d759f656b09abc3e2c73085596d5cdb494428823970a7762" dependencies = [ "gix-actor", "gix-features", @@ -1116,9 +1126,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8587b21e2264a6e8938d940c5c99662779c13a10741a5737b15fc85c252ffc" +checksum = "445ed14e3db78e8e79980085e3723df94e1c8163b3ae5bc8ed6a8fe6cf983b42" dependencies = [ "bstr", "gix-hash", @@ -1130,9 +1140,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.33.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342caa4e158df3020cadf62f656307c3948fe4eacfdf67171d7212811860c3e9" +checksum = "78d0b8e5cbd1c329e25383e088cb8f17439414021a643b30afa5146b71e3c65d" dependencies = [ "bstr", "gix-commitgraph", @@ -1145,9 +1155,9 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc7c3d7e5cdc1ab8d35130106e4af0a4f9f9eca0c81f4312b690780e92bde0d" +checksum = "1bc756b73225bf005ddeb871d1ca7b3c33e2417d0d53e56effa5a36765b52b28" dependencies = [ "gix-commitgraph", "gix-date", @@ -1160,21 +1170,21 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.12" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aeb0f13de9ef2f3033f5ff218de30f44db827ac9f1286f9ef050aacddd5888" +checksum = "d0dabbc78c759ecc006b970339394951b2c8e1e38a37b072c105b80b84c308fd" dependencies = [ "bitflags", "gix-path", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "gix-shallow" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0598aacfe1d52575a21c9492fee086edbb21e228ec36c819c42ab923f434c3" +checksum = "6b9a6f6e34d6ede08f522d89e5c7990b4f60524b8ae6ebf8e850963828119ad4" dependencies = [ "bstr", "gix-hash", @@ -1184,9 +1194,9 @@ dependencies = [ [[package]] name = "gix-status" -version = "0.18.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605a6d0eb5891680c46e24b2ee7a63ef7bd39cb136dc7c7e55172960cf68b2f5" +checksum = "072099c2415cfa5397df7d47eacbcb6016d2cd17e0d674c74965e6ad1b17289f" dependencies = [ "bstr", "filetime", @@ -1207,9 +1217,9 @@ dependencies = [ [[package]] name = "gix-submodule" -version = "0.18.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7390c2059505c365e9548016d4edc9f35749c6a9112b7b1214400bbc68da2" +checksum = "5f51472f05a450cc61bc91ed2f62fb06e31e2bbb31c420bc4be8793f26c8b0c1" dependencies = [ "bstr", "gix-config", @@ -1222,9 +1232,9 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "17.0.0" +version = "17.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6de439bbb9a5d3550c9c7fab0e16d2d637d120fcbe0dfbc538772a187f099b" +checksum = "c750e8c008453a2dba67a2b0d928b7716e05da31173a3f5e351d5457ad4470aa" dependencies = [ "dashmap", "gix-fs", @@ -1242,9 +1252,9 @@ checksum = "7c396a2036920c69695f760a65e7f2677267ccf483f25046977d87e4cb2665f7" [[package]] name = "gix-transport" -version = "0.46.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3f68c2870bfca8278389d2484a7f2215b67d0b0cc5277d3c72ad72acf41787e" +checksum = "edfe22ba26d4b65c17879f12b9882eafe65d3c8611c933b272fce2c10f546f59" dependencies = [ "bstr", "gix-command", @@ -1258,9 +1268,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.45.0" +version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c0b049f8bdb61b20016694102f7b507f2e1727e83e9c5e6dad4f7d84ff7384" +checksum = "39094185f6d9a4d81101130fbbf7f598a06441d774ae3b3ae7930a613bbe1157" dependencies = [ "bitflags", "gix-commitgraph", @@ -1275,9 +1285,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dfe23f93f1ddb84977d80bb0dd7aa09d1bf5d5afc0c9b6820cccacc25ae860" +checksum = "42a1ad0b04a5718b5cb233e6888e52a9b627846296161d81dcc5eb9203ec84b8" dependencies = [ "bstr", "gix-features", @@ -1289,9 +1299,9 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189f8724cf903e7fd57cfe0b7bc209db255cacdcb22c781a022f52c3a774f8d0" +checksum = "5351af2b172caf41a3728eb4455326d84e0d70fe26fc4de74ab0bd37df4191c5" dependencies = [ "bstr", "fastrand", @@ -1300,9 +1310,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b5f1253109da6c79ed7cf6e1e38437080bb6d704c76af14c93e2f255234084" +checksum = "77b9e00cacde5b51388d28ed746c493b18a6add1f19b5e01d686b3b9ece66d4d" dependencies = [ "bstr", "thiserror 2.0.12", @@ -1310,9 +1320,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7760dbc4b79aa274fed30adc0d41dca6b917641f26e7867c4071b1fb4dc727b" +checksum = "54f1916f8d928268300c977d773dd70a8746b646873b77add0a34876a8c847e9" dependencies = [ "bstr", "gix-attributes", @@ -1377,6 +1387,15 @@ dependencies = [ "memmap2", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1398,6 +1417,16 @@ dependencies = [ "foldhash", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "helix-core" version = "25.1.1" @@ -1532,7 +1561,7 @@ dependencies = [ "regex-automata", "regex-cursor", "ropey", - "rustix 1.0.2", + "rustix 1.0.7", "tempfile", "unicode-segmentation", "which", @@ -1640,7 +1669,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "rustix 1.0.2", + "rustix 1.0.7", "serde", "serde_json", "slotmap", @@ -1897,9 +1926,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiff" -version = "0.2.8" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -1912,9 +1941,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.8" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" dependencies = [ "proc-macro2", "quote", @@ -1956,9 +1985,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" @@ -1981,6 +2010,15 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" +dependencies = [ + "zlib-rs", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -2123,9 +2161,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "open" @@ -2368,9 +2406,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -2616,7 +2654,7 @@ dependencies = [ "fastrand", "getrandom 0.3.1", "once_cell", - "rustix 1.0.2", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -3116,9 +3154,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.2" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] @@ -3247,3 +3285,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zlib-rs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index a003ad30c33d..90dba44f46f1 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -58,6 +58,7 @@ impl FileBlame { let message = commit.as_ref().and_then(|c| c.message().ok()); let author = commit.as_ref().and_then(|c| c.author().ok()); + let time = author.and_then(|a| a.time.parse::().ok()); let line_blame = LineBlame { commit_hash: commit @@ -65,12 +66,12 @@ impl FileBlame { .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), author_name: author.map(|a| a.name.to_string()), author_email: author.map(|a| a.email.to_string()), - commit_date: author.map(|a| a.time.format(gix::date::time::format::SHORT)), + commit_date: time.map(|time| time.format(gix::date::time::format::SHORT)), commit_message: message.as_ref().map(|msg| msg.title.to_string()), commit_body: message .as_ref() .and_then(|msg| msg.body.map(|body| body.to_string())), - time_stamp: author.map(|a| (a.time.seconds, a.time.offset)), + time_stamp: time.map(|time| (time.seconds, time.offset)), time_ago: None, }; From 7effac92aa9121a306b4ef8cb575c61d1bd472b6 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 6 May 2025 18:22:25 +0100 Subject: [PATCH 26/55] fix: only render inline blame once per line at most Renders inline blame for the last visual line --- helix-term/src/ui/document.rs | 8 ++++++++ helix-term/src/ui/text_decorations/blame.rs | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index 8423ae8e437a..356027213169 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -81,6 +81,8 @@ pub struct LinePos { pub doc_line: usize, /// Vertical offset from the top of the inner view area pub visual_line: u16, + /// The given visual line is the last visual line of the document line + pub is_last_visual_line: bool, } #[allow(clippy::too_many_arguments)] @@ -154,6 +156,7 @@ pub fn render_text( first_visual_line: false, doc_line: usize::MAX, visual_line: u16::MAX, + is_last_visual_line: true, }; let mut last_line_end = 0; let mut is_in_indent_area = true; @@ -188,6 +191,10 @@ pub fn render_text( // apply decorations before rendering a new line if grapheme.visual_pos.row as u16 != last_line_pos.visual_line { + if last_line_pos.doc_line == grapheme.line_idx { + last_line_pos.is_last_visual_line = false; + } + // we initiate doc_line with usize::MAX because no file // can reach that size (memory allocations are limited to isize::MAX) // initially there is no "previous" line (so doc_line is set to usize::MAX) @@ -202,6 +209,7 @@ pub fn render_text( first_visual_line: grapheme.line_idx != last_line_pos.doc_line, doc_line: grapheme.line_idx, visual_line: grapheme.visual_pos.row as u16, + is_last_visual_line: true, }; decorations.decorate_line(renderer, last_line_pos); } diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 645a0462c027..a7df9f632be2 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -31,6 +31,17 @@ impl Decoration for InlineBlame { pos: LinePos, virt_off: Position, ) -> Position { + // Only render inline blame on the last visual line + // This prevents it being rendered multiple times per line, if the + // line is wrapping. + // + // We want to render it on the last visual line because unless the user + // has `soft-wrap.wrap-at-text-width` enabled, for a document line that wraps + // there will only be space to render inline blame at the last doc line + if !pos.is_last_visual_line { + return Position::new(0, 0); + } + let blame = match &self.lines { LineBlame::OneLine((line, blame)) => { if line == &pos.doc_line { From b8bd060128977f26b6a4046e4246ccaa9bc8df6e Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:11:34 +0100 Subject: [PATCH 27/55] chore: fix merge conflicts --- Cargo.lock | 635 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 362 insertions(+), 273 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b37e797ca6b2..9f1fd40e0e32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -46,9 +40,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -67,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arc-swap" @@ -79,30 +73,30 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "block-buffer" @@ -126,9 +120,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -138,9 +132,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cassowary" @@ -150,9 +144,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" dependencies = [ "shlex", ] @@ -176,9 +170,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -245,9 +239,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -264,9 +258,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -349,9 +343,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encoding_rs" @@ -379,15 +373,15 @@ checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -395,9 +389,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" [[package]] name = "etcetera" @@ -422,9 +416,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fern" @@ -437,9 +431,9 @@ dependencies = [ [[package]] name = "filedescriptor" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" dependencies = [ "libc", "thiserror 1.0.69", @@ -466,7 +460,7 @@ checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "libz-rs-sys", - "miniz_oxide 0.8.8", + "miniz_oxide", ] [[package]] @@ -538,9 +532,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -549,21 +543,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gix" @@ -632,9 +626,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e26b3ac280ddb25bb6980d34f4a82ee326f78bf2c6d4ea45eef2d940048b8e" +checksum = "6f50d813d5c2ce9463ba0c29eea90060df08e38ad8f34b8a192259f8bce5c078" dependencies = [ "bstr", "gix-glob", @@ -686,9 +680,9 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f47f3fb4ba33644061e8e0e1030ef2a937d42dc969553118c320a205a9fb28" +checksum = "d05dd813ef6bb798570308aa7f1245cefa350ec9f30dc53308335eb22b9d0f8b" dependencies = [ "bstr", "gix-path", @@ -746,9 +740,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a98593f1f1e14b9fa15c5b921b2c465e904d698b9463e21bb377be8376c3c1a" +checksum = "139d1d52b21741e3f0c72b0fc65e1ff34d4eaceb100ef529d182725d2e09b8cb" dependencies = [ "bstr", "itoa", @@ -839,9 +833,9 @@ dependencies = [ [[package]] name = "gix-filter" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90c21f0d61778f518bbb7c431b00247bf4534b2153c3e85bcf383876c55ca6c" +checksum = "ecf004912949bbcf308d71aac4458321748ecb59f4d046830d25214208c471f1" dependencies = [ "bstr", "encoding_rs", @@ -874,9 +868,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2926b03666e83b8d01c10cf06e5733521aacbd2d97179a4c9b1fdddabb9e937d" +checksum = "90181472925b587f6079698f79065ff64786e6d6c14089517a1972bca99fb6e9" dependencies = [ "bitflags", "bstr", @@ -922,9 +916,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.40.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d505aea7d7c4267a3153cb90c712a89970b4dd02a2cb3205be322891f530b5" +checksum = "b38e919efd59cb8275d23ad2394b2ab9d002007b27620e145d866d546403b665" dependencies = [ "bitflags", "bstr", @@ -1045,9 +1039,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.17" +version = "0.10.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642" +checksum = "567f65fec4ef10dfab97ae71f26a27fd4d7fe7b8e3f90c8a58551c41ff3fb65b" dependencies = [ "bstr", "gix-trace", @@ -1267,9 +1261,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.46.1" +version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39094185f6d9a4d81101130fbbf7f598a06441d774ae3b3ae7930a613bbe1157" +checksum = "b8648172f85aca3d6e919c06504b7ac26baef54e04c55eb0100fa588c102cc33" dependencies = [ "bitflags", "gix-commitgraph", @@ -1407,9 +1401,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1486,7 +1480,7 @@ dependencies = [ "anyhow", "foldhash", "futures-executor", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "log", "once_cell", "parking_lot", @@ -1686,23 +1680,24 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1718,21 +1713,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1741,31 +1737,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1773,67 +1749,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "idna" version = "1.0.3" @@ -1847,9 +1810,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1877,7 +1840,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1887,7 +1850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1917,9 +1880,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" @@ -1964,10 +1927,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1993,7 +1957,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.0", ] [[package]] @@ -2018,21 +1982,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -2046,9 +2010,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "maybe-async" @@ -2069,22 +2033,13 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.8" @@ -2096,11 +2051,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2149,9 +2103,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -2193,14 +2147,14 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2210,9 +2164,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2235,11 +2189,20 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -2283,6 +2246,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -2298,7 +2267,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2323,9 +2292,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] @@ -2397,7 +2366,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] @@ -2410,15 +2379,21 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.2", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -2532,9 +2507,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -2594,9 +2569,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2616,15 +2591,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str_indices" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2633,9 +2608,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -2649,7 +2624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", "rustix 1.0.7", "windows-sys 0.59.0", @@ -2726,9 +2701,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -2736,9 +2711,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -2751,9 +2726,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.1" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -2791,9 +2766,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -2803,34 +2778,41 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] [[package]] -name = "tree-sitter" -version = "0.22.6" +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + +[[package]] +name = "tree-house" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "803311306ba3279e87699f7fa16ea18fbcc8889d0ff0c20dc0652317f8b58117" dependencies = [ "arc-swap", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "kstring", "once_cell", "regex", @@ -2861,12 +2843,9 @@ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bom" @@ -2882,9 +2861,9 @@ checksum = "24adfe8311434967077a6adff125729161e6e4934d76f6b7c55318ac5c9246d3" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-linebreak" @@ -2894,9 +2873,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -2931,12 +2910,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2967,33 +2940,33 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -3002,9 +2975,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3012,9 +2985,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -3025,19 +2998,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "which" -version = "7.0.2" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" dependencies = [ "either", "env_home", - "rustix 0.38.44", + "rustix 1.0.7", "winsafe", ] @@ -3074,18 +3050,62 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" +dependencies = [ + "windows-link", +] [[package]] name = "windows-sys" @@ -3093,7 +3113,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3102,7 +3122,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3111,14 +3131,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -3127,53 +3163,101 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -3186,24 +3270,18 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xtask" @@ -3218,9 +3296,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -3230,9 +3308,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -3262,18 +3340,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -3281,11 +3359,22 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -3294,9 +3383,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", From 1ca7ee8e669f9640faf43b1721d3dbe8accd2a8a Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:27:54 +0100 Subject: [PATCH 28/55] feat: rename config options Based off uncenter's review --- book/src/editor.md | 22 ++++++++++++++-------- helix-term/src/commands.rs | 4 +--- helix-term/src/commands/typed.rs | 6 +++--- helix-term/src/handlers/blame.rs | 10 ++++------ helix-term/src/ui/editor.rs | 10 +++++----- helix-view/src/document.rs | 9 ++++----- helix-view/src/editor.rs | 21 ++++++--------------- 7 files changed, 37 insertions(+), 45 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index a5e1a18ef2e6..12a77c37de6d 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -172,20 +172,26 @@ Inline blame is virtual text that appears at the end of a line, displaying infor | Key | Description | Default | | ------- | ------------------------------------------ | ------- | -| `behaviour` | Choose when to show inline blame | `"hidden"` | -| `compute` | Choose when inline blame should be computed | `"on-demand"` | +| `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} • {message} • {commit}"` | -The `behaviour` can be one of the following: +`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 not shown. +- `"hidden"`: Inline blame is hidden. -Inline blame will only show if the blame for the file has already been computed. +Inline blame will only show if the blame for the file has already been fetched. -The `compute` key determines under which circumstances the blame is computed, and can be one of the following: -- `"on-demand"`: Blame for the file is computed only when explicitly requested, such as when using `space + B` to blame the line of the cursor. There may be a little delay when loading the blame. When opening new files, even with `behaviour` not set to `"hidden"`, the inline blame won't show. It needs to be computed first in order to become available. This computation can be manually triggered by requesting it with `space + B`. -- `"background"`: Blame for the file is loaded 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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. +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 using `space + B` to blame the line of the cursor. There may be a little delay when loading the blame. + + 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`. +- `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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. `inline-blame-format` allows customization of the blame message, and can be set to any string. Variables can be used like so: `{variable}`. These are the available variables: diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 65f5374b1feb..0a6cb4a103c2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3501,9 +3501,7 @@ pub(crate) fn blame_line_impl(editor: &mut Editor, doc_id: DocumentId, cursor_li let line_blame = match doc.line_blame(cursor_line, &inline_blame_config.format) { result if (result.is_ok() && doc.is_blame_potentially_out_of_date) - || matches!(result, Err(LineBlameError::NotReadyYet) if inline_blame_config.compute - == helix_view::editor::InlineBlameCompute::OnDemand - ) => + || matches!(result, Err(LineBlameError::NotReadyYet) if !inline_blame_config.auto_fetch) => { if let Some(path) = doc.path() { let tx = editor.handlers.blame.clone(); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index cf3b2a753257..f88f2ab3a465 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1329,7 +1329,7 @@ fn reload(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyh } let scrolloff = cx.editor.config().scrolloff; - let inline_compute = cx.editor.config().inline_blame.compute; + let auto_fetch = cx.editor.config().inline_blame.auto_fetch; let (view, doc) = current!(cx.editor); doc.reload(view, &cx.editor.diff_providers).map(|_| { view.ensure_cursor_in_view(doc, scrolloff); @@ -1342,7 +1342,7 @@ fn reload(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyh .file_changed(path.clone()); } - if doc.should_request_full_file_blame(inline_compute) { + if doc.should_request_full_file_blame(auto_fetch) { if let Some(path) = doc.path() { helix_event::send_blocking( &cx.editor.handlers.blame, @@ -1382,7 +1382,7 @@ fn reload_all(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> }) .collect(); - let blame_compute = cx.editor.config().inline_blame.compute; + let blame_compute = cx.editor.config().inline_blame.auto_fetch; for (doc_id, view_ids) in docs_view_ids { let doc = doc_mut!(cx.editor, &doc_id); diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index cf8410897fe0..309b26aee186 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -3,7 +3,6 @@ use std::{mem, time::Duration}; use helix_event::register_hook; use helix_vcs::FileBlame; use helix_view::{ - editor::InlineBlameCompute, events::{DocumentDidOpen, EditorConfigDidChange}, handlers::{BlameEvent, Handlers}, DocumentId, @@ -44,7 +43,7 @@ impl helix_event::AsyncHook for BlameHandler { return; }; doc.file_blame = Some(result); - if editor.config().inline_blame.compute == InlineBlameCompute::OnDemand { + if !editor.config().inline_blame.auto_fetch { if let Some(line) = line_blame { crate::commands::blame_line_impl(editor, doc_id, line); } else { @@ -61,7 +60,7 @@ impl helix_event::AsyncHook for BlameHandler { pub(super) fn register_hooks(handlers: &Handlers) { let tx = handlers.blame.clone(); register_hook!(move |event: &mut DocumentDidOpen<'_>| { - if event.editor.config().inline_blame.compute != InlineBlameCompute::OnDemand { + if event.editor.config().inline_blame.auto_fetch { helix_event::send_blocking( &tx, BlameEvent { @@ -75,9 +74,8 @@ pub(super) fn register_hooks(handlers: &Handlers) { }); let tx = handlers.blame.clone(); register_hook!(move |event: &mut EditorConfigDidChange<'_>| { - let has_enabled_inline_blame = event.old_config.inline_blame.compute - == InlineBlameCompute::OnDemand - && event.editor.config().inline_blame.compute == InlineBlameCompute::Background; + let has_enabled_inline_blame = !event.old_config.inline_blame.auto_fetch + && event.editor.config().inline_blame.auto_fetch; if has_enabled_inline_blame { // request blame for all documents, since any of them could have diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 3f251891810a..e8b0781b8d2a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -25,7 +25,7 @@ use helix_core::{ use helix_view::{ annotations::diagnostics::DiagnosticFilter, document::{Mode, SCRATCH_BUFFER_NAME}, - editor::{CompleteAction, CursorShapeConfig, InlineBlameBehaviour, InlineBlameConfig}, + editor::{CompleteAction, CursorShapeConfig, InlineBlameConfig, InlineBlameShow}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, @@ -238,9 +238,9 @@ impl EditorView { ) { const INLINE_BLAME_SCOPE: &str = "ui.virtual.inline-blame"; let text = doc.text(); - match inline_blame.behaviour { - InlineBlameBehaviour::Hidden => (), - InlineBlameBehaviour::CursorLine => { + match inline_blame.show { + InlineBlameShow::Never => (), + InlineBlameShow::CursorLine => { let cursor_line_idx = doc.cursor_line(view.id); // do not render inline blame for empty lines to reduce visual noise @@ -258,7 +258,7 @@ impl EditorView { }; } } - InlineBlameBehaviour::AllLines => { + InlineBlameShow::AllLines => { let mut blame_lines = vec![None; text.len_lines()]; let blame_for_all_lines = view.line_range(doc).filter_map(|line_idx| { diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index ed009c849217..d5763513bdb8 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -43,7 +43,6 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction, }; -use crate::editor::InlineBlameCompute; use crate::{ editor::Config, events::{DocumentDidChange, SelectionDidChange}, @@ -749,11 +748,11 @@ impl Document { } } - pub fn should_request_full_file_blame(&mut self, blame_fetch: InlineBlameCompute) -> bool { - if blame_fetch == InlineBlameCompute::OnDemand { - self.is_blame_potentially_out_of_date - } else { + pub fn should_request_full_file_blame(&mut self, auto_fetch: bool) -> bool { + if auto_fetch { true + } else { + self.is_blame_potentially_out_of_date } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 9b363460201a..49a9dc3a4c1f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -177,33 +177,24 @@ impl Default for GutterLineNumbersConfig { #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum InlineBlameBehaviour { +pub enum InlineBlameShow { /// Do not show inline blame, and do not request it in the background /// /// When manually requesting the inline blame, it may take several seconds to appear. - Hidden, + Never, /// Show the inline blame on the cursor line CursorLine, /// Show the inline blame on every other line AllLines, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum InlineBlameCompute { - /// Inline blame for a file will be fetched when a document is opened or reloaded, for example - Background, - /// Inline blame for a file will be fetched when explicitly requested, e.g. when using `space + B` - OnDemand, -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct InlineBlameConfig { /// How to show the inline blame - pub behaviour: InlineBlameBehaviour, + pub show: InlineBlameShow, /// Whether the inline blame should be fetched in the background - pub compute: InlineBlameCompute, + pub auto_fetch: bool, /// How the inline blame should look like and the information it includes pub format: String, } @@ -211,9 +202,9 @@ pub struct InlineBlameConfig { impl Default for InlineBlameConfig { fn default() -> Self { Self { - behaviour: InlineBlameBehaviour::Hidden, + show: InlineBlameShow::Never, format: "{author}, {time-ago} • {message} • {commit}".to_owned(), - compute: InlineBlameCompute::OnDemand, + auto_fetch: false, } } } From 0123bac0f0476c52ededf3cb173aa7e05af8d383 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:31:18 +0100 Subject: [PATCH 29/55] 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 --- book/src/editor.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 12a77c37de6d..56d9a245e62e 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -193,7 +193,9 @@ The `auto-fetch` key determines under which circumstances the blame is fetched, 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. -`inline-blame-format` allows customization of the blame message, and can be set to any string. Variables can be used like so: `{variable}`. These are the available variables: +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 commit - `date`: When the commit was made @@ -203,19 +205,6 @@ The `auto-fetch` key determines under which circumstances the blame is fetched, - `commit`: The short hex SHA1 hash of the commit - `email`: 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 `format` value: - -- If `author` is empty: `"{time-ago} • {message} • {commit}"` -- If `time-ago` is empty: `"{author} • {message} • {commit}"` -- If `message` is empty: `"{author}, {time-ago} • {commit}"` -- If `commit` is empty: `"{author}, {time-ago} • {message}"` -- If `time-ago` and `message` is empty: `"{author} • {commit}"` -- If `author` and `message` is empty: `"{time-ago} • {commit}"` - ### `[editor.cursor-shape]` Section Defines the shape of cursor in each mode. From f1a29eeff368c503680f715fe8f3a33124f57408 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:41:01 +0100 Subject: [PATCH 30/55] feat: rename the `message` variable to `title` --- book/src/editor.md | 4 ++-- helix-vcs/src/git/blame.rs | 16 ++++++++++------ helix-view/src/editor.rs | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 56d9a245e62e..1402907a2bab 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -174,7 +174,7 @@ Inline blame is virtual text that appears at the end of a line, displaying infor | ------- | ------------------------------------------ | ------- | | `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} • {message} • {commit}"` | +| `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. @@ -200,7 +200,7 @@ The following variables are available: - `author`: The author of the commit - `date`: When the commit was made - `time-ago`: How long ago the commit was made -- `message`: The message of the commit, excluding the body +- `title`: The title of the commit - `body`: The body of the commit - `commit`: The short hex SHA1 hash of the commit - `email`: The email of the author of the commit diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 90dba44f46f1..82ecbcbdebcc 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -51,8 +51,12 @@ impl FileBlame { let line_blame_unit = blame.get_mut(&blame_line); let commit = match line_blame_unit { + // Slow path: This is the first time we're trying to get the blame for this line Some(LineBlameUnit::Unprocessed(object_id)) => repo.find_commit(*object_id).ok(), + // Fast path: We've already processed this line before so we don't need to + // search all of the repo's commits to compute the blame Some(LineBlameUnit::Processed(line_blame)) => return line_blame.clone(), + // This line does not have any blame associated with it None => None, }; @@ -67,7 +71,7 @@ impl FileBlame { author_name: author.map(|a| a.name.to_string()), author_email: author.map(|a| a.email.to_string()), commit_date: time.map(|time| time.format(gix::date::time::format::SHORT)), - commit_message: message.as_ref().map(|msg| msg.title.to_string()), + commit_title: message.as_ref().map(|msg| msg.title.to_string()), commit_body: message .as_ref() .and_then(|msg| msg.body.map(|body| body.to_string())), @@ -129,7 +133,7 @@ pub struct LineBlame { author_name: Option, author_email: Option, commit_date: Option, - commit_message: Option, + commit_title: Option, commit_body: Option, /// Used to compute `time-ago` time_stamp: Option<(i64, i32)>, @@ -159,7 +163,7 @@ impl LineBlame { "commit" => &self.commit_hash, "author" => &self.author_name, "date" => &self.commit_date, - "message" => &self.commit_message, + "message" => &self.commit_title, "email" => &self.author_email, "body" => &self.commit_body, "time-ago" => { @@ -555,7 +559,7 @@ mod test { author_name: Some("Bob TheBuilder".to_owned()), author_email: Some("bob@bob.com".to_owned()), commit_date: Some("2028-01-10".to_owned()), - commit_message: Some("feat!: extend house".to_owned()), + commit_title: Some("feat!: extend house".to_owned()), commit_body: Some("BREAKING CHANGE: Removed door".to_owned()), time_stamp: None, time_ago: None, @@ -588,7 +592,7 @@ mod test { ); assert_eq!( LineBlame { - commit_message: None, + commit_title: None, author_email: None, ..bob() } @@ -615,7 +619,7 @@ mod test { assert_eq!( LineBlame { author_name: None, - commit_message: None, + commit_title: None, ..bob() } .parse_format(format), diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 49a9dc3a4c1f..587a9d035ce6 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -203,7 +203,7 @@ impl Default for InlineBlameConfig { fn default() -> Self { Self { show: InlineBlameShow::Never, - format: "{author}, {time-ago} • {message} • {commit}".to_owned(), + format: "{author}, {time-ago} • {title} • {commit}".to_owned(), auto_fetch: false, } } From a859cb2b2d7069e034366cace16b5179a07ac6f5 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:44:17 +0100 Subject: [PATCH 31/55] docs: change sentence --- book/src/editor.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 1402907a2bab..a447beb61975 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -193,9 +193,7 @@ The `auto-fetch` key determines under which circumstances the blame is fetched, 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. -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: +Change the `format` string 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 commit - `date`: When the commit was made From 4eebdeca63787c881a72a1eac1688c504a3700a0 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:47:47 +0100 Subject: [PATCH 32/55] test: use renamed `commit_message` --- helix-vcs/src/git/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 82ecbcbdebcc..8851c77bdf94 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -415,7 +415,7 @@ mod test { FileBlame::try_new(file.clone()) .unwrap() .blame_for_line(line_number, added_lines, removed_lines) - .commit_message; + .commit_title; assert_eq!( blame_result, From 00117f83bb2ebec2d32d9839e43530c26982c435 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 09:49:15 +0100 Subject: [PATCH 33/55] fix: use correct variable name `title` instead of `message` --- helix-vcs/src/git/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 8851c77bdf94..f1dafff4b3b4 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -163,7 +163,7 @@ impl LineBlame { "commit" => &self.commit_hash, "author" => &self.author_name, "date" => &self.commit_date, - "message" => &self.commit_title, + "title" => &self.commit_title, "email" => &self.author_email, "body" => &self.commit_body, "time-ago" => { From 01e9dc1e39045c67ef8c721adb34df9dc774d981 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 10:27:10 +0100 Subject: [PATCH 34/55] test: use correct variable name --- helix-vcs/src/git/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index f1dafff4b3b4..dfb4005a96e2 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -568,7 +568,7 @@ mod test { #[test] pub fn inline_blame_format_parser() { - let format = "{author}, {date} • {message} • {commit}"; + let format = "{author}, {date} • {title} • {commit}"; assert_eq!( bob().parse_format(format), From 9d275514cfb3eb9e0664f0d68e5ae2fa5ed3adcc Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon, 19 May 2025 12:20:48 +0100 Subject: [PATCH 35/55] docs: improve wording Co-authored-by: uncenter --- book/src/editor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index a447beb61975..71d424241a3b 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -173,7 +173,7 @@ Inline blame is virtual text that appears at the end of a line, displaying infor | Key | Description | Default | | ------- | ------------------------------------------ | ------- | | `show` | Choose when to show inline blame | `"never"` | -| `auto-fetch` | Choose when inline blame should be computed | `false` | +| `auto-fetch` | Automatically fetch blame information in the background | `false` | | `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {title} • {commit}"` | `show` can be one of the following: From dd1f31d415f4a49dc7a4f218c6ea5738387109bf Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon, 19 May 2025 12:21:05 +0100 Subject: [PATCH 36/55] docs: improve wording Co-authored-by: uncenter --- book/src/editor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index 71d424241a3b..5ad515e18eb4 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -172,7 +172,7 @@ Inline blame is virtual text that appears at the end of a line, displaying infor | Key | Description | Default | | ------- | ------------------------------------------ | ------- | -| `show` | Choose when to show inline blame | `"never"` | +| `show` | When to show inline blame | `"never"` | | `auto-fetch` | Automatically fetch blame information in the background | `false` | | `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {title} • {commit}"` | From eb559cf6777cbc597fcdccfb807746a169bd2fb1 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon, 19 May 2025 13:43:28 +0100 Subject: [PATCH 37/55] docs: remove hard to understand sentence Co-authored-by: uncenter --- book/src/editor.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 5ad515e18eb4..608dfd9722eb 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -181,8 +181,6 @@ Inline blame is virtual text that appears at the end of a line, displaying infor - `"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 using `space + B` to blame the line of the cursor. There may be a little delay when loading the blame. From 92dc3ca521cff61f48ab927247b7d5bceae2c8dd Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon, 19 May 2025 13:44:00 +0100 Subject: [PATCH 38/55] docs: improve wording Co-authored-by: uncenter --- book/src/editor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index 608dfd9722eb..1fe2c5503b67 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -174,7 +174,7 @@ Inline blame is virtual text that appears at the end of a line, displaying infor | ------- | ------------------------------------------ | ------- | | `show` | When to show inline blame | `"never"` | | `auto-fetch` | Automatically fetch blame information in the background | `false` | -| `format` | The format in which to show the inline blame | `"{author}, {time-ago} • {title} • {commit}"` | +| `format` | Inline blame message format | `"{author}, {time-ago} • {title} • {commit}"` | `show` can be one of the following: - `"all-lines"`: Inline blame is on every line. From e64b4fad1ba3521d8b560a1551ad1af8d581c053 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+nik-rev@users.noreply.github.com> Date: Mon, 19 May 2025 13:47:34 +0100 Subject: [PATCH 39/55] docs: improve wording Co-authored-by: uncenter --- book/src/editor.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 1fe2c5503b67..529d49fc807a 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -181,15 +181,9 @@ Inline blame is virtual text that appears at the end of a line, displaying infor - `"cursor-line"`: Inline blame is only on the line of the primary cursor. - `"hidden"`: Inline blame is hidden. -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 using `space + B` to blame the line of the cursor. There may be a little delay when loading the blame. +By default (or 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. When `auto-fetch` is enabled, 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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. - 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`. -- `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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. +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`. Change the `format` string to customize the blame message displayed. Variables are text placeholders wrapped in curly braces: `{variable}`. The following variables are available: From 08c66504b3a7f17bf4f860845740bb389b34f9b1 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Mon, 19 May 2025 13:54:00 +0100 Subject: [PATCH 40/55] docs: Add line breaks to paragraph + improve wording --- book/src/editor.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index 529d49fc807a..959f89c5a399 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -181,10 +181,14 @@ Inline blame is virtual text that appears at the end of a line, displaying infor - `"cursor-line"`: Inline blame is only on the line of the primary cursor. - `"hidden"`: Inline blame is hidden. -By default (or 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. When `auto-fetch` is enabled, 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 + B` will be instant. Inline blame will show as soon as the blame is available when loading new files. +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. + +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. 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`. +#### `format` + Change the `format` string 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 commit From 100ad75d9ebbf53d39c115a7774a21d490271971 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat, 7 Jun 2025 11:35:46 +0100 Subject: [PATCH 41/55] chore: clarify comment --- helix-vcs/src/git/blame.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index dfb4005a96e2..63b52a36dc7e 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -100,7 +100,8 @@ impl FileBlame { head, None, &mut resource_cache, - // bstr always uses unix separators + // NOTE: bstr always uses unix separators `/`, even on + // Windows which uses the `\` separator &gix::path::to_unix_separators_on_windows(gix::path::try_into_bstr( file.strip_prefix( repo.path() From 41cb919b5da4a51694ab54b7d9726c3041f249a3 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat, 7 Jun 2025 11:57:55 +0100 Subject: [PATCH 42/55] feat: if you are the author, use "You" instead of name --- helix-vcs/src/git/blame.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 63b52a36dc7e..c12e1e9cba60 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -61,15 +61,33 @@ impl FileBlame { }; let message = commit.as_ref().and_then(|c| c.message().ok()); - let author = commit.as_ref().and_then(|c| c.author().ok()); - let time = author.and_then(|a| a.time.parse::().ok()); + + let commit_author = commit.as_ref().and_then(|c| c.author().ok()); + + // NOTE: Repo author is not the person who created the repository, + // but it is the person who is using Helix right now. + // + // If the person who is using Helix made the commit, (they have the same name), + // then instead of using the name, use "You". + let repo_author = repo + .author() + .transpose() + .ok() + .flatten() + .is_some_and(|author| { + commit_author.is_some_and(|commit_author| author.name == commit_author.name) + }) + .then(|| "You".to_string()); + let author_name = + repo_author.or_else(|| commit_author.map(|author| author.name.to_string())); + let time = commit_author.and_then(|a| a.time.parse::().ok()); let line_blame = LineBlame { commit_hash: commit .as_ref() .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), - author_name: author.map(|a| a.name.to_string()), - author_email: author.map(|a| a.email.to_string()), + author_name, + author_email: commit_author.map(|a| a.email.to_string()), commit_date: time.map(|time| time.format(gix::date::time::format::SHORT)), commit_title: message.as_ref().map(|msg| msg.title.to_string()), commit_body: message From a476d6dc1cf37b0dedbd892cb058d7461e7e9c77 Mon Sep 17 00:00:00 2001 From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Sat, 7 Jun 2025 14:06:25 +0100 Subject: [PATCH 43/55] Revert "feat: if you are the author, use "You" instead of name" This reverts commit 41cb919b5da4a51694ab54b7d9726c3041f249a3. 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: https://github.com/zed-industries/zed/issues/10557 --- helix-vcs/src/git/blame.rs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index c12e1e9cba60..63b52a36dc7e 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -61,33 +61,15 @@ impl FileBlame { }; let message = commit.as_ref().and_then(|c| c.message().ok()); - - let commit_author = commit.as_ref().and_then(|c| c.author().ok()); - - // NOTE: Repo author is not the person who created the repository, - // but it is the person who is using Helix right now. - // - // If the person who is using Helix made the commit, (they have the same name), - // then instead of using the name, use "You". - let repo_author = repo - .author() - .transpose() - .ok() - .flatten() - .is_some_and(|author| { - commit_author.is_some_and(|commit_author| author.name == commit_author.name) - }) - .then(|| "You".to_string()); - let author_name = - repo_author.or_else(|| commit_author.map(|author| author.name.to_string())); - let time = commit_author.and_then(|a| a.time.parse::().ok()); + let author = commit.as_ref().and_then(|c| c.author().ok()); + let time = author.and_then(|a| a.time.parse::().ok()); let line_blame = LineBlame { commit_hash: commit .as_ref() .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), - author_name, - author_email: commit_author.map(|a| a.email.to_string()), + author_name: author.map(|a| a.name.to_string()), + author_email: author.map(|a| a.email.to_string()), commit_date: time.map(|time| time.format(gix::date::time::format::SHORT)), commit_title: message.as_ref().map(|msg| msg.title.to_string()), commit_body: message From 5e21b7f1183cd7f7b16d6e73cbbf949e7b1932ec Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 17 Jun 2025 11:40:21 +0100 Subject: [PATCH 44/55] fix: Cargo.lock --- Cargo.lock | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 7b6489fb288d..fbacd9f4963d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,6 +228,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -558,6 +567,7 @@ checksum = "01237e8d3d78581f71642be8b0c2ae8c0b2b5c251c9c5d9ebbea3c1ea280dce8" dependencies = [ "gix-actor", "gix-attributes", + "gix-blame", "gix-command", "gix-commitgraph", "gix-config", @@ -640,6 +650,25 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "gix-blame" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6807d2660ea9e15752a5d5867a9b05594ed27395ee18d51df7ebcb84a4809e9" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-diff", + "gix-hash", + "gix-object", + "gix-revwalk", + "gix-trace", + "gix-traverse", + "gix-worktree", + "smallvec", + "thiserror 2.0.12", +] + [[package]] name = "gix-chunk" version = "0.4.11" @@ -789,12 +818,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f4399af6ec4fd9db84dd4cf9656c5c785ab492ab40a7c27ea92b4241923fed" dependencies = [ "crc32fast", + "crossbeam-channel", "flate2", "gix-path", "gix-trace", "gix-utils", "libc", "once_cell", + "parking_lot", "prodash", "thiserror 2.0.12", "walkdir", From 7a83e9e09b89415a665c346c51b1d728ac022787 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Sun, 27 Jul 2025 10:43:39 +0100 Subject: [PATCH 45/55] feat: horizontal scroll of the current document into account when drawing the blame Co-authored-by: Taylor Plewe --- helix-term/src/ui/text_decorations/blame.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index a7df9f632be2..5246df301103 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -65,10 +65,11 @@ impl Decoration for InlineBlame { let end_of_line = virt_off.col as u16; // length of line in the document // draw the git blame 6 spaces after the end of the line - let start_drawing_at = end_of_line + 6; + let start_drawing_at = (end_of_line - renderer.offset.col as u16) + 6; + let start_drawing_at_virtual = end_of_line + 6; let amount_of_characters_drawn = renderer - .column_in_bounds(start_drawing_at as usize, 1) + .column_in_bounds(start_drawing_at_virtual as usize, 1) .then(|| { // the column where we stop drawing the blame let stopped_drawing_at = renderer From 1c0b99db28898166fd9f0e9a1c9f3332e5442322 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Sun, 27 Jul 2025 10:51:12 +0100 Subject: [PATCH 46/55] refactor: Do not use `unwrap_or_default` on simple integer See https://github.com/rust-lang/rust-clippy/pull/15037 --- helix-term/src/ui/text_decorations/blame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs index 5246df301103..bc048ef46141 100644 --- a/helix-term/src/ui/text_decorations/blame.rs +++ b/helix-term/src/ui/text_decorations/blame.rs @@ -88,7 +88,7 @@ impl Decoration for InlineBlame { stopped_drawing_at - line_length }) - .unwrap_or_default(); + .unwrap_or(0); Position::new(0, amount_of_characters_drawn as usize) } From b8b2430b0b212b3da8c465976269bc5dba8425c4 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:28:28 +0000 Subject: [PATCH 47/55] Update for the latest `gix 0.78` --- helix-vcs/src/git/blame.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 63b52a36dc7e..33400b448e82 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -70,7 +70,7 @@ impl FileBlame { .and_then(|c| c.short_id().map(|id| id.to_string()).ok()), author_name: author.map(|a| a.name.to_string()), author_email: author.map(|a| a.email.to_string()), - commit_date: time.map(|time| time.format(gix::date::time::format::SHORT)), + commit_date: time.and_then(|time| time.format(gix::date::time::format::SHORT).ok()), commit_title: message.as_ref().map(|msg| msg.title.to_string()), commit_body: message .as_ref() @@ -92,7 +92,7 @@ impl FileBlame { let thread_safe_repo = open_repo(get_repo_dir(&file)?).context("Failed to open git repo")?; let repo = thread_safe_repo.to_thread_local(); - let head = repo.head()?.peel_to_commit_in_place()?.id; + let head = repo.head()?.peel_to_commit()?.id; let mut resource_cache = repo.diff_resource_cache_for_tree_diff()?; let file_blame = gix::blame::file( From f322b038ec99d8bf159dd0068119ba2dd59b89ae Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:30:26 +0000 Subject: [PATCH 48/55] Remove unnecessary macro This macro doesn't give enough of a performance benefit to be worth it --- helix-stdx/src/lib.rs | 1 - helix-stdx/src/str.rs | 18 ------------------ helix-stdx/src/time.rs | 2 +- 3 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 helix-stdx/src/str.rs diff --git a/helix-stdx/src/lib.rs b/helix-stdx/src/lib.rs index 143d141dfaa2..a77b9c9c0b58 100644 --- a/helix-stdx/src/lib.rs +++ b/helix-stdx/src/lib.rs @@ -6,7 +6,6 @@ pub mod faccess; pub mod path; pub mod range; pub mod rope; -pub mod str; pub mod time; pub use range::Range; diff --git a/helix-stdx/src/str.rs b/helix-stdx/src/str.rs deleted file mode 100644 index 942acea9570b..000000000000 --- a/helix-stdx/src/str.rs +++ /dev/null @@ -1,18 +0,0 @@ -/// Concatenates strings together. -/// -/// `str_concat!(a, " ", b, " ", c)` is: -/// - more performant than `format!("{a} {b} {c}")` -/// - more ergonomic than using `String::with_capacity` followed by a series of `String::push_str` -#[macro_export] -macro_rules! str_concat { - ($($value:expr),*) => {{ - // Rust does not allow using `+` as separator between value - // so we must add that at the end of everything. The `0` is necessary - // at the end so it does not end with "+ " (which would be invalid syntax) - let mut buf = String::with_capacity($($value.len() + )* 0); - $( - buf.push_str(&$value); - )* - buf - }} -} diff --git a/helix-stdx/src/time.rs b/helix-stdx/src/time.rs index 08a45988ca76..cb72a9386093 100644 --- a/helix-stdx/src/time.rs +++ b/helix-stdx/src/time.rs @@ -71,5 +71,5 @@ pub fn format_relative_time(timestamp: i64, timezone_offset: i32) -> String { "from now" }; - crate::str_concat!(value, " ", unit, " ", label) + format!("{value} {unit} {label}") } From e755f63abb9f286fb0f59fdf29dc19c83c949f42 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:35:23 +0000 Subject: [PATCH 49/55] Add documentation for a few fields --- helix-term/src/handlers/blame.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs index 309b26aee186..249113041c60 100644 --- a/helix-term/src/handlers/blame.rs +++ b/helix-term/src/handlers/blame.rs @@ -11,10 +11,16 @@ use tokio::time::Instant; use crate::job; +/// Handles showing Git Blame for a single document #[derive(Default)] pub struct BlameHandler { + /// Computed blame for the file. This is in an `Option` because we + /// need to be able to `mem::take` it, as we will need an owned instance + /// when we only have access to `&mut self` file_blame: Option>, + /// Document for which we will update the blame doc_id: DocumentId, + /// If `Some`, when blame is obtained for the file, the user will be notified show_blame_for_line_in_statusline: Option, } From cd008bba2d6f0b714dd64f93b46d59c993182eb4 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:37:54 +0000 Subject: [PATCH 50/55] Run `cargo fmt` --- helix-core/src/test.rs | 5 +---- helix-term/src/events.rs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 71c71cce2812..05fa3e60693a 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -286,10 +286,7 @@ mod test { #[test] fn print_multi_code_point_grapheme() { assert_eq!( - ( - String::from("hello 👨‍👩‍👧‍👦 goodbye"), - Selection::single(13, 6) - ), + (String::from("hello 👨‍👩‍👧‍👦 goodbye"), Selection::single(13, 6)), print("hello #[|👨‍👩‍👧‍👦]# goodbye") ); } diff --git a/helix-term/src/events.rs b/helix-term/src/events.rs index 182dd4c42208..75d9d607bbe4 100644 --- a/helix-term/src/events.rs +++ b/helix-term/src/events.rs @@ -2,8 +2,8 @@ use helix_event::{events, register_event}; use helix_view::document::Mode; use helix_view::events::{ ConfigDidChange, DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, DocumentDidOpen, - DocumentFocusLost, - EditorConfigDidChange, LanguageServerExited, LanguageServerInitialized, SelectionDidChange, + DocumentFocusLost, EditorConfigDidChange, LanguageServerExited, LanguageServerInitialized, + SelectionDidChange, }; use crate::commands; From ffabf4464ccc2e1caca9305ac68fa33aa22c3c20 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:42:05 +0000 Subject: [PATCH 51/55] Use same `Cargo.lock` as on the `master` branch --- Cargo.lock | 667 +++++++++++++++++++--------------------- helix-loader/Cargo.toml | 2 - helix-stdx/Cargo.toml | 2 - rust-toolchain.toml | 2 +- 4 files changed, 325 insertions(+), 348 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80e0ef521ff8..e7a5491d01fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.4", + "getrandom 0.3.1", "once_cell", "version_check", "zerocopy", @@ -17,18 +17,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.21" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android_system_properties" @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -100,9 +100,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cassowary" @@ -122,9 +122,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chardetng" @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -309,9 +309,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.15.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" @@ -339,25 +339,25 @@ checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.14" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "error-code" -version = "3.3.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" [[package]] name = "etcetera" @@ -382,9 +382,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "faststr" @@ -409,13 +409,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.27" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -444,9 +445,9 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "form_urlencoded" -version = "1.2.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -499,25 +500,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasip2", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -1469,7 +1470,6 @@ dependencies = [ "cc", "etcetera", "helix-stdx", - "home", "log", "once_cell", "serde", @@ -1524,7 +1524,6 @@ dependencies = [ "bitflags", "dunce", "etcetera", - "home", "once_cell", "regex-automata", "regex-cursor", @@ -1657,9 +1656,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "home" @@ -1672,15 +1671,14 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", - "log", "wasm-bindgen", "windows-core", ] @@ -1696,22 +1694,21 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", - "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locale_core" -version = "2.1.1" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", @@ -1720,66 +1717,104 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ + "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", + "utf16_iter", + "utf8_iter", + "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" -version = "2.1.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ + "displaydoc", "icu_collections", - "icu_locale_core", + "icu_locid_transform", "icu_properties_data", "icu_provider", - "zerotrie", + "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", - "icu_locale_core", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", "writeable", "yoke", "zerofrom", - "zerotrie", "zerovec", ] +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "idna" -version = "1.1.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", @@ -1788,9 +1823,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", @@ -1903,9 +1938,9 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2" +checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" [[package]] name = "jiff-tzdb-platform" @@ -1918,9 +1953,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -1943,23 +1978,23 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libloading" -version = "0.8.9" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-link", + "windows-targets 0.53.2", ] [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags", "libc", - "redox_syscall 0.7.0", + "redox_syscall", ] [[package]] @@ -1976,9 +2011,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" @@ -2008,9 +2043,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -2023,30 +2058,31 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "log", - "wasi", - "windows-sys 0.61.2", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] name = "munge" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +checksum = "d7feb0b48aa0a25f9fe0899482c6e1379ee7a11b24a53073eacdecb9adb6dc60" dependencies = [ "munge_macro", ] [[package]] name = "munge_macro" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +checksum = "f2e3795a5d2da581a8b252fec6022eee01aea10161a4d1bf237d4cbe47f7e988" dependencies = [ "proc-macro2", "quote", @@ -2085,9 +2121,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.17.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", @@ -2128,28 +2164,28 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.18", + "redox_syscall", "smallvec", "windows-link", ] [[package]] name = "pathdiff" -version = "0.2.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.3.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2159,9 +2195,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portable-atomic-util" @@ -2172,20 +2208,11 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -2201,18 +2228,18 @@ dependencies = [ [[package]] name = "ptr_meta" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" dependencies = [ "proc-macro2", "quote", @@ -2241,24 +2268,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - [[package]] name = "rancor" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" dependencies = [ "ptr_meta", ] @@ -2278,14 +2299,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.15", ] [[package]] name = "rayon" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -2293,9 +2314,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.13.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2303,36 +2324,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.7.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", @@ -2377,24 +2389,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" -version = "0.5.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" [[package]] name = "rkyv" -version = "0.8.14" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360b333c61ae24e5af3ae7c8660bd6b21ccd8200dbbc5d33c2454421e85b9c69" +checksum = "19f5c3e5da784cd8c69d32cdc84673f3204536ca56e1fa01be31a74b92c932ac" dependencies = [ "bytes", - "hashbrown 0.16.1", + "hashbrown 0.15.5", "indexmap", "munge", "ptr_meta", @@ -2407,9 +2419,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.14" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02f8cdd12b307ab69fe0acf4cd2249c7460eb89dce64a0febadf934ebb6a9e" +checksum = "4270433626cffc9c4c1d3707dd681f2a2718d3d7b09ad754bec137acecda8d22" dependencies = [ "proc-macro2", "quote", @@ -2460,9 +2472,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2554,9 +2566,9 @@ dependencies = [ [[package]] name = "shell-words" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" @@ -2586,9 +2598,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -2597,11 +2609,10 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.8" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ - "errno", "libc", ] @@ -2625,9 +2636,12 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "slotmap" @@ -2663,12 +2677,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2703,18 +2717,18 @@ dependencies = [ [[package]] name = "sonic-simd" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5707edbfb34a40c9f2a55fa09a49101d9fec4e0cc171ce386086bd9616f34257" +checksum = "b421f7b6aa4a5de8f685aaf398dfaa828346ee639d2b1c1061ab43d40baa6223" dependencies = [ "cfg-if", ] [[package]] name = "stable_deref_trait" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" @@ -2724,15 +2738,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str_indices" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" +checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2741,9 +2755,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", @@ -2757,7 +2771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.3.1", "once_cell", "rustix 1.1.3", "windows-sys 0.61.2", @@ -2794,7 +2808,7 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.2.2", + "unicode-width 0.2.0", ] [[package]] @@ -2828,9 +2842,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", @@ -2838,9 +2852,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2948,9 +2962,9 @@ dependencies = [ [[package]] name = "tree-house-bindings" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f24f037be888a6ea5521046288c126aa700ade79e9fe7c74cdef79207281c20b" +checksum = "3f1646788fe0afdbf8e191b5d0f558df7333d8857665a67053c532ec811e6086" dependencies = [ "cc", "libloading", @@ -2961,15 +2975,18 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicase" -version = "2.9.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] [[package]] name = "unicode-bom" @@ -2985,9 +3002,9 @@ checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" @@ -2997,9 +3014,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.25" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3018,23 +3035,28 @@ checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-width" -version = "0.2.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "url" -version = "2.5.8" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", - "serde_derive", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3043,9 +3065,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.20.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3069,24 +3091,24 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" +name = "wasi" +version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" dependencies = [ - "wit-bindgen", + "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -3095,11 +3117,25 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3107,22 +3143,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ - "bumpalo", "proc-macro2", "quote", "syn", + "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] @@ -3156,11 +3192,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.11" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3171,37 +3207,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-targets 0.52.6", ] [[package]] @@ -3210,24 +3220,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -3246,15 +3238,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3282,19 +3265,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.5" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -3305,9 +3287,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" @@ -3317,9 +3299,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" @@ -3329,9 +3311,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" @@ -3341,9 +3323,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" @@ -3353,9 +3335,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" @@ -3365,9 +3347,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" @@ -3377,9 +3359,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" @@ -3389,9 +3371,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" @@ -3409,16 +3391,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] -name = "wit-bindgen" -version = "0.51.0" +name = "wit-bindgen-rt" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" -version = "0.6.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "xtask" @@ -3433,10 +3424,11 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ + "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3444,9 +3436,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", @@ -3456,18 +3448,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.34" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.34" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -3476,18 +3468,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", @@ -3495,22 +3487,11 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - [[package]] name = "zerovec" -version = "0.11.5" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", @@ -3519,9 +3500,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", @@ -3536,6 +3517,6 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" [[package]] name = "zmij" -version = "1.0.17" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" +checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index e275c2bf921f..acbdc5d5e51e 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -23,8 +23,6 @@ toml.workspace = true etcetera = "0.10" once_cell = "1.21" log = "0.4" -# MSRV: update once the MSRV is >=1.85 -home = "=0.5.9" # TODO: these two should be on !wasm32 only diff --git a/helix-stdx/Cargo.toml b/helix-stdx/Cargo.toml index 3455c06fd205..7fa471fe44a5 100644 --- a/helix-stdx/Cargo.toml +++ b/helix-stdx/Cargo.toml @@ -14,8 +14,6 @@ homepage.workspace = true [dependencies] dunce = "1.0" etcetera = "0.10" -# MSRV: update once the MSRV is >=1.85 -home = "=0.5.9" ropey.workspace = true which = "8.0" regex-cursor = "0.1.5" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 00ca8bbbb3c6..74c6fc7a2d28 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.87.0" +channel = "1.82.0" components = ["rustfmt", "rust-src", "clippy"] From 5f5bc86b1ada01c80015254afef0910e146e74d3 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:42:23 +0000 Subject: [PATCH 52/55] Run `cargo fmt` --- helix-core/src/test.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 05fa3e60693a..71c71cce2812 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -286,7 +286,10 @@ mod test { #[test] fn print_multi_code_point_grapheme() { assert_eq!( - (String::from("hello 👨‍👩‍👧‍👦 goodbye"), Selection::single(13, 6)), + ( + String::from("hello 👨‍👩‍👧‍👦 goodbye"), + Selection::single(13, 6) + ), print("hello #[|👨‍👩‍👧‍👦]# goodbye") ); } From 56c65bffe5265e0b0cdaf60d9af3ad7b33a4c039 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:49:49 +0000 Subject: [PATCH 53/55] Remove stray formatting changes Makes the diff less noisy --- helix-term/src/ui/editor.rs | 1 - helix-view/src/document.rs | 4 ++-- helix-view/src/editor.rs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a00a3973e8ff..e05721118cf1 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -199,7 +199,6 @@ impl EditorView { inline_diagnostic_config, config.end_of_line_diagnostics, )); - render_document( surface, inner, diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 1c30592340a8..e373aecbc107 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -215,13 +215,13 @@ pub struct Document { // NOTE: ideally this would live on the handler for color swatches. This is blocked on a // large refactor that would make `&mut Editor` available on the `DocumentDidChange` event. pub color_swatch_controller: TaskController, + pub pull_diagnostic_controller: TaskController, + /// When fetching blame on-demand, if this field is `true` we request the blame for this document again pub is_blame_potentially_out_of_date: bool, // NOTE: this field should eventually go away - we should use the Editor's syn_loader instead // of storing a copy on every doc. Then we can remove the surrounding `Arc` and use the // `ArcSwap` directly. - pub pull_diagnostic_controller: TaskController, - syn_loader: Arc>, } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 099939b026e9..e9f91222df78 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1962,7 +1962,6 @@ impl Editor { doc.set_version_control_head(self.diff_providers.get_current_head_name(&path)); let id = self.new_document(doc); - self.launch_language_servers(id); helix_event::dispatch(DocumentDidOpen { From 1e4d53fb6596fdf599597f5b6e693449b2f09910 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:51:35 +0000 Subject: [PATCH 54/55] Replace call to `with_capacity()` with `new()` This doesn't provide enough of a performance benefit to be worth the additional cognitive cost --- helix-vcs/src/git/blame.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/helix-vcs/src/git/blame.rs b/helix-vcs/src/git/blame.rs index 33400b448e82..2a2a29d2882b 100644 --- a/helix-vcs/src/git/blame.rs +++ b/helix-vcs/src/git/blame.rs @@ -147,11 +147,6 @@ pub struct LineBlame { } impl LineBlame { - /// Longest variable is: `time-ago` (and `message`) - // this is just to reduce allocation by a little bit by specifying the max size we would expect a - // variable to be up-front. This function is called every render. - const LONGEST_VARIABLE_LENGTH: usize = 7; - /// # Returns /// /// None => Invalid variable @@ -192,7 +187,7 @@ impl LineBlame { let mut exclude_content_after_variable = false; while let Some((ch_idx, ch)) = chars.next() { if ch == '{' { - let mut variable = String::with_capacity(Self::LONGEST_VARIABLE_LENGTH); + let mut variable = String::new(); // eat all characters until the end while let Some((_, ch)) = chars.next_if(|(_, ch)| *ch != '}') { variable.push(ch); From 48a87056dc45fdc80bf1c97bccd2e851d20e5749 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Tue, 27 Jan 2026 18:53:13 +0000 Subject: [PATCH 55/55] Remove stray formatting change --- helix-vcs/src/git.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 06cc04cff4a2..a2e124e79af8 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -1,11 +1,11 @@ use anyhow::{bail, Context, Result}; use arc_swap::ArcSwap; -use gix::bstr::ByteSlice as _; use gix::filter::plumbing::driver::apply::Delay; use std::io::Read; use std::path::Path; use std::sync::Arc; +use gix::bstr::ByteSlice; use gix::diff::Rewrites; use gix::dir::entry::Status; use gix::objs::tree::EntryKind;