From adc20aa830449d8e7f221db64baf393222ebe156 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 17:02:47 -0400 Subject: [PATCH 1/9] Change the way pending changes are drawn Only highlights a region if we are extending a selection; otherwise draws only the new insertion point. Also now highlights the starting point, because when the input panel is shown, the current selections are hidden. --- select-until.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/select-until.py b/select-until.py index 02d1f16..e8c0ef0 100644 --- a/select-until.py +++ b/select-until.py @@ -17,6 +17,7 @@ def on_done(view, extend): newSels = view.get_regions("select-until") view.erase_regions("select-until-extended") view.erase_regions("select-until") + view.erase_regions("select-until-originals") sels = view.sel() sels.clear() @@ -55,7 +56,7 @@ def find_matching_point(view, sel, selector): return region.begin() return -1 -def on_change(view, oriSels, selector): +def on_change(view, oriSels, selector, extend): SelectUntilCommand.temp = selector extendedSels = [] newSels = [] @@ -71,12 +72,16 @@ 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.add_regions("select-until-extended", extendedSels, "entity", "", sublime.DRAW_OUTLINED) + else: + 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") + view.erase_regions("select-until-originals") sels = view.sel() sels.clear() @@ -95,7 +100,7 @@ def run(self, edit, extend): "Select Until Next -- chars or [chars] or {count} or /regex/. Use minus (-) to reverse search:", 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() From a96b81e9126dc02d68a9f958d2ae0c25beebdbc2 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 21:41:00 -0400 Subject: [PATCH 2/9] Add clean_up command for on_cancel and on_done --- select-until.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/select-until.py b/select-until.py index e8c0ef0..069545f 100644 --- a/select-until.py +++ b/select-until.py @@ -10,14 +10,16 @@ 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") + 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") - view.erase_regions("select-until-originals") sels = view.sel() sels.clear() @@ -25,6 +27,7 @@ def on_done(view, extend): sels.add(sel) SelectUntilCommand.prevSelector = SelectUntilCommand.temp or SelectUntilCommand.prevSelector + clean_up(view) rSelector = re.compile("^(-?)(?:\{(-?\d+)\}|\[(.+)\]|/(.+)/)$") def find_matching_point(view, sel, selector): @@ -79,15 +82,13 @@ def on_change(view, oriSels, selector, extend): 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") - view.erase_regions("select-until-originals") - sels = view.sel() sels.clear() for sel in oriSels: sels.add(sel) + clean_up(view) + class SelectUntilCommand(sublime_plugin.TextCommand): temp = "" prevSelector = "" From 7d04bdaf18242cf637fbfd70fc6472796b0ba0d9 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 18:53:52 -0700 Subject: [PATCH 3/9] Fix getting called a second time while open --- select-until.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/select-until.py b/select-until.py index 069545f..fec0088 100644 --- a/select-until.py +++ b/select-until.py @@ -14,6 +14,7 @@ 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: @@ -77,8 +78,10 @@ def on_change(view, oriSels, selector, extend): 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): @@ -93,8 +96,25 @@ 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 + 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: + SelectUntilCommand.prevSelector = SelectUntilCommand.temp + SelectUntilCommand.running = True + + #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() ] v = view.window().show_input_panel( From bd2c38c62862744b977a810bea84751443bf16dd Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:06:52 -0700 Subject: [PATCH 4/9] Search regex never fails Simplifies the logic a little bit, I think. --- select-until.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/select-until.py b/select-until.py index fec0088..dad5985 100644 --- a/select-until.py +++ b/select-until.py @@ -30,18 +30,16 @@ def on_done(view, extend): 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] + chars = groups[2] or groups[4] regex = groups[3] if num is not None: From 44dd02623067a6259cd3906906ae33cec8c15d61 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:09:04 -0700 Subject: [PATCH 5/9] Simplify logic in find_matching_point --- select-until.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/select-until.py b/select-until.py index dad5985..3269ec9 100644 --- a/select-until.py +++ b/select-until.py @@ -42,20 +42,20 @@ def find_matching_point(view, sel, selector): chars = groups[2] or groups[4] 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())) + 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, extend): From 33d2ffef6f3a40b81a9e3980e274a46e7687f882 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:21:00 -0700 Subject: [PATCH 6/9] Swap search direction on the second press of the shortcut --- README.md | 4 +++- select-until.py | 11 ++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 64b8e43..37dcbb0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 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. @@ -13,6 +13,8 @@ Fill a void in your Sublime Text multiple selection capabilities! This plugin al - `-/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). On Windows and Linux the default shortcuts use alt. On OSX ctrl is used. diff --git a/select-until.py b/select-until.py index 3269ec9..2f8fc83 100644 --- a/select-until.py +++ b/select-until.py @@ -41,8 +41,9 @@ def find_matching_point(view, sel, selector): num = int(groups[1]) if groups[1] is not None else None chars = groups[2] or groups[4] regex = groups[3] + searchForward = isReverse ^ SelectUntilCommand.searchForward - if not isReverse: + 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)) @@ -98,6 +99,7 @@ class SelectUntilCommand(sublime_plugin.TextCommand): #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): #Make sure the view never refers to the quick panel - if we hit the shortcut @@ -105,7 +107,10 @@ def run(self, edit, extend): view = self.view.window().active_view_in_group(self.view.window().active_group()) if SelectUntilCommand.running: + SelectUntilCommand.searchForward = not SelectUntilCommand.searchForward SelectUntilCommand.prevSelector = SelectUntilCommand.temp + else: + SelectUntilCommand.searchForward = True SelectUntilCommand.running = True #We have to use set_timeout here; otherwise the quick panel doesn't actually @@ -114,9 +119,9 @@ def run(self, edit, extend): 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/. Use minus (-) or press shortcut again to reverse search:".format(direction), SelectUntilCommand.prevSelector, lambda selector: on_done(view, extend), lambda selector: on_change(view, oriSels, selector, extend), From 88f6bc628c5631213e03fa09ba9e274e905d1633 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:23:25 -0700 Subject: [PATCH 7/9] Don't swap direction if changing between extending and not extending selection --- select-until.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/select-until.py b/select-until.py index 2f8fc83..12b70d9 100644 --- a/select-until.py +++ b/select-until.py @@ -107,11 +107,13 @@ def run(self, edit, extend): view = self.view.window().active_view_in_group(self.view.window().active_group()) if SelectUntilCommand.running: - SelectUntilCommand.searchForward = not SelectUntilCommand.searchForward + if 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. From acef88c3bf7990fad612a769834b24ae11244991 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:28:37 -0700 Subject: [PATCH 8/9] Don't switch direction if the panel is open but unfocussed --- select-until.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/select-until.py b/select-until.py index 12b70d9..b4d98aa 100644 --- a/select-until.py +++ b/select-until.py @@ -107,7 +107,8 @@ def run(self, edit, extend): view = self.view.window().active_view_in_group(self.view.window().active_group()) if SelectUntilCommand.running: - if SelectUntilCommand.extend == extend: + #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: From a6354cd862c7d5bf1d20d508fc40351c8540a237 Mon Sep 17 00:00:00 2001 From: Nikolaus Wittenstein Date: Sun, 18 Aug 2013 19:24:49 -0700 Subject: [PATCH 9/9] Leading minus sign no longer reverses search --- README.md | 3 --- select-until.py | 13 ++++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 37dcbb0..fbb9d26 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,6 @@ Fill a void in your Sublime Text multiple selection capabilities! This plugin al - `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. diff --git a/select-until.py b/select-until.py index b4d98aa..8bf7451 100644 --- a/select-until.py +++ b/select-until.py @@ -30,18 +30,17 @@ def on_done(view, extend): 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) groups = result.groups() - isReverse = (groups[0] == "-") - num = int(groups[1]) if groups[1] is not None else None - chars = groups[2] or groups[4] - regex = groups[3] - searchForward = isReverse ^ SelectUntilCommand.searchForward + 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 @@ -124,7 +123,7 @@ 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 {} -- chars or [chars] or {{count}} or /regex/. Use minus (-) or press shortcut again to reverse search:".format(direction), + "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, extend),