X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fcontexts.jsm;fp=common%2Fmodules%2Fcontexts.jsm;h=468193659893eb51ef2d84fead71f676b2ba1c92;hb=9044153cb63835e39b9de8ec4ade237c03e3888a;hp=f5d976cae6dc030069d379599edd318ee66abf63;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/modules/contexts.jsm b/common/modules/contexts.jsm index f5d976c..4681936 100644 --- a/common/modules/contexts.jsm +++ b/common/modules/contexts.jsm @@ -2,16 +2,16 @@ // // 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 { +/* use strict */ Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("contexts", { exports: ["Contexts", "Group", "contexts"], - use: ["commands", "messages", "options", "services", "storage", "styles", "template", "util"] + require: ["services", "util"] }, this); +this.lazyRequire("overlay", ["overlay"]); + var Const = function Const(val) Class.Property({ enumerable: true, value: val }); var Group = Class("Group", { @@ -23,25 +23,42 @@ var Group = Class("Group", { 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, @@ -67,10 +84,21 @@ var Group = Class("Group", { }); }, - 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 +143,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)) @@ -179,29 +207,39 @@ 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; - self = args && !isArray(args) ? args : newContext.apply(null, args || [userContext]); 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 +290,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, /** @@ -271,9 +377,9 @@ var Contexts = Module("contexts", { 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 +387,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 +425,7 @@ var Contexts = Module("contexts", { if (replace) { util.trapErrors("cleanup", group); + if (description) group.description = description; if (filter) @@ -321,7 +437,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; @@ -401,7 +517,7 @@ var Contexts = Module("contexts", { /* fallthrough */ case "-keys": let silent = args["-silent"]; - rhs = events.canonicalKeys(rhs, true); + rhs = DOM.Event.canonicalKeys(rhs, true); var action = function action() { events.feedkeys(action.macro(makeParams(this, arguments)), noremap, silent); @@ -450,6 +566,7 @@ var Contexts = Module("contexts", { get modifiable() this.group.modifiable, get argsExtra() this.group.argsExtra, + get makeArgs() this.group.makeArgs, get builtin() this.group.builtin, get name() this.group.name, @@ -464,7 +581,7 @@ var Contexts = Module("contexts", { get persist() this.group.persist, set persist(val) this.group.persist = val, - prefix: Class.memoize(function () this.name === "builtin" ? "" : this.name + ":"), + prefix: Class.Memoize(function () this.name === "builtin" ? "" : this.name + ":"), get toStringParams() [this.name] }) @@ -507,8 +624,19 @@ var Contexts = Module("contexts", { group.args = args["-args"]; } - if (args.context) + if (args.context) { args.context.group = group; + if (args.context.context) { + args.context.context.group = group; + + let parent = args.context.context.GROUP; + if (parent && parent != group) { + group.parent = parent; + if (!~parent.children.indexOf(group)) + parent.children.push(group); + } + } + } util.assert(!group.builtin || !["-description", "-locations", "-nopersist"] @@ -680,6 +808,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: