Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Restore/retain cursor position when swapping buffers between windows #225

Open
1 task done
scienceplease opened this issue Jul 28, 2024 · 2 comments
Open
1 task done
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers PRs-welcome I'd love to see a PR for this

Comments

@scienceplease
Copy link

scienceplease commented Jul 28, 2024

Similar Issues

  • Before filing, I have searched for similar issues.

Description

When swapping buffers between windows where { move_cursor = true } it would be nice if the cursor position in each respective buffer is preserved/restored after the swap. As an example, I can restore the cursor position in the active buffer after the swap via the following.

local function swap(direction)
    return function()
        local cursor = vim.api.nvim_win_get_cursor(0)
        require("smart-splits")['swap_buf_' .. direction]({ move_cursor = true })
        vim.api.nvim_win_set_cursor(0, cursor)     
    end
end

vim.keymap.set('n', '<leader><leader>h', swap('left'))
vim.keymap.set('n', '<leader><leader>j', swap('down'))
vim.keymap.set('n', '<leader><leader>k', swap('up'))
vim.keymap.set('n', '<leader><leader>l', swap('right'))

Though with this approach I cannot restore the cursor in the buffer that I am swapping with because getting direction-based window ids is internal to the plugin. An alternative to making this behavior the default would be to expose API functions that allow user code to query for window ids that are left/down/up/right to a given window id. The latter would also enable users to implement custom functionality and not require changes to the plugin itself.

@scienceplease scienceplease added the enhancement New feature or request label Jul 28, 2024
@scienceplease
Copy link
Author

scienceplease commented Jul 28, 2024

A silly workaround I have for the time being is just iterating through all the windows on the tab page before and after to detect which have been swapped and then restoring their respective cursor positions.

local function snapshot()
-- Save buffer cursor information for each window in the active tab page.

    local state     = { }
    local tabpagenr = vim.api.nvim_get_current_tabpage()

    for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(tabpagenr)) do
        state[winid] = {
            bufnr  = vim.api.nvim_win_get_buf(winid),
            cursor = vim.api.nvim_win_get_cursor(winid)
        }
    end
    return state
end

local function restore_swapped_buffer_cursors(snapshot)
-- Using snapshot information, detect which buffers have been swapped and restore their cursor positions.
    
    local now = snapshot()
    local swapped_winids = { }

    for winid, buffer in pairs(now) do
        if buffer.bufnr ~= snapshot[winid].bufnr then
        -- Buffer displayed in window has been swapped.
            swapped_winids[#swapped_winids + 1] = winid
        end
    end

    if #swapped_winids ~= 0 then
        assert(#swapped_winids == 2, "Number of swapped windows must be 2.")

        vim.api.nvim_win_set_cursor(swapped_winids[1], snapshot[swapped_winids[2]].cursor)
        vim.api.nvim_win_set_cursor(swapped_winids[2], snapshot[swapped_winids[1]].cursor)
    else
        -- Do nothing. Swap was between windows displaying the same buffer which cannot be detected by this approach.
    end
end

local function swap(direction)
    return function()
        local saved = snapshot()
        smart_splits['swap_buf_' .. direction]({ move_cursor = true })
        restore_swapped_buffer_cursors(saved)
      end
end

vim.keymap.set('n', '<leader><leader>h', swap('left'))
vim.keymap.set('n', '<leader><leader>j', swap('down'))
vim.keymap.set('n', '<leader><leader>k', swap('up'))
vim.keymap.set('n', '<leader><leader>l', swap('right'))

@mrjones2014
Copy link
Owner

Should be easy enough. We can have the swap_buffer function save and restore the cursor position, and the alternate window can have it's position restored via a one-time autocmd.

@mrjones2014 mrjones2014 added good first issue Good for newcomers PRs-welcome I'd love to see a PR for this labels Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers PRs-welcome I'd love to see a PR for this
Projects
None yet
Development

No branches or pull requests

2 participants