more pm28 fixes
[guerillascript.git] / main / modules / concmd.js
blob3db719a47d680180ed66f1a6248915b816481754
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.
9 */
10 ////////////////////////////////////////////////////////////////////////////////
12 / *let gcli =* / uses("resource://gre/modules/devtools/gcli.jsm");
13 //uses("resource://gre/modules/devtools/gcli");
14 //let gcli = require("resource://gre/modules/devtools/gcli.jsm");
16 require("utils/utils");
17 let {oneShotTimer, intervalTimer} = require("utils/timer");
20 ////////////////////////////////////////////////////////////////////////////////
21 function wild2re (wildstr) {
22 wildstr = wildstr.replace(/^\s+/, "").replace(/\s+$/, "");
23 if (wildstr == "") wildstr = "*";
24 if (wildstr == "*") return new RegExp(/./);
25 // regexp?
26 if (wildstr.length >= 2 && wildstr.charCodeAt(0) == 47 && wildstr.charCodeAt(wildstr.length-1) == 47) {
27 if (wildstr.length < 3) return new RegExp(/./);
28 return new RegExp(wildstr.substring(1, wildstr.length-1), "i");
30 // convert glob to regexp
31 let re = "^";
32 for (let f = 0; f < wildstr.length; ++f) {
33 switch (wildstr[f]) {
34 case "*": re += ".*"; break; // any, greedy
35 case ".": case "?": case "^": case "$": case "+":
36 case "{": case "}": case "[": case "]": case "|":
37 case "(": case ")": case "\\":
38 re += "\\"+wildstr[f];
39 break;
40 case " ": re += "\\s"; break;
41 default: re += wildstr[f]; break;
44 re += "$";
45 //if (addonOptions.debugCache) conlog("wildstr:["+wildstr+"] re: ["+re+"]");
46 return new RegExp(re, "i");
50 ////////////////////////////////////////////////////////////////////////////////
51 let editList = {lmod:-1};
52 let editNames;
55 function getEditList () {
56 let cur = scacheAPI.getScriptsForEdit();
57 if (cur.lmod != editList.lmod) {
58 editList = {lmod:cur.lmod, list:cur.list};
59 editNames = new Array();
60 for (let xnfo of editList.list) editNames.push({name:xnfo.name, value:xnfo.path});
62 return editNames;
66 ////////////////////////////////////////////////////////////////////////////////
67 let pkgList = {lmod:-1};
68 let pkgNames;
71 function getPkgList () {
72 let cur = pkgman.getPackageList();
73 //conlog("getPkgList: pkgList.lmod=", pkgList.lmod, "; cur.lmod=", cur.lmod);
74 if (cur.lmod != pkgList.lmod) {
75 pkgList = {lmod:cur.lmod, list:cur.list};
76 pkgNames = new Array();
77 for (let pi of pkgList.list) pkgNames.push({name:pi.name, value:pi});
79 return pkgNames;
83 ////////////////////////////////////////////////////////////////////////////////
84 function addjsext (fn) {
85 if (!/\.js$/.test(fn)) fn += ".js";
86 return fn;
90 ////////////////////////////////////////////////////////////////////////////////
91 function openEditor (fname, chromeWin, newfile) {
92 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
93 fl.followLinks = true;
94 fl.initWithPath(fname);
95 let lmtime = 0;
96 if (fl.exists()) {
97 if (fl.isDirectory()) return;
98 lmtime = fl.lastModifiedTime;
99 } else {
100 if (!newfile) return;
102 let text;
103 try {
104 text = fileReadText(fl);
105 newfile = false;
106 } catch (e) {
107 if (!newfile) {
108 logError("can't read file: "+fname);
109 return;
111 text =
112 "// ==UserScript==\n"+
113 "// @name \n"+
114 "// @description \n"+
115 "// @version 1.0\n"+
116 "// @include *\n"+
117 "// @run-at document-end\n"+
118 "// @noframes\n"+
119 "// @nowrap\n"+
120 "// @libraries \n"+
121 "// @require \n"+
122 "// ==/UserScript==\n\n";
124 let spw = chromeWin.Scratchpad.ScratchpadManager.openScratchpad({
125 filename: fname,
126 text: text,
127 saved: !newfile,
129 // TODO: how can i observe file changes without timer?
130 let wasChange = false;
131 let checkFC = function () {
132 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
133 fl.followLinks = true;
134 fl.initWithPath(fname);
135 if (fl.exists() && !fl.isDirectory() && lmtime != fl.lastModifiedTime) {
136 lmtime = fl.lastModifiedTime;
137 return true;
139 return false;
141 let tm = intervalTimer(function () {
142 if (checkFC()) { scacheAPI.reset(); wasChange = true; }
143 }, 1500);
144 // kill timer on closing
145 spw.addEventListener("close", function sploaded() {
146 spw.removeEventListener("close", sploaded, false);
147 tm.cancel();
148 // just in case
149 if (wasChange || checkFC()) {
150 scacheAPI.reset();
151 scacheAPI.validate();
152 latestUC = scacheAPI.getUC();
154 }, false);
158 ////////////////////////////////////////////////////////////////////////////////
159 let gcliCommandSpecs = [
161 name: "guerilla",
162 description: "GuerillaJS control",
164 // subcommands
166 name: "guerilla about",
167 description: "show various info",
168 params: [
170 name: "type",
171 description: "info to show",
172 type: { name: "selection", data: ["readme", "credits", "thanks", "licenses"] },
173 defaultValue: "readme",
176 exec: function (args, context) {
177 let bro = context.environment.chromeWindow.gBrowser;
178 let list;
179 switch (args.type) {
180 case "credits": list = "CREDITS.txt"; break;
181 case "thanks": list = "THANKS.txt"; break;
182 case "licenses": list = ["LICENSE.bsd.txt", "LICENSE.mit.txt", "LICENSE.mpl.txt", "LICENSE.wtfpl.txt"]; break;
183 default: list = "README.txt"; break;
185 if (typeof(list) == "string") {
186 bro.selectedTab = bro.addTab(gsdoxUrl+list);
187 } else {
188 for (let name of list) bro.selectedTab = bro.addTab(gsdoxUrl+name);
194 name: "guerilla reset",
195 description: "reset all internal caches",
196 exec: function (args, context) {
197 //conlog("clearing guerilla caches...");
198 scacheAPI.reset();
203 name: "guerilla debug",
204 description: "switch debug mode on/off",
205 params: [
207 name: "flag",
208 description: "action to perform",
209 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
210 defaultValue: "show",
213 returnValue: "string",
214 exec: function (args, context) {
215 switch (args.flag) {
216 case "tan": addonOptions.debugMode = true; break;
217 case "ona": addonOptions.debugMode = false; break;
218 case "toggle": addonOptions.debugMode = !addonOptions.debugMode; break;
220 return "guerilla debug mode is "+(addonOptions.debugMode ? "on" : "off");
225 name: "guerilla log",
226 description: "switch logging on/off",
227 params: [
229 name: "flag",
230 description: "action to perform",
231 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
232 defaultValue: "show",
235 returnValue: "string",
236 exec: function (args, context) {
237 switch (args.flag) {
238 case "tan": addonOptions.logEnabled = true; break;
239 case "ona": addonOptions.logEnabled = false; break;
240 case "toggle": addonOptions.logEnabled = !addonOptions.logEnabled; break;
242 return "guerilla logging is "+(addonOptions.logEnabled ? "on" : "off");
247 name: "guerilla state",
248 description: "switch guerilla state",
249 params: [
251 name: "flag",
252 description: "action to perform",
253 type: { name: "selection", data: ["show", "active", "inactive", "toggle"] },
254 defaultValue: "show",
257 returnValue: "string",
258 exec: function (args, context) {
259 switch (args.flag) {
260 case "active": addonOptions.active = true; break;
261 case "inactive": addonOptions.active = false; break;
262 case "toggle": addonOptions.active = !addonOptions.active; break;
264 return "guerilla is "+(addonOptions.active ? "" : "in")+"active";
269 name: "guerilla activate",
270 description: "activate guerilla",
271 returnValue: "string",
272 exec: function (args, context) {
273 addonOptions.active = true;
274 return "guerilla is active";
279 name: "guerilla deactivate",
280 description: "deactivate guerilla",
281 returnValue: "string",
282 exec: function (args, context) {
283 addonOptions.active = false;
284 return "guerilla is inactive";
289 name: "guerilla new",
290 description: "create new userscript",
291 params: [
293 name: "filename",
294 description: "new script name",
295 type: "string",
298 exec: function (args, context) {
299 let fname = args.filename;
300 let mt = fname.match(/^\/?libs\/([^\/]+)$/);
301 if (mt) fname = mt[1];
302 if (fname.length == 0 || fname.indexOf("/") >= 0) return;
303 fname = addjsext(fname);
304 let dir;
305 if (mt) {
306 // new library
307 dir = getUserLibDir();
308 dir.append(fname);
309 } else {
310 //if (args.filename.length == 0 || args.filename.indexOf("/") >= 0) { alert("invalid file name: "+args.filename); return; }
311 dir = getUserJSDir();
312 dir.append(fname);
314 conlog("trying to edit '"+dir.path+"'");
315 openEditor(dir.path, context.environment.chromeDocument.defaultView, true);
320 name: "guerilla edit",
321 description: "edit guerilla script",
322 //returnValue: "string",
323 params: [
325 name: "filename",
326 description: "script name to edit",
327 type: {
328 name: "selection",
329 cacheable: false,
330 lookup: function (context) getEditList(),
331 }, // type
334 exec: function (args, context) {
335 if (args.filename) openEditor(args.filename, context.environment.chromeDocument.defaultView);
338 // package backend
340 name: "guerilla package",
341 description: "GuerillaJS package control",
344 name: "guerilla package abort",
345 description: "abort all operations",
346 exec: function (args, context) { pkgman.cancel(); },
349 name: "guerilla package list",
350 description: "list installed packages",
351 returnValue: "string",
352 params: [
354 name: "mask",
355 description: "mask",
356 defaultValue: "*",
357 type: "string",
360 exec: function (args, context) {
361 let mask = args.mask||"*";
362 let re = wild2re(mask);
363 let res = "=== package list ===";
364 let count = 0;
365 for (let pi of pkgDB.getActivePackages()) {
366 if (re.test(pi.name)) {
367 res += "\n"+pi.name;
368 if (pi.version) res += "\t"+pi.version;
369 ++count;
372 //return (count ? res : "no packages found");
373 //TODO: special output
374 logError(count ? res : "no packages found");
375 return "find result in error console";
379 name: "guerilla package update",
380 description: "update package(s)",
381 params: [
383 name: "mask",
384 description: "mask",
385 defaultValue: "",
386 type: "string",
389 exec: function (args, context) {
390 if (!args.mask) return;
391 let mask = args.mask||"*";
392 let re = wild2re(mask);
393 for (let pi of pkgDB.getActivePackages()) {
394 if (re.test(pi.name)) {
395 try {
396 pkgman.update(pi.name);
397 } catch (e) {
398 logError("ERROR: ", e.message);
405 name: "guerilla package install",
406 description: "install package",
407 params: [
409 name: "name",
410 description: "package name",
411 type: "string",
414 name: "url",
415 description: "package install url",
416 type: "string",
419 exec: function (args, context) {
420 if (!args.name || !args.url) return;
421 try {
422 pkgman.install(args.name, args.url);
423 } catch (e) {
424 logError("ERROR: ", e.message);
429 name: "guerilla package remove",
430 description: "remove package",
431 params: [
433 name: "name",
434 description: "package name",
435 type: {
436 name: "selection",
437 cacheable: false,
438 lookup: function (context) getPkgList(),
439 }, // type
442 exec: function (args, context) {
443 //if (!args.name.name) return;
444 try {
445 pkgman.remove(args.name.name);
446 } catch (e) {
447 logError("ERROR: ", e.message);
454 ////////////////////////////////////////////////////////////////////////////////
455 registerStartupHook("gcli", function () {
456 try {
457 //if (typeof(gcli) === "undefined") return;
458 //if (typeof(gcli.addCommand) !== "function") return;
459 for (let cmd of gcliCommandSpecs) {
460 if (cmd && typeof(cmd) === "object" && cmd.name) gcli.addItems([cmd]);
462 } catch (e) {
463 logError("ERROR: ", e.message);
468 registerShutdownHook("gcli", function () {
469 try {
470 //if (typeof(gcli) === "undefined") return;
471 //if (typeof(gcli.removeCommand) !== "function") return;
472 for (let cmd of gcliCommandSpecs) {
473 if (cmd && typeof(cmd) === "object" && cmd.name) gcli.removeItems([cmd]);
475 } catch (e) {
476 logError("ERROR: ", e.message);