From 7ff03e1ebad8941f53cbc9da349cf2c557a58aff Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 25 Mar 2022 16:52:13 +0000 Subject: [PATCH] feat(nav): add option to auto preview Resolves #494 --- README.md | 23 +++++++++++++++++++++-- doc/gitsigns.txt | 3 +++ lua/gitsigns/actions.lua | 22 +++++++++++++++++----- lua/gitsigns/popup.lua | 21 ++++++++++++++++++++- teal/gitsigns/actions.tl | 22 +++++++++++++++++----- teal/gitsigns/popup.tl | 21 ++++++++++++++++++++- 6 files changed, 98 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index bb9424f..8fef306 100644 --- a/README.md +++ b/README.md @@ -146,8 +146,27 @@ require('gitsigns').setup{ end -- Navigation - map('n', ']c', "&diff ? ']c' : 'Gitsigns next_hunk'", {expr=true}) - map('n', '[c', "&diff ? '[c' : 'Gitsigns prev_hunk'", {expr=true}) + map('n', ']c', function() + if vim.wo.diff then + return ']c' + else + vim.schedule(function() + gitsigns.next_hunk() + end) + return '' + end + end, {expr=true}) + + map('n', '[c', function() + if vim.wo.diff then + return '[c' + else + vim.schedule(function() + gitsigns.prev_hunk() + end) + return '' + end + end, {expr=true}) -- Actions map({'n', 'v'}, 'hs', ':Gitsigns stage_hunk') diff --git a/doc/gitsigns.txt b/doc/gitsigns.txt index 9e8d93e..ab1e4e3 100644 --- a/doc/gitsigns.txt +++ b/doc/gitsigns.txt @@ -312,6 +312,9 @@ next_hunk({opts}) *gitsigns.next_hunk()* Expand folds when navigating to a hunk which is inside a fold. Defaults to `true` if 'foldopen' contains `search`. + • {preview}: (boolean) + Automatically open preview_hunk() upon navigating + to a hunk. reset_buffer_index() *gitsigns.reset_buffer_index()* Unstage all hunks for current buffer in the index. Note: diff --git a/lua/gitsigns/actions.lua b/lua/gitsigns/actions.lua index f33d4e4..ce4f4af 100644 --- a/lua/gitsigns/actions.lua +++ b/lua/gitsigns/actions.lua @@ -28,6 +28,7 @@ local NavHunkOpts = {} + local M = {QFListOpts = {}, } @@ -329,6 +330,15 @@ local function process_nav_opts(opts) end end + +local function defer(fn) + if vim.in_fast_event() then + vim.schedule(fn) + else + vim.defer_fn(fn, 1) + end +end + local function nav_hunk(opts) process_nav_opts(opts) local bcache = cache[current_buf()] @@ -365,8 +375,10 @@ local function nav_hunk(opts) if opts.foldopen then vim.cmd('silent! foldopen!') end - if pcall(api.nvim_buf_get_var, 0, '_gitsigns_preview_open') then - vim.schedule(M.preview_hunk) + if opts.preview or popup.is_open() then + + + defer(M.preview_hunk) end if index ~= nil and opts.navigation_message then @@ -390,6 +402,9 @@ end + + + M.next_hunk = function(opts) opts = opts or {} opts.forwards = true @@ -476,9 +491,6 @@ M.preview_hunk = noautocmd(function() add_highlight(bufnr, -1, 'Title', 0, 0, -1) - api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true) - vim.cmd([[autocmd CursorMoved,CursorMovedI ++once silent! unlet b:_gitsigns_preview_open]]) - local offset = #lines - hunk.removed.count - hunk.added.count highlight_hunk_lines(bufnr, offset, hunk) end) diff --git a/lua/gitsigns/popup.lua b/lua/gitsigns/popup.lua index 83a6f8c..6cd1b06 100644 --- a/lua/gitsigns/popup.lua +++ b/lua/gitsigns/popup.lua @@ -59,6 +59,8 @@ function popup.create(lines, opts) local win_id = api.nvim_open_win(bufnr, false, opts1) + api.nvim_win_set_var(win_id, 'gitsigns_preview', true) + if not opts.height then expand_height(win_id, #lines) end @@ -73,14 +75,21 @@ function popup.create(lines, opts) local group = 'gitsigns_popup' .. win_id nvim.augroup(group) + local old_cursor = api.nvim_win_get_cursor(0) + nvim.autocmd({ 'CursorMoved', 'CursorMovedI' }, { group = group, callback = function() - if api.nvim_get_current_win() ~= win_id then + local cursor = api.nvim_win_get_cursor(0) + + if (old_cursor[1] ~= cursor[1] or old_cursor[2] ~= cursor[2]) and + api.nvim_get_current_win() ~= win_id then nvim.augroup(group) pcall(api.nvim_win_close, win_id, true) + return end + old_cursor = cursor end, }) @@ -88,4 +97,14 @@ function popup.create(lines, opts) end +function popup.is_open() + for _, winid in ipairs(api.nvim_list_wins()) do + local exists = pcall(api.nvim_win_get_var, winid, 'gitsigns_preview') + if exists then + return true + end + end + return false +end + return popup diff --git a/teal/gitsigns/actions.tl b/teal/gitsigns/actions.tl index 03a8d17..22fab8d 100644 --- a/teal/gitsigns/actions.tl +++ b/teal/gitsigns/actions.tl @@ -26,6 +26,7 @@ local record NavHunkOpts wrap: boolean navigation_message: boolean foldopen: boolean + preview: boolean end local record M @@ -329,6 +330,15 @@ local function process_nav_opts(opts: NavHunkOpts) end end +-- Defer function to the next main event +local function defer(fn: function) + if vim.in_fast_event() then + vim.schedule(fn) + else + vim.defer_fn(fn, 1) + end +end + local function nav_hunk(opts: NavHunkOpts) process_nav_opts(opts) local bcache = cache[current_buf()] @@ -365,8 +375,10 @@ local function nav_hunk(opts: NavHunkOpts) if opts.foldopen then vim.cmd('silent! foldopen!') end - if pcall(api.nvim_buf_get_var, 0, '_gitsigns_preview_open') then - vim.schedule(M.preview_hunk) + if opts.preview or popup.is_open() then + -- Use defer so the cursor change can settle, otherwise the popup might + -- appear in the old position + defer(M.preview_hunk) end if index ~= nil and opts.navigation_message then @@ -390,6 +402,9 @@ end --- Expand folds when navigating to a hunk which is --- inside a fold. Defaults to `true` if 'foldopen' --- contains `search`. +--- • {preview}: (boolean) +--- Automatically open preview_hunk() upon navigating +--- to a hunk. M.next_hunk = function(opts: NavHunkOpts) opts = opts or {} opts.forwards = true @@ -476,9 +491,6 @@ M.preview_hunk = noautocmd(function() add_highlight(bufnr, -1, 'Title', 0, 0, -1) - api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true) - vim.cmd[[autocmd CursorMoved,CursorMovedI ++once silent! unlet b:_gitsigns_preview_open]] - local offset = #lines - hunk.removed.count - hunk.added.count highlight_hunk_lines(bufnr as integer, offset, hunk) end) diff --git a/teal/gitsigns/popup.tl b/teal/gitsigns/popup.tl index 1a9d0d3..fb04327 100644 --- a/teal/gitsigns/popup.tl +++ b/teal/gitsigns/popup.tl @@ -59,6 +59,8 @@ function popup.create(lines: {string}, opts: {string:any}): integer, integer local win_id = api.nvim_open_win(bufnr, false, opts1) + api.nvim_win_set_var(win_id, 'gitsigns_preview', true) + if not opts.height then expand_height(win_id, #lines) end @@ -73,14 +75,21 @@ function popup.create(lines: {string}, opts: {string:any}): integer, integer -- itself. local group = 'gitsigns_popup'..win_id nvim.augroup(group) + local old_cursor = api.nvim_win_get_cursor(0) + nvim.autocmd({'CursorMoved', 'CursorMovedI'}, { group = group, callback = function() - if api.nvim_get_current_win() ~= win_id then + local cursor = api.nvim_win_get_cursor(0) + -- Did the cursor REALLY change (neovim/neovim#12923) + if (old_cursor[1] ~= cursor[1] or old_cursor[2] ~= cursor[2]) + and api.nvim_get_current_win() ~= win_id then -- Clear the augroup nvim.augroup(group) pcall(api.nvim_win_close, win_id, true) + return end + old_cursor = cursor end }) @@ -88,4 +97,14 @@ function popup.create(lines: {string}, opts: {string:any}): integer, integer end +function popup.is_open(): boolean + for _, winid in ipairs(api.nvim_list_wins()) do + local exists = pcall(api.nvim_win_get_var, winid, 'gitsigns_preview') + if exists then + return true + end + end + return false +end + return popup