Since your plugin would just be standard Python code, you can create a top level variable that tracks the state and use it in your command code. A potential issue with that would be that either all cursor movement in every open file would work the same way (i.e. the toggle is global) or you have to do a bunch of work to track the state of the flag for every open file as well.
The caret position(s) are selections and the only command that can change a selection is a TextCommand
(technically any command can, but strictly speaking only a TextCommand
should; weird display issues can happen if other types of commands alter the selection).
As it transpires, Sublime creates a new instance of a TextCommand
class for every view
that exists so that the self.view
property is valid, which means that you can easily track the state for any view by just creating an instance variable in the command that does it.
For example:
import sublime
import sublime_plugin
class MoveWithToggleCommand(sublime_plugin.TextCommand):
chars = True
def run(self, edit, forward=True, extend=False, toggle=False):
if toggle:
self.chars = not self.chars
else:
by = ("characters" if self.chars else
("subword_ends" if forward else "subwords"))
self.view.run_command("move",
{"by": by, "forward": forward, "extend": extend})
Leveraging the internal command that already knows how to move the cursor, this either toggles the internal state or performs a move using the existing state. With it you’d need a few key bindings:
{ "keys": ["left"], "command": "move_with_toggle", "args": {"forward": false} },
{ "keys": ["right"], "command": "move_with_toggle", "args": {"forward": true} },
{ "keys": ["shift+left"], "command": "move_with_toggle", "args": {"forward": false, "extend": true} },
{ "keys": ["shift+right"], "command": "move_with_toggle", "args": {"forward": true, "extend": true} },
{ "keys": ["super+shift+t"], "command": "move_with_toggle", "args": {"toggle": true }},
The state of the chars
variable would reset if you quit and restart Sublime; if you want to persist that state you could store it in view.settings()
instead of in an instance variable.
You’d also want to use a global variable if you want the state in one file to track every file (though things like the command palette input and such are view
objects that get their own TextCommand
instances, so that might make it tricky to work the command palette.