akinsho / git-conflict.nvim

A plugin to visualise and resolve merge conflicts in neovim
953 stars 34 forks source link

Feature request: choose under cursor #48

Open pesader opened 1 year ago

pesader commented 1 year ago

It would be great if there was a command to choose whichever hunk (ours or theirs) is currently under the cursor.

Thanks for developing this awesome plugin 🚀

b0o commented 4 months ago

Until this is officially implemented, here's a solution I came up with by looking at the extmarks under the cursor:

vim.keymap.set('n', '<leader>cc', function()
  local actions = {
    GitConflictCurrent = 'ours',
    GitConflictCurrentLabel = 'ours',
    GitConflictAncestor = 'base',
    GitConflictAncestorLabel = 'base',
    GitConflictIncoming = 'theirs',
    GitConflictIncomingLabel = 'theirs',
  }
  local mark = vim.iter(vim.inspect_pos().extmarks):find(function(e)
    return e.ns == 'git-conflict' and actions[e.opts.hl_group]
  end)
  if not mark then
    vim.notify('No conflict under cursor', vim.log.levels.WARN)
    return
  end
  require('git-conflict').choose(actions[mark.opts.hl_group])
end)
jradam commented 4 months ago

Edit: This was a workaround for an issue that has since been fixed.


@b0o I found this so helpful! Thank you.

I noticed that when my cursor is over the final line >>>>>>> (Incoming changes), then choose("theirs") doesn't work for me, which makes it impossible to accept empty incoming conflicts:

<<<<<<< HEAD (Current changes)
-- Changed code that is deleted in new_branch
=======
>>>>>>> new_branch (Incoming changes)
-- Cursor on this ^ line doesn't work

But I found you can do something a bit hacky like:

if vim.api.nvim_get_current_line():match(">>>>>>>") then
  -- Move cursor up, then choose "theirs"
  local cursor_pos = vim.api.nvim_win_get_cursor(0)
  vim.api.nvim_win_set_cursor(0, { cursor_pos[1] - 1, cursor_pos[2] })
  require("git-conflict").choose("theirs")
  return
end

And you can do something similar for choosing both when on the middle ======= line:

if vim.api.nvim_get_current_line():match("=======") then
  require("git-conflict").choose("both")
  return
end

Put together:

vim.keymap.set("n", "<leader>cc", function()
  local actions = {
    GitConflictCurrent = "ours",
    GitConflictCurrentLabel = "ours",
    GitConflictAncestor = "base",
    GitConflictAncestorLabel = "base",
    GitConflictIncoming = "theirs",
    GitConflictIncomingLabel = "theirs",
  }
  local line = vim.api.nvim_get_current_line()
  local choose = require("git-conflict").choose

  if line:match("=======") then
    choose("both")
    return
  end

  if line:match(">>>>>>>") then
    local cursor_pos = vim.api.nvim_win_get_cursor(0)
    vim.api.nvim_win_set_cursor(0, { cursor_pos[1] - 1, cursor_pos[2] })
    choose("theirs")
    return
  end

  local mark = vim.iter(vim.inspect_pos().extmarks):find(
    function(e) return e.ns == "git-conflict" and actions[e.opts.hl_group] end
  )

  if not mark then
    vim.notify("No conflict under cursor", vim.log.levels.WARN)
    return
  end

  choose(actions[mark.opts.hl_group])
end)
b0o commented 4 months ago

I noticed that when my cursor is over the final line >>>>>>> (Incoming changes), then choose("theirs") doesn't work for me, which makes it impossible to accept empty incoming conflicts

Hmm, that's interesting. That sounds like a bug to me. I opened an issue: #84.

And you can do something similar for choosing both when on the middle ======= line:

Nice idea!

jradam commented 4 months ago

Good idea to open https://github.com/akinsho/git-conflict.nvim/issues/84. I have been digging around today and have submitted a couple of pull requests to help with this - it turns out there are two separate issues stopping selection of the final line by extmark: