diff --git a/common/content/abbreviations.js b/common/content/abbreviations.js index 030adc90..c7f5519e 100644 --- a/common/content/abbreviations.js +++ b/common/content/abbreviations.js @@ -39,9 +39,104 @@ var Abbreviation = Class("Abbreviation", { } }); +var AbbrevHive = Class("AbbrevHive", Contexts.Hive, { + init: function init(group) { + init.superapply(this, arguments); + this._store = {}; + }, + + get empty() !values(this._store).nth(util.identity, 0), + + /** + * Adds a new abbreviation. + * + * @param {Abbreviation} abbr The abbreviation to add. + */ + add: function (abbr) { + if (!(abbr instanceof Abbreviation)) + abbr = Abbreviation.apply(null, arguments); + + for (let [, mode] in Iterator(abbr.modes)) { + if (!this._store[mode]) + this._store[mode] = {}; + this._store[mode][abbr.lhs] = abbr; + } + }, + + /** + * Returns the abbreviation with *lhs* in the given *mode*. + * + * @param {Mode} mode The mode of the abbreviation. + * @param {string} lhs The LHS of the abbreviation. + */ + get: function (mode, lhs) { + let abbrevs = this._store[mode]; + return abbrevs && set.has(abbrevs, lhs) ? abbrevs[lhs] : null; + }, + + /** + * @property {Abbreviation[]} The list of the abbreviations merged from + * each mode. + */ + get merged() { + let result = []; + let lhses = []; + let modes = [mode for (mode in this._store)]; + + for (let [, abbrevs] in Iterator(this._store)) + lhses = lhses.concat([key for (key in abbrevs)]); + lhses.sort(); + lhses = array.uniq(lhses); + + for (let [, lhs] in Iterator(lhses)) { + let exists = {}; + for (let [, abbrevs] in Iterator(this._store)) { + let abbr = abbrevs[lhs]; + if (abbr && !exists[abbr.rhs]) { + exists[abbr.rhs] = 1; + result.push(abbr); + } + } + } + + return result; + }, + + /** + * Remove the specified abbreviations. + * + * @param {Array} modes List of modes. + * @param {string} lhs The LHS of the abbreviation. + * @returns {boolean} Did the deleted abbreviation exist? + */ + remove: function (modes, lhs) { + let result = false; + for (let [, mode] in Iterator(modes)) { + if ((mode in this._store) && (lhs in this._store[mode])) { + result = true; + this._store[mode][lhs].removeMode(mode); + delete this._store[mode][lhs]; + } + } + return result; + }, + + /** + * Removes all abbreviations specified in *modes*. + * + * @param {Array} modes List of modes. + */ + clear: function (modes) { + for (let mode in values(modes)) { + for (let abbr in values(this._store[mode])) + abbr.removeMode(mode); + delete this._store[mode]; + } + } +}); + var Abbreviations = Module("abbreviations", { init: function () { - this._store = {}; // (summarized from Vim's ":help abbreviations") // @@ -89,32 +184,10 @@ var Abbreviations = Module("abbreviations", { ]]>, "", params); }, - /** - * Adds a new abbreviation. - * - * @param {Abbreviation} abbr The abbreviation to add. - */ - add: function (abbr) { - if (!(abbr instanceof Abbreviation)) - abbr = Abbreviation.apply(null, arguments); - - for (let [, mode] in Iterator(abbr.modes)) { - if (!this._store[mode]) - this._store[mode] = {}; - this._store[mode][abbr.lhs] = abbr; - } - }, - - /** - * Returns the abbreviation with *lhs* in the given *mode*. - * - * @param {Mode} mode The mode of the abbreviation. - * @param {string} lhs The LHS of the abbreviation. - */ - get: function (mode, lhs) { - let abbrevs = this._store[mode]; - return abbrevs && set.has(abbrevs, lhs) ? abbrevs[lhs] : null; - }, + get: deprecated("group.abbrevs.get", { get: function get() this.user.closure.get }), + set: deprecated("group.abbrevs.set", { get: function set() this.user.closure.set }), + remove: deprecated("group.abbrevs.remove", { get: function remove() this.user.closure.remove }), + removeAll: deprecated("group.abbrevs.clear", { get: function removeAll() this.user.closure.clear }), /** * Returns the abbreviation for the given *mode* if *text* matches the @@ -128,38 +201,10 @@ var Abbreviations = Module("abbreviations", { match: function (mode, text) { let match = this._match.exec(text); if (match) - return abbreviations.get(mode, match[2] || match[4] || match[6]); + return this.hives.map(function (h) h.get(mode, match[2] || match[4] || match[6])).nth(util.identity, 0); return null; }, - /** - * @property {Abbreviation[]} The list of the abbreviations merged from - * each mode. - */ - get merged() { - let result = []; - let lhses = []; - let modes = [mode for (mode in this._store)]; - - for (let [, abbrevs] in Iterator(this._store)) - lhses = lhses.concat([key for (key in abbrevs)]); - lhses.sort(); - lhses = array.uniq(lhses); - - for (let [, lhs] in Iterator(lhses)) { - let exists = {}; - for (let [, abbrevs] in Iterator(this._store)) { - let abbr = abbrevs[lhs]; - if (abbr && !exists[abbr.rhs]) { - exists[abbr.rhs] = 1; - result.push(abbr); - } - } - } - - return result; - }, - /** * Lists all abbreviations matching *modes* and *lhs*. * @@ -167,61 +212,54 @@ var Abbreviations = Module("abbreviations", { * @param {string} lhs The LHS of the abbreviation. */ list: function (modes, lhs) { - let list = this.merged.filter(function (abbr) (abbr.inModes(modes) && abbr.lhs.indexOf(lhs) == 0)); + let hives = contexts.allGroups.abbrevs.filter(function (h) !h.empty); - if (!list.length) + function abbrevs(hive) + hive.merged.filter(function (abbr) (abbr.inModes(modes) && abbr.lhs.indexOf(lhs) == 0)); + + let list = + + + + + + + { + template.map(hives, function (hive) let (i = 0) + + + template.map(abbrevs(hive), function (abbrev) + + + + + + ) + + ) + } +
+ ModeAbbrevReplacement
{!i++ ? hive.name : ""}{abbrev.modeChar}{abbrev.lhs}{abbrev.rhs}
; + + // TODO: Move this to an ItemList to show this automatically + if (list.*.length() === list.text().length() + 2) dactyl.echomsg("No abbreviations found"); - else if (list.length == 1) { - let head = list[0]; - dactyl.echo(head.modeChar + " " + head.lhs + " " + head.rhs, commandline.FORCE_SINGLELINE); // 2 spaces, 3 spaces - } - else { - list = list.map(function (abbr) [abbr.modeChar, abbr.lhs, abbr.rhs]); - list = template.tabular(["", "LHS", "RHS"], [], list); - commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE); - } - }, - - /** - * Remove the specified abbreviations. - * - * @param {Array} modes List of modes. - * @param {string} lhs The LHS of the abbreviation. - * @returns {boolean} Did the deleted abbreviation exist? - */ - remove: function (modes, lhs) { - let result = false; - for (let [, mode] in Iterator(modes)) { - if ((mode in this._store) && (lhs in this._store[mode])) { - result = true; - this._store[mode][lhs].removeMode(mode); - delete this._store[mode][lhs]; - } - } - return result; - }, - - /** - * Removes all abbreviations specified in *modes*. - * - * @param {Array} modes List of modes. - */ - removeAll: function (modes) { - for (let [, mode] in modes) { - if (!(mode in this._store)) - return; - for (let [, abbr] in this._store[mode]) - abbr.removeMode(mode); - delete this._store[mode]; - } + else + commandline.commandOutput(list); } + }, { }, { + contexts: function initContexts(dactyl, modules, window) { + update(Abbreviations.prototype, { + hives: contexts.Hives("abbrevs", AbbrevHive), + user: contexts.hives.abbrevs.user + }); + }, completion: function () { - completion.abbreviation = function abbreviation(context, modes) { + completion.abbreviation = function abbreviation(context, modes, group) { + group = group || abbreviations.user; let fn = modes ? function (abbr) abbr.inModes(modes) : util.identity; context.keys = { text: "lhs" , description: "rhs" }; - context.completions = abbreviations.merged.filter(fn); + context.completions = group.merged.filter(fn); }; }, @@ -242,18 +280,19 @@ var Abbreviations = Module("abbreviations", { else { if (args["-javascript"]) rhs = contexts.bindMacro({ literalArg: rhs }, "-javascript", ["editor"]); - abbreviations.add(modes, lhs, rhs); + args["-group"].add(modes, lhs, rhs); } }, { completer: function (context, args) { if (args.length == 1) - return completion.abbreviation(context, modes); + return completion.abbreviation(context, modes, args["-group"]); else if (args["-javascript"]) return completion.javascript(context); }, hereDoc: true, literal: 1, options: [ + contexts.GroupFlag("abbrevs"), { names: ["-javascript", "-js", "-j"], description: "Expand this abbreviation by evaluating its right-hand-side as JavaScript" @@ -266,7 +305,7 @@ var Abbreviations = Module("abbreviations", { literalArg: abbr.rhs, options: callable(abbr.rhs) ? {"-javascript": null} : {} } - for ([, abbr] in Iterator(abbreviations.merged)) + for ([, abbr] in Iterator(abbreviations.user.merged)) if (abbr.modesEqual(modes)) ] }); @@ -277,18 +316,22 @@ var Abbreviations = Module("abbreviations", { let lhs = args.literalArg; if (!lhs) return dactyl.echoerr("E474: Invalid argument"); - if (!abbreviations.remove(modes, lhs)) + if (!args["-group"].remove(modes, lhs)) return dactyl.echoerr("E24: No such abbreviation"); }, { argCount: "1", - completer: function (context) completion.abbreviation(context, modes), - literal: 0 + completer: function (context) completion.abbreviation(context, modes, args["-group"]), + literal: 0, + options: [contexts.GroupFlag("abbrevs")] }); commands.add([ch + "abc[lear]"], "Remove all abbreviations" + modeDescription, - function () { abbreviations.removeAll(modes); }, - { argCount: "0" }); + function (args) { args["-group"].clear(modes); }, + { + argCount: "0", + options: [contexts.GroupFlag("abbrevs")] + }); } addAbbreviationCommands([modes.INSERT, modes.COMMAND_LINE], "", ""); diff --git a/common/content/browser.js b/common/content/browser.js index 3bda8cc3..20af05b4 100644 --- a/common/content/browser.js +++ b/common/content/browser.js @@ -147,7 +147,7 @@ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), onLocationChange: util.wrapCallback(function onLocationChange(webProgress, request, uri) { onLocationChange.superapply(this, arguments); - delete contexts.groups; + contexts.flush(); statusline.updateUrl(); statusline.progress = ""; diff --git a/common/content/mappings.js b/common/content/mappings.js index 35978537..cc48bb3e 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -321,9 +321,9 @@ var Mappings = Module("mappings", { getDefault: deprecated("mappings.builtin.get", function getDefault(mode, cmd) this.builtin.get(mode, cmd)), getUserIterator: deprecated("mappings.user.iterator", function getUserIterator(modes) this.user.iterator(modes)), - hasMap: deprecated("mappings.user.has", function hasMap(mode, cmd) this.user.has(mode, cmd)), - remove: deprecated("mappings.user.remove", function remove(mode, cmd) this.user.remove(mode, cmd)), - removeAll: deprecated("mappings.user.clear", function removeAll(mode) this.user.clear(mode)), + hasMap: deprecated("group.mappings.has", function hasMap(mode, cmd) this.user.has(mode, cmd)), + remove: deprecated("group.mappings.remove", function remove(mode, cmd) this.user.remove(mode, cmd)), + removeAll: deprecated("group.mappings.clear", function removeAll(mode) this.user.clear(mode)), /** * Adds a new default key mapping. @@ -352,11 +352,11 @@ var Mappings = Module("mappings", { * {@link Map#extraInfo}). * @optional */ - addUserMap: function () { + addUserMap: deprecated("groups.mappings.add", function addUserMap() { let map = this.user.add.apply(this.user, arguments); map.definedAt = contexts.getCaller(Components.stack.caller); return map; - }, + }), /** * Returns the map from *mode* named *cmd*. @@ -425,7 +425,7 @@ var Mappings = Module("mappings", { ; // TODO: Move this to an ItemList to show this automatically - if (list.*.length() === list.text().length()) + if (list.*.length() === list.text().length() + 2) dactyl.echomsg("No mapping found"); else commandline.commandOutput(list); diff --git a/common/modules/commands.jsm b/common/modules/commands.jsm index 4f63fb64..d18dd586 100644 --- a/common/modules/commands.jsm +++ b/common/modules/commands.jsm @@ -686,9 +686,9 @@ var Commands = Module("commands", { repeat: null, add: function () this.builtin._add.apply(this.builtin, arguments), - addUserCommand: deprecated("commands.user.add", { get: function addUserCommand() this.user.closure._add }), - getUserCommands: deprecated("iter(commands.user)", function getUserCommands() iter(this.user).toArray()), - removeUserCommand: deprecated("commands.user.remove", { get: function removeUserCommand() this.user.closure.remove }), + addUserCommand: deprecated("group.commands.add", { get: function addUserCommand() this.user.closure._add }), + getUserCommands: deprecated("iter(group.commands)", function getUserCommands() iter(this.user).toArray()), + removeUserCommand: deprecated("group.commands.remove", { get: function removeUserCommand() this.user.closure.remove }), /** * Returns the specified command invocation object serialized to diff --git a/common/modules/contexts.jsm b/common/modules/contexts.jsm index c4b4a1cb..3b8d9bcc 100644 --- a/common/modules/contexts.jsm +++ b/common/modules/contexts.jsm @@ -151,7 +151,7 @@ var Contexts = Module("contexts", { memoize(contexts.Group.prototype, name, function () { let group = constructor(this); this.hives.push(group); - delete contexts.groups; + contexts.flush(); return group; }); @@ -270,6 +270,11 @@ var Contexts = Module("contexts", { activeGroups: function (hive) this.initializedGroups().filter(function (g) g.filter(this), this.modules.buffer.uri), + flush: function flush() { + delete this.groups; + delete this.allGroups; + }, + initializedGroups: function (hive) let (need = hive ? [hive] : Object.keys(this.hives)) this.groupList.filter(function (group) need.some(function (name) set.has(group, name))), @@ -295,7 +300,7 @@ var Contexts = Module("contexts", { group.persist = persist; } - delete this.groups; + this.flush(); return group; }, @@ -321,7 +326,7 @@ var Contexts = Module("contexts", { delete this.groupMap[name]; delete this.hiveProto[name]; - delete this.groups; + this.flush(); return group; },