From 41335adaae3cbcef469ac48d46c9ed28e4963e68 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Wed, 6 Oct 2010 10:34:28 -0400 Subject: [PATCH 01/16] Fix some major mode changing bugs. Closes issue #55. --HG-- branch : mode-refactoring --- common/content/buffer.js | 6 +- common/content/commandline.js | 16 +-- common/content/dactyl.js | 4 +- common/content/editor.js | 121 +++++++++++----------- common/content/events.js | 187 +++++++++++++--------------------- common/content/modes.js | 149 +++++++++++++++++++-------- common/content/options.js | 30 ++++-- common/modules/util.jsm | 3 +- 8 files changed, 274 insertions(+), 242 deletions(-) diff --git a/common/content/buffer.js b/common/content/buffer.js index 7903bc2c..ef322e21 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -1532,11 +1532,7 @@ const Buffer = Module("buffer", { mappings.add(myModes, ["i", ""], "Start caret mode", - function () { - // setting this option notifies an observer which takes care of the - // mode setting - options.setPref("accessibility.browsewithcaret", true); - }); + function () { modes.push(modes.CARET); }); mappings.add(myModes, [""], "Stop loading the current web page", diff --git a/common/content/commandline.js b/common/content/commandline.js index 95388bac..c2ddf9bd 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -441,7 +441,10 @@ const CommandLine = Module("commandline", { */ open: function open(prompt, cmd, extendedMode) { modes.push(modes.COMMAND_LINE, this.currentExtendedMode, { - leave: commandline.closure.leave + leave: function (params) { + if (params.pop) + commandline.leave(); + } }); this.currentExtendedMode = extendedMode || null; @@ -689,13 +692,12 @@ const CommandLine = Module("commandline", { }; modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, { - leave: function (newMode) { - commandline.leave(newMode); + enter: function (stack) { extra.enter && extra.enter(stack); }, + leave: function (stack) { + commandline.leave(stack); if (extra.leave) - extra.leave(newMode); - }, - restore: function (newMode) { extra.restore && extra.restore(newMode) }, - save: function (newMode) { extra.save && extra.save(newMode) } + extra.leave(stack); + } }); this.currentExtendedMode = modes.PROMPT; diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 73853241..1ea54a8d 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -162,7 +162,7 @@ const Dactyl = Module("dactyl", { * * @returns {string} */ - clipboardRead: function clipboardRead() { + clipboardRead: function clipboardRead(getClipboard) { let str = null; try { @@ -171,7 +171,7 @@ const Dactyl = Module("dactyl", { transferable.addDataFlavor("text/unicode"); - if (clipboard.supportsSelectionClipboard()) + if (!getClipboard && clipboard.supportsSelectionClipboard()) clipboard.getData(transferable, clipboard.kSelectionClipboard); else clipboard.getData(transferable, clipboard.kGlobalClipboard); diff --git a/common/content/editor.js b/common/content/editor.js index ecaa2a58..02140809 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -16,30 +16,11 @@ const Editor = Module("editor", { // this._lastFindChar = null; this._lastFindCharFunc = null; - - // Hack? - dactyl.registerObserver("modeChange", function (oldMode, newMode, stack) { - switch (oldMode[0]) { - case modes.TEXTAREA: - case modes.INSERT: - editor.unselectText(); - break; - - case modes.VISUAL: - if (newMode[0] == modes.CARET) { - try { // clear any selection made; a simple if (selection) does not work - let selection = window.content.getSelection(); - selection.collapseToStart(); - } - catch (e) {} - } - else - editor.unselectText(); - break; - } - }); }, + get isCaret() modes.getStack(1).main === modes.CARET, + get isTextArea() modes.getStack(1).main === modes.TEXTAREA, + line: function () { let line = 1; let text = Editor.getEditor().value; @@ -60,12 +41,15 @@ const Editor = Module("editor", { return col; }, - unselectText: function () { + unselectText: function (toEnd) { let elem = dactyl.focus; // A error occurs if the element has been removed when "elem.selectionStart" is executed. try { if (elem && elem.selectionEnd) - elem.selectionEnd = elem.selectionStart; + if (toEnd) + elem.selectionStart = elem.selectionEnd; + else + elem.selectionEnd = elem.selectionStart; } catch (e) {} }, @@ -75,7 +59,7 @@ const Editor = Module("editor", { return text.substring(Editor.getEditor().selectionStart, Editor.getEditor().selectionEnd); }, - pasteClipboard: function () { + pasteClipboard: function (clipboard, toStart) { if (dactyl.has("WINNT")) { this.executeCommand("cmd_paste"); return; @@ -85,7 +69,7 @@ const Editor = Module("editor", { let elem = dactyl.focus; if (elem.setSelectionRange) { - let text = dactyl.clipboardRead(); + let text = dactyl.clipboardRead(clipboard); if (!text) return; @@ -101,7 +85,7 @@ const Editor = Module("editor", { let tempStr2 = text; let tempStr3 = elem.value.substring(rangeEnd); elem.value = tempStr1 + tempStr2 + tempStr3; - elem.selectionStart = rangeStart + tempStr2.length; + elem.selectionStart = rangeStart + (toStart ? 0 : tempStr2.length); elem.selectionEnd = elem.selectionStart; elem.scrollTop = curTop; @@ -153,7 +137,8 @@ const Editor = Module("editor", { count--; } - modes.set(modes.VISUAL, modes.TEXTAREA); + if (modes.main != modes.VISUAL) + modes.push(modes.VISUAL); switch (motion) { case "j": @@ -204,16 +189,16 @@ const Editor = Module("editor", { switch (cmd) { case "d": this.executeCommand("cmd_delete", 1); - // need to reset the mode as the visual selection changes it - modes.main = modes.TEXTAREA; + modes.pop(modes.TEXTAREA); break; case "c": this.executeCommand("cmd_delete", 1); - modes.set(modes.INSERT, modes.TEXTAREA); + modes.pop(modes.TEXTAREA); + modes.push(modes.INSERT); break; case "y": this.executeCommand("cmd_copy", 1); - this.unselectText(); + modes.pop(modes.TEXTAREA); break; default: @@ -457,19 +442,37 @@ const Editor = Module("editor", { if (hasCount) extraInfo.count = true; + function caretExecute(arg, again) { + function fixSelection() { + sel.removeAllRanges(); + sel.addRange(RangeFind.endpoint( + RangeFind.nodeRange(buffer.focusedFrame.document.documentElement), + true)); + } + + let controller = buffer.selectionController; + let sel = controller.getSelection(controller.SELECTION_NORMAL); + if (!sel.rangeCount) // Hack. + fixSelection(); + + try { + controller[caretModeMethod](caretModeArg, arg); + } + catch (e) { + dactyl.assert(again && e.result === Cr.NS_ERROR_FAILURE); + fixSelection(); + caretExecute(arg, false); + } + return false; + } + mappings.add([modes.CARET], keys, "", function (count) { if (typeof count != "number" || count < 1) count = 1; - let controller = buffer.selectionController; - let sel = controller.getSelection(controller.SELECTION_NORMAL); - if (!sel.rangeCount) // Hack. - sel.addRange(RangeFind.endpoint( - RangeFind.nodeRange(buffer.focusedFrame.document.documentElement), - true)); while (count--) - controller[caretModeMethod](caretModeArg, false); + caretExecute(false, true); }, extraInfo); @@ -479,15 +482,15 @@ const Editor = Module("editor", { count = 1; let controller = buffer.selectionController; - while (count--) { - if (modes.extended & modes.TEXTAREA) { + while (count-- && modes.main == modes.VISUAL) { + if (editor.isTextArea) { if (typeof visualTextareaCommand == "function") visualTextareaCommand(); else editor.executeCommand(visualTextareaCommand); } else - controller[caretModeMethod](caretModeArg, true); + caretExecute(true, true); } }, extraInfo); @@ -508,7 +511,7 @@ const Editor = Module("editor", { function (count) { commands.forEach(function (cmd) editor.executeCommand(cmd, 1)); - modes.set(modes.INSERT, modes.TEXTAREA); + modes.push(modes.INSERT); }); } @@ -608,7 +611,7 @@ const Editor = Module("editor", { mappings.add([modes.INSERT], [""], "Edit text field in Vi mode", - function () { dactyl.mode = modes.TEXTAREA; }); + function () { modes.push(modes.TEXTAREA); }); mappings.add([modes.INSERT], ["", ""], "Expand insert mode abbreviation", @@ -628,7 +631,7 @@ const Editor = Module("editor", { ["u"], "Undo", function (count) { editor.executeCommand("cmd_undo", count); - dactyl.mode = modes.TEXTAREA; + editor.unselectText(); }, { count: true }); @@ -636,7 +639,7 @@ const Editor = Module("editor", { [""], "Redo", function (count) { editor.executeCommand("cmd_redo", count); - dactyl.mode = modes.TEXTAREA; + editor.unselectText(); }, { count: true }); @@ -648,7 +651,7 @@ const Editor = Module("editor", { ["o"], "Open line below current", function (count) { editor.executeCommand("cmd_endLine", 1); - modes.set(modes.INSERT, modes.TEXTAREA); + modes.push(modes.INSERT); events.feedkeys(""); }); @@ -656,7 +659,7 @@ const Editor = Module("editor", { ["O"], "Open line above current", function (count) { editor.executeCommand("cmd_beginLine", 1); - modes.set(modes.INSERT, modes.TEXTAREA); + modes.push(modes.INSERT); events.feedkeys(""); editor.executeCommand("cmd_linePrevious", 1); }); @@ -674,7 +677,7 @@ const Editor = Module("editor", { // visual mode mappings.add([modes.CARET, modes.TEXTAREA], ["v"], "Start visual mode", - function (count) { modes.set(modes.VISUAL, dactyl.mode); }); + function (count) { modes.push(modes.VISUAL); }); mappings.add([modes.VISUAL], ["v"], "End visual mode", @@ -683,7 +686,7 @@ const Editor = Module("editor", { mappings.add([modes.TEXTAREA], ["V"], "Start visual line mode", function (count) { - modes.set(modes.VISUAL, modes.TEXTAREA | modes.LINE); + modes.push(modes.VISUAL, modes.LINE); editor.executeCommand("cmd_beginLine", 1); editor.executeCommand("cmd_selectLineNext", 1); }); @@ -691,17 +694,17 @@ const Editor = Module("editor", { mappings.add([modes.VISUAL], ["c", "s"], "Change selected text", function (count) { - dactyl.assert(modes.extended & modes.TEXTAREA); + dactyl.assert(editor.isTextArea); editor.executeCommand("cmd_cut"); - modes.set(modes.INSERT, modes.TEXTAREA); + modes.replace(modes.VISUAL); }); mappings.add([modes.VISUAL], ["d"], "Delete selected text", function (count) { - if (modes.extended & modes.TEXTAREA) { + if (editor.isTextArea) { editor.executeCommand("cmd_cut"); - modes.set(modes.TEXTAREA); + modes.pop(); } else dactyl.beep(); @@ -710,9 +713,9 @@ const Editor = Module("editor", { mappings.add([modes.VISUAL], ["y"], "Yank selected text", function (count) { - if (modes.extended & modes.TEXTAREA) { + if (editor.isTextArea) { editor.executeCommand("cmd_copy"); - modes.set(modes.TEXTAREA); + modes.pop(); } else dactyl.clipboardWrite(buffer.getCurrentWord(), true); @@ -721,12 +724,12 @@ const Editor = Module("editor", { mappings.add([modes.VISUAL, modes.TEXTAREA], ["p"], "Paste clipboard contents", function (count) { - dactyl.assert(!(modes.extended & modes.CARET)); + dactyl.assert(!editor.isCaret); if (!count) count = 1; while (count--) editor.executeCommand("cmd_paste"); - dactyl.mode = modes.TEXTAREA; + modes.pop(modes.TEXTAREA); }); // finding characters @@ -786,7 +789,7 @@ const Editor = Module("editor", { text.substring(pos + 1); editor.moveToPosition(pos + 1, true, false); } - modes.set(modes.TEXTAREA); + modes.pop(modes.TEXTAREA); }, { count: true }); }, diff --git a/common/content/events.js b/common/content/events.js index 26607990..05cdd7bf 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -76,11 +76,11 @@ const Events = Module("events", { this._activeMenubar = false; this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true); this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true); - this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true); - this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true); - this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true); - this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true); - this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true); + this.addSessionListener(window, "focus", this.wrapListener(this.onFocus), true); + this.addSessionListener(window, "keydown", this.wrapListener(this.onKeyUpOrDown), true); + this.addSessionListener(window, "keypress", this.wrapListener(this.onKeyPress), true); + this.addSessionListener(window, "keyup", this.wrapListener(this.onKeyUpOrDown), true); + this.addSessionListener(window, "mousedown", this.wrapListener(this.onMouseDown), true); this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true); this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true); this.addSessionListener(window, "resize", this.closure.onResize, true); @@ -90,7 +90,8 @@ const Events = Module("events", { destroy: function () { util.dump("Removing all event listeners"); for (let args in values(this.sessionListeners)) - args[0].removeEventListener.apply(args[0], args.slice(1)); + if (args[0].get()) + args[0].get().removeEventListener.apply(args[0].get(), args.slice(1)); }, /** @@ -105,7 +106,8 @@ const Events = Module("events", { */ addSessionListener: function (target, event, callback, capture) { let args = Array.slice(arguments, 0); - target.addEventListener.apply(args[0], args.slice(1)); + args[0].addEventListener.apply(args[0], args.slice(1)); + args[0] = Cu.getWeakReference(args[0]); this.sessionListeners.push(args); }, @@ -113,6 +115,7 @@ const Events = Module("events", { * Wraps an event listener to ensure that errors are reported. */ wrapListener: function wrapListener(method, self) { + self = self || this; return function (event) { try { method.apply(self, arguments); @@ -625,69 +628,17 @@ const Events = Module("events", { * The global escape key handler. This is called in ALL modes. */ onEscape: function () { - if (modes.passNextKey) - return; - - if (modes.passAllKeys) { - modes.passAllKeys = false; - return; - } - switch (dactyl.mode) { - case modes.NORMAL: - // clear any selection made - let selection = window.content.getSelection(); - try { // a simple if (selection) does not seem to work - selection.collapseToStart(); - } - catch (e) {} - - modes.reset(); - break; - - case modes.VISUAL: - if (modes.extended & modes.TEXTAREA) - dactyl.mode = modes.TEXTAREA; - else if (modes.extended & modes.CARET) - dactyl.mode = modes.CARET; - break; - - case modes.CARET: - // setting this option will trigger an observer which will - // take care of all other details like setting the NORMAL - // mode - options.setPref("accessibility.browsewithcaret", false); - break; - - case modes.TEXTAREA: - // TODO: different behaviour for text areas and other input - // fields seems unnecessarily complicated. If the user - // likes Vi-mode then they probably like it for all input - // fields, if not they can enter it explicitly for only - // text areas. The mode name TEXTAREA is confusing and - // would be better replaced with something indicating that - // it's a Vi editing mode. Extended modes really need to be - // displayed too. --djk - function isInputField() { - let elem = dactyl.focus; - return elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type) - || elem instanceof HTMLIsIndexElement; - } - - if (options["insertmode"] || isInputField()) - dactyl.mode = modes.INSERT; - else - modes.reset(); - break; - + case modes.COMMAND_LINE: case modes.INSERT: - if ((modes.extended & modes.TEXTAREA)) - dactyl.mode = modes.TEXTAREA; - else - modes.reset(); + case modes.PASS_THROUGH: + case modes.QUOTE: + case modes.TEXTAREA: + case modes.VISUAL: + modes.pop(); break; - default: // HINTS, CUSTOM or COMMAND_LINE + default: modes.reset(); break; } @@ -752,12 +703,15 @@ const Events = Module("events", { } if (elem instanceof HTMLTextAreaElement || (elem && util.computedStyle(elem).MozUserModify == "read-write")) { + if (modes.main === modes.VISUAL && elem.selectionEnd == elem.selectionStart) + modes.pop(); if (options["insertmode"]) modes.set(modes.INSERT); - else if (elem.selectionEnd - elem.selectionStart > 0) - modes.set(modes.VISUAL, modes.TEXTAREA); - else - modes.main = modes.TEXTAREA; + else { + modes.set(modes.TEXTAREA); + if (elem.selectionEnd - elem.selectionStart > 0) + modes.push(modes.VISUAL); + } if (hasHTMLDocument(win)) buffer.lastInputField = elem; return; @@ -772,7 +726,7 @@ const Events = Module("events", { if (elem == null && urlbar && urlbar.inputField == this._lastFocus) util.threadYield(true); - if (dactyl.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL)) + if (modes.getMode(modes.main).ownsFocus) modes.reset(); } finally { @@ -784,7 +738,7 @@ const Events = Module("events", { // the commandline has focus // TODO: ...help me...please... onKeyPress: function (event) { - function isEscapeKey(key) key == "" || key == ""; + function isEscape(key) key == "" || key == ""; function killEvent() { event.preventDefault(); @@ -802,7 +756,7 @@ const Events = Module("events", { dactyl.echomsg("Recorded macro '" + this._currentMacro + "'"); return killEvent(); } - else if (!mappings.hasMap(dactyl.mode, this._input.buffer + key)) + else if (!mappings.hasMap(mode, this._input.buffer + key)) this._macros.set(this._currentMacro, { keys: this._macros.get(this._currentMacro, {}).keys + key, timeRecorded: Date.now() @@ -832,6 +786,7 @@ const Events = Module("events", { try { let stop = false; + let mode = modes.main; let win = document.commandDispatcher.focusedWindow; if (win && win.document && "designMode" in win.document && win.document.designMode == "on" && !config.isComposeWindow) @@ -839,20 +794,19 @@ const Events = Module("events", { // menus have their own command handlers if (modes.extended & modes.MENU) stop = true; + else if (modes.main == modes.PASS_THROUGH) + // let flow continue to handle these keys to cancel escape-all-keys mode + stop = !isEscape(key) && key != "" // handle Escape-one-key mode (Ctrl-v) - else if (modes.passNextKey && !modes.passAllKeys) { - modes.passNextKey = false; - stop = true; + else if (modes.main == modes.QUOTE) { + stop = modes.getStack(1).main !== modes.PASS_THROUGH || isEscape(key); + // We need to preserve QUOTE mode until the escape + // handler to escape the key + if (!stop || !isEscape(key)) + modes.pop(); + mode = modes.getStack(1).main; } // handle Escape-all-keys mode (Ctrl-q) - else if (modes.passAllKeys) { - if (modes.passNextKey) - modes.passNextKey = false; // and then let flow continue - else if (isEscapeKey(key) || key == "") - ; // let flow continue to handle these keys to cancel escape-all-keys mode - else - stop = true; - } if (stop) { this._input.buffer = ""; @@ -862,7 +816,7 @@ 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 (dactyl.mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) { + if (mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) { commandline.onMultilineOutputEvent(event); return killEvent(); } @@ -871,16 +825,16 @@ const Events = Module("events", { // 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] & dactyl.mode)) { + if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode)) { this._input.buffer = ""; return null; } // TODO: handle middle click in content area - if (!isEscapeKey(key)) { + if (!isEscape(key)) { // custom mode... - if (dactyl.mode == modes.CUSTOM) { + if (mode == modes.CUSTOM) { plugins.onEvent(event); return killEvent(); } @@ -910,15 +864,17 @@ const Events = Module("events", { // whatever reason). if that happens to be correct, well.. // XXX: why not just do that as well for HINTS mode actually? - if (dactyl.mode == modes.CUSTOM) + if (mode == modes.CUSTOM) 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"](dactyl.mode, candidateCommand); + let map = mappings[event.noremap ? "getDefault" : "get"](mode, candidateCommand); - let candidates = mappings.getCandidates(dactyl.mode, candidateCommand); + let candidates = mappings.getCandidates(mode, candidateCommand); if (candidates.length == 0 && !map) { map = this._input.pendingMap; this._input.pendingMap = null; @@ -929,7 +885,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 (!modes.mainMode.count || modes.mainMode.input) + if (!mainMode.count || mainMode.input) stop = false; else this._input.buffer = inputStr; @@ -938,7 +894,7 @@ const Events = Module("events", { this._input.buffer = ""; let map = this._input.pendingArgMap; this._input.pendingArgMap = null; - if (!isEscapeKey(key)) { + if (!isEscape(key)) { if (modes.isReplaying && !this.waitForPageLoad()) return null; map.execute(null, this._input.count, key); @@ -957,7 +913,7 @@ const Events = Module("events", { this._input.pendingArgMap = map; } else if (this._input.pendingMotionMap) { - if (!isEscapeKey(key)) + if (!isEscape(key)) this._input.pendingMotionMap.execute(candidateCommand, this._input.count, null); this._input.pendingMotionMap = null; } @@ -974,14 +930,14 @@ const Events = Module("events", { stop = false; } } - else if (mappings.getCandidates(dactyl.mode, candidateCommand).length > 0 && !event.skipmap) { + else if (mappings.getCandidates(mode, 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 && - (dactyl.mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXTAREA))) + (mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXTAREA))) events.feedkeys(this._input.buffer, { noremap: true, skipmap: true }); this._input.buffer = ""; @@ -989,17 +945,17 @@ const Events = Module("events", { this._input.pendingMotionMap = null; this._input.pendingMap = null; - if (!isEscapeKey(key)) { + if (!isEscape(key)) { // allow key to be passed to the host app if we can't handle it - stop = (dactyl.mode == modes.TEXTAREA); + stop = (mode == modes.TEXTAREA); - if (dactyl.mode == modes.COMMAND_LINE) { + if (mode == modes.COMMAND_LINE) { if (!(modes.extended & modes.INPUT_MULTILINE)) dactyl.trapErrors(function () { commandline.onEvent(event); // reroute event in command line mode }); } - else if (!modes.mainMode.input) + else if (!mainMode.input) dactyl.beep(); } } @@ -1019,9 +975,8 @@ const Events = Module("events", { // this is need for sites like msn.com which focus the input field on keydown onKeyUpOrDown: function (event) { - if (modes.passNextKey ^ modes.passAllKeys || Events.isInputElemFocused()) - return; - event.stopPropagation(); + if (!Events.isInputElemFocused() && !modes.passThrough) + event.stopPropagation(); }, onMouseDown: function (event) { @@ -1052,20 +1007,18 @@ const Events = Module("events", { }, onSelectionChange: function (event) { - let couldCopy = false; let controller = document.commandDispatcher.getControllerForCommand("cmd_copy"); - if (controller && controller.isCommandEnabled("cmd_copy")) - couldCopy = true; + let couldCopy = controller && controller.isCommandEnabled("cmd_copy"); - if (dactyl.mode != modes.VISUAL) { - if (couldCopy) { - if ((dactyl.mode == modes.TEXTAREA || - (modes.extended & modes.TEXTAREA)) - && !options["insertmode"]) - modes.set(modes.VISUAL, modes.TEXTAREA); - else if (dactyl.mode == modes.CARET) - modes.set(modes.VISUAL, modes.CARET); - } + if (dactyl.mode === modes.VISUAL) { + if (!couldCopy) + modes.pop(); // Really not ideal. + } + else if (couldCopy) { + if (modes.main == modes.TEXTAREA && !options["insertmode"]) + modes.push(modes.VISUAL); + else if (dactyl.mode == modes.CARET) + modes.push(modes.VISUAL); } // XXX: disabled, as i think automatically starting visual caret mode does more harm than help // else @@ -1144,11 +1097,11 @@ const Events = Module("events", { mappings.add(modes.all, [""], "Temporarily ignore all " + config.appName + " key bindings", - function () { modes.passAllKeys = true; }); + function () { modes.push(modes.PASS_THROUGH); }); mappings.add(modes.all, [""], "Pass through next key", - function () { modes.passNextKey = true; }); + function () { modes.push(modes.QUOTE); }); mappings.add(modes.all, [""], "Do nothing", diff --git a/common/content/modes.js b/common/content/modes.js index 5b963da4..53b4e8b6 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -30,14 +30,42 @@ const Modes = Module("modes", { this.boundProperties = {}; // main modes, only one should ever be active - this.addMode("NORMAL", { char: "n", display: null }); - this.addMode("INSERT", { char: "i", input: true }); - this.addMode("VISUAL", { char: "v", display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") }); + this.addMode("NORMAL", { char: "n", display: function () null }); + this.addMode("INSERT", { char: "i", input: true, ownsFocus: true }); + this.addMode("VISUAL", { char: "v", ownsFocus: true, display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") }, { + leave: function (stack, newMode) { + if (newMode.main == modes.CARET) { + let selection = window.content.getSelection(); + if (selection && !selection.isCollapsed) + selection.collapseToStart(); + } + else + editor.unselectText(); + } + }); this.addMode("COMMAND_LINE", { char: "c", input: true }); - this.addMode("CARET"); // text cursor is visible - this.addMode("TEXTAREA", { char: "i" }); - this.addMode("EMBED", { input: true }); - this.addMode("CUSTOM", { display: function () plugins.mode }); + this.addMode("CARET", {}, { + get pref() options.getPref("accessibility.browsewithcaret"), + set pref(val) options.setPref("accessibility.browsewithcaret", val), + enter: function (stack) { + if (stack.pop && !this.pref) + modes.pop(); + else if (!stack.pop && !this.pref) + this.pref = true; + }, + leave: function (stack) { + if (!stack.push && this.pref) + this.pref = false; + } + }); + this.addMode("TEXTAREA", { char: "i", ownsFocus: true }); + this.addMode("EMBED", { input: true, ownsFocus: true }); + this.addMode("PASS_THROUGH"); + this.addMode("QUOTE", { + display: function () modes.getStack(1).main == modes.PASS_THROUGH + ? (modes.getStack(2).mainMode.display() || modes.getStack(2).mainMode.name) + " (next)" + : "PASS THROUGH (next)" + }); // this._extended modes, can include multiple modes, and even main modes this.addMode("EX", true); this.addMode("HINTS", true); @@ -45,30 +73,31 @@ const Modes = Module("modes", { this.addMode("OUTPUT_MULTILINE", true); this.addMode("SEARCH_FORWARD", true); this.addMode("SEARCH_BACKWARD", true); - this.addMode("SEARCH_VIEW_FORWARD", true); - this.addMode("SEARCH_VIEW_BACKWARD", true); this.addMode("MENU", true); // a popupmenu is active this.addMode("LINE", true); // linewise visual mode this.addMode("PROMPT", true); this.push(this.NORMAL, 0, { - restore: function (prev) { - // disable caret mode when we want to switch to normal mode + enter: function (stack, prev) { if (options.getPref("accessibility.browsewithcaret")) options.setPref("accessibility.browsewithcaret", false); statusline.updateUrl(); - dactyl.focusContent(true); + if (prev.mainMode.input || prev.mainMode.ownsFocus) + dactyl.focusContent(true); + if (prev.main === modes.NORMAL) { + dactyl.focusContent(true); + // clear any selection made + let selection = window.content.getSelection(); + if (selection && !selection.isCollapsed) + selection.collapseToStart(); + } + } }); }, _getModeMessage: function () { - if (this._passNextKey && !this._passAllKeys) - return "-- PASS THROUGH (next) --"; - else if (this._passAllKeys && !this._passNextKey) - return "-- PASS THROUGH --"; - // when recording a macro let macromode = ""; if (modes.isRecording) @@ -81,7 +110,8 @@ const Modes = Module("modes", { ext += " (menu)"; ext += " --" + macromode; - if (this._main in this._modeMap && typeof this._modeMap[this._main].display == "function") + let val = this._modeMap[this._main].display(); + if (val) return "-- " + this._modeMap[this._main].display() + ext; return macromode; }, @@ -98,27 +128,31 @@ const Modes = Module("modes", { get topOfStack() this._modeStack[this._modeStack.length - 1], - addMode: function (name, extended, options) { + addMode: function (name, extended, options, params) { let disp = name.replace("_", " ", "g"); this[name] = 1 << this._lastMode++; + if (typeof extended == "object") { + params = options; options = extended; extended = false; } + let mode = util.extend({ - extended: extended, count: true, + disp: disp, + extended: extended, input: false, mask: this[name], name: name, - disp: disp + params: params || {} }, options); if (mode.char) { this.modeChars[mode.char] = this.modeChars[mode.char] || []; this.modeChars[mode.char].push(mode); } - if (mode.display !== null) + if (mode.display == null) mode.display = function () disp; this._modeMap[name] = mode; this._modeMap[this[name]] = mode; @@ -129,6 +163,8 @@ const Modes = Module("modes", { getMode: function (name) this._modeMap[name], + getStack: function (idx) this._modeStack[this._modeStack.length - idx - 1] || this._modeStack[0], + getCharModes: function (chr) [m for (m in values(this._modeMap)) if (m.char == chr)], matchModes: function (obj) @@ -158,7 +194,7 @@ const Modes = Module("modes", { // helper function to set both modes in one go // if silent == true, you also need to take care of the mode handling changes yourself set: function (mainMode, extendedMode, params, stack) { - params = params || {}; + params = params || this.getMode(mainMode || this.main).params; if (!stack && mainMode != null && this._modeStack.length > 1) this.reset(); @@ -166,9 +202,8 @@ const Modes = Module("modes", { let push = mainMode != null && !(stack && stack.pop) && Modes.StackElem(mainMode, extendedMode || this.NONE, params, {}); if (push && this.topOfStack) { - if (this.topOfStack.params.save) - this.topOfStack.params.save(push); - + if (this.topOfStack.params.leave) + this.topOfStack.params.leave({ push: push }, push); for (let [id, { obj, prop }] in Iterator(this.boundProperties)) { if (!obj.get()) delete this.boundProperties(id); @@ -189,8 +224,12 @@ const Modes = Module("modes", { this._extended = this.NONE; } + let prev = stack && stack.pop || this.topOfStack; if (push) this._modeStack.push(push); + if (this.topOfStack.params.enter && prev) + this.topOfStack.params.enter(push ? { push: push } : stack || {}, + prev); dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack); @@ -202,22 +241,31 @@ const Modes = Module("modes", { this.set(mainMode, extendedMode, params, { push: this.topOfStack }); }, - pop: function () { - let a = this._modeStack.pop(); - if (a.params.leave) - a.params.leave(this.topOfStack); + pop: function (mode) { + while (this._modeStack.length > 1 && this.main != mode) { + let a = this._modeStack.pop(); + if (a.params.leave) + a.params.leave({ pop: a }, this.topOfStack); - this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a }); - if (this.topOfStack.params.restore) - this.topOfStack.params.restore(a); + this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a }); - for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved)) - obj[prop] = value; + for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved)) + obj[prop] = value; + + if (mode == null) + return; + } + }, + + replace: function (mode, oldMode) { + // TODO: This should really be done in one step. + this.pop(oldMode); + this.push(mode); }, reset: function () { - if (this._modeStack.length == 1 && this.topOfStack.params.restore) - this.topOfStack.params.restore(this.topOfStack); + if (this._modeStack.length == 1 && this.topOfStack.params.enter) + this.topOfStack.params.enter({}, this.topOfStack); while (this._modeStack.length > 1) this.pop(); }, @@ -229,12 +277,6 @@ const Modes = Module("modes", { } }, - get passNextKey() this._passNextKey, - set passNextKey(value) { this._passNextKey = value; this.show(); }, - - get passAllKeys() this._passAllKeys, - set passAllKeys(value) { this._passAllKeys = value; this.show(); }, - get isRecording() this._isRecording, set isRecording(value) { this._isRecording = value; this.show(); }, @@ -247,7 +289,17 @@ const Modes = Module("modes", { get extended() this._extended, set extended(value) { this.set(null, value); } }, { - StackElem: Struct("main", "extended", "params", "saved"), + StackElem: (function () { + let struct = Struct("main", "extended", "params", "saved"); + struct.prototype.__defineGetter__("mainMode", function () modes.getMode(this.main)); + struct.prototype.toString = function () !loaded.modes ? this.main : "[mode " + + modes.getMode(this.main).name + + (!this.extended ? "" : + "(" + + [modes.getMode(1< Date: Wed, 6 Oct 2010 23:28:42 -0400 Subject: [PATCH 02/16] Use JSON.parse rather than eval to parse strings. --HG-- branch : mode-refactoring --- common/content/commands.js | 2 +- common/content/javascript.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/common/content/commands.js b/common/content/commands.js index ecb8751d..014fa7fd 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -917,7 +917,7 @@ const Commands = Module("commands", { if ((res = re2.exec(str))) arg += keepQuotes ? res[0] : res[2].replace(/\\(.)/g, "$1"); else if ((res = /^(")((?:[^\\"]|\\.)*)("?)/.exec(str))) - arg += keepQuotes ? res[0] : window.eval(res[0] + (res[3] ? "" : '"')); + arg += keepQuotes ? res[0] : JSON.parse(res[0] + (res[3] ? "" : '"')); else if ((res = /^(')((?:[^']|'')*)('?)/.exec(str))) arg += keepQuotes ? res[0] : res[2].replace("''", "'", "g"); else diff --git a/common/content/javascript.js b/common/content/javascript.js index 8c6c492f..c5c6cd19 100644 --- a/common/content/javascript.js +++ b/common/content/javascript.js @@ -478,9 +478,7 @@ const JavaScript = Module("javascript", { // The top of the stack is the sting we're completing. // Wrap it in its delimiters and eval it to process escape sequences. let string = this._str.substring(this._get(-1).offset + 1, this._lastIdx); - // This is definitely a properly quoted string. - // Just eval it normally. - string = window.eval(this._last + string + this._last); + string = JSON.parse(this._last + string + this._last); // Is this an object accessor? if (this._get(-2).char == "[") { // Are we inside of []? From 248c906e9cd36ddc030e5f0ce71f1e10ccb5f098 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 7 Oct 2010 23:18:09 -0400 Subject: [PATCH 03/16] Some minor fixes, and add ctypes support to iter(). --HG-- branch : mode-refactoring --- common/content/dactyl.js | 8 ++++---- common/content/io.js | 16 +++++++++------- common/content/javascript.js | 23 ++++++++++++----------- common/modules/base.jsm | 21 ++++++++++++++++++++- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 1ea54a8d..fe375905 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -25,16 +25,16 @@ const FailedAssertion = Class("FailedAssertion", Error, { } }); -deprecated.seen = { "chrome://dactyl/content/javascript.js": true }; -function deprecated(reason, fn) +function deprecated(reason, fn) update( function deprecatedMethod() { let frame = Components.stack.caller; - if (!set.add(deprecated.seen, frame.filename)) + if (!set.add(deprecatedMethod.seen, frame.filename)) dactyl.echoerr(frame.filename + ":" + frame.lineNumber + ": " + (this.className || this.constructor.className) + "." + fn.name + " is deprecated: " + reason); return fn.apply(this, arguments); - } + }, + { seen: { "chrome://dactyl/content/javascript.js": true } }); const Dactyl = Module("dactyl", { init: function () { diff --git a/common/content/io.js b/common/content/io.js index 6660ecac..efab3aa7 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -345,13 +345,15 @@ lookup: dactyl.helpInitialized = false; } catch (e) { - if (isString(e)) - e = { message: e }; - let err = new Error(); - for (let [k, v] in Iterator(e)) - err[k] = v; - err.echoerr = <>{file.path}:{e.lineNumber}: {e}; - throw err; + if (e.fileName) + try { + e.fileName = e.fileName.replace(/^(chrome|resource):.*? -> /, ""); + if (e.fileName == uri.spec) + e.fileName = filename; + e.echoerr = <>{e.fileName}:{e.lineNumber}: {e} + } + catch (e) {} + throw e; } } else if (/\.css$/.test(filename)) diff --git a/common/content/javascript.js b/common/content/javascript.js index c5c6cd19..c0d30380 100644 --- a/common/content/javascript.js +++ b/common/content/javascript.js @@ -358,8 +358,6 @@ const JavaScript = Module("javascript", { } let args = { - completer: compl, - anchored: true, filter: last == null ? key : string, last: last, prefix: last != null ? key : "" @@ -369,39 +367,42 @@ const JavaScript = Module("javascript", { // TODO: Make this a generic completion helper function. for (let [, obj] in Iterator(objects)) this.context.fork(obj[1], this._top.offset, this, this._fill, - update({}, args, { + update({ obj: obj[0], - name: obj[1] - })); + name: obj[1], + anchored: true, + completer: compl + }, args)); if (orig) return; for (let [, obj] in Iterator(objects)) this.context.fork(obj[1] + "/prototypes", this._top.offset, this, this._fill, - update({}, args, { + update({ obj: obj[0], name: obj[1] + " (prototypes)", + anchored: true, completer: function (a, b) compl(a, b, true) - })); + }, args)); for (let [, obj] in Iterator(objects)) this.context.fork(obj[1] + "/substrings", this._top.offset, this, this._fill, - update({}, args, { + update({ obj: obj[0], name: obj[1] + " (substrings)", anchored: false, completer: compl - })); + }, args)); for (let [, obj] in Iterator(objects)) this.context.fork(obj[1] + "/prototypes/substrings", this._top.offset, this, this._fill, - update({}, args, { + update({ obj: obj[0], name: obj[1] + " (prototype substrings)", anchored: false, completer: function (a, b) compl(a, b, true) - })); + }, args)); }, _getKey: function () { diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 33635641..9b360ba8 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -10,6 +10,11 @@ const Cr = Components.results; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +try { + var ctypes; + Components.utils.import("resource://gre/modules/ctypes.jsm"); +} +catch (e) {} let objproto = Object.prototype; let hasOwnProperty = objproto.hasOwnProperty; @@ -149,7 +154,7 @@ defineModule("base", { exports: [ "Cc", "Ci", "Class", "Cr", "Cu", "Module", "Object", "Runnable", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "array", - "call", "callable", "curry", "debuggerProperties", "defineModule", + "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", "keys", "memoize", "properties", "requiresMainThread", "set", "update", "values" @@ -356,6 +361,20 @@ set.remove = function (set, key) { * @returns {Generator} */ function iter(obj) { + if (ctypes && obj instanceof ctypes.CData) { + while (obj.constructor instanceof ctypes.PointerType) + obj = obj.contents; + if (obj.constructor instanceof ctypes.ArrayType) + return array.iterItems(obj); + if (obj.constructor instanceof ctypes.StructType) + return (function () { + for (let prop in values(obj.constructor.fields)) + let ([name, type] = Iterator(prop).next()) { + yield [name, obj[name]]; + } + })(); + obj = {}; + } if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList])) return array.iterItems(obj); if (obj instanceof Ci.nsIDOMNamedNodeMap) From 301a8e53779f08274ee46355316982a499d85fe8 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 7 Oct 2010 23:35:53 -0400 Subject: [PATCH 04/16] Just use with (window) in userEval. Adding it to the prototype chain causes too much trouble. --HG-- branch : mode-refactoring --- common/content/dactyl-overlay.js | 3 ++- common/content/dactyl.js | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/content/dactyl-overlay.js b/common/content/dactyl-overlay.js index 93b054b1..676a403d 100644 --- a/common/content/dactyl-overlay.js +++ b/common/content/dactyl-overlay.js @@ -18,7 +18,8 @@ __proto__: jsmodules, get content() window.content, jsmodules: jsmodules, - newContext: newContext + newContext: newContext, + window: window }; modules.modules = modules; diff --git a/common/content/dactyl.js b/common/content/dactyl.js index fe375905..d089724d 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -294,7 +294,7 @@ const Dactyl = Module("dactyl", { if (!context) context = userContext; - return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber); + return Cu.evalInSandbox("with (window) {" + str + "}", context, "1.8", fileName, lineNumber); }, /** @@ -1876,7 +1876,6 @@ const Dactyl = Module("dactyl", { }; }, load: function () { - jsmodules.__proto__ = window; dactyl.triggerObserver("load"); dactyl.log("All modules loaded", 3); From ce10a9af13ec6951dfe643df2c49cc22bce874e1 Mon Sep 17 00:00:00 2001 From: Doug Kearns Date: Sat, 9 Oct 2010 02:05:00 +1100 Subject: [PATCH 05/16] Fix 'c' and 's' VISUAL mode mappings. --HG-- branch : mode-refactoring --- common/content/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/content/editor.js b/common/content/editor.js index 02140809..0244d5f9 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -696,7 +696,7 @@ const Editor = Module("editor", { function (count) { dactyl.assert(editor.isTextArea); editor.executeCommand("cmd_cut"); - modes.replace(modes.VISUAL); + modes.replace(modes.INSERT, modes.TEXTAREA); }); mappings.add([modes.VISUAL], From c3f977cf74c8d510613cb671fee25e230d741b14 Mon Sep 17 00:00:00 2001 From: Doug Kearns Date: Sat, 9 Oct 2010 04:18:59 +1100 Subject: [PATCH 06/16] Prevent endless TEXTAREA->INSERT->TEXTAREA mode stacking. --HG-- branch : mode-refactoring --- common/content/editor.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/content/editor.js b/common/content/editor.js index 0244d5f9..32052505 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -611,7 +611,12 @@ const Editor = Module("editor", { mappings.add([modes.INSERT], [""], "Edit text field in Vi mode", - function () { modes.push(modes.TEXTAREA); }); + function () { + if (!editor.isTextArea) + modes.push(modes.TEXTAREA); + else + dactyl.beep(); + }); mappings.add([modes.INSERT], ["", ""], "Expand insert mode abbreviation", From 0856343b4078cfd1f368e286f3099b38410e27cb Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 8 Oct 2010 13:42:16 -0400 Subject: [PATCH 07/16] Rename TEXTAREA mode to TEXT EDIT mode, and move it from :imap to :tmap. --HG-- branch : mode-refactoring --- common/content/editor.js | 82 ++++++++++++++++----------------- common/content/events.js | 12 ++--- common/content/finder.js | 4 +- common/content/modes.js | 2 +- common/locale/en-US/index.xml | 2 +- common/locale/en-US/insert.xml | 6 +-- common/locale/en-US/map.xml | 13 ++++++ common/locale/en-US/options.xml | 2 +- common/modules/util.jsm | 2 +- 9 files changed, 69 insertions(+), 56 deletions(-) diff --git a/common/content/editor.js b/common/content/editor.js index 32052505..94347886 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -19,7 +19,7 @@ const Editor = Module("editor", { }, get isCaret() modes.getStack(1).main === modes.CARET, - get isTextArea() modes.getStack(1).main === modes.TEXTAREA, + get isTextEdit() modes.getStack(1).main === modes.TEXT_EDIT, line: function () { let line = 1; @@ -189,16 +189,16 @@ const Editor = Module("editor", { switch (cmd) { case "d": this.executeCommand("cmd_delete", 1); - modes.pop(modes.TEXTAREA); + modes.pop(modes.TEXT_EDIT); break; case "c": this.executeCommand("cmd_delete", 1); - modes.pop(modes.TEXTAREA); + modes.pop(modes.TEXT_EDIT); modes.push(modes.INSERT); break; case "y": this.executeCommand("cmd_copy", 1); - modes.pop(modes.TEXTAREA); + modes.pop(modes.TEXT_EDIT); break; default: @@ -436,8 +436,8 @@ const Editor = Module("editor", { mappings: function () { var myModes = [modes.INSERT, modes.COMMAND_LINE]; - // add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXTAREA mode - function addMovementMap(keys, hasCount, caretModeMethod, caretModeArg, textareaCommand, visualTextareaCommand) { + // add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXT_EDIT mode + function addMovementMap(keys, hasCount, caretModeMethod, caretModeArg, textEditCommand, visualTextEditCommand) { let extraInfo = {}; if (hasCount) extraInfo.count = true; @@ -483,11 +483,11 @@ const Editor = Module("editor", { let controller = buffer.selectionController; while (count-- && modes.main == modes.VISUAL) { - if (editor.isTextArea) { - if (typeof visualTextareaCommand == "function") - visualTextareaCommand(); + if (editor.isTextEdit) { + if (typeof visualTextEditCommand == "function") + visualTextEditCommand(); else - editor.executeCommand(visualTextareaCommand); + editor.executeCommand(visualTextEditCommand); } else caretExecute(true, true); @@ -495,19 +495,19 @@ const Editor = Module("editor", { }, extraInfo); - mappings.add([modes.TEXTAREA], keys, "", + mappings.add([modes.TEXT_EDIT], keys, "", function (count) { if (typeof count != "number" || count < 1) count = 1; - editor.executeCommand(textareaCommand, count); + editor.executeCommand(textEditCommand, count); }, extraInfo); } - // add mappings for commands like i,a,s,c,etc. in TEXTAREA mode + // add mappings for commands like i,a,s,c,etc. in TEXT_EDIT mode function addBeginInsertModeMap(keys, commands) { - mappings.add([modes.TEXTAREA], keys, "", + mappings.add([modes.TEXT_EDIT], keys, "", function (count) { commands.forEach(function (cmd) editor.executeCommand(cmd, 1)); @@ -516,7 +516,7 @@ const Editor = Module("editor", { } function addMotionMap(key) { - mappings.add([modes.TEXTAREA], [key], + mappings.add([modes.TEXT_EDIT], [key], "Motion command", function (motion, count) { editor.executeCommandWithMotion(key, motion, count); }, { count: true, motion: true }); @@ -532,7 +532,7 @@ const Editor = Module("editor", { editor.executeCommand("cmd_selectLineNext"); } - // KEYS COUNT CARET TEXTAREA VISUAL_TEXTAREA + // KEYS COUNT CARET TEXT_EDIT VISUAL_TEXT_EDIT addMovementMap(["k", ""], true, "lineMove", false, "cmd_linePrevious", selectPreviousLine); addMovementMap(["j", "", ""], true, "lineMove", true, "cmd_lineNext", selectNextLine); addMovementMap(["h", "", ""], true, "characterMove", false, "cmd_charPrevious", "cmd_selectCharPrevious"); @@ -612,8 +612,8 @@ const Editor = Module("editor", { mappings.add([modes.INSERT], [""], "Edit text field in Vi mode", function () { - if (!editor.isTextArea) - modes.push(modes.TEXTAREA); + if (!editor.isTextEdit) + modes.push(modes.TEXT_EDIT); else dactyl.beep(); }); @@ -631,8 +631,8 @@ const Editor = Module("editor", { ["", ""], "Expand insert mode abbreviation", function () { editor.expandAbbreviation(modes.INSERT); }); - // textarea mode - mappings.add([modes.TEXTAREA], + // text edit mode + mappings.add([modes.TEXT_EDIT], ["u"], "Undo", function (count) { editor.executeCommand("cmd_undo", count); @@ -640,7 +640,7 @@ const Editor = Module("editor", { }, { count: true }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], [""], "Redo", function (count) { editor.executeCommand("cmd_redo", count); @@ -648,11 +648,11 @@ const Editor = Module("editor", { }, { count: true }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["D"], "Delete the characters under the cursor until the end of the line", function () { editor.executeCommand("cmd_deleteToEndOfLine"); }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["o"], "Open line below current", function (count) { editor.executeCommand("cmd_endLine", 1); @@ -660,7 +660,7 @@ const Editor = Module("editor", { events.feedkeys(""); }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["O"], "Open line above current", function (count) { editor.executeCommand("cmd_beginLine", 1); @@ -669,18 +669,18 @@ const Editor = Module("editor", { editor.executeCommand("cmd_linePrevious", 1); }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["X"], "Delete character to the left", function (count) { editor.executeCommand("cmd_deleteCharBackward", count); }, { count: true }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["x"], "Delete character to the right", function (count) { editor.executeCommand("cmd_deleteCharForward", count); }, { count: true }); // visual mode - mappings.add([modes.CARET, modes.TEXTAREA], + mappings.add([modes.CARET, modes.TEXT_EDIT], ["v"], "Start visual mode", function (count) { modes.push(modes.VISUAL); }); @@ -688,7 +688,7 @@ const Editor = Module("editor", { ["v"], "End visual mode", function (count) { events.onEscape(); }); - mappings.add([modes.TEXTAREA], + mappings.add([modes.TEXT_EDIT], ["V"], "Start visual line mode", function (count) { modes.push(modes.VISUAL, modes.LINE); @@ -699,15 +699,15 @@ const Editor = Module("editor", { mappings.add([modes.VISUAL], ["c", "s"], "Change selected text", function (count) { - dactyl.assert(editor.isTextArea); + dactyl.assert(editor.isTextEdit); editor.executeCommand("cmd_cut"); - modes.replace(modes.INSERT, modes.TEXTAREA); + modes.replace(modes.INSERT, modes.TEXT_EDIT); }); mappings.add([modes.VISUAL], ["d"], "Delete selected text", function (count) { - if (editor.isTextArea) { + if (editor.isTextEdit) { editor.executeCommand("cmd_cut"); modes.pop(); } @@ -718,7 +718,7 @@ const Editor = Module("editor", { mappings.add([modes.VISUAL], ["y"], "Yank selected text", function (count) { - if (editor.isTextArea) { + if (editor.isTextEdit) { editor.executeCommand("cmd_copy"); modes.pop(); } @@ -726,7 +726,7 @@ const Editor = Module("editor", { dactyl.clipboardWrite(buffer.getCurrentWord(), true); }); - mappings.add([modes.VISUAL, modes.TEXTAREA], + mappings.add([modes.VISUAL, modes.TEXT_EDIT], ["p"], "Paste clipboard contents", function (count) { dactyl.assert(!editor.isCaret); @@ -734,11 +734,11 @@ const Editor = Module("editor", { count = 1; while (count--) editor.executeCommand("cmd_paste"); - modes.pop(modes.TEXTAREA); + modes.pop(modes.TEXT_EDIT); }); // finding characters - mappings.add([modes.TEXTAREA, modes.VISUAL], + mappings.add([modes.TEXT_EDIT, modes.VISUAL], ["f"], "Move to a character on the current line after the cursor", function (count, arg) { let pos = editor.findCharForward(arg, count); @@ -747,7 +747,7 @@ const Editor = Module("editor", { }, { arg: true, count: true }); - mappings.add([modes.TEXTAREA, modes.VISUAL], + mappings.add([modes.TEXT_EDIT, modes.VISUAL], ["F"], "Move to a charater on the current line before the cursor", function (count, arg) { let pos = editor.findCharBackward(arg, count); @@ -756,7 +756,7 @@ const Editor = Module("editor", { }, { arg: true, count: true }); - mappings.add([modes.TEXTAREA, modes.VISUAL], + mappings.add([modes.TEXT_EDIT, modes.VISUAL], ["t"], "Move before a character on the current line", function (count, arg) { let pos = editor.findCharForward(arg, count); @@ -765,7 +765,7 @@ const Editor = Module("editor", { }, { arg: true, count: true }); - mappings.add([modes.TEXTAREA, modes.VISUAL], + mappings.add([modes.TEXT_EDIT, modes.VISUAL], ["T"], "Move before a character on the current line, backwards", function (count, arg) { let pos = editor.findCharBackward(arg, count); @@ -774,8 +774,8 @@ const Editor = Module("editor", { }, { arg: true, count: true }); - // textarea and visual mode - mappings.add([modes.TEXTAREA, modes.VISUAL], + // text edit and visual mode + mappings.add([modes.TEXT_EDIT, modes.VISUAL], ["~"], "Switch case of the character under the cursor and move the cursor to the right", function (count) { if (modes.main == modes.VISUAL) @@ -794,7 +794,7 @@ const Editor = Module("editor", { text.substring(pos + 1); editor.moveToPosition(pos + 1, true, false); } - modes.pop(modes.TEXTAREA); + modes.pop(modes.TEXT_EDIT); }, { count: true }); }, diff --git a/common/content/events.js b/common/content/events.js index 05cdd7bf..c69723d8 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -633,7 +633,7 @@ const Events = Module("events", { case modes.INSERT: case modes.PASS_THROUGH: case modes.QUOTE: - case modes.TEXTAREA: + case modes.TEXT_EDIT: case modes.VISUAL: modes.pop(); break; @@ -708,7 +708,7 @@ const Events = Module("events", { if (options["insertmode"]) modes.set(modes.INSERT); else { - modes.set(modes.TEXTAREA); + modes.set(modes.TEXT_EDIT); if (elem.selectionEnd - elem.selectionStart > 0) modes.push(modes.VISUAL); } @@ -937,7 +937,7 @@ const Events = Module("events", { 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.TEXTAREA))) + (mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXT_EDIT))) events.feedkeys(this._input.buffer, { noremap: true, skipmap: true }); this._input.buffer = ""; @@ -947,7 +947,7 @@ 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.TEXTAREA); + stop = (mode == modes.TEXT_EDIT); if (mode == modes.COMMAND_LINE) { if (!(modes.extended & modes.INPUT_MULTILINE)) @@ -1015,7 +1015,7 @@ const Events = Module("events", { modes.pop(); // Really not ideal. } else if (couldCopy) { - if (modes.main == modes.TEXTAREA && !options["insertmode"]) + if (modes.main == modes.TEXT_EDIT && !options["insertmode"]) modes.push(modes.VISUAL); else if (dactyl.mode == modes.CARET) modes.push(modes.VISUAL); @@ -1091,7 +1091,7 @@ const Events = Module("events", { [""], "Advance keyboard focus", function () { document.commandDispatcher.advanceFocus(); }); - mappings.add([modes.NORMAL, modes.PLAYER, modes.VISUAL, modes.CARET, modes.INSERT, modes.TEXTAREA], + mappings.add([modes.NORMAL, modes.PLAYER, modes.VISUAL, modes.CARET, modes.INSERT, modes.TEXT_EDIT], [""], "Rewind keyboard focus", function () { document.commandDispatcher.rewindFocus(); }); diff --git a/common/content/finder.js b/common/content/finder.js index d3182b7e..c92ac86d 100644 --- a/common/content/finder.js +++ b/common/content/finder.js @@ -189,14 +189,14 @@ const RangeFinder = Module("rangefinder", { ["N"], "Find previous", function () { rangefinder.findAgain(true); }); - mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"], + mappings.add(myModes.concat([modes.CARET, modes.TEXT_EDIT]), ["*"], "Find word under cursor", function () { rangefinder.find(buffer.getCurrentWord(), false); rangefinder.findAgain(); }); - mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"], + mappings.add(myModes.concat([modes.CARET, modes.TEXT_EDIT]), ["#"], "Find word under cursor backwards", function () { rangefinder.find(buffer.getCurrentWord(), true); diff --git a/common/content/modes.js b/common/content/modes.js index 53b4e8b6..32521510 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -58,7 +58,7 @@ const Modes = Module("modes", { this.pref = false; } }); - this.addMode("TEXTAREA", { char: "i", ownsFocus: true }); + this.addMode("TEXT_EDIT", { char: "t", ownsFocus: true }); this.addMode("EMBED", { input: true, ownsFocus: true }); this.addMode("PASS_THROUGH"); this.addMode("QUOTE", { diff --git a/common/locale/en-US/index.xml b/common/locale/en-US/index.xml index c533535f..965fd886 100644 --- a/common/locale/en-US/index.xml +++ b/common/locale/en-US/index.xml @@ -18,7 +18,7 @@ This file contains a list of all available commands, mappings and options.
i
Start Insert mode in text areas when insertmode is not set
Launch the external editor
-
Enter Textarea mode
+
Enter TextEdit mode
Expand an Insert-mode abbreviation
diff --git a/common/locale/en-US/insert.xml b/common/locale/en-US/insert.xml index 7a7e1d7a..3ec7d65a 100644 --- a/common/locale/en-US/insert.xml +++ b/common/locale/en-US/insert.xml @@ -20,8 +20,8 @@

- i_i - i_i + t_i + t_i

Starts Insert mode in text areas when insertmode is not set.

@@ -42,7 +42,7 @@ <C-t>

- Enter Textarea mode. This is useful for quick editing of text fields + Enter TextEdit mode. This is useful for quick editing of text fields with basic Vim-keys support. See also insertmode.

diff --git a/common/locale/en-US/map.xml b/common/locale/en-US/map.xml index a1c8a1b9..3382fbec 100644 --- a/common/locale/en-US/map.xml +++ b/common/locale/en-US/map.xml @@ -52,6 +52,7 @@
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
+
t
TextEdit mode: When editing text fields in Vim-like NORMAL mode
c
Command-line mode: When typing into the &dactyl.appName; command line
@@ -82,6 +83,8 @@ :vmap lhs rhs :im :imap :imap lhs rhs + :tm :tmap + :tmap lhs rhs :cm :cmap :cmap lhs rhs @@ -126,6 +129,8 @@ :vnoremap lhs rhs :ino :inoremap :inoremap lhs rhs + :tno :tnoremap + :tnoremap lhs rhs :cno :cnoremap :cnoremap lhs rhs @@ -150,6 +155,8 @@ :vunmap lhs rhs :iu :iunmap :iunmap lhs rhs + :tu :tunmap + :tunmap lhs rhs :cu :cunmap :cunmap lhs rhs @@ -166,6 +173,8 @@ :vmapclear :imapc :imapclear :imapclear + :tmapc :tmapclear + :tmapclear :cmapc :cmapclear :cmapclear @@ -180,6 +189,7 @@ :nmap :vmap :imap + :tmap :cmap

List all mappings for the applicable mode(s).

@@ -195,6 +205,8 @@ :vmap lhs :imap_l :imap lhs + :tmap_l + :tmap lhs :cmap_l :cmap lhs @@ -224,6 +236,7 @@ :nmap :nnoremap :nunmap :nmapclear – Normal mode :vmap :vnoremap :vunmap :vmapclear – Visual mode :imap :inoremap :iunmap :imapclear – Insert mode +:tmap :tnoremap :tunmap :tmapclear – TextArea mode :cmap :cnoremap :cunmap :cmapclear – Command-line mode diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index e1f6a0f5..5cddc7c7 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -833,7 +833,7 @@

- Textarea mode can be entered with from Insert mode. + TextEdit mode can be entered with from Insert mode.

diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 14a43a59..3e8e7ffc 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -74,7 +74,7 @@ const Util = Module("Util", { if (services.get("threadManager").isMainThread) callback.call(self); else - mainThread.dispatch(Runnable(self, callback), mainThread.DISPATCH_NORMAL); + mainThread.dispatch(Runnable(self, callback, Array.slice(arguments, 2)), mainThread.DISPATCH_NORMAL); }, /** From 16f67b0d7dd9cae7f5b7ffd1cf25695ae51dafa0 Mon Sep 17 00:00:00 2001 From: Doug Kearns Date: Sat, 9 Oct 2010 05:49:10 +1100 Subject: [PATCH 08/16] Fix some outdated TEXTAREA mode references. --HG-- branch : mode-refactoring --- common/locale/en-US/map.xml | 2 +- teledactyl/content/config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/locale/en-US/map.xml b/common/locale/en-US/map.xml index 3382fbec..de3a9952 100644 --- a/common/locale/en-US/map.xml +++ b/common/locale/en-US/map.xml @@ -236,7 +236,7 @@ :nmap :nnoremap :nunmap :nmapclear – Normal mode :vmap :vnoremap :vunmap :vmapclear – Visual mode :imap :inoremap :iunmap :imapclear – Insert mode -:tmap :tnoremap :tunmap :tmapclear – TextArea mode +:tmap :tnoremap :tunmap :tmapclear – Text Edit mode :cmap :cnoremap :cunmap :cmapclear – Command-line mode diff --git a/teledactyl/content/config.js b/teledactyl/content/config.js index d2183827..1711774c 100644 --- a/teledactyl/content/config.js +++ b/teledactyl/content/config.js @@ -62,7 +62,7 @@ const Config = Module("config", ConfigBase, { // we switch to -- MESSAGE -- mode for Teledactyl when the main HTML widget gets focus if (win && win.document instanceof HTMLDocument || dactyl.focus instanceof HTMLAnchorElement) { if (config.isComposeWindow) - modes.set(modes.INSERT, modes.TEXTAREA); + modes.set(modes.INSERT, modes.TEXT_EDIT); else if (dactyl.mode != modes.MESSAGE) dactyl.mode = modes.MESSAGE; } From 9295b36aad1aee730b766d83da9fd1bc9c5cff1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Fri, 8 Oct 2010 21:34:01 +0200 Subject: [PATCH 09/16] Fix the help index to match docs updated during the recent TextEdit frenzy. --HG-- branch : mode-refactoring --- common/locale/en-US/index.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/locale/en-US/index.xml b/common/locale/en-US/index.xml index 965fd886..fb267897 100644 --- a/common/locale/en-US/index.xml +++ b/common/locale/en-US/index.xml @@ -16,7 +16,7 @@ This file contains a list of all available commands, mappings and options.

Insert mode

-
i
Start Insert mode in text areas when insertmode is not set
+
i
Start Insert mode in text areas when insertmode is not set
Launch the external editor
Enter TextEdit mode
Expand an Insert-mode abbreviation
From c05ad658954dfeec4da3e37a7cd0f8a768125490 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 8 Oct 2010 15:37:30 -0400 Subject: [PATCH 10/16] Remove spurious modes.reset() in RangeFinder#onSubmit. Fixes focusing links on submit. --HG-- branch : mode-refactoring extra : rebase_source : 494ba7809803499905f135c4410f5e87af4417d6 --- common/content/dactyl-overlay.js | 2 +- common/content/finder.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/common/content/dactyl-overlay.js b/common/content/dactyl-overlay.js index f764ef9d..676a403d 100644 --- a/common/content/dactyl-overlay.js +++ b/common/content/dactyl-overlay.js @@ -13,7 +13,7 @@ sandbox.__proto__ = proto || modules; return sandbox; } - const jsmodules = { dump: function dump_(arg) window.dump("dactyl: " + arg + "\n") }; + const jsmodules = {}; const modules = { __proto__: jsmodules, get content() window.content, diff --git a/common/content/finder.js b/common/content/finder.js index c92ac86d..0ef0dea0 100644 --- a/common/content/finder.js +++ b/common/content/finder.js @@ -114,8 +114,6 @@ const RangeFinder = Module("rangefinder", { if (options["hlsearch"]) this.highlight(); this.rangeFind.focus(); - - modes.reset(); }, // Called when the search is canceled - for example if someone presses From 42d79460e2ce970f693b1b6824e185c8fb43a2fb Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 8 Oct 2010 20:49:54 -0400 Subject: [PATCH 11/16] Change the timing of mode-change callbacks slightly. Fix some message display bugs. --HG-- branch : mode-refactoring --- common/content/commandline.js | 3 +++ common/content/events.js | 6 ------ common/content/modes.js | 39 ++++++++++++++++------------------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/common/content/commandline.js b/common/content/commandline.js index c2ddf9bd..fb4a8cd7 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -440,6 +440,8 @@ const CommandLine = Module("commandline", { * @param {number} extendedMode */ open: function open(prompt, cmd, extendedMode) { + this.widgets.message = null; + modes.push(modes.COMMAND_LINE, this.currentExtendedMode, { leave: function (params) { if (params.pop) @@ -556,6 +558,7 @@ const CommandLine = Module("commandline", { let doc = this.widgets.multilineOutput.contentDocument; let win = this.widgets.multilineOutput.contentWindow; + this.widgets.message = null; if (!this.commandVisible) this.hide(); diff --git a/common/content/events.js b/common/content/events.js index c69723d8..eca59980 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -1020,12 +1020,6 @@ const Events = Module("events", { else if (dactyl.mode == modes.CARET) modes.push(modes.VISUAL); } - // XXX: disabled, as i think automatically starting visual caret mode does more harm than help - // else - // { - // if (!couldCopy && modes.extended & modes.CARET) - // dactyl.mode = modes.CARET; - // } } }, { editableInputs: set(["date", "datetime", "datetime-local", "email", "file", diff --git a/common/content/modes.js b/common/content/modes.js index 32521510..ec78fca5 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -175,7 +175,8 @@ const Modes = Module("modes", { let msg = null; if (options["showmode"]) msg = this._getModeMessage(); - commandline.widgets.mode = msg || null; + if (loaded.commandline) + commandline.widgets.mode = msg || null; }, // add/remove always work on the this._extended mode only @@ -199,8 +200,21 @@ const Modes = Module("modes", { if (!stack && mainMode != null && this._modeStack.length > 1) this.reset(); + let oldMain = this._main, oldExtended = this._extended; + + if (typeof extendedMode === "number") + this._extended = extendedMode; + if (typeof mainMode === "number") { + this._main = mainMode; + if (!extendedMode) + this._extended = this.NONE; + } + + if (stack && stack.pop && stack.pop.params.leave) + stack.pop.params.leave(stack, this.topOfStack); + let push = mainMode != null && !(stack && stack.pop) && - Modes.StackElem(mainMode, extendedMode || this.NONE, params, {}); + Modes.StackElem(this._main, this._extended, params, {}); if (push && this.topOfStack) { if (this.topOfStack.params.leave) this.topOfStack.params.leave({ push: push }, push); @@ -212,18 +226,6 @@ const Modes = Module("modes", { } } - let silent = this._main === mainMode && this._extended === extendedMode; - // if a this._main mode is set, the this._extended is always cleared - let oldMain = this._main, oldExtended = this._extended; - - if (typeof extendedMode === "number") - this._extended = extendedMode; - if (typeof mainMode === "number") { - this._main = mainMode; - if (!extendedMode) - this._extended = this.NONE; - } - let prev = stack && stack.pop || this.topOfStack; if (push) this._modeStack.push(push); @@ -232,9 +234,7 @@ const Modes = Module("modes", { prev); dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack); - - if (!silent) - this.show(); + this.show(); }, push: function (mainMode, extendedMode, params) { @@ -244,9 +244,6 @@ const Modes = Module("modes", { pop: function (mode) { while (this._modeStack.length > 1 && this.main != mode) { let a = this._modeStack.pop(); - if (a.params.leave) - a.params.leave({ pop: a }, this.topOfStack); - this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a }); for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved)) @@ -325,7 +322,7 @@ const Modes = Module("modes", { }, { options: function () { options.observePref("accessibility.browsewithcaret", function (value) { - if (!value && modes.topOfStack.main === modes.CARET) + if (!value && modes.main === modes.CARET) modes.pop(); if (value && modes.main === modes.NORMAL) modes.push(modes.CARET); From a682373e27f5ff366a1dd59f261f88c22b605cfd Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sat, 9 Oct 2010 02:26:12 -0400 Subject: [PATCH 12/16] Replace spurious modes.replace call that Doug, er, warned be about before I committed it. --HG-- branch : mode-refactoring --- common/content/editor.js | 2 +- common/content/modes.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/common/content/editor.js b/common/content/editor.js index 94347886..b737a93a 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -701,7 +701,7 @@ const Editor = Module("editor", { function (count) { dactyl.assert(editor.isTextEdit); editor.executeCommand("cmd_cut"); - modes.replace(modes.INSERT, modes.TEXT_EDIT); + modes.push(modes.INSERT); }); mappings.add([modes.VISUAL], diff --git a/common/content/modes.js b/common/content/modes.js index 141c6afa..39e4f836 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -265,8 +265,10 @@ const Modes = Module("modes", { }, replace: function (mode, oldMode) { - // TODO: This should really be done in one step. - this.pop(oldMode); + while (oldMode && this._modeStack.length > 1 && this.main != oldMode) + this.pop(); + + this.set(mode, null, null, { push: this.topOfStack, pop: this._modeStack.pop() }); this.push(mode); }, From 29448adaa6f9271a6f3ae85ce9d2ada4917528fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Sat, 9 Oct 2010 12:24:43 +0200 Subject: [PATCH 13/16] Fix a typo. --HG-- branch : mode-refactoring --- common/content/dactyl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 14a6d9e1..d79f9089 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1519,7 +1519,7 @@ const Dactyl = Module("dactyl", { perm: "disable" }, { - name: "extu[update]", + name: "extu[pdate]", description: "Update an extension", actions: updateAddons, filter: function ({ item }) !item.userDisabled, From 08ed30f07a6a0a0511b49b3417c388875107a59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= Date: Sat, 9 Oct 2010 12:26:20 +0200 Subject: [PATCH 14/16] Fix :extupdate documentation markup. --HG-- branch : mode-refactoring --- common/locale/en-US/gui.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/locale/en-US/gui.xml b/common/locale/en-US/gui.xml index 81d32a5a..6b638a01 100644 --- a/common/locale/en-US/gui.xml +++ b/common/locale/en-US/gui.xml @@ -154,7 +154,8 @@ :extu :extupdate - :extupdate! extension + :extupdate extension + :extupdate!

Update an extension. When ! is given, update all From 0d3c9bd613f2789ce041ff5195c5beb7bd5ad2eb Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sat, 9 Oct 2010 12:56:05 -0400 Subject: [PATCH 15/16] Fix now spurious :autocmd examples. --HG-- branch : mode-refactoring --- common/content/buffer.js | 4 +++- common/locale/en-US/autocommands.xml | 10 ++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/content/buffer.js b/common/content/buffer.js index ef322e21..747c33b8 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -271,7 +271,9 @@ const Buffer = Module("buffer", { statusline.updateUrl(); statusline.updateProgress(); - autocommands.trigger("LocationChange", { url: buffer.URL }); + util.timeout(function () { + autocommands.trigger("LocationChange", { url: buffer.URL }); + }); // if this is not delayed we get the position of the old buffer util.timeout(function () { diff --git a/common/locale/en-US/autocommands.xml b/common/locale/en-US/autocommands.xml index e2a06c3b..3ba97b52 100644 --- a/common/locale/en-US/autocommands.xml +++ b/common/locale/en-US/autocommands.xml @@ -90,18 +90,16 @@

Enable passthrough mode on all Google sites:

-:autocmd LocationChange .* js modes.passAllKeys = /google\.com/.test(buffer.URL) +:autocmd LocationChange google\.com -js modes.push(modes.PASS_THROUGH)

Enable passthrough mode on some Google sites:

-:autocmd LocationChange .* js modes.passAllKeys = /(www|mail)\.google\.com/.test(buffer.URL) +:autocmd LocationChange (www|mail)\.google\.com -js modes.push(modes.PASS_THROUGH)

Set the filetype to mail when editing email at Gmail:

- -:autocmd LocationChange !'mail\.google\.com' :set editor=gvim -f -:autocmd LocationChange 'mail\.google\.com' :set editor=gvim -f -c 'set ft=mail' - +:autocmd LocationChange !mail\.google\.com :set editor=gvim -f +:autocmd LocationChange mail\.google\.com :set editor=gvim -f -c 'set ft=mail' From d7ff35c565742460cb0b40cfe1f02a7019fd3c05 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sun, 10 Oct 2010 15:19:27 -0400 Subject: [PATCH 16/16] Get rid of a lot of special casing in the event loops. Merge default. --HG-- branch : mode-refactoring --- common/content/commandline.js | 36 +++++------- common/content/events.js | 100 +++++++++++--------------------- common/content/help.xsl | 4 +- common/content/hints.js | 70 +++++++++++----------- common/locale/en-US/cmdline.xml | 6 +- common/locale/en-US/map.xml | 6 +- common/locale/en-US/marks.xml | 6 +- common/locale/en-US/options.xml | 26 ++++----- common/locale/en-US/pattern.xml | 4 +- common/locale/en-US/styling.xml | 9 ++- common/locale/en-US/tabs.xml | 2 +- common/locale/en-US/various.xml | 9 ++- pentadactyl/NEWS | 10 +++- 13 files changed, 129 insertions(+), 159 deletions(-) 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.