diff --git a/common/content/commandline.js b/common/content/commandline.js index 74f20bf8..be39ccef 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -303,24 +303,29 @@ var CommandMode = Class("CommandMode", { this.keepCommand = userContext.hidden_option_command_afterimage; }, - open: function (command) { - this.command = command; + get command() this.widgets.command[1], + set command(val) this.widgets.command = val, + get prompt() this.widgets.prompt, + set prompt(val) this.widgets.prompt = val, + + open: function (command) { dactyl.assert(isinstance(this.mode, modes.COMMAND_LINE), "Not opening command line in non-command-line mode."); commandline.clearMessage(); - modes.push(this.mode, null, this.closure); + modes.push(this.mode, this.extendedMode, this.closure); this.widgets.active.commandline.collapsed = false; this.widgets.prompt = this.prompt; this.widgets.command = command || ""; + this.input = this.widgets.active.command.inputField; if (this.historyKey) - this.history = CommandLine.History(commandline.widgets.active.command.inputField, this.historyKey, this); + this.history = CommandLine.History(this.input, this.historyKey, this); if (this.complete) - this.completions = CommandLine.Completions(commandline.widgets.active.command.inputField, this); + this.completions = CommandLine.Completions(this.input, this); if (this.completions && command && commandline.commandSession === this) this.completions.autocompleteTimer.flush(true); @@ -346,6 +351,7 @@ var CommandMode = Class("CommandMode", { leave: function (stack) { if (!stack.push) { commandline.commandSession = null; + this.input.dactylKeyPress = undefined; if (this.completions) this.completions.cleanup(); @@ -1010,6 +1016,7 @@ var CommandLine = Module("commandline", { this.tabTimer.reset(); this.autocompleteTimer.reset(); this.itemList.visible = false; + this.input.dactylKeyPress = undefined; }, ignoredCount: 0, diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 933de1b9..c3eee956 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -401,7 +401,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { if (fileName == null) if (info && info.file[0] !== "[") ({ file: fileName, line: lineNumber, context: ctxt }) = info; - else try { + + if (!context) + context = _userContext || ctxt; + + if (isinstance(context, ["Sandbox"])) + return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber); + else + try { if (!context) context = userContext || ctxt; @@ -424,10 +431,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { delete context[EVAL_RESULT]; delete context[EVAL_STRING]; } - - if (!context) - context = _userContext || ctxt; - return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber); }, /** @@ -1749,21 +1752,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }); }); - commands.add(["javas[cript]", "js"], - "Evaluate a JavaScript string", - function (args) { - if (args.bang) // open JavaScript console - dactyl.open("chrome://global/content/console.xul", - { from: "javascript" }); - else - dactyl.userEval(args[0]); - }, { - bang: true, - completer: function (context) completion.javascript(context), - hereDoc: true, - literal: 0 - }); - commands.add(["loadplugins", "lpl"], "Load all plugins immediately", function (args) { diff --git a/common/content/editor.js b/common/content/editor.js index 41811221..60b36e40 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -31,6 +31,8 @@ var Editor = Module("editor", { } let elem = dactyl.focusedElement; + if (elem.inputField) + elem = elem.inputField; if (elem.setSelectionRange) { let text = dactyl.clipboardRead(clipboard); @@ -49,7 +51,8 @@ var Editor = Module("editor", { let value = elem.value.substring(0, start) + text + elem.value.substring(end); elem.value = value; - Editor.getEditor(elem).rootElement.firstChild.textContent = value; + if (/^(search|text)$/.test(elem.type)) + Editor.getEditor(elem).rootElement.firstChild.textContent = value; elem.selectionStart = Math.min(start + (toStart ? 0 : text.length), elem.value.length); elem.selectionEnd = elem.selectionStart; diff --git a/common/content/events.js b/common/content/events.js index adb34768..32630d88 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -217,7 +217,12 @@ var KeyProcessor = Class("KeyProcessor", { else if (map.motion) return KeyArgProcessor(this, map, true, "motion"); - return this.execute(map, { count: this.count, command: this.command, events: this.events, allEvents: this.allEvents }); + return this.execute(map, { + allEvents: this.allEvents, + command: this.command, + count: this.count, + events: this.events + }); } if (!this.waiting) @@ -347,7 +352,6 @@ var Events = Module("events", { this._fullscreen = window.fullScreen; this._lastFocus = null; - this._currentMacro = ""; this._macroKeys = []; this._lastMacro = ""; @@ -426,8 +430,8 @@ var Events = Module("events", { * @param {boolean} capture When true, listen during the capture * phase, otherwise during the bubbling phase. */ - get addSessionListener() this.builtin.closure.listen, get listen() this.builtin.closure.listen, + addSessionListener: deprecated("events.listen", { get: function addSessionListener() this.listen }), /** * Wraps an event listener to ensure that errors are reported. @@ -462,34 +466,33 @@ var Events = Module("events", { * * @param {string} macro The name for the macro. */ - startRecording: function (macro) { - // TODO: ignore this like Vim? - dactyl.assert(/[a-zA-Z0-9]/.test(macro), + _recording: null, + get recording() this._recording, + + set recording(macro) { + dactyl.assert(macro == null || /[a-zA-Z0-9]/.test(macro), "E354: Invalid register name: '" + macro + "'"); - modes.recording = true; + modes.recording = !!macro; if (/[A-Z]/.test(macro)) { // uppercase (append) - this._currentMacro = macro.toLowerCase(); - this._macroKeys = events.fromString((this._macros.get(this._currentMacro) || { keys: "" }).keys, true) + macro = macro.toLowerCase(); + this._macroKeys = events.fromString((this._macros.get(macro) || { keys: "" }).keys, true) .map(events.closure.toString); } - else { - this._currentMacro = macro; + else if (macro) { this._macroKeys = []; } - }, + else { + this._macros.set(this.recording, { + keys: this._macroKeys.join(""), + timeRecorded: Date.now() + }); - /** Terminates the recording of the current key event macro. */ - finishRecording: function () { - modes.recording = false; - this._macros.set(this._currentMacro, { - keys: this._macroKeys.join(""), - timeRecorded: Date.now() - }); - - dactyl.log("Recorded " + this._currentMacro + ": " + this._macroKeys.join(""), 9); - dactyl.echomsg("Recorded macro '" + this._currentMacro + "'"); + dactyl.log("Recorded " + this.recording + ": " + this._macroKeys.join(""), 9); + dactyl.echomsg("Recorded macro '" + this.recording + "'"); + } + this._recording = macro || null; }, /** @@ -1457,7 +1460,7 @@ var Events = Module("events", { ["q", ""], "Record a key sequence into a macro", function ({ arg }) { events._macroKeys.pop(); - events[modes.recording ? "finishRecording" : "startRecording"](arg); + events.recording = arg; }, { get arg() !modes.recording }); diff --git a/common/content/hints.js b/common/content/hints.js index bd27ef2b..a473e6c9 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -10,6 +10,8 @@ /** @instance hints */ var HintSession = Class("HintSession", CommandMode, { + get extendedMode() modes.HINTS, + init: function init(mode, opts) { init.supercall(this); @@ -465,7 +467,7 @@ var HintSession = Class("HintSession", CommandMode, { } this.timeout(function () { - if (isinstance(modes.main, modes.HINTS) && !this.continue) + if ((modes.extended & modes.HINTS) && !this.continue) modes.pop(); commandline.lastEcho = null; // Hack. dactyl.trapErrors("action", this.hintMode, diff --git a/common/modules/config.jsm b/common/modules/config.jsm index bbc8426d..dab1db23 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -447,6 +447,11 @@ var ConfigBase = Class("ConfigBase", { EditorBlink1;;* background: yellow !important; EditorBlink2;;* + REPL overflow: auto; max-height: 40em; + REPL-R;;;Question + REPL-E white-space: pre-wrap; + REPL-P white-space: pre-wrap; margin-bottom: 1em; + Indicator color: blue; width: 1.5em; text-align: center; Filter font-weight: bold; diff --git a/common/modules/highlight.jsm b/common/modules/highlight.jsm index 782b9ca5..5d26af32 100644 --- a/common/modules/highlight.jsm +++ b/common/modules/highlight.jsm @@ -213,7 +213,7 @@ var Highlights = Module("Highlight", { */ selector: function (class_) let (self = this) - class_.replace(/(^|[>\s])([A-Z]\w+)\b/g, + class_.replace(/(^|[>\s])([A-Z][\w-]+)\b/g, function (m, n1, hl) n1 + (self.highlight[hl] && self.highlight[hl].class != class_ ? self.highlight[hl].selector : "[dactyl|highlight~=" + hl + "]")), diff --git a/common/modules/javascript.jsm b/common/modules/javascript.jsm index e172d000..8a2f1ad6 100644 --- a/common/modules/javascript.jsm +++ b/common/modules/javascript.jsm @@ -108,6 +108,7 @@ var JavaScript = Module("javascript", { return cache[key]; } catch (e) { + util.reportError(e); this.context.message = "Error: " + e; return null; } @@ -306,6 +307,7 @@ var JavaScript = Module("javascript", { this._cacheKey = null; let obj = [[this.cache.evalContext, "Local Variables"], + [this.replContext, "REPL Variables"], [this.modules.userContext, "Global Variables"], [this.modules, "modules"], [this.window, "window"]]; // Default objects; @@ -673,6 +675,7 @@ var JavaScript = Module("javascript", { }, { init: function init(dactyl, modules, window) { init.superapply(this, arguments); + modules.JavaScript = Class("JavaScript", JavaScript, { modules: modules, window: window }); }, completion: function (dactyl, modules, window) { const { completion } = modules; @@ -681,6 +684,142 @@ var JavaScript = Module("javascript", { javascriptCompleter: JavaScript // Backwards compatibility }); }, + modes: function initModes(dactyl, modules, window) { + const { modes } = modules; + + modes.addMode("REPL", { + description: "JavaScript Read Eval Print Loop", + bases: [modes.COMMAND_LINE] + }); + }, + commandline: function initCommandLine(dactyl, modules, window) { + const { modes } = modules; + + var REPL = Class("REPL", { + init: function init(context) { + this.context = context; + this.results = []; + }, + + addOutput: function addOutput(js) { + default xml namespace = XHTML; + this.count++; + + try { + var result = dactyl.userEval(js, this.context); + var xml = util.objectToString(result, true); + } + catch (e) { + util.reportError(e); + result = e; + + if (e.fileName) + e = util.fixURI(e.fileName) + ":" + e.lineNumber + ": " + e; + xml = {e}; + } + + let prompt = "js" + this.count; + Class.replaceProperty(this.context, prompt, result); + + XML.ignoreWhitespace = XML.prettyPrinting = false; + let nodes = {}; + this.rootNode.appendChild( + util.xmlToDom( +
{prompt}> {js}
+
{xml}
+
.elements(), this.document, nodes)); + + this.rootNode.scrollTop = nodes.e.getBoundingClientRect().top + - this.rootNode.getBoundingClientRect().top; + }, + + count: 0, + + message: Class.memoize(function () { + default xml namespace = XHTML; + util.xmlToDom(
, + this.document, this); + + return this.rootNode; + }) + }); + + modules.CommandREPLMode = Class("CommandREPLMode", modules.CommandMode, { + open: function open() { + let self = this; + + this.context = modules.newContext(modules.userContext, true); + this.js = modules.JavaScript(); + this.js.replContext = this.context; + this.js.newContext = function newContext() modules.newContext(self.context, true); + this.repl = REPL(this.context); + + this.updatePrompt(); + + modules.mow.echo(this.repl); + + open.superapply(this, arguments); + }, + + complete: function complete(context) { + context.fork("js", 0, this.js, "complete"); + }, + + historyKey: "javascript", + + mode: modes.REPL, + + accept: function accept() { + dactyl.trapErrors(function () { this.repl.addOutput(this.command) }, this); + + this.updatePrompt(); + this.completions.cleanup(); + this.history.save(); + + modules.mow.resize(); + }, + + leave: function leave(params) { + leave.superapply(this, arguments); + if (!params.push) + modes.delay(function () { modes.pop(); }); + }, + + updatePrompt: function updatePrompt() { + this.command = ""; + this.prompt = ["REPL-R", "js" + (this.repl.count + 1) + "> "]; + } + }); + }, + commands: function initCommands(dactyl, modules, window) { + const { commands } = modules; + + commands.add(["javas[cript]", "js"], + "Evaluate a JavaScript string", + function (args) { + if (args.bang) // open JavaScript console + dactyl.open("chrome://global/content/console.xul", + { from: "javascript" }); + else if (args[0]) + dactyl.userEval(args[0]); + else { + modules.commandline; + modules.CommandREPLMode().open(); + } + }, { + bang: true, + completer: function (context) modules.completion.javascript(context), + hereDoc: true, + literal: 0 + }); + }, + mappings: function initMappings(dactyl, modules, window) { + const { mappings, modes } = modules; + + mappings.add([modes.REPL], [""], + "Accept the current input", + function ({ self }) { self.accept(); }); + }, options: function (dactyl, modules, window) { modules.options.add(["jsdebugger", "jsd"], "Enable the JavaScript debugger service for use in JavaScript completion", diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm index 6bf393c0..b64f0af0 100644 --- a/common/modules/overlay.jsm +++ b/common/modules/overlay.jsm @@ -314,7 +314,7 @@ var Overlay = Module("Overlay", { defineModule.loadLog.push("Loaded in " + (Date.now() - start) + "ms"); - modules.events.addSessionListener(window, "unload", function onUnload() { + modules.events.listen(window, "unload", function onUnload() { window.removeEventListener("unload", onUnload.wrapped, false); for (let prop in properties(modules)) { let desc = Object.getOwnPropertyDescriptor(modules, prop); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index e8b02d41..32fe8af7 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -986,7 +986,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), obj = Object.prototype.toString.call(obj); } obj = template.highlightFilter(util.clip(obj, 150), "\n", !color ? function () "^J" : function () ^J); - let string = <>{obj}::
; + let string = <>{obj}:: ; let keys = []; @@ -1016,7 +1016,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), i = parseInt(i); else if (/^[A-Z_]+$/.test(i)) i = ""; - keys.push([i, <>{key}{noVal ? "" : <>: {value}}
]); + keys.push([i, <>{key}{noVal ? "" : <>: {value}} ]); } } catch (e) {} @@ -1027,7 +1027,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), return String.localeCompare(a[0], b[0]); } string += template.map(keys.sort(compare), function (f) f[1]); - return color ? string : [s for each (s in string)].join(""); + return color ?
{string}
: [s for each (s in string)].join(""); }, observers: { diff --git a/pentadactyl/content/config.js b/pentadactyl/content/config.js index 1ec62711..66d97443 100644 --- a/pentadactyl/content/config.js +++ b/pentadactyl/content/config.js @@ -336,7 +336,7 @@ var Config = Module("config", ConfigBase, { completion.location); }, events: function (dactyl, modules, window) { - modules.events.addSessionListener(window, "SidebarFocused", function (event) { + modules.events.listen(window, "SidebarFocused", function (event) { modules.config.lastSidebar = window.document.getElementById("sidebar-box") .getAttribute("sidebarcommand"); }, false);