diff --git a/common/content/autocommands.js b/common/content/autocommands.js index 7f31c44a..5bd58e43 100644 --- a/common/content/autocommands.js +++ b/common/content/autocommands.js @@ -71,12 +71,6 @@ var AutoCmdHive = Class("AutoCmdHive", Contexts.Hive, { */ var AutoCommands = Module("autocommands", { init: function () { - update(this, { - hives: contexts.Hives("autocmd", AutoCmdHive), - user: contexts.hives.autocmd.user, - allHives: contexts.allGroups.autocmd, - matchingHives: function matchingHives(uri, doc) contexts.matchingGroups(uri, doc).autocmd - }); }, get activeHives() contexts.allGroups.autocmd.filter(function (h) h._store.length), @@ -172,6 +166,14 @@ var AutoCommands = Module("autocommands", { } }, { }, { + contexts: function () { + update(AutoCommands.prototype, { + hives: contexts.Hives("autocmd", AutoCmdHive), + user: contexts.hives.autocmd.user, + allHives: contexts.allGroups.autocmd, + matchingHives: function matchingHives(uri, doc) contexts.matchingGroups(uri, doc).autocmd + }); + }, commands: function () { commands.add(["au[tocmd]"], "Execute commands automatically on events", diff --git a/common/content/commandline.js b/common/content/commandline.js index 8519fa22..b66ec5b7 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -1915,7 +1915,7 @@ var ItemList = Class("ItemList", { // would force a reflow after each DOM modification. this.activeGroups.filter(function (g) !g.collapsed) .map(function (g) g.rescrollFunc) - .forEach(function (f) f()); + .forEach(call); this._resize.tell(ItemList.RESIZE_BRIEF); }, diff --git a/common/content/dactyl.js b/common/content/dactyl.js index f291aa17..8c9c7d24 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1611,6 +1611,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { if (args.trailing) storage.session.rehashCmd = args.trailing; // Hack. args.break = true; + + if (args["+purgecaches"]) + cache.flush(); + util.rehash(args); }, { @@ -1620,7 +1624,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { commands.add(["res[tart]"], "Force " + config.host + " to restart", - function (args) { dactyl.restart(args.string); }, + function (args) { + if (args["+purgecaches"]) + cache.flush(); + + dactyl.restart(args.string); + }, { argCount: "0", options: startupOptions @@ -1838,9 +1847,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { args = dactyl.parseCommandLine(args); if (args) { - if (args["+purgecaches"]) - cache.flush(); - dactyl.commandLineOptions.rcFile = args["+u"]; dactyl.commandLineOptions.noPlugins = "++noplugin" in args; dactyl.commandLineOptions.postCommands = args["+c"]; diff --git a/common/content/editor.js b/common/content/editor.js index 55553ae2..9d33f5d9 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -1237,9 +1237,7 @@ var Editor = Module("editor", XPCOM(Ci.nsIEditActionListener, ModuleBase), { var range = editor.selectedRange; if (range.collapsed) { count = count || 1; - util.dump(count, range); Editor.extendRange(range, true, { test: function (c) !!count-- }, true); - util.dump(count, range); } editor.mungeRange(range, munger, count != null); diff --git a/common/content/history.js b/common/content/history.js index 30d5935c..d87f4471 100644 --- a/common/content/history.js +++ b/common/content/history.js @@ -122,8 +122,6 @@ var History = Module("history", { steps -= sign; } - util.dump(idx, sh.index, sh.length, steps); - dactyl.assert(idx != null); sh.index = idx; }, diff --git a/common/modules/cache.jsm b/common/modules/cache.jsm index 4dfbcedb..cebd562e 100644 --- a/common/modules/cache.jsm +++ b/common/modules/cache.jsm @@ -15,6 +15,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { this.queue = []; this.cache = {}; this.providers = {}; + this.globalProviders = this.providers; this.providing = {}; this.localProviders = {}; @@ -173,7 +174,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { if (Set.has(this.localProviders, name) && !this.isLocal) { for each (let { cache } in overlay.modules) - if (cache.has(name)) + if (cache._has(name)) return cache.force(name, true); } @@ -209,7 +210,10 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { return this.cache[name]; }, - has: function has(name) Set.has(this.providers, name) || set.has(this.cache, name), + _has: function _has(name) Set.has(this.providers, name) || set.has(this.cache, name), + + has: function has(name) [this.globalProviders, this.cache, this.localProviders] + .some(function (obj) Set.has(obj, name)), register: function register(name, callback, self) { if (this.isLocal) diff --git a/common/modules/commands.jsm b/common/modules/commands.jsm index f7f99bda..5ceb25eb 100644 --- a/common/modules/commands.jsm +++ b/common/modules/commands.jsm @@ -188,8 +188,7 @@ var Command = Class("Command", { * @param {string} name The candidate name. * @returns {boolean} */ - hasName: function hasName(name) this.parsedSpecs.some( - function ([long, short]) name.indexOf(short) == 0 && long.indexOf(name) == 0), + hasName: function hasName(name) Command.hasName(this.parsedSpecs, name), /** * A helper function to parse an argument string. @@ -329,7 +328,7 @@ var Command = Class("Command", { }); this.options.forEach(function (opt) { - if (opt.default !== undefined) + if ("default" in opt) Object.defineProperty(res, opt.names[0], Object.getOwnPropertyDescriptor(opt, "default") || { configurable: true, enumerable: true, get: function () opt.default }); @@ -386,6 +385,10 @@ var Command = Class("Command", { this.modules.dactyl.warn(loc + message); } }, { + hasName: function hasName(specs, name) + specs.some(function ([long, short]) + name.indexOf(short) == 0 && long.indexOf(name) == 0), + // TODO: do we really need more than longNames as a convenience anyway? /** * Converts command name abbreviation specs of the form @@ -463,12 +466,56 @@ var Ex = Module("Ex", { var CommandHive = Class("CommandHive", Contexts.Hive, { init: function init(group) { init.supercall(this, group); + this._map = {}; this._list = []; + this._specs = []; }, + /** + * Caches this command hive. + */ + + cache: function cache() { + let self = this; + let { cache } = this.modules; + this.cached = true; + + cache.register(this.cacheKey, function () { + self.cached = false; + this.modules.moduleManager.initDependencies("commands"); + + let map = {}; + for (let [name, cmd] in Iterator(self._map)) + if (cmd.sourceModule) + map[name] = { sourceModule: cmd.sourceModule, isPlaceholder: true }; + + let specs = []; + for (let cmd in values(self._list)) + for each (let spec in cmd.parsedSpecs) + specs.push(spec.concat(cmd.name)); + + return { map: map, specs: specs }; + }); + + let cached = cache.get(this.cacheKey); + if (this.cached) { + this._specs = cached.specs; + for (let [k, v] in Iterator(cached.map)) + this._map[k] = v; + } + }, + + get cacheKey() "commands/hives/" + this.name + ".json", + /** @property {Iterator(Command)} @private */ - __iterator__: function __iterator__() array.iterValues(this._list.sort(function (a, b) a.name > b.name)), + __iterator__: function __iterator__() { + util.dumpStack("ITERATOR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! eleventy one eleven!"); + if (this.cached) + this.modules.initDependencies("commands"); + this.cached = false; + return array.iterValues(this._list.sort(function (a, b) a.name > b.name)) + }, /** @property {string} The last executed Ex command line. */ repeat: null, @@ -491,6 +538,8 @@ var CommandHive = Class("CommandHive", Contexts.Hive, { extra = extra || {}; if (!extra.definedAt) extra.definedAt = contexts.getCaller(Components.stack.caller); + if (!extra.sourceModule) + extra.sourceModule = commands.currentDependency; extra.hive = this; extra.parsedSpecs = Command.parseSpecs(specs); @@ -498,15 +547,17 @@ var CommandHive = Class("CommandHive", Contexts.Hive, { let names = array.flatten(extra.parsedSpecs); let name = names[0]; - util.assert(!names.some(function (name) name in commands.builtin._map), - _("command.cantReplace", name)); + if (this.name != "builtin") { + util.assert(!names.some(function (name) name in commands.builtin._map), + _("command.cantReplace", name)); - util.assert(replace || names.every(function (name) !(name in this._map), this), - _("command.wontReplace", name)); + util.assert(replace || names.every(function (name) !(name in this._map), this), + _("command.wontReplace", name)); + } for (let name in values(names)) { ex.__defineGetter__(name, function () this._run(name)); - if (name in this._map) + if (name in this._map && !this._map[name].isPlaceholder) this.remove(name); } @@ -549,9 +600,22 @@ var CommandHive = Class("CommandHive", Contexts.Hive, { * its names matches *name* exactly. * @returns {Command} */ - get: function get(name, full) this._map[name] - || !full && array.nth(this._list, function (cmd) cmd.hasName(name), 0) - || null, + get: function get(name, full) { + let cmd = this._map[name] + || !full && array.nth(this._list, function (cmd) cmd.hasName(name), 0) + || null; + + if (!cmd && full) { + let name = array.nth(this.specs, function (spec) Command.hasName(spec, name), 0); + return name && this.get(name); + } + + if (cmd && cmd.isPlaceholder) { + this.modules.moduleManager.initDependencies("commands", [cmd.sourceModule]); + cmd = this._map[name]; + } + return cmd; + }, /** * Remove the user-defined command with matching *name*. @@ -574,6 +638,7 @@ var CommandHive = Class("CommandHive", Contexts.Hive, { */ var Commands = Module("commands", { lazyInit: true, + lazyDepends: true, Local: function Local(dactyl, modules, window) let ({ Group, contexts } = modules) ({ init: function init() { @@ -585,6 +650,13 @@ var Commands = Module("commands", { }); }, + reallyInit: function reallyInit() { + if (false) + this.builtin.cache(); + else + this.modules.moduleManager.initDependencies("commands"); + }, + get context() contexts.context, get readHeredoc() modules.io.readHeredoc, diff --git a/common/modules/contexts.jsm b/common/modules/contexts.jsm index 0cf60472..ed43c3eb 100644 --- a/common/modules/contexts.jsm +++ b/common/modules/contexts.jsm @@ -4,8 +4,6 @@ // 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"], @@ -35,7 +33,7 @@ var Group = Class("Group", { modifiable: true, - cleanup: function cleanup() { + cleanup: function cleanup(reason) { for (let hive in values(this.hives)) util.trapErrors("cleanup", hive); @@ -43,13 +41,15 @@ var Group = Class("Group", { for (let hive in keys(this.hiveMap)) delete this[hive]; - this.children.splice(0).forEach(this.contexts.closure.removeGroup); + 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); - this.children.splice(0).forEach(this.contexts.closure.removeGroup); + if (reason != "shutdown") + this.children.splice(0).forEach(this.contexts.closure.removeGroup); }, argsExtra: function argsExtra() ({}), @@ -143,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)) @@ -808,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: diff --git a/common/modules/dom.jsm b/common/modules/dom.jsm index 06aef32b..ea3e857f 100644 --- a/common/modules/dom.jsm +++ b/common/modules/dom.jsm @@ -879,7 +879,6 @@ var DOM = Class("DOM", { if (isect.height < Math.min(viewport.height, rect.height)) { let { top } = parent.scrollPos(); - util.dump(" " + top + " " + (viewport.top - rect.top) + " " + (viewport.bottom - rect.bottom)); if (getAlignment(viewport)) parent.scrollPos(null, top - (viewport.top - rect.top)); else diff --git a/common/modules/main.jsm b/common/modules/main.jsm index 834551eb..d2a2cf17 100644 --- a/common/modules/main.jsm +++ b/common/modules/main.jsm @@ -171,6 +171,9 @@ config.loadStyles(); overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({ ready: function onInit(document) { const modules = Modules(window); + modules.moduleManager = this; + this.modules = modules; + window.dactyl = { modules: modules }; defineModule.time("load", null, function _load() { @@ -183,117 +186,50 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({ }, load: function onLoad(document) { - // This is getting to be horrible. --Kris + let self = this; - var { modules, Module } = window.dactyl.modules; + var { modules, Module } = this.modules; delete window.dactyl; this.startTime = Date.now(); - const deferredInit = { load: {} }; - const seen = Set(); - const loaded = Set(); - modules.loaded = loaded; - - function load(module, prereq, frame) { - if (isString(module)) { - if (!Module.constructors.hasOwnProperty(module)) - modules.load(module); - module = Module.constructors[module]; - } - - try { - if (module.className in loaded) - return; - - if (module.className in seen) - throw Error("Module dependency loop."); - - Set.add(seen, module.className); - - for (let dep in values(module.requires)) - load(Module.constructors[dep], module.className); - - defineModule.loadLog.push("Load" + (isString(prereq) ? " " + prereq + " dependency: " : ": ") + module.className); - - if (frame && frame.filename) - defineModule.loadLog.push(" from: " + util.fixURI(frame.filename) + ":" + frame.lineNumber); - - let obj = defineModule.time(module.className, "init", module); - Class.replaceProperty(modules, module.className, obj); - - loaded[module.className] = true; - - if (loaded.dactyl && obj.signals) - modules.dactyl.registerObservers(obj); - - frob(module.className); - } - catch (e) { - util.dump("Loading " + (module && module.className) + ":"); - util.reportError(e); - } - return modules[module.className]; - } - - function deferInit(name, INIT, mod) { - let init = deferredInit[name] = deferredInit[name] || {}; - let className = mod.className || mod.constructor.className; - - init[className] = function callee() { - if (!callee.frobbed) - defineModule.time(className, name, INIT[name], mod, - modules.dactyl, modules, window); - callee.frobbed = true; - }; - - INIT[name].require = function (name) { init[name](); }; - } - - function frobModules() { - Module.list.forEach(function frobModule(mod) { - if (!mod.frobbed) { - modules.__defineGetter__(mod.className, function () { - delete modules[mod.className]; - return load(mod.className, null, Components.stack.caller); - }); - Object.keys(mod.prototype.INIT) - .forEach(function (name) { deferInit(name, mod.prototype.INIT, mod); }); - } - mod.frobbed = true; - }); - } + this.deferredInit = { load: {} }; + this.seen = {}; + this.loaded = {}; + modules.loaded = this.loaded; defineModule.modules.forEach(function defModule(mod) { let names = Set(Object.keys(mod.INIT)); if ("init" in mod.INIT) Set.add(names, "init"); - keys(names).forEach(function (name) { deferInit(name, mod.INIT, mod); }); + keys(names).forEach(function (name) { self.deferInit(name, mod.INIT, mod); }); }); - - function frob(name) { values(deferredInit[name] || {}).forEach(call); } - this.frob = frob; this.modules = modules; - frobModules(); - frob("init"); + this.scanModules(); + this.initDependencies("init"); modules.config.scripts.forEach(modules.load); - frobModules(); + this.scanModules(); defineModule.modules.forEach(function defModule({ lazyInit, constructor: { className } }) { if (!lazyInit) { - frob(className); Class.replaceProperty(modules, className, modules[className]); + this.initDependencies(className); } else modules.__defineGetter__(className, function () { - delete modules[className]; - frob(className); - return modules[className] = modules[className]; + let module = modules.jsmodules[className]; + Class.replaceProperty(modules, className, module); + if (module.reallyInit) + module.reallyInit(); // :( + + if (!module.lazyDepends) + self.initDependencies(className); + return module; }); - }); + }, this); }, cleanup: function cleanup(window) { @@ -311,12 +247,106 @@ overlay.overlayWindow(Object.keys(config.overlays), function _overlay(window) ({ visible: function visible(window) { // Module.list.forEach(load); - this.frob("load"); + this.initDependencies("load"); this.modules.times = update({}, defineModule.times); defineModule.loadLog.push("Loaded in " + (Date.now() - this.startTime) + "ms"); overlay.windows = array.uniq(overlay.windows.concat(window), true); + }, + + loadModule: function loadModule(module, prereq, frame) { + let { loaded, seen } = this; + let { Module, modules } = this.modules; + + if (isString(module)) { + if (!Module.constructors.hasOwnProperty(module)) + modules.load(module); + module = Module.constructors[module]; + } + + try { + if (Set.has(loaded, module.className)) + return; + + if (Set.add(seen, module.className)) + throw Error("Module dependency loop."); + + for (let dep in values(module.requires)) + this.loadModule(Module.constructors[dep], module.className); + + defineModule.loadLog.push( + "Load" + (isString(prereq) ? " " + prereq + " dependency: " : ": ") + + module.className); + + if (frame && frame.filename) + defineModule.loadLog.push(" from: " + util.fixURI(frame.filename) + ":" + frame.lineNumber); + + let obj = defineModule.time(module.className, "init", module); + Class.replaceProperty(modules, module.className, obj); + + Set.add(loaded, module.className); + + if (loaded.dactyl && obj.signals) + modules.dactyl.registerObservers(obj); + + if (!module.lazyDepends) + this.initDependencies(module.className); + } + catch (e) { + util.dump("Loading " + (module && module.className) + ":"); + util.reportError(e); + } + return modules[module.className]; + }, + + deferInit: function deferInit(name, INIT, mod) { + let { modules } = this.modules; + + let init = this.deferredInit[name] || {}; + this.deferredInit[name] = init; + + let className = mod.className || mod.constructor.className; + + init[className] = function callee() { + function finish() { + this.currentDependency = className; + defineModule.time(className, name, INIT[name], mod, + modules.dactyl, modules, window); + } + if (!callee.frobbed) { + callee.frobbed = true; + if (modules[name] instanceof Class) + modules[name].withSavedValues(["currentDependency"], finish); + else + finish.call({}); + } + }; + + INIT[name].require = function (name) { init[name](); }; + }, + + scanModules: function scanModules() { + let self = this; + let { Module, modules } = this.modules; + + Module.list.forEach(function frobModule(mod) { + if (!mod.frobbed) { + modules.__defineGetter__(mod.className, function () { + delete modules[mod.className]; + return self.loadModule(mod.className, null, Components.stack.caller); + }); + Object.keys(mod.prototype.INIT) + .forEach(function (name) { self.deferInit(name, mod.prototype.INIT, mod); }); + } + mod.frobbed = true; + }); + }, + + initDependencies: function initDependencies(name, parents) { + for (let [k, v] in Iterator(this.deferredInit[name] || {})) + if (!parents || ~parents.indexOf(k)) + util.trapErrors(v); } }));