Sublime Forum

"Smart" horizontal cursor positioning



Just came across Sublime, and it looks awesome :smile:. I’m in the first day of playing with it, and am seeing no reason not to switch and buy at this point. One thing that I am missing from my previous editor (Textpad), that I havne’t seen anywhere else, is the way cursor movement is handled when switching lines. It’s a bit hard to describe, but it is very handy. I’ll try to describe it below, but it’s probably easier if you follow along by trying firsthand by downloading Textpad 4.x (e.g.

For example, say I have the following two lines, with the cursor positioned at the pipe:

The quick | fox jumped over the lazy dog.

…and then I typed “brown”, the cursor would end up here:

The quick brown| fox jumped over the lazy dog.

…in most editors (including Sublime), if I then pressed the down arrow, I’d wind up with this:

The quick brown fox jumped over the lazy d|og.

However, Textpad ends up with this:

The quick brown fox jumped over the l|azy dog.

This comes in very handy when doing multiple similar edits across multiple lines.

It seems the editor is keeping track of both the cursor’s “current X position” and the “base X position”, which is “the original X position before any editing occurred since the last horizontal cursor navigation command”. Then, if you move the cursor up or down (with either up/down arrows, or pgup/pgdn), the cursor tries to keep as close to the original X position as possible, but within the current line’s constraints. The base X position is updated next time you manually position the cursor horizontally (e.g. left/right arrows, mouse click, etc).

Anyway, like I said, it’s hard to appreciate without trying, and it’d be awesome to see added to what already looks to be a great editor.

1 Like

Moving to Sublime 3 after fifteen years with TextPad

I had never seen this in any editor, though I can see the use in that behavior as I’ve encountered that many times, in which I wished the editor worked in precisely that way.

1 Like


It sounds like the sort of feature that would take me a little while to get used to, but then which I’d be unable to live without forever after… kind of like multiple selections.

1 Like


Sidenote - please upvote :smile: - … sitioning/
I’m honestly not sure if this is the place to track the issue, or if the userecho place is…



I too have migrated from Textpad - there are only 2 features I still miss after 4 months - this one and the ability to simply find and replace using the current selection as the target.

1 Like


[quote=“sublimator”]Can anyone show a screenie of that?

I don’t have OSX else I’d download it.[/quote]

It is a windows app.

1 Like


Last year, found the idea interesting and try to implement it with the limited ST2 API, result:
A nightmare and nothing really useful.

But thinking it again last week and found a better way to do it:
Put the cursor back to the first edit position of the line BEFORE running the move command.
Still a nightmare with the actual ST2 api events, but works pretty well in most case.
And found it pretty useful.

Get it at and add some keybindings to your user file based on the Example.sublime-keymap.

As I actually never try an editor with this behavior, feedback are welcomed.

1 Like


I’m trying it out! I’ll let you know how I like it.

1 Like


[quote=“adzenith”]I’m trying it out! I’ll let you know how I like it.

Thanks for trying it.

I pushed a small modification a few minutes ago.

Currently, IMHO, the only thing that doesn’t work as expected is when your starting edit point is beyond the end of the line when you move the cursor, as when you remove the end of a line using DEL key.
As this plugin put the cursor(s) back to the start edit position before moving it, there’s no way to do it with the current API.

If ST2 had virtual space (, this will not be an issue.
But it looks like virtual space potentially break most of the current API, or lot of new methods need to be added to deal with it.

1 Like


Just had this thing fire for the first time while I was editing just now, and it turned out to be really awesome. Thanks!

1 Like


I was going to report a bug, but then it was already fixed by that “small modification” you made. Thanks!

1 Like


Bizoo, you may be able to implement this is a cleaner way using the xpos attribute of selection regions. If it’s not -1 when the caret is moved down a row, then it specifies the column (in layout coords) for the caret to be placed in.

You can see it in action by pressing end and then down: the caret will be maintained at EOL. Currently, it automatically set to -1 whenever the buffer is edited, so you’d need to find appropriate places to get and set the value.


Problem with xpos
How: Cursor beyond end-of-line?
Reset the move by lines target column
Vintage mode, retain column position

Didn’t know about xpos, thanks for the heads-up.

But I don’t understand exactly what to do with it:
xpos() give me the ‘expected’ position for the cursor, but I don’t think there’s a way to set the xpos(), am I wrong ?

With my current implementation, I set the caret horizontal position before executing the move command.
This way the navigation are still managed by ST2 and work fine even if the next line (when move down) is smaller than the current caret position (so the xpos is correct out of the box).
The only problem is when you need the caret beyond the end of line, so when I need to set xpos.

If xpos is a read-only value, I don’t see any uses for this plugin (but could be useful for others).
Am I missing something ???

1 Like


You can set the xpos by passing a 3rd argument to the Region constructor: sublime.Region(a, b, xpos)

1 Like


Yeah ! Thanks for the helping hand John.

It looks like everything works fine now.
Maybe there’s still something to do to simplify the code, but I have no time right now to dig further… Maybe later.

Actually, I seriously think to replace the standard up/down cursor with these ones. But maybe jps already thought about putting something similar in the core ST2 :wink:

Grab it at and give it a try.

1 Like


For what it’s worth, I’ve replaced the standard up and down arrows with this. I did this:

[code] { “keys”: “up”], “command”: “smart_cursor”, “args”: {“cmd”: “move”, “by”: “lines”, “forward”: false}, “context”:

  { "key": "auto_complete_visible", "operator": "equal", "operand": false }

{ “keys”: “down”], “command”: “smart_cursor”, “args”: {“cmd”: “move”, “by”: “lines”, “forward”: true}, “context”:

  { "key": "auto_complete_visible", "operator": "equal", "operand": false }


1 Like


Thanks adzenith for the keybindings, will replace the examples from github with these ones.
I’ve just added it to my keybindings !

1 Like


This sounds cool. I need to give this a try.

1 Like


Updated github right now with the new keybindings from adzenith and the fixes for the only issues I’ve found after a day of work:
-After selecting a text from right to left and delete/modify it, caret must be placed to the starting point of the selection (so, technically, always sel.a and not sel.begin()).
-Move down after an edit at the last line of the file move the caret horizontally but, of course, not vertically, which is IMHO not what users are expecting.

1 Like


[quote=“adzenith”]For what it’s worth, I’ve replaced the standard up and down arrows with this. I did this:

[code] { “keys”: “up”], “command”: “smart_cursor”, “args”: {“cmd”: “move”, “by”: “lines”, “forward”: false}, “context”:

  { "key": "auto_complete_visible", "operator": "equal", "operand": false }

{ “keys”: “down”], “command”: “smart_cursor”, “args”: {“cmd”: “move”, “by”: “lines”, “forward”: true}, “context”:

  { "key": "auto_complete_visible", "operator": "equal", "operand": false }


I used these keymaps but found a small issue:
When you go at the end of the auto complete list, press one more down close the auto complete and execute a move down command, not a smart_cursor down command.
If I remove the context, it works as expected.

Did you find an issue with enabling the smart_cursor for auto complete or did you add context ‘in case of’ ?
Thanks for your reply.

1 Like