diff --git a/common/content/commandline.js b/common/content/commandline.js index d277cf73..87f5ba1f 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -567,7 +567,9 @@ const CommandLine = Module("commandline", { this._startHints = false; if (!(modes.extended & modes.OUTPUT_MULTILINE)) - modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE); + modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE, { + onEvent: this.closure.onMultilineOutputEvent + }); // If it's already XML, assume it knows what it's doing. // Otherwise, white space is significant. @@ -695,14 +697,13 @@ const CommandLine = Module("commandline", { cancel: extra.onCancel }; - modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, { - enter: function (stack) { extra.enter && extra.enter(stack); }, - leave: function (stack) { - commandline.leave(stack); - if (extra.leave) - extra.leave(stack); - } - }); + modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, + update(Object.create(extra), { + leave: function leave(stack) { + commandline.leave(stack); + leave.supercall(this, stack); + } + })); this.currentExtendedMode = modes.PROMPT; this.widgets.prompt = !prompt ? null : [extra.promptHighlight || "Question", prompt]; @@ -934,14 +935,7 @@ const CommandLine = Module("commandline", { } if (event instanceof MouseEvent) - return; - - if (this._startHints) { - statusline.updateInputBuffer(""); - this._startHints = false; - hints.show(key, { window: win }); - return; - } + return false; function isScrollable() !win.scrollMaxY == 0; function atEnd() win.scrollY / win.scrollMaxY >= 1; @@ -953,7 +947,7 @@ const CommandLine = Module("commandline", { case ":": commandline.open(":", "", modes.EX); - return; + return false; // down a line case "j": @@ -1065,9 +1059,8 @@ const CommandLine = Module("commandline", { break; case ";": - statusline.updateInputBuffer(";"); - this._startHints = true; - break; + hints.open(";", { window: win }); + return false; // unmapped key default: @@ -1085,6 +1078,7 @@ const CommandLine = Module("commandline", { } else commandline.updateMorePrompt(showMorePrompt, showMoreHelpPrompt); + return false; }, getSpaceNeeded: function getSpaceNeeded() { diff --git a/common/content/events.js b/common/content/events.js index dd10e32d..a3d0a450 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -47,17 +47,16 @@ const Events = Module("events", { this._code_key = {}; this._key_code = {}; - for (let [k, v] in Iterator(KeyEvent)) - if (/^DOM_VK_(?![A-Z0-9]$)/.test(k)) { - k = k.substr(7).toLowerCase(); - let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase()) - .replace(/^NUMPAD/, "k")]; - if (k in this._keyTable) - names = this._keyTable[k]; - this._code_key[v] = names[0]; - for (let [, name] in Iterator(names)) - this._key_code[name.toLowerCase()] = v; - } + for (let [k, v] in Iterator(KeyEvent)) { + k = k.substr(7).toLowerCase(); + let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase()) + .replace(/^NUMPAD/, "k")]; + if (k in this._keyTable) + names = this._keyTable[k]; + this._code_key[v] = names[0]; + for (let [, name] in Iterator(names)) + this._key_code[name.toLowerCase()] = v; + } // HACK: as Gecko does not include an event for <, we must add this in manually. if (!("<" in this._key_code)) { @@ -374,7 +373,7 @@ const Events = Module("events", { * @param {string} keys The string to parse. * @returns {Array[Object]} */ - fromString: function (input) { + fromString: function (input, unknownOk) { let out = []; let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g"); @@ -388,9 +387,10 @@ const Events = Module("events", { let [match, modifier, keyname] = evt_str.match(/^<((?:[CSMA]-)*)(.+?)>$/i) || [false, '', '']; modifier = modifier.toUpperCase(); keyname = keyname.toLowerCase(); + evt_obj.dactylKeyname = keyname; if (keyname && !(keyname.length == 1 && modifier.length == 0 || // disallow <> and - !(keyname.length == 1 || this._key_code[keyname] || keyname == "nop" || /mouse$/.test(keyname)))) { // disallow + !(unknownOk || keyname.length == 1 || this._key_code[keyname] || keyname == "nop" || /mouse$/.test(keyname)))) { // disallow evt_obj.ctrlKey = /C-/.test(modifier); evt_obj.altKey = /A-/.test(modifier); evt_obj.shiftKey = /S-/.test(modifier); @@ -504,7 +504,7 @@ const Events = Module("events", { else if (charCode > 0) { key = String.fromCharCode(charCode); - if (key in this._key_code) { + if (!/^[a-z0-9]$/i.test(key) && key in this._key_code) { // a named charcode key ( and ) space can be shifted, must be forced if ((key.match(/^\s$/) && event.shiftKey) || event.dactylShift) modifier += "S-"; @@ -786,7 +786,7 @@ const Events = Module("events", { try { let stop = false; - let mode = modes.main; + let mode = modes.getStack(0); let win = document.commandDispatcher.focusedWindow; if (win && win.document && "designMode" in win.document && win.document.designMode == "on" && !config.isComposeWindow) @@ -804,7 +804,7 @@ const Events = Module("events", { // handler to escape the key if (!stop || !isEscape(key)) modes.pop(); - mode = modes.getStack(1).main; + mode = modes.getStack(1); } // handle Escape-all-keys mode (Ctrl-q) @@ -815,66 +815,32 @@ const Events = Module("events", { stop = true; // set to false if we should NOT consume this event but let the host app handle it - // just forward event without checking any mappings when the MOW is open - if (mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) { - commandline.onMultilineOutputEvent(event); - return killEvent(); - } - // XXX: ugly hack for now pass certain keys to the host app as // they are without beeping also fixes key navigation in combo // boxes, submitting forms, etc. // FIXME: breaks iabbr for now --mst - if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode)) { + if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode.main)) { this._input.buffer = ""; return null; } - // TODO: handle middle click in content area + if (mode.params.onEvent) { + this._input.buffer = ""; + // Bloody hell. + if (key === "") + key = event.dactylString = ""; - if (!isEscape(key)) { - // custom mode... - if (mode == modes.CUSTOM) { - plugins.onEvent(event); - return killEvent(); - } - - // All of these special cases for hint mode are driving - // me insane! -Kris - if (modes.extended & modes.HINTS) { - // under HINT mode, certain keys are redirected to hints.onEvent - if (key == "" || key == "" || key == "" - || key == options["mapleader"] - || (key == "" && hints.prevInput == "number") - || (hints.isHintKey(key) && !hints.escNumbers)) { - hints.onEvent(event); - this._input.buffer = ""; - return killEvent(); - } - - // others are left to generate the 'input' event or handled by the host app - return null; - } - } - - // FIXME (maybe): (is an ESC or C-] here): on HINTS mode, it enters - // into 'if (map && !skipMap) below. With that (or however) it - // triggers the onEscape part, where it resets mode. Here I just - // return true, with the effect that it also gets to there (for - // whatever reason). if that happens to be correct, well.. - // XXX: why not just do that as well for HINTS mode actually? - - if (mode == modes.CUSTOM) + if (mode.params.onEvent(event) === false) + killEvent(); return null; - - let mainMode = modes.getMode(mode); + } let inputStr = this._input.buffer + key; let countStr = inputStr.match(/^[1-9][0-9]*|/)[0]; let candidateCommand = inputStr.substr(countStr.length); - let map = mappings[event.noremap ? "getDefault" : "get"](mode, candidateCommand); + let map = mappings[event.noremap ? "getDefault" : "get"](mode.main, candidateCommand); - let candidates = mappings.getCandidates(mode, candidateCommand); + let candidates = mappings.getCandidates(mode.main, candidateCommand); if (candidates.length == 0 && !map) { map = this._input.pendingMap; this._input.pendingMap = null; @@ -885,7 +851,7 @@ const Events = Module("events", { // counts must be at the start of a complete mapping (10j -> go 10 lines down) if (countStr && !candidateCommand) { // no count for insert mode mappings - if (!mainMode.count || mainMode.input) + if (!mode.mainMode.count || mode.mainMode.input) stop = false; else this._input.buffer = inputStr; @@ -930,14 +896,14 @@ const Events = Module("events", { stop = false; } } - else if (mappings.getCandidates(mode, candidateCommand).length > 0 && !event.skipmap) { + else if (mappings.getCandidates(mode.main, candidateCommand).length > 0 && !event.skipmap) { this._input.pendingMap = map; this._input.buffer += key; } else { // if the key is neither a mapping nor the start of one // the mode checking is necessary so that things like g do not beep if (this._input.buffer != "" && !event.skipmap && - (mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXT_EDIT))) + (mode.main & (modes.INSERT | modes.COMMAND_LINE | modes.TEXT_EDIT))) events.feedkeys(this._input.buffer, { noremap: true, skipmap: true }); this._input.buffer = ""; @@ -947,15 +913,15 @@ const Events = Module("events", { if (!isEscape(key)) { // allow key to be passed to the host app if we can't handle it - stop = (mode == modes.TEXT_EDIT); + stop = (mode.main === modes.TEXT_EDIT); - if (mode == modes.COMMAND_LINE) { + if (mode.main === modes.COMMAND_LINE) { if (!(modes.extended & modes.INPUT_MULTILINE)) dactyl.trapErrors(function () { commandline.onEvent(event); // reroute event in command line mode }); } - else if (!mainMode.input) + else if (!mode.mainMode.input) dactyl.beep(); } } diff --git a/common/content/help.xsl b/common/content/help.xsl index 727e21ed..908ae3ec 100644 --- a/common/content/help.xsl +++ b/common/content/help.xsl @@ -352,8 +352,8 @@
- - + + diff --git a/common/content/hints.js b/common/content/hints.js index 4e672459..6721398b 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -83,7 +83,7 @@ const Hints = Module("hints", { this._hintNumber = 0; this._hintString = ""; statusline.updateInputBuffer(""); - commandline.command = ""; + commandline.widgets.command = ""; } this._pageHints = []; this._validHints = []; @@ -97,9 +97,9 @@ const Hints = Module("hints", { if (!this._usedTabKey) { this._hintNumber = 0; } - if (this.__continue && this._validHints.length <= 1) { + if (this._continue && this._validHints.length <= 1) { this._hintString = ""; - commandline.command = this._hintString; + commandline.widgets.command = this._hintString; this._showHints(); } this._updateStatusline(); @@ -347,8 +347,10 @@ const Hints = Module("hints", { let prefix = (elem.getAttributeNS(NS, "class") || "") + " "; if (active) elem.setAttributeNS(NS, "highlight", prefix + "HintActive"); - else + else if (active != null) elem.setAttributeNS(NS, "highlight", prefix + "HintElem"); + else + elem.removeAttributeNS(NS, "highlight"); }, /** @@ -429,7 +431,6 @@ const Hints = Module("hints", { */ _removeHints: function (timeout, slight) { for (let [,{ doc: doc, start: start, end: end }] in Iterator(this._docs)) { - util.dump(String(doc), start, end); for (let elem in util.evaluateXPath("//*[@dactyl:highlight='hints']", doc)) elem.parentNode.removeChild(elem); for (let i in util.range(start, end + 1)) @@ -489,12 +490,10 @@ const Hints = Module("hints", { let n = 5; (function next() { - this._setClass(elem, n % 2); - util.dump(n, String(this._top)); + let hinted = n || this._validHints.some(function (e) e === elem); + this._setClass(elem, n ? n % 2 : !hinted ? null : this._validHints[Math.max(0, this._hintNumber-1)] === elem); if (n--) this.timeout(next, 50); - else if (!this._validHints.some(function (h) h.elem == elem)) - elem.removeAttributeNS(NS, "highlight"); }).call(this); this.timeout(function () { @@ -765,6 +764,20 @@ const Hints = Module("hints", { */ isHintKey: function (key) this.hintKeys.indexOf(key) >= 0, + open: function (mode, opts) { + this._extendedhintCount = opts.count; + commandline.input(";", null, { + promptHighlight: "Normal", + completer: function (context) { + context.compare = function () 0; + context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints._hintModes))]; + }, + onAccept: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); }, + get onCancel() this.onAccept, + onChange: function () { modes.pop(); } + }); + }, + /** * Updates the display of hints. * @@ -782,7 +795,8 @@ const Hints = Module("hints", { if (!stack.push) hints.hide(); }, - onChange: this.closure._onInput + onChange: this.closure._onInput, + onEvent: this.closure.onEvent }); modes.extended = modes.HINTS; @@ -864,9 +878,12 @@ const Hints = Module("hints", { } this._showActiveHint(this._hintNumber, oldId); this._updateStatusline(); - return; + return false; case "": + if (this.prevInput !== "number") + return true; + if (this._hintNumber > 0 && !this._usedTabKey) { this._hintNumber = Math.floor(this._hintNumber / this.hintKeys.length); if (this._hintNumber == 0) @@ -886,10 +903,10 @@ const Hints = Module("hints", { this._hintNumber = 0; this._updateStatusline(); - return; + return false; default: - if (this.isHintKey(key)) { + if (!this.escNumbers && this.isHintKey(key)) { this.prevInput = "number"; let oldHintNumber = this._hintNumber; @@ -914,8 +931,9 @@ const Hints = Module("hints", { dactyl.assert(this._hintNumber != 0); this._checkUnique(); - return; + return false; } + return true; } this._updateStatusline(); @@ -927,6 +945,7 @@ const Hints = Module("hints", { this._showHints(); this._processHints(followFirst); } + return false; } //}}} }, { @@ -1052,30 +1071,15 @@ const Hints = Module("hints", { "Start QuickHint mode, but open link in a new tab", function () { hints.show(options.get("activate").has("links") ? "t" : "b"); }); - function inputOpts(opts) ({ - promptHighlight: "Normal", - completer: function (context) { - context.compare = function () 0; - context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints._hintModes))]; - }, - onAccept: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); }, - onChange: function () { modes.pop(); }, - onCancel: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); } - }); - mappings.add(myModes, [";"], "Start an extended hint mode", - function (count) { - this._extendedhintCount = count; - commandline.input(";", null, inputOpts()); - }, { count: true }); + function (count) { hints.open(";", { count: count }); }, + { count: true }); mappings.add(myModes, ["g;"], "Start an extended hint mode and stay there until is pressed", - function (count) { - this._extendedhintCount = count; - commandline.input("g;", null, inputOpts({ continue: true })); - }, { count: true }); + function (count) { hints.open("g;", { continue: true, count: count }); }, + { count: true }); }, options: function () { const DEFAULT_HINTTAGS = diff --git a/common/locale/en-US/cmdline.xml b/common/locale/en-US/cmdline.xml index 825f56b1..4e40f784 100644 --- a/common/locale/en-US/cmdline.xml +++ b/common/locale/en-US/cmdline.xml @@ -164,7 +164,7 @@ given in a single command line and will be executed consecutively. | can be included as an argument to a command by escaping it with a backslash. E.g. - :map \| :echo "bar" + :map \| :echo bar Several commands process the entire command line string literally. These commands will include any | as part of their @@ -239,7 +239,7 @@ optional quoting characters are available:

-
+
\
This is the most basic quoting character. When it is encountered @@ -261,7 +261,7 @@ included by preceding it with a backslash. Any other occurrence of a backslash starts an escape sequence as in JavaScript strings. Among the available escape sequences are: -
+
\n
A newline character.
\t
A tab character.
\0nn
Where each n is a digit between 0 and 7, represents an octal character code.
diff --git a/common/locale/en-US/map.xml b/common/locale/en-US/map.xml index de3a9952..4b125a2e 100644 --- a/common/locale/en-US/map.xml +++ b/common/locale/en-US/map.xml @@ -48,7 +48,7 @@ common modes,

-
+
n
Normal mode: When browsing normally
v
Visual mode: When selecting text with the cursor keys
i
Insert mode: When interacting with text fields on a website
@@ -108,7 +108,7 @@ Any of the map commands may be given the following options:

-
+
-builtin
Execute this mapping as if there were no user-defined mappings (short name -b)
@@ -303,7 +303,7 @@ sequences are interpreted as described,

-
+
xc
Type the ā€˜X’ key followed by the ā€˜C’ key
diff --git a/common/locale/en-US/marks.xml b/common/locale/en-US/marks.xml index bf457cf3..04958499 100644 --- a/common/locale/en-US/marks.xml +++ b/common/locale/en-US/marks.xml @@ -45,7 +45,7 @@

The following options are available,

-
+
-keyword
A keyword which may be used to open the bookmark via @@ -124,7 +124,7 @@

The bookmarks may also be filtered via the following options,

-
+
-keyword
The bookmark's keyword (short name -k). @@ -273,7 +273,7 @@

The pages may also be filtered via the following options,

-
+
-max
The maximum number of items to list or open diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index b963df15..db8b69fc 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -25,8 +25,8 @@ achieve special effects. These options come in 8 forms:

-
-
boolean
Can only be on or off
+
+
boolean
Can only be on or off
number
A numeric value
string
A string value
@@ -44,7 +44,7 @@
stringmap
-
A comma-separated list of key-value pairs, e.g., key:val,foo:bar
+
A comma-separated list of key-value pairs, e.g., key:val,foo:bar
regexlist
@@ -430,7 +430,7 @@

Items which are completed at the :open prompts. Available items:

-
+
s
Search engines and keyword URLs
f
Local files
l
&dactyl.host; location bar entries (bookmarks and history sorted in an intelligent way)
@@ -598,7 +598,7 @@

Possible values:

-
+
0
Follow the first hint as soon as typed text uniquely identifies it.
1
Follow the selected hint on .
2
Follow the selected hint on only if it's been -selected.
@@ -630,7 +630,7 @@

Supported characters:

-
+
B
Bookmark bar
C
Always show the command-line outside of the status line
M
Always show messages outside of the status line
@@ -676,7 +676,7 @@ given, and the first successful value is used.

-
+
value
The hint is the value displayed in a text input, or the selected option for a drop-down.
label
The value of an explicit label for the input; this will not match most manually added labels that are found on sites.
name
The name of the input will be used; although the name is not designed for user consumption, it is frequently very similar to the label.
@@ -869,7 +869,7 @@

Possible values:

-
+
0
Never
1
Only if there are multiple windows
2
Always
@@ -1045,7 +1045,7 @@

Items available by default:

-
+
g
General info
f
Feeds
m
Meta tags
@@ -1073,7 +1073,7 @@

Possible values are:

-
+
tab
Open pop-ups in a new tab
window
Open pop-ups in a new window
resized
Open resized pop-ups in a new window
@@ -1185,7 +1185,7 @@ deleted. The value must be of the one of:

-
+
all
Everything
session
The current session
nm
Past n Minutes
@@ -1258,7 +1258,7 @@

Possible values are:

-
+
0
Don't show link destination
1
Show the link's destination in the status-line
2
Show the link's destination in the command-line
@@ -1276,7 +1276,7 @@

Possible values are:

-
+
0
Never show tab line
1
Show tab line only if more than one tab is open
2
Always show tab line
diff --git a/common/locale/en-US/pattern.xml b/common/locale/en-US/pattern.xml index f4448ecb..5d5cb129 100644 --- a/common/locale/en-US/pattern.xml +++ b/common/locale/en-US/pattern.xml @@ -55,7 +55,7 @@ appear is the one that takes effect.

-
+
\c
Perform case insensitive search (default if ignorecase is set).
\C
Perform case sensitive search
\l
Search only in links, as defined by hinttags. (default if linksearch is set).
@@ -66,7 +66,7 @@ Additionally, if the /Find Bar/ extension is installed, the following flags may be used,

-
+
\r
Process the entire pattern as a regular expression.
\R
Process the entire pattern as an ordinary string.
diff --git a/common/locale/en-US/styling.xml b/common/locale/en-US/styling.xml index 3c3d98f0..f5320164 100644 --- a/common/locale/en-US/styling.xml +++ b/common/locale/en-US/styling.xml @@ -197,27 +197,30 @@ :styleenable :stylee :styenable :stye + :styledisable -name=name -index=index filter css -

Enable any matching styles. Arguments are the same as for :delstyle.

+

Enable any matching styles. Arguments are the same as for :delstyle

:styledisable :styled :stydisable :styd + :styleenable -name=name -index=
index filter css -

Disable any matching styles. Arguments are the same as for :delstyle.

+

Disable any matching styles. Arguments are the same as for :delstyle

:styletoggle :stylet :stytoggle :styt + :styletoggle -name=name -index=index filter css -

Toggle any matching styles. Arguments are the same as for :delstyle.

+

Toggle any matching styles. Arguments are the same as for :delstyle

diff --git a/common/locale/en-US/tabs.xml b/common/locale/en-US/tabs.xml index 99760426..9beab050 100644 --- a/common/locale/en-US/tabs.xml +++ b/common/locale/en-US/tabs.xml @@ -40,7 +40,7 @@

A buffer may be marked with one of the following indicators:

-
+
%
The current buffer
#
The alternate buffer for :e # and
diff --git a/common/locale/en-US/various.xml b/common/locale/en-US/various.xml index 31aceb41..bdcc3af2 100644 --- a/common/locale/en-US/various.xml +++ b/common/locale/en-US/various.xml @@ -122,16 +122,15 @@

- &dactyl.appName; fully supports &dactyl.host;'s private browsing mode. When in private browsing mode, no data other than Bookmarks and QuickMarks - are written to disk. Further, upon exiting private mode, all new data, - including command-line history, local and URL marks, and macros, - are purged. For more information, see private. + are written to disk. Further, upon exiting private mode, all newly + accumulated data, including command-line history, local and URL + marks, and macros, are purged from memory. For more information, see + private.

- In addition to private mode, &dactyl.appName; provides a comprehensive facility for clearing any potentially sensitive data generated by either &dactyl.appName; or &dactyl.host;. It directly integrates with diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS index 20987801..df7b5ff8 100644 --- a/pentadactyl/NEWS +++ b/pentadactyl/NEWS @@ -21,6 +21,13 @@ * Multiple Ex commands may now be separated by | * Command-line is now hidden by default. Added C and M to 'guioptions'. + * Hint mode improvements, including: + - Added g; continued extended hint mode, which allows + selecting multiple hints. Removed ;F + - Hints are now updated after scrolling and window resizing. + - Added ;S mode for creating search keywords. + - Added 'hintkeys' option. + - Added "transliterated" option to 'hintmatching'. * JavaScript completion improvements, including: - The prototype of the function whose arguments are currently being typed is displayed during completion. @@ -48,7 +55,6 @@ * IMPORTANT: 'guioptions' default value has changed. * IMPORTANT: 'mapleader' is now an option rather than a :let variable. - * Added g; continued extended hint mode and removed ;F * Added "bookmarks", "diverted", and "links" to 'activate' option * Added 'altwildmode' and command-line key binding. @@ -59,8 +65,6 @@ * Added -keyword, -tags, -title to :delbmarks. * Added "passwords" and "venkman" dialogs to :dialog. * Added :extupdate command - * Added 'hintkeys' option. - * Added "transliterated" option to 'hintmatching'. * Replaced 'focuscontent' with 'strictfocus'. * Changed 'urlseparator' default value to '|' * Added 'wildanchor' option.