3 Interpreter: JavaScript Interactive Interpreter
6 InterpreterManager
= function () {
10 InterpreterManager
.prototype.initialize
= function () {
11 connect("interpreter_text", "onkeyup", this.keyUp
);
12 connect("interpreter_textarea", "onkeydown", this.areaKeyDown
);
13 connect("interpreter_form", "onsubmit", this.submit
);
14 getElement("interpreter_text").focus();
19 this.currentHistory
= "";
21 this.blockingOn
= null;
22 if (typeof(this.doEval
) == "undefined") {
23 // detect broken eval, warn at some point if a namespace ever gets used
24 this.doEval
= function () {
25 return eval(arguments
[0]);
28 window
.help
= this.help
;
29 this.help
.NAME
= 'type help(func) for help on a MochiKit function';
32 InterpreterManager
.prototype.banner
= function () {
33 var _ua
= window
.navigator
.userAgent
;
34 var ua
= _ua
.replace(/^Mozilla\/.*?\(.*?\)\s*/
, "");
37 ua
= _ua
.replace(/^Mozilla\/4\.0 \(compatible
; MS(IE
.*?);.*$/, "$1");
39 appendChildNodes("interpreter_output",
40 SPAN({"class": "banner"},
41 "MochiKit v" + MochiKit
.Base
.VERSION
+ " [" + ua
+ "]",
43 "Type your expression in the input box below and press return, or see the notes below for more information.",
50 InterpreterManager
.prototype.submit
= function (event
) {
51 if (this.blockingOn
) {
53 this.blockingOn
.cancel();
57 this.blockingOn
= null;
64 InterpreterManager
.prototype.help
= function (fn
) {
68 if (typeof(fn
) != "string" || fn
.length
== 0) {
69 writeln("help(func) on any MochiKit function for help");
72 var comps
= fn
.split('.');
73 var base
= comps
.splice(0, 2);
74 var shortfn
= comps
.join('.');
75 var url
= '../../doc/html/' + base
.join('/') + '.html';
76 var d
= doXHR(url
, {mimeType
: 'text/xml'});
77 d
.addCallback(function (req
) {
78 var els
= getElementsByTagAndClassName(
79 'a', 'mochidef', req
.responseXML
);
80 var match
= '#fn-' + shortfn
.toLowerCase();
81 for (var i
= 0; i
< els
.length
; i
++) {
84 var idx
= href
.indexOf('#');
85 if (idx
!= -1 && href
.substring(idx
) == match
) {
86 writeln(A({href
: url
+ match
, target
: '_blank'},
91 writeln('documentation for ' + fn
+ ' not found');
97 InterpreterManager
.prototype.doScroll
= function () {
98 var p
= getElement("interpreter_output").lastChild
;
99 if (typeof(p
) == "undefined" || p
== null) {
102 var area
= getElement("interpreter_area");
103 if (area
.offsetHeight
> area
.scrollHeight
) {
106 area
.scrollTop
= area
.scrollHeight
;
110 InterpreterManager
.prototype.moveHistory
= function (dir
) {
111 // totally bogus value
112 if (dir
== 0 || this.history
.length
== 0) {
115 var elem
= getElement("interpreter_text");
116 if (this.historyPos
== -1) {
117 this.currentHistory
= elem
.value
;
121 this.historyPos
= this.history
.length
- 1;
122 elem
.value
= this.history
[this.historyPos
];
125 if (this.historyPos
== 0 && dir
< 0) {
128 if (this.historyPos
== this.history
.length
- 1 && dir
> 0) {
129 this.historyPos
= -1;
130 elem
.value
= this.currentHistory
;
133 this.historyPos
+= dir
;
134 elem
.value
= this.history
[this.historyPos
];
137 InterpreterManager
.prototype.runMultipleLines
= function (text
) {
138 var lines
= rstrip(text
).replace("\r\n", "\n").split(/\n/);
139 appendChildNodes("interpreter_output",
140 SPAN({"class": "code"}, ">>> ", izip(lines
, imap(BR
, cycle([null]))))
145 InterpreterManager
.prototype.areaKeyDown
= function (e
) {
146 var mod
= e
.modifier();
147 var hasMod
= mod
.alt
|| mod
.ctrl
|| mod
.meta
;
148 if (e
.key().string
== 'KEY_ENTER' && hasMod
) {
149 var elem
= getElement("interpreter_textarea");
150 var text
= elem
.value
;
152 this.runMultipleLines(text
);
157 InterpreterManager
.prototype.keyUp
= function (e
) {
159 // if any meta key is pressed, don't handle the signal
160 if (e
.modifier().any
) {
163 switch (key
.string
) {
164 case 'KEY_ARROW_UP': this.moveHistory(-1); break;
165 case 'KEY_ARROW_DOWN': this.moveHistory(1); break;
171 InterpreterManager
.prototype.blockOn
= function (d
) {
172 var node
= SPAN({"class": "banner"}, "blocking on " + repr(d
) + "...");
174 appendChildNodes("interpreter_output", node
);
176 d
.addBoth(function (res
) {
178 this.blockingOn
= null;
179 if (res
instanceof CancelledError
) {
180 window
.writeln(SPAN({"class": "error"}, repr(d
) + " cancelled!"));
185 d
.addCallbacks(this.showResult
, this.showError
);
188 InterpreterManager
.prototype.showError
= function (e
) {
189 if (typeof(e
) != "object") {
192 appendChildNodes("interpreter_output",
193 SPAN({"class": "error"}, "Error:"),
194 TABLE({"class": "error"},
195 THEAD({"class": "invisible"}, TD({"colspan": 2})),
196 TFOOT({"class": "invisible"}, TD({"colspan": 2})),
200 if (typeof(v
) == "function") {
203 if (typeof(v
) == "object") {
207 TD({"class": "error"}, kv
[0]),
208 TD({"class": "data"}, v
)
219 evalWith
: function () {
220 with (arguments
[1] || window
) { return eval(arguments
[0]); };
222 evalCall
: function () {
223 return eval
.call(arguments
[1] || window
, arguments
[0]);
225 choose
: function () {
226 var ns
= {__test__
: this};
229 if (this.evalWith("return __test__", ns
) === this) {
230 return this.evalWith
;
236 if (this.evalCall("return __test__", ns
) === this) {
237 return this.evalCall
;
246 InterpreterManager
.prototype.doEval
= EvalFunctions
.choose();
248 InterpreterManager
.prototype.doSubmit
= function () {
249 var elem
= getElement("interpreter_text");
250 var code
= elem
.value
;
252 var isContinuation
= false;
253 if (code
.length
>= 2 && code
.lastIndexOf("//") == code
.length
- 2) {
254 isContinuation
= true;
255 code
= code
.substr(0, code
.length
- 2);
257 appendChildNodes("interpreter_output",
258 SPAN({"class": "code"}, ">>> ", code
),
261 this.lines
.push(code
);
262 this.history
.push(code
);
263 this.historyPos
= -1;
264 this.currentHistory
= "";
265 if (isContinuation
) {
268 var allCode
= this.lines
.join("\n");
270 this.runCode(allCode
);
274 InterpreterManager
.prototype.runCode
= function (allCode
) {
277 res
= this.doEval(allCode
);
279 // mozilla shows some keys more than once!
283 this.showResult(res
);
286 InterpreterManager
.prototype.showResult
= function (res
) {
287 if (typeof(res
) != "undefined") {
290 if (typeof(res
) != "undefined") {
291 appendChildNodes("interpreter_output",
292 SPAN({"class": "data"}, repr(res
)),
299 window
.writeln
= function () {
300 appendChildNodes("interpreter_output",
301 SPAN({"class": "data"}, arguments
),
304 interpreterManager
.doScroll();
307 window
.clear
= function () {
308 replaceChildNodes("interpreter_output");
309 getElement("interpreter_area").scrollTop
= 0;
312 window
.blockOn
= function (d
) {
313 if (!(d
instanceof Deferred
)) {
314 throw new TypeError(repr(d
) + " is not a Deferred!");
316 interpreterManager
.blockOn(d
);
319 window
.dir
= function (o
) {
320 // Python muscle memory!
321 return sorted(keys(o
));
324 window
.inspect
= function (o
) {
326 if ((typeof(o
) != "function" && typeof(o
) != "object") || o
== null) {
327 window
.writeln(repr(o
));
330 var pairs
= items(o
);
331 if (pairs
.length
== 0) {
332 window
.writeln(repr(o
));
335 window
.writeln(TABLE({"border": "1"},
336 THEAD({"class": "invisible"}, TR(null, TD(), TD())),
337 TFOOT({"class": "invisible"}, TR(null, TD(), TD())),
341 var click
= function () {
343 window
.inspect(kv
[1]);
345 interpreterManager
.showError(e
);
350 TD(null, A({href
: "#", onclick
: click
}, kv
[0])),
351 TD(null, repr(kv
[1]))
360 interpreterManager
= new InterpreterManager();
361 addLoadEvent(interpreterManager
.initialize
);
363 // rewrite the view-source links
364 addLoadEvent(function () {
365 var elems
= getElementsByTagAndClassName("A", "view-source");
366 var page
= "interpreter/";
367 for (var i
= 0; i
< elems
.length
; i
++) {
369 var href
= elem
.href
.split(/\//).pop();
370 elem
.target
= "_blank";
371 elem
.href
= "../view-source/view-source.html#" + page
+ href
;