There may or may not be a plugin for this on Package Control already (probably with more functionality) but here’s an example that does something like this:
import sublime
import sublime_plugin
class ChangeSelectionEndpointCommand(sublime_plugin.TextCommand):
def run(self, edit, begin):
new_sel = []
for sel in self.view.sel():
reverse = (sel.a < sel.b) if begin else (sel.b < sel.a)
new_sel.append(sublime.Region(sel.b, sel.a) if reverse else sel)
self.view.sel().clear()
self.view.sel().add_all(new_sel)
Basically, when invoked it looks at every selection, and reverses the beginning and end of the selection (which changes the end at which the caret is positioned) based on the value of the parameter that you pass in. To use, you can select Tools > Developer > New Plugin...
from the menu, then replace the stub file contents with this text and save it.
Key bindings like the following will activate it as you describe above. The contexts make the binding only active while there is a selection (i.e. when selection_empty
is false
) so that the default bindings will still work as expected.
{
"keys": ["alt+left"], "command": "change_selection_endpoint",
"args": { "begin": true },
"context": [
{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": false },
]
},
{
"keys": ["alt+right"], "command": "change_selection_endpoint",
"args": { "begin": false },
"context": [
{ "key": "selection_empty", "operator": "equal", "operand": false, "match_all": false },
]
},
Here I’ve set match_all
to false
, which means that in cases when there is more than one caret, as long as one of them has a selection the command will trigger and the caret position will jump (any caret without a selection will be visibly unchanged).
To me at least, this seems to make the most sense for this operation. If you like, you can set match_all
to true
in the bindings, in which case if there are multiple carets, all of them have to have a selection for the command to trigger.