better directory layout; unification with non-bootstrapping addons
[guerillascript.git] / main / modules / concmd.js
blobb4288b47531ae9bc8687dfa204a7d959039c7c9f
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 ////////////////////////////////////////////////////////////////////////////////
11 uses("resource://gre/modules/devtools/gcli.jsm");
13 let {oneShotTimer, intervalTimer} = require("utils/timer");
16 ////////////////////////////////////////////////////////////////////////////////
17 let editList = {lmod:-1};
18 let editNames;
21 function getEditList () {
22 let cur = scacheAPI.getScriptsForEdit();
23 if (cur.lmod != editList.lmod) {
24 editList = {lmod:cur.lmod, list:cur.list};
25 editNames = new Array();
26 for (let xnfo of editList.list) editNames.push({name:xnfo.name, value:xnfo.path});
28 return editNames;
32 ////////////////////////////////////////////////////////////////////////////////
33 let pkgList = {lmod:-1};
34 let pkgNames;
37 function getPkgList () {
38 let cur = pkgman.getPackageList();
39 //conlog("getPkgList: pkgList.lmod=", pkgList.lmod, "; cur.lmod=", cur.lmod);
40 if (cur.lmod != pkgList.lmod) {
41 pkgList = {lmod:cur.lmod, list:cur.list};
42 pkgNames = new Array();
43 for (let pi of pkgList.list) pkgNames.push({name:pi.name, value:pi});
45 return pkgNames;
49 ////////////////////////////////////////////////////////////////////////////////
50 function addjsext (fn) {
51 if (!/\.js$/.test(fn)) fn += ".js";
52 return fn;
56 ////////////////////////////////////////////////////////////////////////////////
57 function openEditor (fname, chromeWin, newfile) {
58 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
59 fl.followLinks = true;
60 fl.initWithPath(fname);
61 let lmtime = 0;
62 if (fl.exists()) {
63 if (fl.isDirectory()) return;
64 lmtime = fl.lastModifiedTime;
65 } else {
66 if (!newfile) return;
68 let text;
69 try {
70 text = fileReadText(fl);
71 newfile = false;
72 } catch (e) {
73 if (!newfile) {
74 logError("can't read file: "+fname);
75 return;
77 text =
78 "// ==UserScript==\n"+
79 "// @name \n"+
80 "// @description \n"+
81 "// @version 1.0\n"+
82 "// @include *\n"+
83 "// @run-at document-end\n"+
84 "// @noframes\n"+
85 "// @nowrap\n"+
86 "// @libraries \n"+
87 "// @require \n"+
88 "// ==/UserScript==\n\n";
90 let spw = chromeWin.Scratchpad.ScratchpadManager.openScratchpad({
91 filename: fname,
92 text: text,
93 saved: !newfile,
94 });
95 // TODO: how can i observe file changes without timer?
96 let wasChange = false;
97 let checkFC = function () {
98 let fl = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
99 fl.followLinks = true;
100 fl.initWithPath(fname);
101 if (fl.exists() && !fl.isDirectory() && lmtime != fl.lastModifiedTime) {
102 lmtime = fl.lastModifiedTime;
103 return true;
105 return false;
107 let tm = intervalTimer(function () {
108 if (checkFC()) { scacheAPI.reset(); wasChange = true; }
109 }, 1500);
110 // kill timer on closing
111 spw.addEventListener("close", function sploaded() {
112 spw.removeEventListener("close", sploaded, false);
113 tm.cancel();
114 // just in case
115 if (wasChange || checkFC()) {
116 scacheAPI.reset();
117 scacheAPI.validate();
118 latestUC = scacheAPI.getUC();
120 }, false);
124 ////////////////////////////////////////////////////////////////////////////////
125 let gcliCommandSpecs = [
127 name: "guerilla",
128 description: "GuerillaJS control",
130 // subcommands
132 name: "guerilla about",
133 description: "show various info",
134 params: [
136 name: "type",
137 description: "info to show",
138 type: { name: "selection", data: ["readme", "credits", "thanks", "licenses"] },
139 defaultValue: "readme",
142 exec: function (args, context) {
143 let bro = context.environment.chromeWindow.gBrowser;
144 let list;
145 switch (args.type) {
146 case "credits": list = "CREDITS.txt"; break;
147 case "thanks": list = "THANKS.txt"; break;
148 case "licenses": list = ["LICENSE.bsd.txt", "LICENSE.mit.txt", "LICENSE.mpl.txt", "LICENSE.wtfpl.txt"]; break;
149 default: list = "README.txt"; break;
151 if (typeof(list) == "string") {
152 bro.selectedTab = bro.addTab(gsdoxURL+list);
153 } else {
154 for (let name of list) bro.selectedTab = bro.addTab(gsdoxURL+name);
160 name: "guerilla reset",
161 description: "reset all internal caches",
162 exec: function (args, context) {
163 //conlog("clearing guerilla caches...");
164 scacheAPI.reset();
169 name: "guerilla debug",
170 description: "switch debug mode on/off",
171 params: [
173 name: "flag",
174 description: "action to perform",
175 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
176 defaultValue: "show",
179 returnValue: "string",
180 exec: function (args, context) {
181 switch (args.flag) {
182 case "tan": guerillaOptions.debugMode = true; break;
183 case "ona": guerillaOptions.debugMode = false; break;
184 case "toggle": guerillaOptions.debugMode = !guerillaOptions.debugMode; break;
186 return "guerilla debug mode is "+(guerillaOptions.debugMode ? "on" : "off");
191 name: "guerilla log",
192 description: "switch logging on/off",
193 params: [
195 name: "flag",
196 description: "action to perform",
197 type: { name: "selection", data: ["show", "tan", "ona", "toggle"] },
198 defaultValue: "show",
201 returnValue: "string",
202 exec: function (args, context) {
203 switch (args.flag) {
204 case "tan": guerillaOptions.logEnabled = true; break;
205 case "ona": guerillaOptions.logEnabled = false; break;
206 case "toggle": guerillaOptions.logEnabled = !guerillaOptions.logEnabled; break;
208 return "guerilla logging is "+(guerillaOptions.logEnabled ? "on" : "off");
213 name: "guerilla state",
214 description: "switch guerilla state",
215 params: [
217 name: "flag",
218 description: "action to perform",
219 type: { name: "selection", data: ["show", "active", "inactive", "toggle"] },
220 defaultValue: "show",
223 returnValue: "string",
224 exec: function (args, context) {
225 switch (args.flag) {
226 case "active": guerillaOptions.active = true; break;
227 case "inactive": guerillaOptions.active = false; break;
228 case "toggle": guerillaOptions.active = !guerillaOptions.active; break;
230 return "guerilla is "+(guerillaOptions.active ? "" : "in")+"active";
235 name: "guerilla activate",
236 description: "activate guerilla",
237 returnValue: "string",
238 exec: function (args, context) {
239 guerillaOptions.active = true;
240 return "guerilla is active";
245 name: "guerilla deactivate",
246 description: "deactivate guerilla",
247 returnValue: "string",
248 exec: function (args, context) {
249 guerillaOptions.active = false;
250 return "guerilla is inactive";
255 name: "guerilla new",
256 description: "create new userscript",
257 params: [
259 name: "filename",
260 description: "new script name",
261 type: "string",
264 exec: function (args, context) {
265 let fname = args.filename;
266 let mt = fname.match(/^\/?libs\/([^\/]+)$/);
267 if (mt) fname = mt[1];
268 if (fname.length == 0 || fname.indexOf("/") >= 0) return;
269 fname = addjsext(fname);
270 let dir;
271 if (mt) {
272 // new library
273 dir = getUserLibDir();
274 dir.append(fname);
275 } else {
276 //if (args.filename.length == 0 || args.filename.indexOf("/") >= 0) { alert("invalid file name: "+args.filename); return; }
277 dir = getUserJSDir();
278 dir.append(fname);
280 conlog("trying to edit '"+dir.path+"'");
281 openEditor(dir.path, context.environment.chromeDocument.defaultView, true);
286 name: "guerilla edit",
287 description: "edit guerilla script",
288 //returnValue: "string",
289 params: [
291 name: "filename",
292 description: "script name to edit",
293 type: {
294 name: "selection",
295 cacheable: false,
296 lookup: function (context) getEditList(),
297 }, // type
300 exec: function (args, context) {
301 if (args.filename) openEditor(args.filename, context.environment.chromeDocument.defaultView);
304 // package backend
306 name: "guerilla package",
307 description: "GuerillaJS package control",
310 name: "guerilla package abort",
311 description: "abort all operations",
312 exec: function (args, context) { pkgman.cancel(); },
315 name: "guerilla package list",
316 description: "list installed packages",
317 returnValue: "string",
318 params: [
320 name: "mask",
321 description: "mask",
322 defaultValue: "*",
323 type: "string",
326 exec: function (args, context) {
327 let mask = args.mask||"*";
328 let re = wild2re(mask);
329 let res = "=== package list ===";
330 let count = 0;
331 for (let pi of pkgDB.getActivePackages()) {
332 if (re.test(pi.name)) {
333 res += "\n"+pi.name;
334 if (pi.version) res += "\t"+pi.version;
335 ++count;
338 //return (count ? res : "no packages found");
339 //TODO: special output
340 logError(count ? res : "no packages found");
341 return "find result in error console";
345 name: "guerilla package update",
346 description: "update package(s)",
347 params: [
349 name: "mask",
350 description: "mask",
351 defaultValue: "",
352 type: "string",
355 exec: function (args, context) {
356 if (!args.mask) return;
357 let mask = args.mask||"*";
358 let re = wild2re(mask);
359 for (let pi of pkgDB.getActivePackages()) {
360 if (re.test(pi.name)) {
361 try {
362 pkgman.update(pi.name);
363 } catch (e) {
364 logError("ERROR: ", e.message);
371 name: "guerilla package install",
372 description: "install package",
373 params: [
375 name: "name",
376 description: "package name",
377 type: "string",
380 name: "url",
381 description: "package install url",
382 type: "string",
385 exec: function (args, context) {
386 if (!args.name || !args.url) return;
387 try {
388 pkgman.install(args.name, args.url);
389 } catch (e) {
390 logError("ERROR: ", e.message);
395 name: "guerilla package remove",
396 description: "remove package",
397 params: [
399 name: "name",
400 description: "package name",
401 type: {
402 name: "selection",
403 cacheable: false,
404 lookup: function (context) getPkgList(),
405 }, // type
408 exec: function (args, context) {
409 //if (!args.name.name) return;
410 try {
411 pkgman.remove(args.name.name);
412 } catch (e) {
413 logError("ERROR: ", e.message);
417 // wtf
419 name: "guerilla wtf",
420 description: "wtf",
421 params: [
423 name: "filename",
424 description: "file name",
425 //defaultValue: "",
426 type: "string",
429 exec: function (args, context) {
430 if (!args.filename) return;
431 try {
432 let h = calcFileSha512(args.filename);
433 logError("h="+h+"; "+args.filename);
434 } catch (e) {
435 logError("ERROR: ", e.message);
442 ////////////////////////////////////////////////////////////////////////////////
443 registerStartupHook("gcli", function () {
444 for (let f = 0; f < gcliCommandSpecs.length; ++f) {
445 if (gcliCommandSpecs[f].name) gcli.addCommand(gcliCommandSpecs[f]);
450 registerShutdownHook("gcli", function () {
451 for (let f = 0; f < gcliCommandSpecs.length; ++f) {
452 if (gcliCommandSpecs[f].name) gcli.removeCommand(gcliCommandSpecs[f]);