From b4d40802a8debfbbde702162e2da5636707a57f2 Mon Sep 17 00:00:00 2001
From: yetone <yetoneful@gmail.com>
Date: Thu, 15 Aug 2024 20:07:44 +0800
Subject: [PATCH] feat: more like Cursor

---
 lua/avante/diff.lua    | 78 +++++++++++++++++++++++++-----------------
 lua/avante/sidebar.lua | 19 +++++-----
 2 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/lua/avante/diff.lua b/lua/avante/diff.lua
index 309f807..63cfbc2 100644
--- a/lua/avante/diff.lua
+++ b/lua/avante/diff.lua
@@ -110,10 +110,9 @@ local INCOMING_LABEL_HL = "AvanteConflictIncomingLabel"
 local ANCESTOR_LABEL_HL = "AvanteConflictAncestorLabel"
 local PRIORITY = vim.highlight.priorities.user
 local NAMESPACE = api.nvim_create_namespace("avante-conflict")
+local KEYBINDING_NAMESPACE = api.nvim_create_namespace("avante-conflict-keybinding")
 local AUGROUP_NAME = "AvanteConflictCommands"
 
-local sep = package.config:sub(1, 1)
-
 local conflict_start = "^<<<<<<<"
 local conflict_middle = "^======="
 local conflict_end = "^>>>>>>>"
@@ -165,35 +164,6 @@ local visited_buffers = create_visited_buffers()
 
 -----------------------------------------------------------------------------//
 
----Get full path to the repository of the directory passed in
----@param dir any
----@param callback fun(data: string)
-local function get_git_root(dir, callback)
-  job({ "git", "-C", dir, "rev-parse", "--show-toplevel" }, function(data)
-    callback(data[1])
-  end)
-end
-
---- Get a list of the conflicted files within the specified directory
---- NOTE: only conflicted files within the git repository of the directory passed in are returned
---- also we add a line prefix to the git command so that the full path is returned
---- e.g. --line-prefix=`git rev-parse --show-toplevel`
----@reference: https://stackoverflow.com/a/10874862
----@param dir string?
----@param callback fun(files: table<string, integer[]>, string)
-local function get_conflicted_files(dir, callback)
-  local cmd = { "git", "-C", dir, "diff", ("--line-prefix=%s%s"):format(dir, sep), "--name-only", "--diff-filter=U" }
-  job(cmd, function(data)
-    local files = {}
-    for _, filename in ipairs(data) do
-      if #filename > 0 then
-        files[filename] = files[filename] or {}
-      end
-    end
-    callback(files, dir)
-  end)
-end
-
 ---Add the positions to the buffer in our in memory buffer list
 ---positions are keyed by a list of range start and end for each mark
 ---@param buf integer
@@ -397,6 +367,50 @@ local function set_cursor(position, side)
   api.nvim_win_set_cursor(0, { target.range_start + 1, 0 })
 end
 
+local function register_cursor_move_events(bufnr)
+  local show_keybinding_hint_extmark_id = nil
+
+  local function show_keybinding_hint(lnum)
+    if show_keybinding_hint_extmark_id then
+      api.nvim_buf_del_extmark(bufnr, KEYBINDING_NAMESPACE, show_keybinding_hint_extmark_id)
+    end
+
+    local hint = string.format(
+      " [Press <%s> for CHOICE OURS, <%s> for CHOICE THEIRS, <%s> for PREV, <%s> for NEXT] ",
+      config.default_mappings.ours,
+      config.default_mappings.theirs,
+      config.default_mappings.prev,
+      config.default_mappings.next
+    )
+    local win_width = api.nvim_win_get_width(0)
+    local col = win_width - #hint - math.ceil(win_width * 0.3) - 4
+
+    if col < 0 then
+      col = 0
+    end
+
+    show_keybinding_hint_extmark_id = api.nvim_buf_set_extmark(bufnr, KEYBINDING_NAMESPACE, lnum - 1, -1, {
+      hl_group = "Keyword",
+      virt_text = { { hint, "Keyword" } },
+      virt_text_win_col = col,
+      priority = PRIORITY,
+    })
+  end
+
+  api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
+    buffer = bufnr,
+    callback = function()
+      local position = get_current_position(bufnr)
+
+      if position then
+        show_keybinding_hint(position.current.range_start + 1)
+      else
+        api.nvim_buf_clear_namespace(bufnr, KEYBINDING_NAMESPACE, 0, -1)
+      end
+    end,
+  })
+end
+
 ---Get the conflict marker positions for a buffer if any and update the buffers state
 ---@param bufnr integer
 ---@param range_start integer
@@ -408,6 +422,7 @@ local function parse_buffer(bufnr, range_start, range_end)
 
   update_visited_buffers(bufnr, positions)
   if has_conflict then
+    register_cursor_move_events(bufnr)
     highlight_conflicts(positions, lines)
   else
     M.clear(bufnr)
@@ -664,6 +679,7 @@ function M.clear(bufnr)
   end
   bufnr = bufnr or 0
   api.nvim_buf_clear_namespace(bufnr, NAMESPACE, 0, -1)
+  api.nvim_buf_clear_namespace(bufnr, KEYBINDING_NAMESPACE, 0, -1)
 end
 
 ---@param side ConflictSide
diff --git a/lua/avante/sidebar.lua b/lua/avante/sidebar.lua
index be3f3b1..9d5b435 100644
--- a/lua/avante/sidebar.lua
+++ b/lua/avante/sidebar.lua
@@ -11,7 +11,8 @@ local fn = vim.fn
 local RESULT_BUF_NAME = "AVANTE_RESULT"
 local CONFLICT_BUF_NAME = "AVANTE_CONFLICT"
 
-local NAMESPACE = vim.api.nvim_create_namespace("AVANTE_CODEBLOCK")
+local CODEBLOCK_KEYBINDING_NAMESPACE = vim.api.nvim_create_namespace("AVANTE_CODEBLOCK_KEYBINDING")
+local PRIORITY = vim.highlight.priorities.user
 
 local function parse_codeblocks(buf)
   local codeblocks = {}
@@ -370,14 +371,16 @@ function M.render_sidebar()
 
   local function show_apply_button(block)
     if current_apply_extmark_id then
-      api.nvim_buf_del_extmark(result_buf, NAMESPACE, current_apply_extmark_id)
+      api.nvim_buf_del_extmark(result_buf, CODEBLOCK_KEYBINDING_NAMESPACE, current_apply_extmark_id)
     end
 
-    current_apply_extmark_id = api.nvim_buf_set_extmark(result_buf, NAMESPACE, block.start_line, -1, {
-      virt_text = { { "[Press A to Apply these patches]", "Keyword" } },
-      virt_text_pos = "right_align",
-      hl_group = "Keyword",
-    })
+    current_apply_extmark_id =
+      api.nvim_buf_set_extmark(result_buf, CODEBLOCK_KEYBINDING_NAMESPACE, block.start_line, -1, {
+        virt_text = { { " [Press <A> to Apply these patches] ", "Keyword" } },
+        virt_text_pos = "right_align",
+        hl_group = "Keyword",
+        priority = PRIORITY,
+      })
   end
 
   local function apply()
@@ -429,7 +432,7 @@ function M.render_sidebar()
         show_apply_button(block)
         bind_apply_key()
       else
-        vim.api.nvim_buf_clear_namespace(result_buf, NAMESPACE, 0, -1)
+        api.nvim_buf_clear_namespace(result_buf, CODEBLOCK_KEYBINDING_NAMESPACE, 0, -1)
         unbind_apply_key()
       end
     end,