This is a quick little plugin you can drop in your user package and use in addition to ⌘D and ⌘K⌘D (where skip_last is true in the command arguments). Basically, it searches for the current word, albeit bounded by \b in the regex (that is, word boundaries - so it won’t work for everything [for example, searching for #/ using this plugin will not work since # and / are both word boundaries themselves, so consider using a different key instead of replacing ⌘D and such]).
It’s handy if you’re a terrible human being and use single-letter variable names other than (because there’s really no better way to refer to texture coordinates and vector components than with UVW and XYZ), which ⌘D will punish you for doing by finding every instance of that character. So, your best bet is to just not be an absolutely loathsome person who uses single letter variables (like all you horrible web developers do), but if you happen to be someone the entire world should despise because you absolutely cannot resist the allure of single letter variables like the absolutely awful depth-spawn that you might be, then this plugin is probably for you.
It’s also handy if you have variable names that share words, like event and event_name and event_id, in which case ⌘D will unintentionally hate you and you’re not an awful person, just unlucky. In those cases, it’s probably fairly useful, though chances are you could ⌘K⌘D around the false positives without a lot of problems.
This came up on IRC (as usual) and it’s something I’d experienced before, so I figured I might as well write a plugin for it. Did a cursory search and found nobody else had done it either, but I got lazy, so it wasn’t thorough. Probably been solved before.
So, drop this in your user package if you think you might need it for something:
[code]# bounded_grab_next.py
import sublime, sublime_plugin, re
class BoundedGrabNextCommand(sublime_plugin.TextCommand):
def init(self, p):
super(BoundedGrabNextCommand, self).init§
self._last_word = None
self._last_regex = None
#/init
def run(self, edit, skip_last = False):
last_selection = None
view = self.view
selections = view.sel()
last_selection = selections-1]
# If the last selection is empty, expand to the current word. In other
# words, just do the usual Cmd+D operation.
if last_selection.a == last_selection.b:
view.window().run_command('find_under_expand')
return
#/if
regex = None
word = view.substr(last_selection)
if self._last_word == word:
regex = self._last_regex
else:
regex = "\\b{0}\\b".format(re.escape(word))
#/if
if skip_last:
selections.subtract(last_selection)
#/if
last_point = max(last_selection.a, last_selection.b)
next_find = view.find(regex, last_point)
if next_find is None:
next_find = view.find(regex, 0)
while next_find and selections.contains(next_find):
next_find = view.find(regex, next_find.b)
#/while
#/if
if next_find:
selections.add(next_find)
#/if
self._last_word = word
self._last_regex = regex
#/run
#/BoundedGrabNextCommand[/code]
The command takes a single argument, skip_last, which behaves mostly the same as ⌘K⌘D. I rarely find this useful, and in this case the chance of a false positive is a bit lower than normal, so you may not need it.
You’ll want to set up a keybinding for it as well. Here’s an example that replaces the “Use Selection for Find” and “Use Selection for Replace” bindings because I never use those. Adjust as necessary, obviously.
{ "command": "bounded_grab_next", "args": {"skip_last": false}, "keys": "super+e"]},
{ "command": "bounded_grab_next", "args": {"skip_last": true}, "keys": "super+shift+e"]}
]
So, have fun.