Sublime Forum

Sublime API request

#1

i played again with vi-like input mode (i.e. control mode vs. edit mode), the motivation is to reduce the need to use modifier keys like shift/ctrl/alt which i find myself stretch my fingers in order to press those, too many times.

i have encountered few obstacles:

  1. when switching to control mode, keystrokes need to not alter the edited text. i have workaround lack of support in such feature by using showInputPanel to open an input panel, so all keystrokes are sent to it rather than the edited text.
  2. i found that i need a callback from sublime each time a keybind is triggered
  • to be able to exit the control mode before the keybinded-action takes place (else, the user is still with my special keybinding, which is not good).
  • to be able to exit or clear the control mode after the keybinded-action already finished.
  • to be able to print the key stokes of the user, including the actual keys used to trigger the action

not related to this special mode, i have thought of the following:

  • it could also be nice if sublime could export the keybindings it knows, so i can get this list with a function.
  • it would be nice if sublime would show key strokes sequence which match a keybinding, as i type them, for example on the status bar. so if i bind x,1,2 i will see as i press:

x -see-on-status-bar-> x x1 -see-on-status-bar-> x,1 x12 x -see-on-status-bar-> x,1,2 and trigger keybinded action
or

x -see-on-status-bar-> x xy -see-on-status-bar-> <nothing to show>
i guess i can implement this feature if the above API (2) was exposed.

0 Likes

#2

ohhh! i didn’t know that one.

searched the forum, read jon’s email, i will have to play some with this…

0 Likes

Vim like editing modes in sublime text x?
#3

If you’re interested in making a proper vi mode, then I’m happy to help out on the API side of things. I’ve done part of what’s required already (commandMode, times, sequence, and key binding namespaces all come from some initial work to support vi emulation), but more still needs to be done.

You’ll want to use key binding namespaces at some point, e.g.:

<binding key="d" command="deleteRange ${motion}"><context name="option" value="commandMode"/></binding>

<namespace name="motion">
	<binding key="w" command="words 1"/>
	<binding key="b" command="words -1"/>
	<binding key="j" command="lines 1"/>
	<binding key="k" command="lines -1"/>
	<binding key="enter" command="lines 1"/>
	<binding key="shift+enter" command="lines -1"/>
	<binding key="h" command="characters -1"/>
	<binding key="l" command="characters 1"/>
	<binding key=" " command="characters 1"/>
	<binding key="shift+space" command="characters -1"/>
	<binding key="$" command="eol"/>
	<binding key="^" command="bol"/>
	<binding key="G" command="eof"/>
</namespace>

(You’ll need to implement deleteRange for the above to be useful, of course)

The basic cursor movement commands will all need to be reimplemented for vi mode, because a few of the principles are different: the cursor can only move to EOL - 1, rather than to EOL, for example.

For entering / exiting insert mode, I reccomend something along the lines of:

class InsertModeCommand(sublimeplugin.TextCommand):
	def run(self, view, args):
		print "entering insert mode"
		
		view.options().set('commandMode', False)
		view.runCommand('markUndoGroupsForGluing')
		
		if len(args) > 0:
			if args[0] == 'bol':
				view.runCommand('moveTo bol')
			elif args[0] == 'eol':
				view.runCommand('moveTo eol')
			elif args[0] == 'append':
				view.runCommand('move characters 0')
				

class CommandModeCommand(sublimeplugin.TextCommand):
	def run(self, view, args):
		print "entering command mode"
		
		view.options().set('commandMode', True)
		view.runCommand('glueMarkedUndoGroups')
<binding key="i" command="insertMode"><context name="option" value="commandMode"/></binding>
<binding key="I" command="insertMode bol"><context name="option" value="commandMode"/></binding>
<binding key="a" command="insertMode append"><context name="option" value="commandMode"/></binding>
<binding key="A" command="insertMode eol"><context name="option" value="commandMode"/></binding>

The otherwise unused commands markUndoGroupsForGluing and glueMarkedUndoGroups are used so that all actions done in insert mode will be combined into a single entry in the undo stack, which in turn allows repeat (i.e., ‘.’ in vi) to work as expected.

More API support will be required, such as displaying the current mode on the status bar, and allowing the cursor to be drawn under a character rather that between characters while not in insert mode, is still required, but I’m happy to add these.

0 Likes

#4

If you don’t have them, it won’t cause any problems, so I wouldn’t think it’s related.

Normally, when running several different commands, you’ll get several different undo groups, each one of which will get undone in turn when ctrl+z is pressed.

‘markUndoGroupsForGluing’ simply records the current location in the undo stack.

glueMarkedUndoGroups’ takes every entry in the undo stack between the marked one and the current one, and combines them into a single undo group. This means that a single ctrl+z will undo them all in one go.

0 Likes

#5

this is actually one of the differences from Vi. on Vi, when having two key bindings that over lap, e.g. d - action1 and dd - action2, after you press d once, Vi will wait for a short period of time (half a sec +/-) and if no more inputs it will decide you wanted action1 (d). Sublime Text it will wait till it sure what is the key sequence you entered, so when you enter d once it will wait till your next key press, to see if it’s another d (->action2) or another key (->action1 and use the other input as normal key stroke).

this have always seems odd to me, because due to this behavior i can’t bind frequent commands to shorter sequences. i would prefer to be able to group similar commands, like that:

<binding key="ctrl+h" command="open"/> <binding key="ctrl+h,2" command="openIn"/> <binding key="ctrl+h,2,a" command="openInSomething"/> <binding key="ctrl+h,p" command="openProj"/> <binding key="ctrl+h,p,p" command="openProj quickpanel"/>

0 Likes

#6

anyway, check this out:

i have pushed this: code.google.com/p/sublime-text-c … /trunk/Vim

do you think this is the right direction to go with?

0 Likes

#7

Looks good to me, yeah.

0 Likes

#8

[quote=“vim”]this is actually one of the differences from Vi. on Vi, when having two key bindings that over lap, e.g. d - action1 and dd - action2, after you press d once, Vi will wait for a short period of time (half a sec +/-) and if no more inputs it will decide you wanted action1 (d). Sublime Text it will wait till it sure what is the key sequence you entered, so when you enter d once it will wait till your next key press, to see if it’s another d (->action2) or another key (->action1 and use the other input as normal key stroke).

this have always seems odd to me, because due to this behavior i can’t bind frequent commands to shorter sequences. i would prefer to be able to group similar commands, like that:

<binding key="ctrl+h" command="open"/> <binding key="ctrl+h,2" command="openIn"/> <binding key="ctrl+h,2,a" command="openInSomething"/> <binding key="ctrl+h,p" command="openProj"/> <binding key="ctrl+h,p,p" command="openProj quickpanel"/>[/quote]

quoting my self :smile: anyway, there is a real issue here, when i bind sequences that overlap shorter sequences, the shorter become unpractical to use. need to think ho to solve this, the VIM way is some kind of timer (which has its drawbacks - lag on response for the shorter keybindings), but maybe there are better ways.

0 Likes