diff --git a/common/content/contexts.js b/common/content/contexts.js index 8fc22bd6..f674b3bc 100644 --- a/common/content/contexts.js +++ b/common/content/contexts.js @@ -51,6 +51,8 @@ var Group = Class("Group", { }) }); +plugins.contexts = {}; + var Contexts = Module("contexts", { init: function () { this.groupList = []; @@ -72,6 +74,10 @@ var Contexts = Module("contexts", { groups: { value: this.groupList } })), + activeGroups: function (subgroup) + let (need = subgroup ? [subgroup] : Object.keys(this.subGroup)) + this.groupList.filter(function (group) need.some(function (name) set.has(group, name))), + get subGroup() Group.subGroupMap, addGroup: function addGroup(name, description, filter, persist) { @@ -152,6 +158,44 @@ var Contexts = Module("contexts", { return action; } }, { + Context: modules.Script = function Context(file, group, args) { + let isPlugin = io.getRuntimeDirectories("plugins") + .some(function (dir) dir.contains(file, false)) + + let self = set.has(plugins, file.path) && plugins[file.path]; + if (self) { + if (set.has(self, "onUnload")) + self.onUnload(); + } + else { + self = update(modules.newContext.apply(null, args || [userContext]), { + NAME: file.leafName.replace(/\..*/, "").replace(/-([a-z])/g, function (m, n1) n1.toUpperCase()), + PATH: file.path, + CONTEXT: self + }); + Class.replaceProperty(plugins, file.path, self); + + // This belongs elsewhere + if (isPlugin && args) + Object.defineProperty(plugins, self.NAME, { + configurable: true, + enumerable: true, + value: self, + writeable: false + }); + } + + self.GROUP = group || + contexts.addGroup(isPlugin ? "plugin-" + self.NAME + : "script-" + array(commands.nameRegexp.iterate(file.path)).join("-"), + "Script group for " + file.path, + null, false); + + return plugins.contexts[file.path] = self; + }, + Script: function Script(file, group) { + return this.Context(file, group, [plugins, true]); + } }, { commands: function initCommands() { @@ -161,7 +205,7 @@ var Contexts = Module("contexts", { dactyl.assert(args.length <= 2, "Trailing characters"); if (args.length == 0) - return void completion.listCompleter("group", ""); + return void completion.listCompleter("group", "", null, null); let name = Option.dequote(args[0]); dactyl.assert(commands.validName.test(name), "Invalid group name"); @@ -306,10 +350,11 @@ var Contexts = Module("contexts", { }); }, completion: function initCompletion() { - completion.group = function group(context, modes) { + completion.group = function group(context, active) { context.title = ["Group"]; context.keys = { text: "name", description: function (h) h.description || h.filter }; - context.completions = contexts.groupList.slice(0, -1); + context.completions = (active === undefined ? contexts.groupList : contexts.activeGroups(active)) + .slice(0, -1); }; } }); diff --git a/common/content/dactyl.js b/common/content/dactyl.js index a9ea5907..e889769c 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1040,7 +1040,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { dir.readDirectory(true).forEach(function (file) { if (file.isFile() && loadplugins.getKey(file.path) && !(file.path in dactyl.pluginFiles)) { try { - io.source(file.path, false); + io.source(file.path); dactyl.pluginFiles[file.path] = true; } catch (e) { @@ -2075,14 +2075,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { if (dactyl.commandLineOptions.rcFile) { let filename = dactyl.commandLineOptions.rcFile; if (!/^(NONE|NORC)$/.test(filename)) - io.source(io.File(filename).path, false); // let io.source handle any read failure like Vim + io.source(io.File(filename).path, { group: contexts.user }); } else { if (init) dactyl.execute(init); else { if (rcFile) { - io.source(rcFile.path, false); + io.source(rcFile.path, { group: contexts.user }); services.environment.set("MY_" + config.idName + "RC", rcFile.path); } else @@ -2092,7 +2092,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { if (options["exrc"] && !dactyl.commandLineOptions.rcFile) { let localRCFile = io.getRCFile(io.cwd); if (localRCFile && !localRCFile.equals(rcFile)) - io.source(localRCFile.path, false); + io.source(localRCFile.path, { group: contexts.user }); } } diff --git a/common/modules/io.jsm b/common/modules/io.jsm index e0fdc00f..3354ddd9 100644 --- a/common/modules/io.jsm +++ b/common/modules/io.jsm @@ -29,7 +29,7 @@ var IO = Module("io", { this.config = config; }, - Local: function (dactyl, modules, window) let ({ Script, io, plugins } = modules) ({ + Local: function (dactyl, modules, window) let ({ io, plugins } = modules) ({ init: function init() { this.config = modules.config; @@ -144,18 +144,23 @@ var IO = Module("io", { * Reads Ex commands, JavaScript or CSS from *filename*. * * @param {string} filename The name of the file to source. - * @param {boolean} silent Whether errors should be reported. + * @param {object} params Extra parameters: + * group: The group in which to execute commands. + * silent: Whether errors should not be reported. */ - source: function source(filename, silent) { + source: function source(filename, params) { + const { Contexts, contexts } = modules; defineModule.loadLog.push("sourcing " + filename); + params = params || {}; + let time = Date.now(); - this.withSavedValues(["sourcing"], function _source() { - this.sourcing = null; + contexts.withSavedValues(["context"], function _source() { + contexts.context = null; try { var file = util.getFile(filename) || io.File(filename); if (!file.exists() || !file.isReadable() || file.isDirectory()) { - if (!silent) + if (!params.silent) dactyl.echoerr("E484: Can't open file " + filename.quote()); return; } @@ -167,7 +172,7 @@ var IO = Module("io", { // handle pure JavaScript files specially if (/\.js$/.test(filename)) { try { - dactyl.loadScript(uri.spec, Script(file)); + dactyl.loadScript(uri.spec, Contexts.Script(file, params.group)); dactyl.helpInitialized = false; } catch (e) { @@ -185,10 +190,14 @@ var IO = Module("io", { else if (/\.css$/.test(filename)) styles.registerSheet(uri.spec, false, true); else { - if (!(file.path in plugins)) - plugins[file.path] = modules.newContext(modules.userContext); - modules.commands.execute(file.read(), null, silent || "loud", null, - { file: file.path, line: 1, context: plugins[file.path] }); + let context = Contexts.Context(file, params.group); + modules.commands.execute(file.read(), null, params.silent || "loud", + null, { + context: context, + file: file.path, + group: context.GROUP, + line: 1 + }); } if (this._scriptNames.indexOf(file.path) == -1) @@ -202,13 +211,13 @@ var IO = Module("io", { if (!(e instanceof FailedAssertion)) dactyl.reportError(e); let message = "Sourcing file: " + (e.echoerr || file.path + ": " + e); - if (!silent) + if (!params.silent) dactyl.echoerr(message); } finally { defineModule.loadLog.push("done sourcing " + filename + ": " + (Date.now() - time) + "ms"); } - }); + }, this); }, }), @@ -545,35 +554,6 @@ var IO = Module("io", { */ PATH_SEP: deprecated("File.PATH_SEP", { get: function PATH_SEP() File.PATH_SEP }) }, { - init: function init(dactyl, modules, window) { - Class.replaceProperty(modules.plugins, "contexts", {}); - modules.Script = function Script(file) { - const { io, plugins } = modules; - - let self = set.has(plugins, file.path) && plugins[file.path]; - if (self) { - if (set.has(self, "onUnload")) - self.onUnload(); - } - else { - self = update(modules.newContext(plugins, true), { - NAME: file.leafName.replace(/\..*/, "").replace(/-([a-z])/g, function (m, n1) n1.toUpperCase()), - PATH: file.path, - CONTEXT: self - }); - Class.replaceProperty(plugins, file.path, self); - - // This belongs elsewhere - if (io.getRuntimeDirectories("plugins").some( - function (dir) dir.contains(file, false))) - Class.replaceProperty(plugins, self.NAME, self); - } - plugins.contexts[file.path] = self; - return self; - } - - init.superapply(this, arguments); - }, commands: function (dactyl, modules, window) { const { commands, completion, io } = modules;