1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
10 ////////////////////////////////////////////////////////////////////////////////
11 uses("resource://gre/modules/devtools/gcli.jsm");
13 require("utils/utils");
14 let {oneShotTimer, intervalTimer} = require("utils/timer");
17 ////////////////////////////////////////////////////////////////////////////////
18 function wild2re (wildstr) {
19 wildstr = wildstr.replace(/^\s+/, "").replace(/\s+$/, "");
20 if (wildstr == "") wildstr = "*";
21 if (wildstr == "*") return new RegExp(/./);
23 if (wildstr.length >= 2 && wildstr.charCodeAt(0) == 47 && wildstr.charCodeAt(wildstr.length-1) == 47) {
24 if (wildstr.length < 3) return new RegExp(/./);
25 return new RegExp(wildstr.substring(1, wildstr.length-1), "i");
27 // convert glob to regexp
29 for (let f = 0; f < wildstr.length; ++f) {
31 case "*": re += ".*"; break; // any, greedy
32 case ".": case "?": case "^": case "$": case "+":
33 case "{": case "}": case "[": case "]": case "|":
34 case "(": case ")": case "\\":
35 re += "\\"+wildstr[f];
37 case " ": re += "\\s"; break;
38 default: re += wildstr[f]; break;
42 //if (addonOptions.debugCache) conlog("wildstr:["+wildstr+"] re: ["+re+"]");
43 return new RegExp(re, "i");
47 ////////////////////////////////////////////////////////////////////////////////
48 let editList = {lmod:-1};
52 function getEditList () {
53 let cur = scacheAPI.getScriptsForEdit();
54 if (cur.lmod != editList.lmod) {
55 editList = {lmod:cur.lmod, list:cur.list};
56 editNames = new Array();
57 for (let xnfo of editList.list) editNames.push({name:xnfo.name, value:xnfo.path});
63 ////////////////////////////////////////////////////////////////////////////////
64 let pkgList = {lmod:-1};
68 function getPkgList () {
69 let cur = pkgman.getPackageList();
70 //conlog("getPkgList: pkgList.lmod=", pkgList.lmod, "; cur.lmod=", cur.lmod);
71 if (cur.lmod != pkgList.lmod) {
72 pkgList = {lmod:cur.lmod, list:cur.list};
73 pkgNames = new Array();
74 for (let pi of pkgList.list) pkgNames.push({name:pi.name, value:pi});
80 ////////////////////////////////////////////////////////////////////////////////
81 function addjsext (fn) {
82 if (!/\.js$/.test(fn)) fn += ".js";
87 ////////////////////////////////////////////////////////////////////////////////
88 function openEditor (fname, chromeWin, newfile) {
89 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
90 fl.followLinks = true;
91 fl.initWithPath(fname);
94 if (fl.isDirectory()) return;
95 lmtime = fl.lastModifiedTime;
101 text = fileReadText(fl);
105 logError("can't read file: "+fname);
109 "// ==UserScript==\n"+
111 "// @description \n"+
114 "// @run-at document-end\n"+
119 "// ==/UserScript==\n\n";
121 let spw = chromeWin.Scratchpad.ScratchpadManager.openScratchpad({
126 // TODO: how can i observe file changes without timer?
127 let wasChange = false;
128 let checkFC = function () {
129 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
130 fl.followLinks = true;
131 fl.initWithPath(fname);
132 if (fl.exists() && !fl.isDirectory() && lmtime != fl.lastModifiedTime) {
133 lmtime = fl.lastModifiedTime;
138 let tm = intervalTimer(function () {
139 if (checkFC()) { scacheAPI.reset(); wasChange = true; }
141 // kill timer on closing
142 spw.addEventListener("close", function sploaded() {
143 spw.removeEventListener("close", sploaded, false);
146 if (wasChange || checkFC()) {
148 scacheAPI.validate();
149 latestUC = scacheAPI.getUC();
155 ////////////////////////////////////////////////////////////////////////////////
156 let gcliCommandSpecs = [
159 description: "GuerillaJS control",
163 name: "guerilla about",
164 description: "show various info",
168 description: "info to show",
169 type: { name: "selection", data: ["readme", "credits", "thanks", "licenses"] },
170 defaultValue: "readme",
173 exec: function (args, context) {
174 let bro = context.environment.chromeWindow.gBrowser;
177 case "credits": list = "CREDITS.txt"; break;
178 case "thanks": list = "THANKS.txt"; break;
179 case "licenses": list = ["LICENSE.bsd.txt", "LICENSE.mit.txt", "LICENSE.mpl.txt", "LICENSE.wtfpl.txt"]; break;
180 default: list = "README.txt"; break;
182 if (typeof(list) == "string") {
183 bro.selectedTab = bro.addTab(gsdoxUrl+list);
185 for (let name of list) bro.selectedTab = bro.addTab(gsdoxUrl+name);
191 name: "guerilla reset",
192 description: "reset all internal caches",
193 exec: function (args, context) {
194 //conlog("clearing guerilla caches...");
200 name: "guerilla debug",
201 description: "switch debug mode on/off",
205 description: "action to perform",
206 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
207 defaultValue: "show",
210 returnValue: "string",
211 exec: function (args, context) {
213 case "tan": addonOptions.debugMode = true; break;
214 case "ona": addonOptions.debugMode = false; break;
215 case "toggle": addonOptions.debugMode = !addonOptions.debugMode; break;
217 return "guerilla debug mode is "+(addonOptions.debugMode ? "on" : "off");
222 name: "guerilla log",
223 description: "switch logging on/off",
227 description: "action to perform",
228 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
229 defaultValue: "show",
232 returnValue: "string",
233 exec: function (args, context) {
235 case "tan": addonOptions.logEnabled = true; break;
236 case "ona": addonOptions.logEnabled = false; break;
237 case "toggle": addonOptions.logEnabled = !addonOptions.logEnabled; break;
239 return "guerilla logging is "+(addonOptions.logEnabled ? "on" : "off");
244 name: "guerilla state",
245 description: "switch guerilla state",
249 description: "action to perform",
250 type: { name: "selection", data: ["show", "active", "inactive", "toggle"] },
251 defaultValue: "show",
254 returnValue: "string",
255 exec: function (args, context) {
257 case "active": addonOptions.active = true; break;
258 case "inactive": addonOptions.active = false; break;
259 case "toggle": addonOptions.active = !addonOptions.active; break;
261 return "guerilla is "+(addonOptions.active ? "" : "in")+"active";
266 name: "guerilla activate",
267 description: "activate guerilla",
268 returnValue: "string",
269 exec: function (args, context) {
270 addonOptions.active = true;
271 return "guerilla is active";
276 name: "guerilla deactivate",
277 description: "deactivate guerilla",
278 returnValue: "string",
279 exec: function (args, context) {
280 addonOptions.active = false;
281 return "guerilla is inactive";
286 name: "guerilla new",
287 description: "create new userscript",
291 description: "new script name",
295 exec: function (args, context) {
296 let fname = args.filename;
297 let mt = fname.match(/^\/?libs\/([^\/]+)$/);
298 if (mt) fname = mt[1];
299 if (fname.length == 0 || fname.indexOf("/") >= 0) return;
300 fname = addjsext(fname);
304 dir = getUserLibDir();
307 //if (args.filename.length == 0 || args.filename.indexOf("/") >= 0) { alert("invalid file name: "+args.filename); return; }
308 dir = getUserJSDir();
311 conlog("trying to edit '"+dir.path+"'");
312 openEditor(dir.path, context.environment.chromeDocument.defaultView, true);
317 name: "guerilla edit",
318 description: "edit guerilla script",
319 //returnValue: "string",
323 description: "script name to edit",
327 lookup: function (context) getEditList(),
331 exec: function (args, context) {
332 if (args.filename) openEditor(args.filename, context.environment.chromeDocument.defaultView);
337 name: "guerilla package",
338 description: "GuerillaJS package control",
341 name: "guerilla package abort",
342 description: "abort all operations",
343 exec: function (args, context) { pkgman.cancel(); },
346 name: "guerilla package list",
347 description: "list installed packages",
348 returnValue: "string",
357 exec: function (args, context) {
358 let mask = args.mask||"*";
359 let re = wild2re(mask);
360 let res = "=== package list ===";
362 for (let pi of pkgDB.getActivePackages()) {
363 if (re.test(pi.name)) {
365 if (pi.version) res += "\t"+pi.version;
369 //return (count ? res : "no packages found");
370 //TODO: special output
371 logError(count ? res : "no packages found");
372 return "find result in error console";
376 name: "guerilla package update",
377 description: "update package(s)",
386 exec: function (args, context) {
387 if (!args.mask) return;
388 let mask = args.mask||"*";
389 let re = wild2re(mask);
390 for (let pi of pkgDB.getActivePackages()) {
391 if (re.test(pi.name)) {
393 pkgman.update(pi.name);
395 logError("ERROR: ", e.message);
402 name: "guerilla package install",
403 description: "install package",
407 description: "package name",
412 description: "package install url",
416 exec: function (args, context) {
417 if (!args.name || !args.url) return;
419 pkgman.install(args.name, args.url);
421 logError("ERROR: ", e.message);
426 name: "guerilla package remove",
427 description: "remove package",
431 description: "package name",
435 lookup: function (context) getPkgList(),
439 exec: function (args, context) {
440 //if (!args.name.name) return;
442 pkgman.remove(args.name.name);
444 logError("ERROR: ", e.message);
451 ////////////////////////////////////////////////////////////////////////////////
452 registerStartupHook("gcli", function () {
453 for (let cmd of gcliCommandSpecs) {
454 if (cmd && typeof(cmd) === "object" && cmd.name) gcli.addCommand(cmd);
459 registerShutdownHook("gcli", function () {
460 for (let cmd of gcliCommandSpecs) {
461 if (cmd && typeof(cmd) === "object" && cmd.name) gcli.removeCommand(cmd);