Sublime Forum

A better paging behaviour


I have been trying to get a desirable paging behaviour for a while in sublime text. I have not been able to get where I want.

The default sublime pageup/pagedown behaviour moves by too many lines. I basically would like to move by half a page only.

To solve this issue I used the following key mapping…

{ “keys”: [“pageup”], “command”: “scroll_lines”, “args” : {“amount”: 26.0} },
{ “keys”: [“pagedown”], “command”: “scroll_lines”, “args” : {“amount”: -26.0} },

Now the pageup/pagedown buttons move by a more desirable amount. The new downside is that the caret is always positions 26 lines back from the currently viewable page lines range. As soon as I press a key to move the caret, the view jumps up 26 lines to back to where the caret is.

So the original pageup/pagedown behaviour is good, because the caret always ends up in a position on the viewable page. And the second approach is good because it move by less then a page.

Is there anyway I can have the best of both worlds?



Nobody has any ideas? This is so rare on here :stuck_out_tongue:



This plugin provides a move_amount function which is a drop-in replacement for the internal move command that takes an optional amount argument to get it to execute the move that many times (the default is to behave like move).

With that in place, you can use key bindings like this instead:

        "keys": ["pageup"],
        "command": "move_amount",
        "args" : {
            "by": "lines",
            "forward": false,
            "amount": 26
        "keys": ["pagedown"],
        "command": "move_amount",
        "args" : {
            "by": "lines",
            "forward": true,
            "amount": 26

That would perform the page up and page down operation by simulating what happens if you just move 26 lines in either direction, which will move the cursor as well.



This plugin moves the caret. So if the caret is not within 26 lines of the bottom, pagedown will not move the page.



An alternate solution would be a plugin that automatically centers the caret in the visible lines. That way if my scroll by N lines leaves the caret off screen, I could just immediately center it.



It’s pretty easy to get the caret to be centered in the view (I think one of the other threads is discussing it).

I think you could also combine the plugin and your original key binding in a macro so that it scrolls the view and then ensures that the cursor moves by the same amount.



I found a way to center the view on the caret, but not a way to center the caret in the view.



Ahh, yeah. I misread what you said there; sorry about that. Here’s an example of a plugin that jumps the cursor to the center of the current view:

import sublime
import sublime_plugin

class CenterCaretCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        # To shorten things up a bit, alias the view
        v = self.view

        # Based on the view, get the height of a line, the height of the
        # viewport in general, and the viewport position information.
        lh = v.line_height()
        vh = v.viewport_extent()[1]
        vp = v.viewport_position()

        # Calculate the number of lines the view can hold, the line currently
        # at the top of the view (even partially), and the line that falls at
        # the middle of the view; note that these are 0 based, not 1 based.
        view_lines = vh / lh
        top_line = vp[1] / lh
        window_mid = (view_lines / 2) + top_line

        # Get the caret position of the first selection and convert it from a
        # point (buffer offset) into a (row, column) value instead.
        cur_rowcol = v.rowcol(v.sel()[0].b)

        # Get the region that spans the line in the middle of the window and
        # convert it's endpoint to a (row, column) offset so that we know at
        # what column it ends.
        mid_line = v.rowcol(v.line(v.text_point(window_mid, 0)).end())

        # Create the new caret location; place it on the line in the middle of
        # the window and using either the original column, or the end of the
        # mid line if the mid line is shorter than the line it was already on.
        pt = v.text_point(window_mid, min(cur_rowcol[1], mid_line[1]))

        # If the point falls outside of the view, put it at the last character
        # instead.
        if pt > v.size():
            pt = v.size()

        # Clear the selection and replace it with the new one

This inherently converts multiple selections into a single selection centered on the line in the middle of the view; for multiple cursors it would have to do similar manipulations on the existing selections one at a time, perhaps by calculating the line offset of the first selection and then applying it to the remainder.

1 Like


The crude plugin I posted in Move up or down by N lines also does something similar, but not what is asked for I see now.

It moves the caret and then moves the view to show the caret in the middle (calling Sublime API view.show_at_center()). It seemed like I didn’t really need to do any error/range checking, ST just handled it gracefully.

I then added these to my keybindings:

    { "keys": ["pageup"], "command": "partial_pager",
        "args": {"amount": -0.5}
    { "keys": ["pagedown"], "command": "partial_pager",
        "args": {"amount": 0.5}


My issue was actually solved in the latest version of Sublime 3.2.1!

I can now use scroll_lines to implement a shorter pageup/pagedown behaviour, and in the latest version, the caret never lags of the screen.