From 6ed8983b11eaddbf063ef88def6ae7b71688c0e3 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Mon, 3 Oct 2011 23:48:38 -0400 Subject: [PATCH] Kill :bwipeout, :bunload. Change the semantics of :tabc and :bd: the former operates on visible tabs, the latter on all tabs. Bang enables regexp matching against title and URL, otherwise site-filter matching is used. --- common/content/tabs.js | 152 +++++++++++++++++++++-------------- common/locale/en-US/tabs.xml | 21 +++-- common/modules/util.jsm | 2 +- pentadactyl/NEWS | 2 + pentadactyl/TODO | 4 +- 5 files changed, 109 insertions(+), 72 deletions(-) diff --git a/common/content/tabs.js b/common/content/tabs.js index aa3a7bd3..15be8462 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -333,6 +333,60 @@ var Tabs = Module("tabs", { completion.listCompleter("buffer", filter); }, + + /** + * Return an iterator of tabs matching the given filter. If no + * filter or count is provided, returns the currently selected + * tab. If *filter* is a number or begins with a number followed + * by a colon, the tab of that ordinal is returned. Otherwise, + * tabs matching the filter as below are returned. + * + * @param {string} filter The filter. If *regex*, this is a + * regular expression against which the tab's URL or title + * must match. Otherwise, it is a site filter. + * @optional + * @param {number|null} count If non-null, return only the + * *count*th matching tab. + * @optional + * @param {boolean} regexp Whether to interpret *filter* as a + * regular expression. + * @param {boolean} all If true, match against all tabs. If + * false, match only tabs in the current tab group. + */ + match: function match(filter, count, regexp, all) { + if (!filter && count == null) + yield tabs.getTab(); + else if (!filter) + yield dactyl.assert(tabs.getTab(count - 1)); + else { + let matches = /^(\d+)(?:$|:)/.exec(filter); + if (matches) + yield dactyl.assert(count == null && + tabs.getTab(parseInt(matches[1], 10) - 1, !all)); + else { + if (regexp) + regexp = util.regexp(filter, "i"); + else + var matcher = Styles.matchFilter(filter); + + for (let tab in values(tabs[all ? "allTabs" : "visibleTabs"])) { + let browser = tab.linkedBrowser; + let uri = browser.currentURI; + let title; + if (uri.spec == "about:blank") + title = "(Untitled)"; + else + title = browser.contentTitle; + + if (matcher && matcher(uri) + || regexp && (regexp.test(title) || regexp.test(uri.spec))) + if (count == null || --count == 0) + yield tab; + } + } + } + }, + /** * Moves a tab to a new position in the tab list. * @@ -548,71 +602,45 @@ var Tabs = Module("tabs", { tabs.updateTabCount(); }, commands: function () { - commands.add(["bd[elete]", "bw[ipeout]", "bun[load]", "tabc[lose]"], - "Delete current buffer", - function (args) { - let removed = 0; - for (let tab in matchTabs(args, args.bang, true)) { - config.removeTab(tab); - removed++; - } - - if (args[0]) - if (removed > 0) - dactyl.echomsg(_("buffer.fewerTab" + (removed == 1 ? "" : "s"), removed), 9); - else - dactyl.echoerr(_("buffer.noMatching", arg)); - }, { - argCount: "?", - bang: true, - count: true, - completer: function (context) completion.buffer(context), - literal: 0, - privateData: true - }); - - function matchTabs(args, substr, all) { - let filter = args[0]; - - if (!filter && args.count == null) - yield tabs.getTab(); - else if (!filter) - yield dactyl.assert(tabs.getTab(args.count - 1)); - else { - let matches = /^(\d+)(?:$|:)/.exec(filter); - if (matches) - yield dactyl.assert(args.count == null && - tabs.getTab(parseInt(matches[1], 10) - 1, !all)); - else { - let str = filter.toLowerCase(); - for (let tab in values(tabs[all ? "allTabs" : "visibleTabs"])) { - let host, title; - let browser = tab.linkedBrowser; - let uri = browser.currentURI.spec; - if (browser.currentURI.schemeIs("about")) { - host = ""; - title = "(Untitled)"; - } - else { - host = browser.currentURI.host; - title = browser.contentTitle; - } - - [host, title, uri] = [host, title, uri].map(String.toLowerCase); - - if (host.indexOf(str) >= 0 || uri == str || - (substr && (title.indexOf(str) >= 0 || uri.indexOf(str) >= 0))) - if (args.count == null || --args.count == 0) - yield tab; - } - } + [ + { + name: ["bd[elete]"], + description: "Delete matching buffers", + visible: false + }, + { + name: ["tabc[lose]"], + description: "Delete matching tabs", + visible: true } - } + ].forEach(function (params) { + commands.add(params.name, params.description, + function (args) { + let removed = 0; + for (let tab in tabs.match(args[0], args.count, args.bang, !params.visible)) { + config.removeTab(tab); + removed++; + } + + if (args[0]) + if (removed > 0) + dactyl.echomsg(_("buffer.fewerTab" + (removed == 1 ? "" : "s"), removed), 9); + else + dactyl.echoerr(_("buffer.noMatching", args[0])); + }, { + argCount: "?", + bang: true, + count: true, + completer: function (context) completion.buffer(context), + literal: 0, + privateData: true + }); + }); commands.add(["pin[tab]"], "Pin tab as an application tab", function (args) { - for (let tab in matchTabs(args)) + for (let tab in tabs.match(args[0], args.count)) config.browser[!args.bang || !tab.pinned ? "pinTab" : "unpinTab"](tab); }, { @@ -629,7 +657,7 @@ var Tabs = Module("tabs", { commands.add(["unpin[tab]"], "Unpin tab as an application tab", function (args) { - for (let tab in matchTabs(args)) + for (let tab in tabs.match(args[0], args.count)) config.browser.unpinTab(tab); }, { @@ -805,7 +833,7 @@ var Tabs = Module("tabs", { let arg = args[0]; if (tabs.indexFromSpec(arg) == -1) { - let tabs = [tab for (tab in matchTabs(args, true))]; + let tabs = [tab for (tab in tabs.match(args[0], args.count, true))]; dactyl.assert(tabs.length, _("error.invalidArgument", arg)); dactyl.assert(tabs.length == 1, _("buffer.multipleMatching", arg)); arg = tabs[0]; diff --git a/common/locale/en-US/tabs.xml b/common/locale/en-US/tabs.xml index ff387c57..12ff217e 100644 --- a/common/locale/en-US/tabs.xml +++ b/common/locale/en-US/tabs.xml @@ -316,10 +316,6 @@ d :tabc :tabclose - :bun :bunload :bw :bwipeout :bd :bdelete - :countbdelete! arg - :countbunload! arg - :countbwipeout! arg :counttabclose! arg countd @@ -329,9 +325,20 @@

- When used with arg, remove all tabs which contain arg in the - currently opened hostname. With !, remove all tabs for which - the currently opened page's URL or title contains arg. + When used with arg, remove all visible tabs which match the + site-filter arg. With !, remove all tabs + for which the currently opened page's URL or title matches the + regular expression arg. +

+
+
+ + + :bd :bdelete + :countbdelete! arg + +

+ Like :tabclose but include hidden tabs.

diff --git a/common/modules/util.jsm b/common/modules/util.jsm index ab14517b..f9db472b 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1098,7 +1098,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), expr = String.replace(expr, /\\(.)/, function (m, m1) { if (m1 === "c") flags = flags.replace(/i/g, "") + "i"; - else if (m === "C") + else if (m1 === "C") flags = flags.replace(/i/g, ""); else return m; diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS index dc7697aa..4037315c 100644 --- a/pentadactyl/NEWS +++ b/pentadactyl/NEWS @@ -108,6 +108,8 @@ - :style now supports regexp site-filters on Firefox 6+. [b7] - :qa closes only the current window, per Vim. [b7] - Added :background command. [b8] + - Removed :bwipeout and :bunload. Changed the semantics of :bdelete + and :tabclose slightly. [b8] - Added -id flag to :bmark command and changed updating semantics. [b8] - Added :exit command. [b7] - Added :dlclear command. [b7] diff --git a/pentadactyl/TODO b/pentadactyl/TODO index cbe8780e..22ca8c1a 100644 --- a/pentadactyl/TODO +++ b/pentadactyl/TODO @@ -16,14 +16,14 @@ FEATURES: 9 / should work as in Vim (i.e., save page positions as well as locations in the history list). 9 clean up error message codes and document -9 option groups, including buffer-local and site-specific +9 option groups +9 global, window-local, tab-local, buffer-local, script-local groups 9 add [count] support to :b* and :tab* commands where missing 8 wherever possible: get rid of dialogs and ask console-like dialog questions or write error prompts directly on the webpage or with :echo() 8 registers 8 add support for filename special characters such as % 8 :redir and 'verbosefile' -8 middleclick in content == p, and if command line is open, paste there the clipboard buffer 8 Add information to dactyl/HACKING file about testing and optimization 7 describe-key command (prompt for a key and display its binding with documentation) 7 use ctrl-n/p in insert mode for word completion