diff --git a/common/content/hints.js b/common/content/hints.js index f145f7f0..ae58c0c7 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -42,31 +42,30 @@ const Hints = Module("hints", { const Mode = Hints.Mode; Mode.defaultValue("tags", function () function () options["hinttags"]); - function extended() options["extendedhinttags"]; - function images() util.makeXPath(["img"]); + Mode.prototype.__defineGetter__("xpath", function () + options.get("extendedhinttags").getKey(this.name, this.tags())); - this._hintModes = { - ";": Mode("Focus hint", function (elem) buffer.focusElement(elem), extended), - "?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended), - s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)), - a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)), - f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () ["body"]), - o: Mode("Follow hint", function (elem) buffer.followLink(elem, dactyl.CURRENT_TAB)), - t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB)), - b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB)), - w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW), extended), - F: Mode("Open multiple hints in tabs", function (elem) { buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB); hints.show("F"); }), - O: Mode("Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)), - T: Mode("Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)), - W: Mode("Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)), - v: Mode("View hint source", function (elem, loc) buffer.viewSource(loc, false), extended), - V: Mode("View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true), extended), - y: Mode("Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true)), - Y: Mode("Yank hint description", function (elem) dactyl.clipboardWrite(elem.textContent || "", true), extended), - c: Mode("Open context menu", function (elem) buffer.openContextMenu(elem), extended), - i: Mode("Show image", function (elem) dactyl.open(elem.src), images), - I: Mode("Show image in a new tab", function (elem) dactyl.open(elem.src, dactyl.NEW_TAB), images) - }; + this._hintModes = {}; + this.addMode(";", "Focus hint", function (elem) buffer.focusElement(elem)); + this.addMode("?", "Show information for hint", function (elem) buffer.showElementInfo(elem)); + this.addMode("s", "Save hint", function (elem) buffer.saveLink(elem, true)); + this.addMode("a", "Save hint with prompt", function (elem) buffer.saveLink(elem, false)); + this.addMode("f", "Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () ["body"]); + this.addMode("o", "Follow hint", function (elem) buffer.followLink(elem, dactyl.CURRENT_TAB)); + this.addMode("t", "Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB)); + this.addMode("b", "Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB)); + this.addMode("w", "Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW)); + this.addMode("F", "Open multiple hints in tabs", function (elem) { buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB); hints.show("F"); }); + this.addMode("O", "Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)); + this.addMode("T", "Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)); + this.addMode("W", "Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)); + this.addMode("v", "View hint source", function (elem, loc) buffer.viewSource(loc, false)); + this.addMode("V", "View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true)); + this.addMode("y", "Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true)); + this.addMode("Y", "Yank hint description", function (elem) dactyl.clipboardWrite(elem.textContent || "", true)); + this.addMode("c", "Open context menu", function (elem) buffer.openContextMenu(elem)); + this.addMode("i", "Show image", function (elem) dactyl.open(elem.src)); + this.addMode("I", "Show image in a new tab", function (elem) dactyl.open(elem.src, dactyl.NEW_TAB)); }, /** @@ -260,7 +259,7 @@ const Hints = Module("hints", { let baseNodeAbsolute = util.xmlToDom(, doc); - let res = util.evaluateXPath(this._hintMode.tags(), doc, null, true); + let res = util.evaluateXPath(this._hintMode.xpath, doc, null, true); let fragment = util.xmlToDom(
, doc); let start = this._pageHints.length; @@ -722,7 +721,7 @@ const Hints = Module("hints", { * @optional */ addMode: function (mode, prompt, action, tags) { - this._hintModes[mode] = Hints.Mode.apply(Hints.Mode, Array.slice(arguments, 1)); + this._hintModes[mode] = Hints.Mode.apply(Hints.Mode, arguments); }, /** @@ -1014,7 +1013,7 @@ const Hints = Module("hints", { return -1; }, - Mode: Struct("prompt", "action", "tags") + Mode: Struct("name", "prompt", "action", "tags") }, { mappings: function () { var myModes = config.browserModes; @@ -1069,7 +1068,7 @@ const Hints = Module("hints", { options.add(["extendedhinttags", "eht"], "XPath string of hintable elements activated by ';'", - "string", DEFAULT_HINTTAGS, + "regexmap", "[iI]:" + Option.quote(util.makeXPath(["img"])), { validator: checkXPath }); options.add(["hinttags", "ht"], diff --git a/common/content/options.js b/common/content/options.js index 09ee0d31..84654447 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -372,15 +372,15 @@ const Option = Class("Option", { */ SCOPE_BOTH: 3, - parseRegex: function (val, result) { - let [, bang, val] = /^(!?)(.*)/.exec(val); - let re = RegExp(val); + parseRegex: function (value, result) { + let [, bang, val] = /^(!?)(.*)/.exec(value); + let re = RegExp(Option.dequote(val)); re.bang = bang; re.result = arguments.length == 2 ? result : !bang; re.toString = function () Option.unparseRegex(this); return re; }, - unparseRegex: function (re) re.bang + Option.quote(re.source.replace(/\\(.)/g, function (m, n1) n1 == "/" ? n1 : m)) + + unparseRegex: function (re) re.bang + Option.quote(re.source.replace(/\\(.)/g, function (m, n1) n1 == "/" ? n1 : m), /^!|:/) + (typeof re.result == "string" ? ":" + Option.quote(re.result) : ""), getKey: { @@ -399,7 +399,7 @@ const Option = Class("Option", { joinValues: { charlist: function (vals) Commands.quote(vals.join("")), stringlist: function (vals) vals.map(Option.quote).join(","), - stringmap: function (vals) [Option.quote(k) + ":" + Option.quote(v) for ([k, v] in Iterator(vals))].join(","), + stringmap: function (vals) [Option.quote(k, /:/) + ":" + Option.quote(v) for ([k, v] in Iterator(vals))].join(","), regexlist: function (vals) vals.join(","), get regexmap() this.regexlist }, @@ -409,11 +409,20 @@ const Option = Class("Option", { boolean: function (value) Option.dequote(value) == "true" || value == true ? true : false, charlist: function (value) Array.slice(Option.dequote(value)), stringlist: function (value) (value === "") ? [] : Option.splitList(value), - stringmap: function (value) array(util.split(v, /:/g, 2) for (v in values(Option.splitList(value)))).toObject(), - regexlist: function (value) (value === "") ? [] : Option.splitList(value).map(Option.parseRegex), - regexmap: function (value) Option.splitList(value) - .map(function (v) util.split(v, /:/g, 2)) - .map(function ([k, v]) v != null ? Option.parseRegex(k, v) : Option.parseRegex(".?", k)) + regexlist: function (value) (value === "") ? [] : Option.splitList(value, true).map(Option.parseRegex), + stringmap: function (value) array.toObject( + Option.splitList(value, true).map(function (v) { + let [count, key, quote] = Commands.parseArg(v, /:/); + return [key, Option.dequote(v.substr(count + 1))] + })), + regexmap: function (value) + Option.splitList(value, true).map(function (v) { + let [count, re, quote] = Commands.parseArg(v, /:/, true); + v = Option.dequote(v.substr(count + 1)); + if (count === v.length) + [v, re] = [re, ".?"]; + return Option.parseRegex(re, v); + }) }, dequote: function (value) { @@ -422,20 +431,20 @@ const Option = Class("Option", { Option._splitAt = 0; return arg; }, - splitList: function (value) { + splitList: function (value, keepQuotes) { let res = []; Option._splitAt = 0; do { if (count !== undefined) Option._splitAt += count + 1; - var [count, arg, quote] = Commands.parseArg(value, /,/); + var [count, arg, quote] = Commands.parseArg(value, /,/, keepQuotes); Option._quote = quote; // FIXME res.push(arg); value = value.slice(count + 1); } while (value.length); return res; }, - quote: function quote(str) Commands.quoteArg[/[\s|"'\\,]|^$/.test(str) ? "'" : ""](str), + quote: function quote(str, re) Commands.quoteArg[/[\s|"'\\,]|^$/.test(str) || re && re.test && re.test(str) ? "'" : ""](str, re), ops: { boolean: function (operator, values, scope, invert) { diff --git a/common/locale/en-US/hints.xml b/common/locale/en-US/hints.xml index 7fc8e277..6f30df3f 100644 --- a/common/locale/en-US/hints.xml +++ b/common/locale/en-US/hints.xml @@ -116,17 +116,11 @@
  • I to open an image in a new tab.
  • -

    Of the previous modes, the value of the hinttags - option is used to choose the highlighted elements for - the modes, ;;, ;?, ;w, ;v, - ;V, ;Y and ;c. The value of - extendedhinttags is used to choose the elements - for, ;s, ;a, ;o, ;t, - ;b, ;O, ;T, ;W, ;y, + option is used to choose the highlighted elements, + unless an override can be found in + extendedhinttags.

    diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index be99fb43..2b9b6f43 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -51,10 +51,11 @@
    A comma-separated list of regular expressions. Expressions may be prefixed with a !, in which case the match will be negated. A - literal ! at the begining of the expression may be matched with - [!]. Generally, the first matching regular expression is - used. Any comma appearing within single or double quotes, or prefixed - with a \, will not be treated as an item separator. + literal ! at the begining of the expression may be matched + with [!] or by placing the regular expression in quotes. + Generally, the first matching regular expression is used. Any comma + appearing within single or double quotes, or prefixed with a + \, will not be treated as an item separator.
    @@ -559,10 +560,14 @@ 'eht' 'extendedhinttags' 'extendedhinttags' 'eht' - string - &hinttags; + regexmap + [iI]:'//img | //xhtml:img' -

    The XPath string of hintable elements activated by ;.

    +

    + Defines specialized XPath expressions for arbitrary + extended-hints modes. If no matches are found, the value of + hinttags is used. +

    @@ -756,7 +761,12 @@ string &hinttags; -

    XPath string of hintable elements activated by f and F

    +

    + The XPath string used to select for + hinting. Can be overridden for + individual extended-hints modes with the + extendedhinttags option. +

    diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS index 256397bf..9acae799 100644 --- a/pentadactyl/NEWS +++ b/pentadactyl/NEWS @@ -32,6 +32,8 @@ operators, and = sign may no longer be quoted. This will break certain automatically-generated configuration files. See :help stringlist + * IMPORTANT: 'extendedhinttags' is now a regexmap rather than a + string. * Added 'altwildmode' and commandline key binding. * Added 'autocomplete' option for specifying which completion groups should be auto-completed. diff --git a/pentadactyl/TODO b/pentadactyl/TODO index a1f9ad41..7a5e89af 100644 --- a/pentadactyl/TODO +++ b/pentadactyl/TODO @@ -34,8 +34,6 @@ BUGS: FEATURES: 9 Add quoting help tag -9 Fix the arbitrary distinction between 'hinttags' and - 'extendedhinttags' 9 Support multiple bookmarks, -keyword, -tags in :delbmarks 8 Document Caret and Visual modes. 8 finish :help TODOs