neoscroll.nvim
neoscroll.nvim copied to clipboard
[Feature request] Scrolling cursor alone, without viewport
Could we get option for scrolling only cursor, without viewport, unless the cursor goes out of bounds. It will be really useful if you create custom scrolling with chaining multiple scrolls with hooks. I am doing equivalent of <C-d>zz that looks nice, which is combination of scrolling only cursor (not possible), scrolling viewport, and scrolling both
For anyone interested here is my config for auto zz after <C-d> and <C-u>, without weird jumping.
local function post_hook(info)
local neoscroll = require("neoscroll")
if info == nil then
return
end
if info.move_view ~= nil then
vim.defer_fn(function()
neoscroll.scroll(info.move_view.lines, {
move_cursor = false,
duration = info.move_view.duration,
})
end, 10)
end
if info.move_cursor ~= nil then
vim.defer_fn(function()
vim.api.nvim_win_set_cursor(0, {
math.max(1 - vim.fn.line("."), math.min(vim.fn.line("$"), vim.fn.line(".") + info.move_cursor.lines)),
vim.api.nvim_win_get_cursor(0)[2],
})
end, 10 + info.move_cursor.duration)
end
end
local function scroll_and_center(scroll, half_win_duration)
local window_height = vim.api.nvim_win_get_height(0)
local topmost_line = vim.fn.line("w0")
local current_middle_line = topmost_line + math.ceil(window_height / 2)
local current_line = vim.fn.line(".")
local off_target = math.max(-current_line + 1, math.min(scroll, vim.fn.line("$") - current_line))
local off_center = current_line - current_middle_line
local both_scroll = 0
local view_scroll = 0
local cursor_scroll = 0
-- both scrolls work together in one direction
if off_center * off_target >= 0 then
both_scroll = off_target
view_scroll = off_center
cursor_scroll = 0
else
both_scroll = off_target + off_center -- off_center is opposite to off target here, so actually its substracting
view_scroll = 0
cursor_scroll = -off_center
end
local both_scroll_duration = math.floor(half_win_duration * (math.abs(both_scroll) / (window_height / 2)) + 0.5)
local view_scroll_duration = math.floor(half_win_duration * (math.abs(view_scroll) / (window_height / 2)) + 0.5)
local cursor_scroll_duration = math.floor(half_win_duration * (math.abs(cursor_scroll) / (window_height / 2)) + 0.5)
if both_scroll == 0 then
post_hook({
move_view = {
duration = view_scroll_duration,
lines = view_scroll,
},
move_cursor = {
duration = cursor_scroll_duration,
lines = cursor_scroll,
},
})
else
require("neoscroll").scroll(both_scroll, {
move_cursor = true,
duration = both_scroll_duration,
info = {
move_view = {
duration = view_scroll_duration,
lines = view_scroll,
},
move_cursor = {
duration = cursor_scroll_duration,
lines = cursor_scroll,
},
},
})
end
end
return {
"karb94/neoscroll.nvim",
config = function()
local neoscroll = require("neoscroll")
neoscroll.setup({
mappings = {},
-- pre_hook = function(info) end,
post_hook = post_hook,
})
local keymap = {
["<C-u>"] = function()
scroll_and_center(-vim.wo.scroll, 100)
end,
["<C-d>"] = function()
scroll_and_center(vim.wo.scroll, 100)
end,
["<C-y>"] = function()
neoscroll.scroll(-0.1, { move_cursor = false, duration = 80 })
end,
["<C-e>"] = function()
neoscroll.scroll(0.1, { move_cursor = false, duration = 80 })
end,
["zz"] = function()
neoscroll.zz({ half_win_duration = 100 })
end,
-- ["G"] = function()
-- neoscroll.G({ half_win_duration = 100 })
-- end,
-- ["gg"] = function()
-- neoscroll.gg({ half_win_duration = 100 })
}
local modes = { "n", "v", "x" }
for key, func in pairs(keymap) do
vim.keymap.set(modes, key, func)
end
end,
}
Can you explain in more detail what kind of animation are you looking to achieve? I copied your config but I can't really tell what is going on.
When the view is at the bottom of a file the cursor keeps scrolling until it hits eof (At least when this option is set in config). I would love to have this possibility whenever i want. My config makes it so C-d is basically C-D + zz, but doign these two commands one after another makes view go down first and then back up after (If cursor is at the top half of screen). I wanted to do it, so view scrolls down just enough to be centered around line that is vim.wo.scroll lines down.
Behavior for C-d (analogous to C-u)
- Cursor at the center of screen: scroll both cursor and view half a page (scroll with move_cursor = true)
- Cursor at the bottom half of screen: scroll both cursor and view half a page, and scroll only view (move_cursor=false) additional amount required to center the screen
- Cursor at the top half of screen: scroll both cursor and view a little amount, and cursor only, with view staying in place (not possible, right now just teleporting the cursor) the rest of half page movement. This makes sure that cursor moves half a page and view is centered after movement
If cursor is on to half, for example first line of window: cursor scrolls half a page, but the view doesnt need to scroll at all. This is problematic because plugin doesn't allow for smooth scrolling cursor, without moving view. Let me know if I need to explain more, english isn't my first language and my lua skills are not great either so it's kind of messy
Thanks for sharing your config @Rumi152 -- I was just trying to customize C-u and C-d so that it keeps the cursor in the middle of the screen.
To piggyback on this request, it would be great if this case was natively supported as an option on the plugin itself. My default remap for <C-d> used to be "<C-d>zz" (based on ThePrimeagen's dotfiles). Feels less disorienting than the default vim behaviour personally.
In any case, big thanks for neoscroll @karb94!
This is just a thought but what about using the pre_hook functionality to move the cursor to the centre before starting the scrolling animation? You could even hide the cursor so that the transition is seamless.
I mean yeah, it kind of works right now. Just the option of smoothly moving the cursor instead of hiding it and showing again is not possible. Even without that the plugin is great and I love using similiar solution, it just doesn't seamlessly integrate with defaults (Where both the view and cursor scroll together, not the one where cursor is hidden during animation).
I wanted to achieve the same effect and also couldn't manage with neoscroll, so I wrote my own animation and it works well. I thought I would share it here in case it helps, as an inspiration.
https://gist.github.com/Lcchy/a438997093438785db4796ebcb97b873
ps: it uses coop.nvim for async execution
I tried to create a good scrolling behavior for myself using "Hzz" and "Lzz" as mappings, but the zz smooth scrolling doesn't work with this implementation. Any ideas as to why? I am decently new to NVim, so I don't konw if there is some implicit reason as to why this isn't registered as a normal "zz". Because when I use the command manually, aka, H then zz, it works just fine.
I wanted to achieve the same effect and also couldn't manage with neoscroll, so I wrote my own animation and it works well. I thought I would share it here in case it helps, as an inspiration.
https://gist.github.com/Lcchy/a438997093438785db4796ebcb97b873
ps: it uses
coop.nvimfor async execution
wow! doing zz doesn't bounce anymore. thanks
You're welcome! Although I have noticed it being slower with multiple panes, see https://gist.github.com/Lcchy/a438997093438785db4796ebcb97b873?permalink_comment_id=5334532#gistcomment-5334532
@Rumi152 this works really well! thank you for putting this together, the only issue for me is that gg<C-d> doesn't do anything - as in when the cursor is on start of file <C-d> doesn't work for some reason..?
Thanks for sharing your config @Rumi152 -- I was just trying to customize C-u and C-d so that it keeps the cursor in the middle of the screen.
To piggyback on this request, it would be great if this case was natively supported as an option on the plugin itself. My default remap for <C-d> used to be "<C-d>zz" (based on ThePrimeagen's dotfiles). Feels less disorienting than the default vim behaviour personally.
In any case, big thanks for neoscroll @karb94!
Yeah I was also trying to accomplish this behavior. But haven't been able to make it work.