├── CREDITS
├── Makefile
├── README.md
├── bootstrap.js
├── chrome.manifest
├── chrome
├── icon.png
├── jsterm.js
├── jsterm.xul
└── vendor
│ ├── coffee-script.js
│ ├── livescript.js
│ └── prelude-ls.js
├── install.rdf
├── jsterm.xpi
├── locale
└── en-US
│ ├── jsterm.dtd
│ └── jsterm.properties
└── skin
├── jsterm.css
└── orion.css
/CREDITS:
--------------------------------------------------------------------------------
1 | * Authors: @paulrouget @paulmillr
2 | * Icon: http://soundforge.deviantart.com/
3 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | FILES = chrome/ \
2 | locale/ \
3 | bootstrap.js \
4 | chrome.manifest \
5 | install.rdf
6 |
7 | all:
8 | rm -f jsterm.xpi && zip -r jsterm.xpi $(FILES)
9 | wget --post-file=$(PWD)/jsterm.xpi http://localhost:8888/
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Terminal for Firefox
2 |
3 | **Warning:** the addon is being integrated into Firefox natively. It is no longer supported.
4 |
5 | This Firefox addon contains full-featured console that supports
6 | JS, [CoffeeScript](http://coffeescript.org) and [LiveScript](http://livescript.net).
7 |
8 | Info and screencast are available at http://paulrouget.com/e/jsterm/.
9 | To switch between languages, use `:js`, `:coffee` & `:livescript`.
10 | The language you choose will be saved for the next console session.
11 |
12 | Screenshot:
13 |
14 | 
15 |
16 | ## Installation
17 |
18 | Drag’n’drop .xpi on your Firefox.
19 |
20 | If you prefer stable versions, you can
21 | [install the addon from addons.mozilla.org](https://addons.mozilla.org/en-US/firefox/addon/javascript-terminal/).
22 |
--------------------------------------------------------------------------------
/bootstrap.js:
--------------------------------------------------------------------------------
1 | const Cu = Components.utils;
2 | const Cc = Components.classes;
3 | const Ci = Components.interfaces;
4 |
5 | Cu.import("resource://gre/modules/XPCOMUtils.jsm");
6 | Cu.import("resource://gre/modules/Services.jsm");
7 | Cu.import("resource:///modules/devtools/gDevTools.jsm");
8 |
9 | /* Depending on the version of Firefox, promise module can have different path */
10 | try { Cu.import("resource://gre/modules/commonjs/promise/core.js"); } catch(e) {}
11 | try { Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); } catch(e) {}
12 |
13 | XPCOMUtils.defineLazyGetter(this, "osString",
14 | function() Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
15 |
16 | const jstermProps = "chrome://jsterm/locale/jsterm.properties";
17 | let jstermStrings = Services.strings.createBundle(jstermProps);
18 |
19 | let jstermDefinition = {
20 | id: "jsterm",
21 | key: jstermStrings.GetStringFromName("JSTerm.commandkey"),
22 | ordinal: 0,
23 | modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
24 | icon: "chrome://browser/skin/devtools/tool-webconsole.png",
25 | url: "chrome://jsterm/content/jsterm.xul",
26 | label: jstermStrings.GetStringFromName("JSTerm.label"),
27 | tooltip: jstermStrings.GetStringFromName("JSTerm.tooltip"),
28 |
29 | isTargetSupported: function(target) {
30 | return target.isLocalTab;
31 | },
32 |
33 | build: function(iframeWindow, toolbox) {
34 | iframeWindow.JSTermUI.init(JSTermGlobalHistory, toolbox);
35 | return Promise.resolve(iframeWindow.JSTermUI);
36 | }
37 | };
38 |
39 | function startup() {
40 | gDevTools.registerTool(jstermDefinition);
41 | }
42 |
43 | function shutdown() {
44 | gDevTools.unregisterTool(jstermDefinition);
45 | }
46 |
47 | function install() {}
48 | function uninstall() {}
49 |
50 | let JSTermGlobalHistory = {
51 | _limit: 100, // Should be a pref
52 | _entries: [],
53 |
54 | _cut: function() {
55 | let newStart = this._entries.length - this._limit;
56 | if (newStart <= 0) return;
57 |
58 | this._entries = this._entries.slice(newStart);
59 |
60 | for (let cursor of this._cursors) {
61 | if (cursor) {
62 | cursor.idx -= newStart;
63 | cursor.origin -= newStart;
64 | }
65 | }
66 | },
67 |
68 | add: function(aEntry) {
69 | if (!aEntry) {
70 | return;
71 | }
72 | if (this._entries.length) {
73 | let lastEntry = this._entries[this._entries.length - 1];
74 | if (lastEntry == aEntry)
75 | return;
76 | }
77 | this._entries.push(aEntry);
78 |
79 | if (this._entries.length > this._limit) {
80 | this._cut();
81 | }
82 | },
83 |
84 | initFromPref: function() {
85 | let history = [];
86 |
87 | // Try to load history from pref
88 | if (Services.prefs.prefHasUserValue("devtools.jsterm.history")) {
89 | try {
90 | history = JSON.parse(Services.prefs.getCharPref("devtools.jsterm.history"));
91 | } catch(e) {
92 | // User pref is malformated.
93 | Cu.reportError("Could not parse pref `devtools.jsterm.history`: " + e);
94 | }
95 | }
96 |
97 | if (Array.isArray(history)) {
98 | this._entries = history;
99 | } else {
100 | Cu.reportError("History (devtools.jsterm.history) is malformated.");
101 | this._entries = [];
102 | }
103 | },
104 |
105 | saveToPref: function() {
106 | Services.prefs.setCharPref("devtools.jsterm.history", JSON.stringify(this._entries));
107 | },
108 |
109 | _cursors: [],
110 | getCursor: function(aInitialValue) {
111 | let cursor = {idx: this._entries.length,
112 | origin: this._entries.length,
113 | initialEntry: aInitialValue};
114 | this._cursors.push(cursor);
115 | return cursor;
116 | },
117 |
118 | releaseCursor: function(cursor) {
119 | this._cursors[cursor.idx] = null;
120 | },
121 |
122 | getEntryForCursor: function(cursor) {
123 | if (cursor.idx < 0) {
124 | return "";
125 | } else if (cursor.idx < cursor.origin) {
126 | return this._entries[cursor.idx];
127 | } else {
128 | return cursor.initialEntry;
129 | }
130 | },
131 |
132 | canGoBack: function(cursor) {
133 | return (cursor.idx > 0)
134 | },
135 |
136 | canGoForward: function(cursor) {
137 | return (cursor.idx < cursor.origin);
138 | },
139 |
140 | goBack: function(cursor) {
141 | if (this.canGoBack(cursor)) {
142 | cursor.idx--;
143 | return true;
144 | } else {
145 | return false;
146 | }
147 | },
148 |
149 | goForward: function(cursor) {
150 | if (this.canGoForward(cursor)) {
151 | cursor.idx++;
152 | return true;
153 | } else {
154 | return false;
155 | }
156 | },
157 | }
158 | JSTermGlobalHistory.initFromPref();
159 |
--------------------------------------------------------------------------------
/chrome.manifest:
--------------------------------------------------------------------------------
1 | content jsterm chrome/
2 | locale jsterm en-US locale/en-US/
3 | skin jsterm classic/1.0 skin/
4 |
--------------------------------------------------------------------------------
/chrome/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/firefox-jsterm/cd6e9b17551aa98bf1714adc1d3a44745c62a3e4/chrome/icon.png
--------------------------------------------------------------------------------
/chrome/jsterm.js:
--------------------------------------------------------------------------------
1 | let Cu = Components.utils;
2 | let Ci = Components.interfaces;
3 | Cu.import("resource:///modules/source-editor.jsm");
4 | Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm");
5 | Cu.import("resource://gre/modules/Services.jsm");
6 | Cu.import("resource:///modules/devtools/VariablesView.jsm");
7 |
8 | /**
9 | * Todo
10 | * . keybindings for linux & windows
11 | * . Use jsm's
12 | * . delete listeners & map
13 | * . underline the current autocompletion item
14 | * . :connect (remote protocol)
15 | * . ctrl-r
16 | */
17 |
18 | const JSTERM_MARK = "orion.annotation.jstermobject";
19 |
20 | const compilers = {
21 | js: function(input) {
22 | return input;
23 | },
24 | coffee: function(input) {
25 | return CoffeeScript.compile(input, {bare: true}).trim();
26 | },
27 | livescript: function(input) {
28 | return LiveScript.compile(input, {bare: true}).trim();
29 | }
30 | };
31 |
32 | let serializeNode = function(node) {
33 | var tag = node.tagName.toLowerCase();
34 | var id = node.id ? '#' + node.id : '';
35 | return '<' + tag + id + '>';
36 | };
37 |
38 | let JSTermUI = {
39 | input: new SourceEditor(),
40 | output: new SourceEditor(),
41 | objects: new Map(),
42 | printQueue: "",
43 | printTimeout: null,
44 | logCompiledCode: false,
45 |
46 | close: function() {
47 | this.toolbox.destroy();
48 | },
49 |
50 | registerCommands: function() {
51 | this.commands = [
52 | {name: ":close", help: "close terminal",
53 | exec: this.close.bind(this)},
54 | {name: ":clear", help: "clear screen",
55 | exec: this.clear.bind(this)},
56 | {name: ":help", help: "show this help",
57 | exec: this.help.bind(this)},
58 | {name: ":js", help: "switch to JS language",
59 | exec: this.switchToLanguage.bind(this, 'js')},
60 | {name: ":coffee", help: "switch to CoffeeScript language",
61 | exec: this.switchToLanguage.bind(this, 'coffee')},
62 | {name: ":livescript", help: "switch to LiveScript language",
63 | exec: this.switchToLanguage.bind(this, 'livescript')},
64 | {name: ":logCompiled", help: "log compiled code for non-js languages",
65 | exec: this.logCompiled.bind(this)},
66 | {name: ":content", help: "switch to Content mode",
67 | exec: this.switchToContentMode.bind(this)},
68 | {name: ":chrome", help: "switch to Chrome mode",
69 | exec: this.switchToChromeMode.bind(this)},
70 | {name: ":toggleLightTheme", help: "Toggle the light (white) theme",
71 | exec: this.toggleLightTheme.bind(this)},
72 | {name: "ls", hidden: true, exec: this.ls.bind(this)},
73 | ];
74 | },
75 |
76 | get multiline() {
77 | return this.inputContainer.classList.contains("multiline");
78 | },
79 |
80 | set multiline(val) {
81 | if (val)
82 | this.inputContainer.classList.add("multiline");
83 | else
84 | this.inputContainer.classList.remove("multiline");
85 | },
86 |
87 | focus: function() {
88 | this.input.focus();
89 | },
90 |
91 | //init: function(aManager, aGlobalHistory, aBrowser, aContent, aChrome, aDefaultContent) {
92 | init: function(aGlobalHistory, aToolbox) {
93 | this.toolbox = aToolbox;
94 |
95 | this.content = this.toolbox.target.tab.linkedBrowser.contentWindow;
96 | this.chrome = this.toolbox.target.tab.ownerDocument.defaultView;
97 |
98 | this.version = "n/a";
99 | this.chrome.AddonManager.getAddonByID("jsterm@paulrouget.com", function(addon) {
100 | this.version = addon.version;
101 | }.bind(this));
102 |
103 | this.registerCommands();
104 |
105 | this.handleKeys = this.handleKeys.bind(this);
106 | this.handleClick = this.handleClick.bind(this);
107 | this.focus = this.focus.bind(this);
108 | this.container = document.querySelector("#editors-container");
109 |
110 | let defaultInputText = "";
111 | let defaultOutputText = "// type ':help' for help\n// Report bug here: https://github.com/paulrouget/firefox-jsterm/issues";
112 |
113 | this.history = new JSTermLocalHistory(aGlobalHistory);
114 |
115 | let outputContainer = document.querySelector("#output-container");
116 | this.inputContainer = document.querySelector("#input-container");
117 | this.output.init(outputContainer, {
118 | initialText: defaultOutputText,
119 | mode: SourceEditor.MODES.JAVASCRIPT,
120 | readOnly: true,
121 | theme: "chrome://jsterm/skin/orion.css",
122 | }, this.initOutput.bind(this));
123 |
124 | this.input.init(this.inputContainer, {
125 | initialText: defaultInputText,
126 | mode: SourceEditor.MODES.JAVASCRIPT,
127 | theme: "chrome://jsterm/skin/orion.css",
128 | }, this.initInput.bind(this));
129 |
130 | this.variableView = new VariablesView(document.querySelector("#variables"));
131 |
132 | let pref = "devtools.jsterm.language";
133 | if (Services.prefs.prefHasUserValue(pref)) {
134 | this.languageName = Services.prefs.getCharPref(pref);
135 | } else {
136 | this.languageName = 'js';
137 | }
138 | this.compile = compilers[this.languageName];
139 |
140 | try { // This might be too early. But still, we try.
141 | if (Services.prefs.getBoolPref("devtools.jsterm.lightTheme")) {
142 | this._setLightTheme();
143 | }
144 | } catch(e){}
145 | },
146 |
147 | switchToChromeMode: function() {
148 | let label = document.querySelector("#completion-candidates > label");
149 | this.sb = this.buildSandbox(this.chrome);
150 | this.print("// Switched to chrome mode.");
151 | if (this.completion) this.completion.destroy();
152 | this.completion = new JSCompletion(this.input, label, this.sb);
153 | this.inputContainer.classList.add("chrome");
154 | window.document.title = "JSTerm: (chrome) " + this.chrome.document.title;
155 | },
156 |
157 | switchToLanguage: function(language) {
158 | this.languageName = language;
159 | Services.prefs.setCharPref("devtools.jsterm.language", language);
160 | this.compile = compilers[language].bind(this);
161 |
162 | if (language == "livescript") {
163 | for (let key in prelude) {
164 | this.defineSandboxProp(key, prelude[key]);
165 | }
166 | }
167 | },
168 |
169 | logCompiled: function() {
170 | this.logCompiledCode = !this.logCompiledCode;
171 | },
172 |
173 | switchToContentMode: function() {
174 | let label = document.querySelector("#completion-candidates > label");
175 | let needMessage = !!this.sb;
176 | this.sb = this.buildSandbox(this.content);
177 | if (this.completion) this.completion.destroy();
178 | this.completion = new JSCompletion(this.input, label, this.sb);
179 |
180 | if (needMessage) {
181 | this.print("// Switched to content mode.");
182 | }
183 | this.inputContainer.classList.remove("chrome");
184 | window.document.title = "JSTerm: " + this.content.document.title;
185 | },
186 |
187 | buildSandbox: function(win) {
188 | let sb = Cu.Sandbox(win, {sandboxPrototype: win, wantXrays: false});
189 | this.target = win;
190 | sb.print = this.print.bind(this);
191 |
192 | this.defineSandboxProp('$', function(aSelector) {
193 | return win.document.querySelector(aSelector);
194 | }, sb);
195 |
196 | this.defineSandboxProp('$$', function(aSelector) {
197 | return win.document.querySelectorAll(aSelector);
198 | }, sb);
199 |
200 | if (this.languageName == "livescript") {
201 | for (let key in prelude) {
202 | this.defineSandboxProp(key, prelude[key], sb);
203 | }
204 | }
205 |
206 | return sb;
207 | },
208 |
209 | defineSandboxProp: function(name, prop, sandbox = this.sb) {
210 | if (hasOwnProperty.call(sandbox, name)) return;
211 | try {
212 | sandbox[name] = prop
213 | } catch(ex) {}
214 | },
215 |
216 | print: function(msg = "", startWith = "\n", isAnObject = false, object = null) {
217 | clearTimeout(this.printTimeout);
218 |
219 | if (isAnObject) {
220 | // let's do that synchronously, because we want to add a mark
221 | if (this.printQueue) {
222 | // flush
223 | this.output.setText(this.printQueue, this.output.getCharCount());
224 | this.printQueue = "";
225 | }
226 | this.output.setText(startWith + msg, this.output.getCharCount());
227 | let line = this.output.getLineCount() - 1;
228 | this.objects.set(line, object);
229 | this.markRange(line);
230 |
231 | } else {
232 | this.printQueue += startWith + msg;
233 |
234 | this.printTimeout = setTimeout(function printCommit() {
235 | this.output.setText(this.printQueue, this.output.getCharCount());
236 | this.printQueue = "";
237 | }.bind(this), 0);
238 | }
239 | },
240 |
241 | initOutput: function() {
242 | try {
243 | if (Services.prefs.getBoolPref("devtools.jsterm.lightTheme")) {
244 | this._setLightTheme();
245 | }
246 | } catch(e){}
247 |
248 | this.makeEditorFitContent(this.output);
249 | this.ensureInputIsAlwaysVisible(this.output);
250 | this.output._annotationStyler.addAnnotationType(JSTERM_MARK);
251 | this.output.editorElement.addEventListener("click", this.handleClick, true);
252 | this.output.editorElement.addEventListener("keyup", this.focus, true);
253 | },
254 |
255 | initInput: function() {
256 | try {
257 | if (Services.prefs.getBoolPref("devtools.jsterm.lightTheme")) {
258 | this._setLightTheme();
259 | }
260 | } catch(e){}
261 |
262 | this.switchToContentMode();
263 |
264 | this.makeEditorFitContent(this.input);
265 | this.ensureInputIsAlwaysVisible(this.input);
266 | this.input.editorElement.addEventListener("keydown", this.handleKeys, true);
267 |
268 | this.input.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, function() {
269 | this.multiline = this.isMultiline(this.input.getText());
270 | }.bind(this));
271 |
272 | this.input.editorElement.ownerDocument.defaultView.setTimeout(function() {
273 | this.input.focus();
274 | }.bind(this), 0);
275 | },
276 |
277 | makeEditorFitContent: function(editor) {
278 | let lineHeight = editor._view.getLineHeight();
279 | editor.previousLineCount = editor.getLineCount();
280 | this.setEditorSize(editor, Math.max(lineHeight * editor.previousLineCount, 1));
281 | editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, function() {
282 | let count = editor.getLineCount();
283 | if (count != editor.previousLineCount) {
284 | editor.previousLineCount = count;
285 | this.setEditorSize(editor, lineHeight * count);
286 | }
287 | }.bind(this));
288 | },
289 |
290 | setEditorSize: function(e, height) {
291 | let winHeight = e.editorElement.ownerDocument.defaultView.innerHeight;
292 | // We want to resize if the editor doesn't overflow on the Y axis.
293 | e.editorElement.style.minHeight =
294 | e.editorElement.style.maxHeight =
295 | e.editorElement.style.height =
296 | (e._view.getLineHeight() * e.getLineCount() +
297 | this.input.editorElement.scrollHeight <= winHeight
298 | ? (height) + "px"
299 | : "");
300 | },
301 |
302 | ensureInputIsAlwaysVisible: function(editor) {
303 | editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, function() {
304 | this.container.scrollTop = this.container.scrollTopMax;
305 | }.bind(this));
306 | },
307 |
308 | newEntry: function(rawCode) {
309 | if (this.evaluating) return;
310 | this.evaluating = true;
311 |
312 | this.history.stopBrowsing();
313 | this.history.add(rawCode);
314 |
315 | this.input.setText("");
316 | this.multiline = false;
317 |
318 | if (rawCode == "") {
319 | this.print();
320 | this.onceEntryResultPrinted();
321 | return;
322 | }
323 |
324 | for (let cmd of this.commands) {
325 | if (cmd.name == rawCode) {
326 | this.print(rawCode);
327 | cmd.exec();
328 | this.onceEntryResultPrinted();
329 | return;
330 | }
331 | }
332 |
333 | let code;
334 |
335 | try {
336 | code = this.compile(rawCode);
337 | } catch(ex) {
338 | this.dumpEntryResult('', ex.toString().slice(7), rawCode);
339 | this.onceEntryResultPrinted();
340 | return;
341 | }
342 |
343 | var output = this.languageName != 'js' && this.logCompiledCode ?
344 | rawCode + '\n\n/*' + code + '*/' : rawCode;
345 | this.print(output);
346 |
347 | let error, result;
348 | try {
349 | result = Cu.evalInSandbox(code, this.sb, "1.8", "JSTerm", 1);
350 | } catch (ex) {
351 | error = ex;
352 | }
353 |
354 | this.dumpEntryResult(result, error, rawCode);
355 | this.onceEntryResultPrinted();
356 | },
357 |
358 | onceEntryResultPrinted: function() {
359 | /* Ugly hack to scrollback */
360 | this.output.editorElement.contentDocument.querySelector("iframe")
361 | .contentDocument.querySelector(".view").scrollLeft = 0;
362 |
363 | /* Clear Selection if any */
364 | let cursor = this.output.getLineStart(this.output.getLineCount() - 1);
365 | this.output.setSelection(cursor, cursor);
366 |
367 | this.evaluating = false;
368 | },
369 |
370 | dumpEntryResult: function(result, error, code) {
371 | if (error) {
372 | error = error.toString();
373 | if (this.isMultiline(error) || this.isMultiline(code)) {
374 | this.print("/* error:\n" + error + "\n*/");
375 | } else {
376 | this.print(" // error: " + error, startWith = "");
377 | }
378 | return;
379 | }
380 |
381 | let maxLength = 80;
382 | let type = ({}).toString.call(result).slice(8, -1);
383 | let isAnObject = typeof result == "object";
384 | let elementClass = /^HTML\w+Element$/;
385 |
386 | let resultStr;
387 | if (result == null) {
388 | resultStr = "" + result;
389 | isAnObject = false;
390 | } else if (type == "String") {
391 | resultStr = "\"" + result + "\"";
392 | } else if (type == "NodeList") {
393 | let isEmpty = result.length == 0;
394 | let tagNames = [].slice.call(result).map(serializeNode);
395 | resultStr = "[" + tagNames.join(", ") + "]";
396 | } else if (elementClass.test(type)) {
397 | resultStr = serializeNode(result);
398 | } else if (isAnObject && 'length' in result) {
399 | let serialized = [].slice.call(result)
400 | .map(function(item) {
401 | let cls = toString.call(item).slice(8, -1);
402 | if (elementClass.test(cls)) {
403 | return serializeNode(item);
404 | } else {
405 | return item;
406 | }
407 | })
408 | .join(", ");
409 | resultStr = "[" + serialized + "]";
410 | } else {
411 | resultStr = result.toString();
412 | }
413 |
414 | if (code == resultStr) {
415 | return;
416 | }
417 |
418 | // TODO: Check for long output that looks shitty.
419 | // if (resultStr.length > maxLength) {
420 | // resultStr = resultStr.slice(0, maxLength) + ' ...';
421 | // }
422 |
423 | if (isAnObject) {
424 | resultStr += " [+]";
425 | }
426 |
427 | if (this.isMultiline(resultStr)) {
428 | if (type == "Function") {
429 | resultStr = "\n" + resultStr;
430 | } else {
431 | resultStr = "\n/*\n" + resultStr + "\n*/";
432 | }
433 | } else {
434 | if (this.isMultiline(code)) {
435 | resultStr = "\n// " + resultStr;
436 | } else {
437 | resultStr = " // " + resultStr;
438 | }
439 | }
440 |
441 | this.print(resultStr, startWith = "", isAnObject, isAnObject ? result : null);
442 | },
443 |
444 | isMultiline: function(text) {
445 | return text.indexOf("\n") > -1;
446 | },
447 |
448 | clear: function() {
449 | this.objects = new Map();
450 | this.output.setText("");
451 | this.hideObjInspector();
452 | },
453 |
454 | help: function() {
455 | let text = "/**";
456 | text += "\n * JSTerm (version " + this.version + ")";
457 | text += "\n * ";
458 | text += "\n * 'Return' to evaluate entry,";
459 | text += "\n * 'Tab' for autocompletion,";
460 | text += "\n * 'Ctrl-l' clear screen,";
461 | text += "\n * 'Ctrl-d' close term,";
462 | text += "\n * 'up/down' to browser history,";
463 | text += "\n * 'Shift+Return' to switch to multiline editing,";
464 | text += "\n * 'Shift+Return' to evaluate multiline entry,";
465 | text += "\n * ";
466 | text += "\n * Use 'print(aString)' to dump text in the terminal,";
467 | text += "\n * Click on [+] to inspect an object,";
468 | text += "\n * ";
469 | text += "\n * Commands:";
470 | for (let cmd of this.commands) {
471 | if (cmd.help) {
472 | text += "\n * " + cmd.name + " - " + cmd.help;
473 | }
474 | }
475 | text += "\n * ";
476 | text += "\n * Bugs? Suggestions? Questions? -> https://github.com/paulrouget/firefox-jsterm/issues";
477 | text += "\n */";
478 | this.print(text);
479 | },
480 |
481 | handleKeys: function(e) {
482 | let code = this.input.getText();
483 |
484 | if (e.keyCode != 38 && e.keyCode != 40) {
485 | this.history.stopBrowsing();
486 | }
487 |
488 | if (e.keyCode == 13 && e.shiftKey) {
489 | if (this.multiline) {
490 | e.stopPropagation();
491 | e.preventDefault();
492 | this.newEntry(code);
493 | } else {
494 | this.multiline = true;
495 | }
496 | }
497 |
498 | if (e.keyCode == 13 && !e.shiftKey) {
499 | if (this.multiline) {
500 | // Do nothing.
501 | } else {
502 | e.stopPropagation();
503 | e.preventDefault();
504 | this.newEntry(code);
505 | }
506 | }
507 |
508 | if (e.keyCode == 68 && e.ctrlKey) {
509 | e.stopPropagation();
510 | e.preventDefault();
511 | this.close();
512 | }
513 | if (e.keyCode == 76 && e.ctrlKey) {
514 | e.stopPropagation();
515 | e.preventDefault();
516 | this.clear();
517 | }
518 |
519 | if (e.keyCode == 38) {
520 | if (!this.history.isBrowsing() && this.multiline) {
521 | return;
522 | }
523 | e.stopPropagation();
524 | e.preventDefault();
525 | if (!this.history.isBrowsing() ) {
526 | this.history.startBrowsing(this.input.getText());
527 | }
528 | let entry = this.history.goBack();
529 | if (entry) {
530 | JSTermUI.input.setText(entry);
531 | JSTermUI.input.setCaretPosition(JSTermUI.input.getLineCount(), 1000);
532 | }
533 | }
534 | if (e.keyCode == 40) {
535 | if (this.history.isBrowsing()) {
536 | e.stopPropagation();
537 | e.preventDefault();
538 | let entry = this.history.goForward();
539 | JSTermUI.input.setText(entry);
540 | JSTermUI.input.setCaretPosition(JSTermUI.input.getLineCount(), 1000);
541 | }
542 | }
543 | },
544 |
545 | handleClick: function(e) {
546 | if (e.target.parentNode && e.target.parentNode.lineIndex) {
547 | let idx = e.target.parentNode.lineIndex;
548 | if (this.objects.has(idx)) {
549 | let obj = this.objects.get(idx);
550 | e.stopPropagation();
551 | this.inspect(obj);
552 | }
553 | }
554 | },
555 |
556 | markRange: function(line) {
557 | let annotation = {
558 | type: JSTERM_MARK,
559 | start: this.output.getLineStart(line),
560 | end: this.output.getLineEnd(line),
561 | title: "Object",
562 | lineStyle: {styleClass: "annotationLine object"},
563 | }
564 | this.output._annotationModel.addAnnotation(annotation);
565 | },
566 |
567 |
568 | destroy: function() {
569 | this.input.editorElement.removeEventListener("keydown", this.handleKeys, true);
570 | if (this.completion) this.completion.destroy();
571 | this.completion = null;
572 | this.treeview = null;
573 | this.input = null;
574 | this.output = null;
575 | this.objects = null;
576 | this.printQueue = null;
577 | this.printTimeout = null;
578 | this.compile = null;
579 | },
580 |
581 | inspect: function(obj) {
582 | let box = document.querySelector("#variables");
583 | box.hidden = false;
584 | this.variableView.rawObject = obj;
585 | this.focus();
586 | },
587 |
588 | hideObjInspector: function() {
589 | this.variableView.empty();
590 | let box = document.querySelector("#variables");
591 | box.hidden = true;
592 | },
593 |
594 | getContent: function() {
595 | return {
596 | input: this.input.getText(),
597 | output: this.output.getText(),
598 | };
599 | },
600 |
601 | ls: function() {
602 | this.print("// Did you just type \"ls\"? You know this is not a unix shell, right?");
603 | },
604 |
605 | toggleLightTheme: function() {
606 | let isLight = document.documentElement.classList.contains("light");
607 |
608 | Services.prefs.setBoolPref("devtools.jsterm.lightTheme", !isLight);
609 |
610 | if (isLight) {
611 | this._setDarkTheme();
612 | } else {
613 | this._setLightTheme();
614 | }
615 | },
616 |
617 | _setLightTheme: function() {
618 | document.documentElement.classList.add("light");
619 | let inputView = this.input.editorElement.contentDocument.querySelector("iframe")
620 | .contentDocument.querySelector(".view");
621 | inputView.classList.add("light");
622 | let outputView = this.output.editorElement.contentDocument.querySelector("iframe")
623 | .contentDocument.querySelector(".view");
624 | outputView.classList.add("light");
625 | },
626 |
627 | _setDarkTheme: function() {
628 | document.documentElement.classList.remove("light");
629 | let inputView = this.input.editorElement.contentDocument.querySelector("iframe")
630 | .contentDocument.querySelector(".view");
631 | inputView.classList.remove("light");
632 | let outputView = this.output.editorElement.contentDocument.querySelector("iframe")
633 | .contentDocument.querySelector(".view");
634 | outputView.classList.remove("light");
635 | },
636 | }
637 |
638 |
639 |
640 | /* Auto Completion */
641 |
642 | function JSCompletion(editor, candidatesWidget, sandbox) {
643 | this.editor = editor;
644 | this.candidatesWidget = candidatesWidget;
645 |
646 | this.handleKeys = this.handleKeys.bind(this);
647 |
648 | this.editor.editorElement.addEventListener("keydown", this.handleKeys, true);
649 |
650 | this.buildDictionnary();
651 |
652 | this.sb = sandbox;
653 | }
654 |
655 | JSCompletion.prototype = {
656 | buildDictionnary: function() {
657 | let JSKeywords = "break delete case do catch else class export continue finally const for debugger function default if import this in throw instanceof try let typeof new var return void super while switch with";
658 | this.dictionnary = JSKeywords.split(" ");
659 | for (let cmd of JSTermUI.commands) {
660 | if (!cmd.hidden) {
661 | this.dictionnary.push(cmd.name);
662 | }
663 | }
664 | },
665 | handleKeys: function(e) {
666 | if (e.keyCode == 9) {
667 | this.handleTab(e);
668 | } else {
669 | this.stopCompletion();
670 | }
671 | },
672 | handleTab: function(e) {
673 | if (this.isCompleting) {
674 | this.continueCompleting();
675 | e.stopPropagation();
676 | e.preventDefault();
677 | return;
678 | }
679 |
680 | // Can we complete?
681 | let caret = this.editor.getCaretPosition();
682 | if (caret.col == 0) return;
683 |
684 | let lines = this.editor.getText().split("\n");
685 | let line = lines[caret.line]
686 | let previousChar = line[caret.col - 1];
687 |
688 | if (!previousChar.match(/\w|\.|:/i)) return;
689 |
690 | // Initiate Completion
691 | e.preventDefault();
692 | e.stopPropagation();
693 |
694 | let root = line.substr(0, caret.col);
695 |
696 | let candidates = JSPropertyProvider(this.sb, root);
697 |
698 | let completeFromDict = false;
699 | if (candidates && candidates.matchProp) {
700 | if (root.length == candidates.matchProp.length) {
701 | completeFromDict = true;
702 | } else {
703 | let charBeforeProp = root[root.length - candidates.matchProp.length - 1];
704 | if (charBeforeProp.match(/\s|{|;|\(/)) {
705 | completeFromDict = true;
706 | }
707 | }
708 | }
709 | if (completeFromDict) {
710 | for (let word of this.dictionnary) {
711 | if (word.indexOf(candidates.matchProp) == 0) {
712 | candidates.matches.push(word);
713 | }
714 | }
715 | }
716 |
717 | if (!candidates || candidates.matches.length == 0) return;
718 |
719 | let offset = this.editor.getCaretOffset();
720 |
721 | // if one candidate
722 | if (candidates.matches.length == 1) {
723 | let suffix = candidates.matches[0].substr(candidates.matchProp.length);
724 | this.editor.setText(suffix, offset, offset);
725 | return;
726 | }
727 |
728 | // if several candidate
729 |
730 | let commonPrefix = candidates.matches.reduce(function(commonPrefix, nextValue) {
731 | if (commonPrefix == "")
732 | return "";
733 |
734 | if (!commonPrefix)
735 | return nextValue;
736 |
737 | if (commonPrefix.length > nextValue.length) {
738 | commonPrefix = commonPrefix.substr(0, nextValue.length);
739 | }
740 | let res = "";
741 | let idx = 0;
742 | for (let p = 0; p < commonPrefix.length; p++) {
743 | let c = commonPrefix[p];
744 | if (nextValue[idx++] == c)
745 | res += c;
746 | else
747 | break;
748 | }
749 | return res;
750 | });
751 |
752 | if (commonPrefix) {
753 | let suffix = commonPrefix.substr(candidates.matchProp.length);
754 | this.editor.setText(suffix, offset, offset);
755 | offset += suffix.length;
756 | candidates.matchProp = commonPrefix;
757 | }
758 |
759 | this.whereToInsert = {start: offset, end: offset};
760 | this.candidates = candidates;
761 | this.candidatesWidget.setAttribute("value", this.candidates.matches.join(" "));
762 | this.isCompleting = true;
763 |
764 | if (this.candidates.matches[0] == this.candidates.matchProp)
765 | this.candidatesIndex = 0;
766 | else
767 | this.candidatesIndex = -1;
768 | },
769 |
770 | continueCompleting: function() {
771 | this.candidatesIndex++;
772 | if (this.candidatesIndex == this.candidates.matches.length) {
773 | this.candidatesIndex = 0;
774 | }
775 |
776 | let prefixLength = this.candidates.matchProp.length;
777 | let suffix = this.candidates.matches[this.candidatesIndex].substr(prefixLength);
778 | this.editor.setText(suffix, this.whereToInsert.start, this.whereToInsert.end);
779 | this.whereToInsert.end = this.whereToInsert.start + suffix.length;
780 | },
781 |
782 | stopCompletion: function() {
783 | if (!this.isCompleting) return;
784 | this.candidatesWidget.setAttribute("value", "");
785 | this.isCompleting = false;
786 | this.candidates = null;
787 | },
788 | destroy: function() {
789 | this.editor.editorElement.removeEventListener("keydown", this.handleKeys, true);
790 | this.editor = null;
791 | },
792 | }
793 |
794 | /** HISTORY **/
795 |
796 | function JSTermLocalHistory(aGlobalHistory) {
797 | this.global = aGlobalHistory;
798 | }
799 | JSTermLocalHistory.prototype = {
800 | _browsing: false,
801 | isBrowsing: function() {
802 | return this._browsing;
803 | },
804 | startBrowsing: function(aInitialValue) {
805 | this._browsing = true;
806 | this.cursor = this.global.getCursor(aInitialValue);
807 | },
808 | stopBrowsing: function() {
809 | if (this.isBrowsing()) {
810 | this._browsing = false;
811 | this.global.releaseCursor(this.cursor);
812 | this.cursor = null;
813 | }
814 | },
815 | add: function(entry) {
816 | this.global.add(entry);
817 | },
818 | canGoBack: function() {
819 | return this.isBrowsing() && this.global.canGoBack(this.cursor);
820 | },
821 | canGoForward: function() {
822 | return this.isBrowsing() && this.global.canGoForward(this.cursor);
823 | },
824 | goBack: function() {
825 | if (this.canGoBack()) {
826 | this.global.goBack(this.cursor);
827 | let entry = this.global.getEntryForCursor(this.cursor);
828 | return entry;
829 | }
830 | return null;
831 | },
832 | goForward: function() {
833 | if (this.canGoForward()) {
834 | this.global.goForward(this.cursor);
835 | let entry = this.global.getEntryForCursor(this.cursor);
836 | return entry;
837 | }
838 | return null;
839 | },
840 | }
841 |
--------------------------------------------------------------------------------
/chrome/jsterm.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 | %JSTermDTD;
10 | ]>
11 |
12 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/chrome/vendor/prelude-ls.js:
--------------------------------------------------------------------------------
1 | // prelude.ls 0.6.0
2 | // Copyright (c) 2012 George Zahariev
3 | // Released under the MIT License
4 | // raw.github.com/gkz/prelude-ls/master/LICNSE
5 | this.prelude=function(){function Gt(e,t){return e.length>1?function(){var n=t?t.concat():[];return n.push.apply(n,arguments)>>0;while(n0;--t)n=[e[t-1].apply(this,n)];return n[0]}}function en(e){return!e}function tn(e,t){var n={}.hasOwnProperty;for(var r in t)n.call(t,r)&&(e[r]=t[r]);return e}exports={};var e,t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z,W,X,V,$,J,K,Q,G,Y,Z,et,tt,nt,rt,it,st,ot,ut,at,ft,lt,ct,ht,pt,dt,vt,mt,gt,yt,bt,wt,Et,St,xt,Tt,Nt,Ct,kt,Lt,At,Ot,Mt,_t,Dt,Pt,Ht,Bt,jt,Ft,It,qt,Rt,Ut,zt,Wt,Xt,Vt,$t,Jt,Kt={}.toString,Qt=[].slice;return exports.objToFunc=e=function(e){return function(t){return e[t]}},exports.each=t=Gt(function(e,t){var n,r,i;if(Kt.call(t).slice(8,-1)==="Object")for(n in t)r=t[n],e(r);else for(n=0,i=t.length;nt):return 1;case!(ee(n)):return 1;case!(e(t)t?e:t}),exports.min=yt=Gt(function(e,t){return e>t?t:e}),exports.negate=bt=function(e){return-e},exports.abs=wt=Math.abs,exports.signum=Et=function(e){switch(!1){case!(e<0):return-1;case!(e>0):return 1;default:return 0}},exports.quot=St=Gt(function(e,t){return~~(e/t)}),exports.rem=xt=Gt(function(e,t){return e%t}),exports.div=Tt=Gt(function(e,t){return Math.floor(e/t)}),exports.mod=Nt=Gt(function(e,t){var n;return(e%(n=t)+n)%n}),exports.recip=Ct=function(e){return 1/e},exports.pi=kt=Math.PI,exports.tau=Lt=kt*2,exports.exp=At=Math.exp,exports.sqrt=Ot=Math.sqrt,exports.ln=Mt=Math.log,exports.pow=_t=Gt(function(e,t){return Math.pow(e,t)}),exports.sin=Dt=Math.sin,exports.tan=Pt=Math.tan,exports.cos=Ht=Math.cos,exports.asin=Bt=Math.asin,exports.acos=jt=Math.acos,exports.atan=Ft=Math.atan,exports.atan2=It=Gt(function(e,t){return Math.atan2(e,t)}),exports.truncate=qt=function(e){return~~e},exports.round=Rt=Math.round,exports.ceiling=Ut=Math.ceil,exports.floor=zt=Math.floor,exports.isItNaN=Wt=function(e){return e!==e},exports.even=Xt=function(e){return e%2===0},exports.odd=Vt=function(e){return e%2!==0},exports.gcd=$t=Gt(function(e,t){var n;e=Math.abs(e),t=Math.abs(t);while(t!==0)n=e%t,e=t,t=n;return e}),exports.lcm=Jt=Gt(function(e,t){return Math.abs(Math.floor(e/$t(e,t)*t))}),exports.installPrelude=function(e){var t;if((t=e.prelude)==null||!t.isInstalled)tn(e,exports),e.prelude.isInstalled=!0},exports.prelude=exports,exports}()
6 |
--------------------------------------------------------------------------------
/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | Paul Rouget
6 | jsterm@paulrouget.com
7 | Firefox Terminal
8 | 3
9 | true
10 | 2
11 | chrome://jsterm/content/icon.png
12 | http://github.com/paulrouget/firefox-jsterm
13 | JavaScript, CoffeeScript and LiveScript Terminal for Firefox
14 |
15 |
16 |
17 |
18 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
19 | 20.0a1
20 | 22.0a1
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/jsterm.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/firefox-jsterm/cd6e9b17551aa98bf1714adc1d3a44745c62a3e4/jsterm.xpi
--------------------------------------------------------------------------------
/locale/en-US/jsterm.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/locale/en-US/jsterm.properties:
--------------------------------------------------------------------------------
1 | JSTerm.commandkey=l
2 | JSTerm.label=JSTerm
3 | JSTerm.tooltip=JavaScript Terminal
4 |
--------------------------------------------------------------------------------
/skin/jsterm.css:
--------------------------------------------------------------------------------
1 | window {
2 | background-color: #131c26;
3 | color: white;
4 | font-family: Monaco, monospace;
5 | font-size: 12px;
6 | }
7 |
8 | window,
9 | #variables {
10 | background-image: url("data:image/png;base64,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");
11 | }
12 |
13 | #editors-container {
14 | padding: 5px;
15 | overflow-y: auto;
16 | }
17 |
18 | #prompt {
19 | color: #8fa1b2;
20 | width: 12px;
21 | min-width: 12px;
22 | max-width: 12px;
23 | }
24 |
25 | #input-container {
26 | border-left: 1px dotted transparent;
27 | margin-left: -1px;
28 | }
29 |
30 | #input-container.multiline {
31 | border-color: white;
32 | }
33 |
34 | #input-container.multiline > #prompt {
35 | visibility: hidden;
36 | }
37 |
38 | #input-container.chrome > #prompt {
39 | color: #F06;
40 | }
41 |
42 | #input-container.chrome.multiline {
43 | border-color: #F06;
44 | }
45 |
46 | #output-container {
47 | margin-left: 12px;
48 | }
49 |
50 | #completion-candidates {
51 | margin-left: 15px;
52 | color: #7a8a99;
53 | font-size: 12px;
54 | }
55 |
56 | /* -- Light Theme -- */
57 |
58 | window.light {
59 | background-color: #F3F3F3;
60 | color: black;
61 | }
62 |
63 | /* -- Variable View --*/
64 |
65 | #variables {
66 | background: #EEE;
67 | }
68 |
--------------------------------------------------------------------------------
/skin/orion.css:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 |
5 | #viewDiv {
6 | padding-top: 0;
7 | padding-bottom: 0;
8 | }
9 |
10 | .viewContainer {
11 | font-family: Monaco, monospace;
12 | font-weight: lighter;
13 | font-size: 12px;
14 | }
15 |
16 | .view {
17 | color: #FFF; /* Default text color */
18 | padding-left: 4px;
19 | overflow-x: hidden!important;
20 | }
21 |
22 | .ruler {
23 | color: #7a8a99;
24 | }
25 | .ruler.jsterminput {
26 | width: 15px;
27 | padding-left: 4px;
28 | }
29 |
30 | .ruler.lines {
31 | border-right: 1px solid #303b47;
32 | min-width: 1.4em;
33 | padding-left: 4px;
34 | padding-right: 4px;
35 | text-align: end;
36 | }
37 |
38 | .ruler.linesWithAnnotations {
39 | min-width: 0;
40 | padding-left: 0;
41 | }
42 |
43 | .ruler.overview {
44 | border-left: 1px solid #303b47;
45 | width: 14px;
46 | text-align: start;
47 | }
48 |
49 | .annotationLine.object {
50 | cursor: pointer;
51 | }
52 |
53 | .annotationLine.object:hover > * {
54 | color: white!important;
55 | }
56 |
57 | .token_doc_comment,
58 | .token_singleline_comment,
59 | .token_multiline_comment {
60 | color: #5c6773;
61 | }
62 |
63 | .token_string {
64 | color: #3689b2;
65 | }
66 |
67 | .token_keyword {
68 | color: #a673bf;
69 | color: #F06;
70 | }
71 |
72 | .invalid {
73 | color: red;
74 | }
75 |
76 |
77 | /* -- Light Theme -- */
78 |
79 | .view.light {
80 | color: #000;
81 | }
82 |
83 | .view.light .annotationLine.object:hover > * {
84 | color: #000!important;
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------