From ddf8ac11587b26ddb093f09f7badfd48fb281d46 Mon Sep 17 00:00:00 2001
From: Nik Revenco <154856872+NikitaRevenco@users.noreply.github.com>
Date: Tue, 18 Mar 2025 19:09:02 +0000
Subject: [PATCH] feat: implement inline git blame

---
 helix-term/src/handlers.rs                  |  2 +-
 helix-term/src/handlers/blame.rs            | 17 +++++------
 helix-term/src/ui/editor.rs                 | 14 +++++----
 helix-term/src/ui/text_decorations/blame.rs | 32 ++-------------------
 helix-vcs/src/git.rs                        |  2 +-
 helix-view/src/document.rs                  |  2 +-
 helix-view/src/view.rs                      |  8 ------
 7 files changed, 23 insertions(+), 54 deletions(-)

diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs
index 2ea0bf90..6f18d43b 100644
--- a/helix-term/src/handlers.rs
+++ b/helix-term/src/handlers.rs
@@ -37,6 +37,6 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
     auto_save::register_hooks(&handlers);
     diagnostics::register_hooks(&handlers);
     snippet::register_hooks(&handlers);
-    // blame::register_hooks(&handlers);
+    blame::register_hooks(&handlers);
     handlers
 }
diff --git a/helix-term/src/handlers/blame.rs b/helix-term/src/handlers/blame.rs
index e733f953..720556d4 100644
--- a/helix-term/src/handlers/blame.rs
+++ b/helix-term/src/handlers/blame.rs
@@ -62,12 +62,13 @@ fn request_git_blame(editor: &mut Editor) {
         return;
     };
 
-    doc.blame = Some(vec![InlineAnnotation::new(
-        text.try_line_to_char(cursor_lin + 1)
-            .unwrap_or(text.len_chars())
-        // to get the last position in the current line
-        - 1,
-        output.to_string(),
-    )]);
-    log::error!("{:?}", doc.blame);
+    doc.blame = Some(output.to_string());
+    // doc.blame = Some(vec![InlineAnnotation::new(
+    //     text.try_line_to_char(cursor_lin + 1)
+    //         .unwrap_or(text.len_chars())
+    //     // to get the last position in the current line
+    //     - 1,
+    //     output.to_string(),
+    // )]);
+    // log::error!("{:?}", doc.blame);
 }
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 3ce7aa4e..107dbce7 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -202,12 +202,14 @@ impl EditorView {
             config.end_of_line_diagnostics,
         ));
         if config.vcs.blame {
-            decorations.add_decoration(text_decorations::blame::EolBlame::new(
-                doc,
-                theme,
-                doc.text().char_to_line(primary_cursor),
-                "hello world".to_string(),
-            ));
+            if let Some(blame) = &doc.blame {
+                decorations.add_decoration(text_decorations::blame::EolBlame::new(
+                    doc,
+                    theme,
+                    doc.text().char_to_line(primary_cursor),
+                    blame,
+                ));
+            }
         }
         render_document(
             surface,
diff --git a/helix-term/src/ui/text_decorations/blame.rs b/helix-term/src/ui/text_decorations/blame.rs
index 3f64522e..766074da 100644
--- a/helix-term/src/ui/text_decorations/blame.rs
+++ b/helix-term/src/ui/text_decorations/blame.rs
@@ -1,6 +1,5 @@
 #![allow(dead_code, unused_variables, unused_mut)]
 
-use helix_core::doc_formatter::FormattedGrapheme;
 use helix_core::Position;
 
 use helix_view::theme::Style;
@@ -10,14 +9,14 @@ use crate::ui::document::{LinePos, TextRenderer};
 use crate::ui::text_decorations::Decoration;
 
 pub struct EolBlame<'a> {
-    message: String,
+    message: &'a str,
     doc: &'a Document,
     cursor: usize,
     style: Style,
 }
 
 impl<'a> EolBlame<'a> {
-    pub fn new(doc: &'a Document, theme: &Theme, cursor: usize, message: String) -> Self {
+    pub fn new(doc: &'a Document, theme: &Theme, cursor: usize, message: &'a str) -> Self {
         EolBlame {
             style: theme.get("ui.virtual.blame"),
             message,
@@ -28,12 +27,6 @@ impl<'a> EolBlame<'a> {
 }
 
 impl Decoration for EolBlame<'_> {
-    // fn decorate_line(&mut self, renderer: &mut TextRenderer, pos: LinePos) {
-    //     // renderer.draw_dec
-    //     //     ration_grapheme(grapheme, style, row, col)
-    //     let col_off = 50;
-    // }
-
     fn render_virt_lines(
         &mut self,
         renderer: &mut TextRenderer,
@@ -45,9 +38,6 @@ impl Decoration for EolBlame<'_> {
         }
         let row = pos.visual_line;
         let col = virt_off.col as u16;
-        // if col != self.cursor as u16 {
-        //     return Position::new(0, 0);
-        // }
         let style = self.style;
         let width = renderer.viewport.width;
         let start_col = col - renderer.offset.col as u16;
@@ -61,7 +51,7 @@ impl Decoration for EolBlame<'_> {
                     .set_string_truncated(
                         renderer.viewport.x + draw_col,
                         row,
-                        &self.message,
+                        self.message,
                         width.saturating_sub(draw_col) as usize,
                         |_| self.style,
                         true,
@@ -75,20 +65,4 @@ impl Decoration for EolBlame<'_> {
 
         Position::new(0, col_off as usize)
     }
-
-    // fn reset_pos(&mut self, _pos: usize) -> usize {
-    //     usize::MAX
-    // }
-
-    // fn skip_concealed_anchor(&mut self, conceal_end_char_idx: usize) -> usize {
-    //     self.reset_pos(conceal_end_char_idx)
-    // }
-
-    // fn decorate_grapheme(
-    //     &mut self,
-    //     _renderer: &mut TextRenderer,
-    //     _grapheme: &FormattedGrapheme,
-    // ) -> usize {
-    //     usize::MAX
-    // }
 }
diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs
index 1ea004d8..5847f810 100644
--- a/helix-vcs/src/git.rs
+++ b/helix-vcs/src/git.rs
@@ -137,7 +137,7 @@ impl fmt::Display for BlameInformation {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
-            "    {} - {} - {} - {}",
+            "{} • {} • {} • {}",
             self.author_name, self.commit_date, self.commit_message, self.commit_hash
         )
     }
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index 46d84b7e..482cd1df 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -143,7 +143,7 @@ pub struct Document {
     ///
     /// To know if they're up-to-date, check the `id` field in `DocumentInlayHints`.
     pub(crate) inlay_hints: HashMap<ViewId, DocumentInlayHints>,
-    pub blame: Option<Vec<InlineAnnotation>>,
+    pub blame: Option<String>,
     pub(crate) jump_labels: HashMap<ViewId, Vec<Overlay>>,
     /// Set to `true` when the document is updated, reset to `false` on the next inlay hints
     /// update from the LSP
diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs
index a45f74a7..a229f01e 100644
--- a/helix-view/src/view.rs
+++ b/helix-view/src/view.rs
@@ -452,14 +452,6 @@ impl View {
             text_annotations.add_overlay(labels, style);
         }
 
-        if let Some(blame_annotation) = &doc.blame {
-            let annotation_style = theme
-                .and_then(|t| t.find_scope_index("ui.virtual.inlay-hint.type"))
-                .map(Highlight);
-
-            text_annotations.add_inline_annotations(blame_annotation, annotation_style);
-        }
-
         if let Some(DocumentInlayHints {
             id: _,
             type_inlay_hints,