Skip to content

Smooth scrolling for Kakoune with inertial movement

License

Notifications You must be signed in to change notification settings

caksoylar/kakoune-smooth-scroll

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kakoune-smooth-scroll

Smooth scrolling for the Kakoune text editor, with inertial movement

demo
(click for asciicast)

This plugin implements smooth scrolling similar to various plugins for Vim/Emacs etc. such as vim-smooth-scroll. It gives you better visual feedback while scrolling and arguably helps you preserve your "sense of place" when making large jumps such as when using <c-f>/<c-b> movements. The latest version of the plugin adds the smooth scrolling effect to most operations in normal, goto and object modes -- see the "Configuration" section below.

It also has support for inertial scrolling, also called the "easing out" or "soft stop" effect as seen above. This effect is similar to Vim plugins such as comfortable-motion.vim, vim-smoothie and sexy-scroller.vim.

Installation

Important

kakoune-smooth-scroll doesn't work with Kakoune master branch due to this commit, see issue mawww/kakoune#5017. It works with release version v2023.08.05. You can use this patch to revert the problematic commit in the kakoune repo:

curl -sL https://raw.githubusercontent.com/caksoylar/kakoune-smooth-scroll/master/revert_9787756.patch | git am

Download smooth-scroll.kak and smooth-scroll.py to your autoload folder, e.g. into ~/.config/kak/autoload. Or you can put them both in any location and source path/to/smooth-scroll.kak in your kakrc.

If you are using plug.kak:

plug "caksoylar/kakoune-smooth-scroll" config %{
     # configuration here
}

Configuration

kakoune-smooth-scroll operates through a mapping mechanism for keys in normal, goto and object modes. Mapped keys will perform their usual functions but when they need to scroll the window the scrolling will happen smoothly.

Smooth scrolling is enabled and disabled on a per-window basis using smooth-scroll-enable and smooth-scroll-disable commands. If you would like to automatically enable it for every window, you can use window-based hooks:

hook global WinCreate [^*].* %{
    hook -once window WinDisplay .* %{
        smooth-scroll-enable
    }
}

Above excludes special buffers that start with * like *debug*, *scratch* or *plug*.

Customizing mapped keys

Keys that are mapped for each mode are customized via the scroll_keys_normal, scroll_keys_goto and scroll_keys_object options. If for a mode the corresponding option is not set, keys that are mapped by default are the following:

normal keys description
<c-f>, <pagedown>, <c-b>, <pageup> scroll one page down/up
<c-d>, <c-u> scroll half a page down/up
), ( rotate main selection forward/backward
m, M select/extend to next matching character
<a-semicolon> (<a-;>) flip direction of selection
<percent> (%) select whole buffer
n, <a-n>, N, <a-N> select/extend to next/previous match
u, U undo/redo
goto keys description
g, k buffer top
j buffer bottom
e buffer end
. last buffer change
object keys description
B, {, } braces block
p paragraph
i indent

Default behavior is equivalent to the following configuration:

set-option global scroll_keys_normal <c-f> <c-b> <c-d> <c-u> <pageup> <pagedown> ( ) m M <a-semicolon> <percent> n <a-n> N <a-N> u U
set-option global scroll_keys_goto g k j e .
set-option global scroll_keys_object B { } p i

You can override which keys are mapped for each mode by setting the corresponding option. For example if you only want to map page-wise motions in normal mode and disable any mappings for goto mode, you can configure it as such:

set-option global scroll_keys_normal <c-f> <c-b> <c-d> <c-u>
set-option global scroll_keys_goto

Scrolling parameters

There are a few parameters related to the scrolling behavior that are adjustable through the scroll_options option which is a list of <key>=<value> pairs. Following keys are accepted and all of them are optional:

  • speed: number of lines to scroll per tick, 0 for inertial scrolling (default: 0)
  • interval: average milliseconds between each tick (default: 10)
  • max_duration: maximum duration of a scroll in milliseconds (default: 500)

The default configuration is equivalent to:

set-option global scroll_options speed=0 interval=10 max_duration=500

Advanced usage

When defining scroll_keys_* options, each listed key is mapped to its regular function by default. You might want to customize source and destination keys for each map, especially if you are already mapping other keys to these functions. For instance if you use <a-d> instead of <c-d> and <a-u> instead of <c-u>, you can specify the option using <src>=<dst> pairs:

set-option global scroll_keys_normal <c-f> <c-b> <a-d>=<c-d> <a-u>=<c-u>

Note that these options need to be set before smooth scrolling is enabled for a window.

For more fine-tuned control you can map keys individually with smooth-scroll-map-key, which has an interface similar to Kakoune's map command:

smooth-scroll-map-key normal <a-percent> *<percent>s<ret>

The mappings are applied in the window scope. You can call this command inside the WinDisplay hook after smooth-scroll-enable.

An analogue to execute-keys is also available if you want to utilize smooth scrolling programmatically:

smooth-scroll-execute-keys /TODO|FIXME<ret>

Note: Smooth scrolling still has to be enabled in the window scope using smooth-scroll-enable for above commands to work properly.

Customization using hooks

kakoune-smooth-scroll triggers three user hooks during a movement: ScrollBegin just before scrolling, ScrollStep after each scroll step and ScrollEnd after scrolling is finished. These can be used to customize appearance changes during scrolling. For instance, you could change line numbers to absolute while scrolling, then restore them to relative after the scroll is complete with the following hook definitions:

# say "window/nl" is the name of your per-window number-lines highlighter
hook -group smooth-scroll window User ScrollBegin %{
    add-highlighter -override window/nl number-lines
}
hook -group smooth-scroll window User ScrollEnd %{
    add-highlighter -override window/nl number-lines -relative -hlcursor
}

These hooks can also help with integrating with other plugins. For instance, if you are using scrollbar.kak you can force the scrollbar to update at each scrolling step by defining the following hook:

hook window User ScrollStep %{ update-scrollbar }

Caveats

  • Smooth scrolling is not performed for movements that do not modify the selection, such as any movement through the view mode. See related Kakoune issue
    • Keys that scroll by page (<c-f>,<c-b>,<c-d>,<c-u>) are handled specially to work around this limitation
  • Movements that are caused by the prompt mode such as /search_word<ret> can not be mapped at the moment
  • Repeating selections with <a-.> is not possible if the selection was made through mapped keys
    • You can disable mappings for object mode to enable repeating, using set-option global scroll_keys_object
  • Does not work for large vertical scrolloff values which are frequently used for keeping the cursor centered in the window, see issue
  • For optimal performance it uses a Python implementation which requires Python 3.6+ in path, falling back to sh if not available
    • This implementation utilizes Kakoune's internal remote API

Acknowledgments

Thanks @Screwtapello and @Guest0x0 for valuable feedback and fixes!

License

MIT