Sublime Forum

Move behind next "|'|)|]|}|> character?

#1

Hi,

Atm I use this keybinding:

[code] // Move out of parenthesis, quotes, etc.
{ “keys”: “ctrl+l”], “command”: “move”, “args”: {“by”: “characters”, “forward”: true}, “context”:

		{ "key": "following_text", "operator": "regex_contains", "operand": "^\"')\\]}>]", "match_all": true },
		{ "key": "auto_complete_visible", "operator": "equal", "operand": false }
	]
},[/code]

This works for all characters that are defined in the regex (single / double quote, square / round / angle / curly bracket), but only when the cursor is right in front of any of them.

Two questions:
1.) Is it possible to modify this binding so that it jumps behind the next bracket / quote, regardless if the cursor isn’t in front of such a character?
E.g.: The “|” is the current position of the cursor

"sm|arter"

and when I press the associated keyboard shortcut the cursor moves behind the second quote?

2.) Would it also be possible to modify it in a way, that it jumps behind the last bracket / quote that it can find on the same line?
E.g.:

find("sm|arter", "newer"]);

and after pressing the shortcut the cursor is at:

find("smarter", "newer"])|;

Regards,
Highend

1 Like

#2

I recommend checking out the BracketHighlighter plugin—I believe it has a keyboard shortcut to move to the end of “brackets”, such as quotes or parentheses (or brackets).

0 Likes

#3

I’ve written my first plugin that does (exactly) what I want.

It moves the cursor behind the next / last occurrence of any of the 5 delimiters on the right side of the current cursor position (only on the same line) and to the previous / first occurrence on the left. Keybindings are only triggered as long as you are inside a pair of any of these delimiters.

If anyone can make some use of it, here is the code (I’ve put all files in a folder named “JumpOverDelimiters” in the packages directory):

Please bare with me, it’s my first experience with a scripting language… If anyone wants to comment on how I could make the code better, don’t hesitate to do so^^

JumpOverDelimiters.py

[code]import re
import sublime
import sublime_plugin

class JumpOverDelimitersCommand(sublime_plugin.TextCommand):
def run(self, edit, direction={}, find={}):
cur_position = self.view.sel()[0]
current_line = self.view.line(cur_position)

	if direction == "right":
		if find == "next":
			tokens = [r'\>', r'\)', r'\]', r'\}', r'\"', r'\'']
		elif find == "last":
			tokens = [r'\>(?!.*\>)', r'\)(?!.*\))', r'\](?!.*\])', r'\}(?!.*\})', r'\"(?!.*\")', r'\'(?!.*\')']
		search_line_part = self.view.substr(sublime.Region(cur_position.begin(), current_line.end()))
	elif direction == "left":
		if find == "next":
			tokens = [r'\<(?!.*\<)', r'\((?!.*\()', r'\[(?!.*\[)', r'\{(?!.*\{)', r'\"(?!.*\")', r'\'(?!.*\')']
		elif find == "first":
			tokens = [r'\<', r'\(', r'\[', r'\{', r'\"', r'\'']
		search_line_part = self.view.substr(sublime.Region(current_line.begin(), cur_position.begin()))

	distances = ]
	for token in tokens:
		value = re.search(token, search_line_part)
		if value is not None:
			distances.append(value.start())

	# Valid values (Matches found) => continue
	if distances != "]":
		min_distance = min(distances)
		max_distance = max(distances)
		if direction == "right":
			if find == "next":
				new_cursor = cur_position.begin() + min_distance +1
			elif find == "last":
				new_cursor = cur_position.begin() + max_distance +1
		elif direction == "left":
			if find == "next":
				new_cursor = current_line.begin() + max_distance
			elif find == "first":
				new_cursor = current_line.begin() + min_distance
		self.view.sel().clear()
		self.view.sel().add(sublime.Region(new_cursor))

[/code]

Default.sublime-commands (if you want to have it in the command palette):

	{
		"caption": "Jump behind next right delimiter",
		"command": "jump_over_delimiters",
		"args": {"direction": "right", "find": "next"}
	},
	{
		"caption": "Jump behind last right delimiter",
		"command": "jump_over_delimiters",
		"args": {"direction": "right", "find": "last"}
	},
	{
		"caption": "Jump before next left delimiter",
		"command": "jump_over_delimiters",
		"args": {"direction": "left", "find": "previous"}
	},
	{
		"caption": "Jump before first left delimiter",
		"command": "jump_over_delimiters",
		"args": {"direction": "left", "find": "first"}
	}
]

User keybinding look like this:
If you want the cursor to move before the previous / first delimiter:
“direction”: “left”
“find”: “previous” | “find”: “first”

[code] { “keys”: “ctrl+l”], “command”: “jump_over_delimiters”, “args”: {“direction”: “right”, “find”: “next”}, “context”:

		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\"'(\\{<]", "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "\"')\\]}>]", "match_all": true },
		{ "key": "auto_complete_visible", "operator": "equal", "operand": false }
	]
},
// Move out left
{ "keys": "ctrl+shift+l"], "command": "jump_over_delimiters", "args": {"direction": "right", "find": "last"}, "context":
	
		{ "key": "preceding_text", "operator": "regex_contains", "operand": "\"'(\\{<]", "match_all": true },
		{ "key": "following_text", "operator": "regex_contains", "operand": "\"')\\]}>]", "match_all": true },
		{ "key": "auto_complete_visible", "operator": "equal", "operand": false }
	]
},[/code]
0 Likes

#4

Nice script. Works great, exactly what I needed, except it doesn’t support multiple cursors.

If I had the time and the knowhow, I’d add the feature myself.

Does anyone know of an updated version of this?

0 Likes