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]