diff --git a/README.md b/README.md
index 64b8e43..fbb9d26 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,13 @@ Fill a void in your Sublime Text multiple selection capabilities! This plugin al
## Usage
-- ctrl/alt + shift + s: pulls up an input field, where you can type:
+- ctrl/alt + shift + s once: pulls up an input field, where you can type:
- `search term` or `[search term]`: for each selection, select up to and including the first occurrence of the search term.
- `/regex search/`: select through the first occurrence of the regex.
- `{character count}`: select forward the given number of characters.
- - `-[search term]`: select backwards up to and including the search term.
- - `-/regex/`: backwards regex.
- - `-{character count}`: select backwards a certain number of characters (`{-count}` works too).
+
+- ctrl/alt + shift + s a second time: reverse the search direction.
- ctrl/alt + shift + r: reverse all selections (so if the insertion point is at the end of the selection, it is moved to the beginning, and vice versa).
diff --git a/select-until.py b/select-until.py
index 02d1f16..8bf7451 100644
--- a/select-until.py
+++ b/select-until.py
@@ -10,13 +10,17 @@ def safe_end(region):
return -1
return region.end()
+def clean_up(view):
+ view.erase_regions("select-until-extended")
+ view.erase_regions("select-until")
+ view.erase_regions("select-until-originals")
+ SelectUntilCommand.running = False
+
def on_done(view, extend):
if extend:
newSels = view.get_regions("select-until-extended")
else:
newSels = view.get_regions("select-until")
- view.erase_regions("select-until-extended")
- view.erase_regions("select-until")
sels = view.sel()
sels.clear()
@@ -24,38 +28,37 @@ def on_done(view, extend):
sels.add(sel)
SelectUntilCommand.prevSelector = SelectUntilCommand.temp or SelectUntilCommand.prevSelector
+ clean_up(view)
-rSelector = re.compile("^(-?)(?:\{(-?\d+)\}|\[(.+)\]|/(.+)/)$")
+rSelector = re.compile("^\{(-?\d+)\}|\[(.+)\]|/(.+)/|(.*)$")
def find_matching_point(view, sel, selector):
if selector == "": return -1
result = rSelector.search(selector)
- if result is None: return safe_end(view.find(selector, sel.end(), sublime.LITERAL))
-
groups = result.groups()
- isReverse = (groups[0] == "-")
- num = int(groups[1]) if groups[1] is not None else None
- chars = groups[2]
- regex = groups[3]
-
- if num is not None:
- if isReverse: return sel.begin() - num
- else: return sel.end() + num
-
- if not isReverse:
- if regex is not None: return safe_end(view.find(regex, sel.end()))
+ num = int(groups[0]) if groups[0] is not None else None
+ chars = groups[1] or groups[3]
+ regex = groups[2]
+ searchForward = SelectUntilCommand.searchForward
+
+ if searchForward:
+ if num is not None: return sel.end() + num
+ elif regex is not None: return safe_end(view.find(regex, sel.end()))
else: return safe_end(view.find(chars, sel.end(), sublime.LITERAL))
- if regex is not None: regions = view.find_all(regex)
- else: regions = view.find_all(chars, sublime.LITERAL)
+ else:
+ if num is not None: return sel.begin() - num
+ elif regex is not None: regions = view.find_all(regex)
+ else: regions = view.find_all(chars, sublime.LITERAL)
+
+ for region in reversed(regions):
+ if region.end() <= sel.begin():
+ return region.begin()
- for region in reversed(regions):
- if region.end() <= sel.begin():
- return region.begin()
return -1
-def on_change(view, oriSels, selector):
+def on_change(view, oriSels, selector, extend):
SelectUntilCommand.temp = selector
extendedSels = []
newSels = []
@@ -71,31 +74,59 @@ def on_change(view, oriSels, selector):
newSels.append(region)
- view.add_regions("select-until-extended", extendedSels, "comment", "", sublime.DRAW_OUTLINED)
- view.add_regions("select-until", newSels, "comment", "", sublime.DRAW_OUTLINED)
+ view.add_regions("select-until-originals", oriSels, "comment", "", sublime.DRAW_EMPTY)
+ if extend:
+ view.erase_regions("select-until")
+ view.add_regions("select-until-extended", extendedSels, "entity", "", sublime.DRAW_OUTLINED)
+ else:
+ view.erase_regions("select-until-extended")
+ view.add_regions("select-until", newSels, "entity", "", sublime.DRAW_EMPTY)
def on_cancel(view, oriSels):
- view.erase_regions("select-until-extended")
- view.erase_regions("select-until")
-
sels = view.sel()
sels.clear()
for sel in oriSels:
sels.add(sel)
+ clean_up(view)
+
class SelectUntilCommand(sublime_plugin.TextCommand):
temp = ""
prevSelector = ""
+ #If we get called again while the quick panel's up, on_cancel gets called.
+ #There's no way in the API to distinguish this from the user pressing esc, so
+ #we have to do it ourselves.
+ running = False
+ searchForward = True
+
def run(self, edit, extend):
- view = self.view
+ #Make sure the view never refers to the quick panel - if we hit the shortcut
+ #while the panel is up, the wrong view is targetted.
+ view = self.view.window().active_view_in_group(self.view.window().active_group())
+
+ if SelectUntilCommand.running:
+ #Don't switch direction if the panel is open but unfocussed
+ if view != self.view and SelectUntilCommand.extend == extend:
+ SelectUntilCommand.searchForward = not SelectUntilCommand.searchForward
+ SelectUntilCommand.prevSelector = SelectUntilCommand.temp
+ else:
+ SelectUntilCommand.searchForward = True
+ SelectUntilCommand.running = True
+ SelectUntilCommand.extend = extend
+
+ #We have to use set_timeout here; otherwise the quick panel doesn't actually
+ #update correctly if we open it a second time. Seems to be a bug in Sublime.
+ sublime.set_timeout(lambda : self.show_panel(view, extend), 0)
+
+ def show_panel(self, view, extend):
oriSels = [ sel for sel in view.sel() ]
-
+ direction = "Next" if SelectUntilCommand.searchForward else "Previous"
v = view.window().show_input_panel(
- "Select Until Next -- chars or [chars] or {count} or /regex/. Use minus (-) to reverse search:",
+ "Select Until {} -- chars or [chars] or {{count}} or /regex/. Press shortcut again to reverse search:".format(direction),
SelectUntilCommand.prevSelector,
lambda selector: on_done(view, extend),
- lambda selector: on_change(view, oriSels, selector),
+ lambda selector: on_change(view, oriSels, selector, extend),
lambda : on_cancel(view, oriSels)
)
v.sel().clear()