X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fcontexts.jsm;h=ffada2b7635446021f543c06cdc5c2a6e8165f7b;hb=3d837eb266a3a01d424192aa4ec1a167366178c5;hp=f5d976cae6dc030069d379599edd318ee66abf63;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/modules/contexts.jsm b/common/modules/contexts.jsm index f5d976c..ffada2b 100644 --- a/common/modules/contexts.jsm +++ b/common/modules/contexts.jsm @@ -1,53 +1,71 @@ -// Copyright (c) 2010-2011 by Kris Maglione +// Copyright (c) 2010-2012 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. "use strict"; -try { - -Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("contexts", { exports: ["Contexts", "Group", "contexts"], - use: ["commands", "messages", "options", "services", "storage", "styles", "template", "util"] -}, this); + require: ["services", "util"] +}); + +lazyRequire("commands", ["ArgType", "CommandOption", "commands"]); +lazyRequire("options", ["Option"]); +lazyRequire("overlay", ["overlay"]); +lazyRequire("storage", ["File"]); +lazyRequire("template", ["template"]); var Const = function Const(val) Class.Property({ enumerable: true, value: val }); var Group = Class("Group", { init: function init(name, description, filter, persist) { - const self = this; - this.name = name; this.description = description; this.filter = filter || this.constructor.defaultFilter; this.persist = persist || false; this.hives = []; + this.children = []; }, + get contexts() this.modules.contexts, + + set lastDocument(val) { this._lastDocument = util.weakReference(val); }, + get lastDocument() this._lastDocument && this._lastDocument.get(), + modifiable: true, - cleanup: function cleanup() { + cleanup: function cleanup(reason) { for (let hive in values(this.hives)) util.trapErrors("cleanup", hive); this.hives = []; for (let hive in keys(this.hiveMap)) delete this[hive]; + + if (reason != "shutdown") + this.children.splice(0).forEach(this.contexts.closure.removeGroup); }, - destroy: function destroy() { + destroy: function destroy(reason) { for (let hive in values(this.hives)) util.trapErrors("destroy", hive); + + if (reason != "shutdown") + this.children.splice(0).forEach(this.contexts.closure.removeGroup); }, argsExtra: function argsExtra() ({}), + makeArgs: function makeArgs(doc, context, args) { + let res = update({ doc: doc, context: context }, args); + return update(res, this.argsExtra(res), args); + }, + get toStringParams() [this.name], get builtin() this.modules.contexts.builtinGroups.indexOf(this) >= 0, }, { - compileFilter: function (patterns, default_) { + compileFilter: function (patterns, default_ = false) { if (arguments.length < 2) default_ = false; @@ -58,19 +76,31 @@ var Group = Class("Group", { return update(siteFilter, { toString: function () this.filters.join(","), - toXML: function (modules) let (uri = modules && modules.buffer.uri) + toJSONXML: function (modules) let (uri = modules && modules.buffer.uri) template.map(this.filters, - function (f) {f}, - <>,), + function (f) ["span", { highlight: uri && f(uri) ? "Filter" : "" }, + "toJSONXML" in f ? f.toJSONXML() : String(f)], + ","), filters: Option.parse.sitelist(patterns) }); }, - defaultFilter: Class.memoize(function () this.compileFilter(["*"])) + defaultFilter: Class.Memoize(function () this.compileFilter(["*"])) }); var Contexts = Module("contexts", { + init: function () { + this.pluginModules = {}; + }, + + cleanup: function () { + for each (let module in this.pluginModules) + util.trapErrors("unload", module); + + this.pluginModules = {}; + }, + Local: function Local(dactyl, modules, window) ({ init: function () { const contexts = this; @@ -115,13 +145,13 @@ var Contexts = Module("contexts", { }, cleanup: function () { - for (let hive in values(this.groupList)) - util.trapErrors("cleanup", hive); + for each (let hive in this.groupList.slice()) + util.trapErrors("cleanup", hive, "shutdown"); }, destroy: function () { - for (let hive in values(this.groupList)) - util.trapErrors("destroy", hive); + for each (let hive in values(this.groupList.slice())) + util.trapErrors("destroy", hive, "shutdown"); for (let [name, plugin] in iter(this.modules.plugins.contexts)) if (plugin && "onUnload" in plugin && callable(plugin.onUnload)) @@ -139,13 +169,12 @@ var Contexts = Module("contexts", { Hives: Class("Hives", Class.Property, { init: function init(name, constructor) { const { contexts } = modules; - const self = this; if (this.Hive) return { enumerable: true, - get: function () array(contexts.groups[self.name]) + get: () => array(contexts.groups[this.name]) }; this.Hive = constructor; @@ -179,29 +208,42 @@ var Contexts = Module("contexts", { function (dir) dir.contains(file, true), 0); + let name = isPlugin ? file.getRelativeDescriptor(isPlugin).replace(File.PATH_SEP, "-") + : file.leafName; + let id = util.camelCase(name.replace(/\.[^.]*$/, "")); + let contextPath = file.path; let self = Set.has(plugins, contextPath) && plugins.contexts[contextPath]; + if (!self && isPlugin && false) + self = Set.has(plugins, id) && plugins[id]; + if (self) { if (Set.has(self, "onUnload")) - self.onUnload(); + util.trapErrors("onUnload", self); } else { - let name = isPlugin ? file.getRelativeDescriptor(isPlugin).replace(File.PATH_SEP, "-") - : file.leafName; + let params = Array.slice(args || [userContext]); + params[2] = params[2] || File(file).URI.spec; - self = args && !isArray(args) ? args : newContext.apply(null, args || [userContext]); + self = args && !isArray(args) ? args : newContext.apply(null, params); update(self, { - NAME: Const(name.replace(/\.[^.]*$/, "").replace(/-([a-z])/g, function (m, n1) n1.toUpperCase())), + NAME: Const(id), PATH: Const(file.path), CONTEXT: Const(self), + set isGlobalModule(val) { + // Hack. + if (val) + throw Contexts; + }, + unload: Const(function unload() { if (plugins[this.NAME] === this || plugins[this.PATH] === this) if (this.onUnload) - this.onUnload(); + util.trapErrors("onUnload", this); if (plugins[this.NAME] === this) delete plugins[this.NAME]; @@ -252,6 +294,74 @@ var Contexts = Module("contexts", { return this.Context(file, group, [this.modules.userContext, true]); }, + Module: function Module(uri, isPlugin) { + const { io, plugins } = this.modules; + + let canonical = uri.spec; + if (uri.scheme == "resource") + canonical = services["resource:"].resolveURI(uri); + + if (uri instanceof Ci.nsIFileURL) + var file = File(uri.file); + + let isPlugin = array.nth(io.getRuntimeDirectories("plugins"), + function (dir) dir.contains(file, true), + 0); + + let name = isPlugin && file && file.getRelativeDescriptor(isPlugin) + .replace(File.PATH_SEP, "-"); + let id = util.camelCase(name.replace(/\.[^.]*$/, "")); + + let self = Set.has(this.pluginModules, canonical) && this.pluginModules[canonical]; + + if (!self) { + self = Object.create(jsmodules); + + update(self, { + NAME: Const(id), + + PATH: Const(file && file.path), + + CONTEXT: Const(self), + + get isGlobalModule() true, + set isGlobalModule(val) { + util.assert(val, "Loading non-global module as global", + false); + }, + + unload: Const(function unload() { + if (contexts.pluginModules[canonical] == this) { + if (this.onUnload) + util.trapErrors("onUnload", this); + + delete contexts.pluginModules[canonical]; + } + + for each (let { plugins } in overlay.modules) + if (plugins[this.NAME] == this) + delete plugins[this.name]; + }) + }); + + JSMLoader.loadSubScript(uri.spec, self, File.defaultEncoding); + this.pluginModules[canonical] = self; + } + + // This belongs elsewhere + if (isPlugin) + Object.defineProperty(plugins, self.NAME, { + configurable: true, + enumerable: true, + get: function () self, + set: function (val) { + util.dactyl(val).reportError(FailedAssertion(_("plugin.notReplacingContext", self.NAME), 3, false), true); + } + }); + + return self; + }, + context: null, /** @@ -265,15 +375,15 @@ var Contexts = Module("contexts", { return { __proto__: frame, filename: this.context.file[0] == "[" ? this.context.file - : services.io.newFileURI(File(this.context.file)).spec, + : File(this.context.file).URI.spec, lineNumber: this.context.line }; return frame; }, - groups: Class.memoize(function () this.matchingGroups(this.modules.buffer.uri)), + groups: Class.Memoize(function () this.matchingGroups()), - allGroups: Class.memoize(function () Object.create(this.groupsProto, { + allGroups: Class.Memoize(function () Object.create(this.groupsProto, { groups: { value: this.initializedGroups() } })), @@ -281,10 +391,19 @@ var Contexts = Module("contexts", { groups: { value: this.activeGroups(uri) } }), - activeGroups: function (uri, doc) { + activeGroups: function (uri) { + if (uri instanceof Ci.nsIDOMDocument) + var [doc, uri] = [uri, uri.documentURIObject || util.newURI(uri.documentURI)]; + if (!uri) - ({ uri, doc }) = this.modules.buffer; - return this.initializedGroups().filter(function (g) uri && g.filter(uri, doc)); + var { uri, doc } = this.modules.buffer; + + return this.initializedGroups().filter(function (g) { + let res = uri && g.filter(uri, doc); + if (doc) + g.lastDocument = res && doc; + return res; + }); }, flush: function flush() { @@ -310,6 +429,7 @@ var Contexts = Module("contexts", { if (replace) { util.trapErrors("cleanup", group); + if (description) group.description = description; if (filter) @@ -321,7 +441,7 @@ var Contexts = Module("contexts", { return group; }, - removeGroup: function removeGroup(name, filter) { + removeGroup: function removeGroup(name) { if (isObject(name)) { if (this.groupList.indexOf(name) === -1) return; @@ -361,10 +481,12 @@ var Contexts = Module("contexts", { getDocs: function getDocs(context) { try { if (isinstance(context, ["Sandbox"])) { - let info = "INFO" in context && Cu.evalInSandbox("this.INFO instanceof XML && INFO.toXMLString()", context); - return info && XML(info); + let info = "INFO" in context && Cu.evalInSandbox("this.INFO instanceof XML ? INFO.toXMLString() : this.INFO", context); + return /^{g.filter.toXML ? g.filter.toXML(modules) + <>  : ""}{g.description || ""} + description: function (g) ["", g.filter.toJSONXML ? g.filter.toJSONXML(modules).concat("\u00a0") : "", g.description || ""] }; context.completions = (active === undefined ? contexts.groupList : contexts.initializedGroups(active)) .slice(0, -1); @@ -680,6 +814,6 @@ var Contexts = Module("contexts", { endModule(); -} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); } +// catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); } -// vim: set fdm=marker sw=4 ts=4 et ft=javascript: +// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: