1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-22 14:27:58 +01:00

Preliminary REPL mode.

This commit is contained in:
Kris Maglione
2011-02-17 03:59:28 -05:00
parent caefc819bc
commit bd71135b08
11 changed files with 203 additions and 56 deletions

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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-macro>"], "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 });

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 + "]")),

View File

@@ -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 = <span highlight="ErrorMsg">{e}</span>;
}
let prompt = "js" + this.count;
Class.replaceProperty(this.context, prompt, result);
XML.ignoreWhitespace = XML.prettyPrinting = false;
let nodes = {};
this.rootNode.appendChild(
util.xmlToDom(<e4x>
<div highlight="REPL-E" key="e"><span highlight="REPL-R">{prompt}></span> {js}</div>
<div highlight="REPL-P" key="p">{xml}</div>
</e4x>.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(<div highlight="REPL" key="rootNode"/>,
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], ["<Return>"],
"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",

View File

@@ -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);

View File

@@ -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 () <span highlight="NonText">^J</span>);
let string = <><span highlight="Title Object">{obj}</span>::<br/>&#x0a;</>;
let string = <><span highlight="Title Object">{obj}</span>::&#x0a;</>;
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}</>}<br/>&#x0a;</>]);
keys.push([i, <>{key}{noVal ? "" : <>: {value}</>}&#x0a;</>]);
}
}
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 ? <div style="white-space: pre-wrap;">{string}</div> : [s for each (s in string)].join("");
},
observers: {

View File

@@ -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);