diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js index b6643e87..692c5fcc 100644 --- a/common/content/bookmarks.js +++ b/common/content/bookmarks.js @@ -13,12 +13,13 @@ var Bookmarks = Module("bookmarks", { init: function () { storage.addObserver("bookmark-cache", function (key, event, arg) { if (["add", "change", "remove"].indexOf(event) >= 0) - autocommands.trigger("Bookmark" + event[0].toUpperCase() + event.substr(1), iterAll({ - bookmark: { - toString: function () "bookmarkcache.bookmarks[" + arg.id + "]", - valueOf: function () arg - } - }, arg)); + autocommands.trigger("Bookmark" + event[0].toUpperCase() + event.substr(1), + iter({ + bookmark: { + toString: function () "bookmarkcache.bookmarks[" + arg.id + "]", + valueOf: function () arg + } + }, arg)); statusline.updateUrl(); }, window); }, @@ -195,7 +196,7 @@ var Bookmarks = Module("bookmarks", { get searchEngines() { let searchEngines = []; let aliases = {}; - return array.toObject(services.browserSearch.getVisibleEngines({}).map(function (engine) { + return array(services.browserSearch.getVisibleEngines({})).map(function (engine) { let alias = engine.alias; if (!alias || !/^[a-z_-]+$/.test(alias)) alias = engine.name.replace(/^\W*([a-zA-Z_-]+).*/, "$1").toLowerCase(); @@ -208,7 +209,7 @@ var Bookmarks = Module("bookmarks", { aliases[alias] = 0; return [alias, { keyword: alias, __proto__: engine, title: engine.description, icon: engine.iconURI && engine.iconURI.spec }]; - })); + }).toObject(); }, /** @@ -579,7 +580,7 @@ var Bookmarks = Module("bookmarks", { completion.bookmark = function bookmark(context, tags, extra) { context.title = ["Bookmark", "Title"]; context.format = bookmarks.format; - forEach(iter(extra || {}), function ([k, v]) { + iter(extra || {}).forEach(function ([k, v]) { if (v != null) context.filters.push(function (item) item.item[k] != null && this.matchString(v, item.item[k])); }); @@ -593,7 +594,7 @@ var Bookmarks = Module("bookmarks", { let engines = bookmarks.searchEngines; context.title = ["Search Keywords"]; - context.completions = iterAll(values(keywords), values(engines)); + context.completions = iter(values(keywords), values(engines)); context.keys = { text: "keyword", description: "title", icon: "icon" }; if (!space || noSuggest) diff --git a/common/content/buffer.js b/common/content/buffer.js index aeb3cfc3..1fa14e19 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -1440,7 +1440,7 @@ var Buffer = Module("buffer", { context.title = ["Stylesheet", "Location"]; // unify split style sheets - let styles = array.toObject([[s.title, []] for (s in values(buffer.alternateStyleSheets))]); + let styles = iter([s.title, []] for (s in values(buffer.alternateStyleSheets))).toObject(); buffer.alternateStyleSheets.forEach(function (style) { styles[style.title].push(style.href || "inline"); @@ -1477,7 +1477,7 @@ var Buffer = Module("buffer", { context.fork(id, 0, this, function (context, [name, browsers]) { context.title = [name || "Buffers"]; context.generate = function () - util.map(array.iterValues(browsers), function ([i, browser]) { + Array.map(browsers, function ([i, browser]) { let indicator = " "; if (i == tabs.index()) indicator = "%"; diff --git a/common/content/commands.js b/common/content/commands.js index 3ee6b0d6..43c508ed 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -114,7 +114,7 @@ var Command = Class("Command", { let parsedSpecs = Command.parseSpecs(specs); this.specs = specs; - this.shortNames = array(parsedSpecs).map(function (n) n[1]).compact(); + this.shortNames = array.compact(parsedSpecs.map(function (n) n[1])); this.longNames = parsedSpecs.map(function (n) n[0]); this.name = this.longNames[0]; this.names = array(parsedSpecs).flatten(); @@ -321,12 +321,12 @@ var Command = Class("Command", { if (callable(params)) function makeParams(self, args) - array.toObject([[k, process(v)] - for ([k, v] in iter(params.apply(self, args)))]) + iter.toObject([k, process(v)] + for ([k, v] in iter(params.apply(self, args)))) else if (params) function makeParams(self, args) - array.toObject([[name, process(args[i])] - for ([i, name] in Iterator(params))]); + iter.toObject([name, process(args[i])] + for ([i, name] in Iterator(params))); let rhs = args.literalArg; let type = ["-builtin", "-ex", "-javascript", "-keys"].reduce(function (a, b) args[b] ? b : a, default_); @@ -551,8 +551,8 @@ var Commands = Module("commands", { let str = args.literalArg; if (str) res.push(!/\n/.test(str) ? str : - this.hereDoc ? "< end ? -1 : 1; start = Math.max(0, start || 0); end = Math.min(items.length, end ? end : items.length); - return util.map(util.range(start, end, step), function (i) items[i]); + return iter.map(util.range(start, end, step), function (i) items[i]); }, getRows: function getRows(start, end, doc) { diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 3e4400ad..1c6dfb88 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -577,7 +577,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { // Find the tags in the document. function addTags(file, doc) { for (let elem in util.evaluateXPath("//@tag|//dactyl:tags/text()|//dactyl:tag/text()", doc)) - for (let tag in array((elem.value || elem.textContent).split(/\s+/)).compact().iterValues()) + for (let tag in values((elem.value || elem.textContent).split(/\s+/))) tagMap[tag] = file; } @@ -1285,14 +1285,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { let items = []; addChildren(document.getElementById(config.guioptions["m"][1]), ""); return items; - }, - - // show a usage index either in the MOW or as a full help page - showHelpIndex: function (tag, items, inMow) { - if (inMow) - commandline.commandOutput(template.usage(array(items).sort(function (a, b) String.localeCompare(a.name, b.name)))); - else - dactyl.help(tag); } }, { // Only general options are added here, which are valid for all Dactyl extensions diff --git a/common/content/history.js b/common/content/history.js index 5e13c0de..a713191d 100644 --- a/common/content/history.js +++ b/common/content/history.js @@ -36,14 +36,14 @@ var History = Module("history", { // execute the query let root = services.history.executeQuery(query, options).root; root.containerOpen = true; - let items = util.map(util.range(0, root.childCount), function (i) { + let items = iter(util.range(0, root.childCount)).map(function (i) { let node = root.getChild(i); return { url: node.uri, title: node.title, icon: node.icon ? node.icon.spec : DEFAULT_FAVICON }; - }); + }).toArray(); root.containerOpen = false; // close a container after using it! return items; diff --git a/common/content/io.js b/common/content/io.js index ceef0ef8..7e494fa4 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -466,7 +466,7 @@ var IO = Module("io", { * otherwise, the return value of *func*. */ withTempFiles: function (func, self, checked) { - let args = util.map(util.range(0, func.length), this.createTempFile); + let args = array(util.range(0, func.length)).map(this.createTempFile); try { if (!args.every(util.identity)) return false; @@ -688,7 +688,7 @@ unlet s:cpo_save let lines = []; lines.__defineGetter__("last", function () this[this.length - 1]); - for (let item in (isArray(items) ? array.iterValues : iter)(items)) { + for (let item in values(items.array || items)) { if (item.length > width && (!lines.length || lines.last.length > 1)) { lines.push([prefix]); width = WIDTH - prefix.length; diff --git a/common/content/javascript.js b/common/content/javascript.js index 9325aa91..614b3791 100644 --- a/common/content/javascript.js +++ b/common/content/javascript.js @@ -34,13 +34,13 @@ var JavaScript = Module("javascript", { return undefined; }, - iter: function iter(obj, toplevel) { + iter: function iter_(obj, toplevel) { if (obj == null) return; let seen = isinstance(obj, ["Sandbox"]) ? set(JavaScript.magicalNames) : {}; let globals = values(toplevel && window === obj ? JavaScript.globalNames : []); - for (let key in iterAll(globals, properties(obj, !toplevel, true))) + for (let key in iter(globals, properties(obj, !toplevel, true))) if (!set.add(seen, key)) yield key; diff --git a/common/content/mappings.js b/common/content/mappings.js index 4cd189d3..f3ecbd73 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -37,13 +37,17 @@ var Map = Class("Map", { this.id = ++Map.id; this.modes = modes; - this.names = keys.map(events.canonicalKeys); + this.names = keys.map(events.closure.canonicalKeys); + this._keys = keys; this.name = this.names[0]; this.action = action; this.description = description; + if (Object.freeze) + Object.freeze(this.modes); if (extraInfo) update(this, extraInfo); + util.dump("\n\n\n", this.name, extraInfo); }, /** @property {number[]} All of the modes for which this mapping applies. */ @@ -160,13 +164,12 @@ var Mappings = Module("mappings", { let names; for (let [i, map] in Iterator(maps)) { - for (let [j, name] in Iterator(map.names)) { - if (name == cmd) { - map.names.splice(j, 1); - if (map.names.length == 0) - maps.splice(i, 1); - return; - } + let j = map.names.indexOf(cmd); + if (j >= 0) { + map.names.splice(j, 1); + if (map.names.length == 0) + maps.splice(i, 1); + return; } } }, @@ -183,7 +186,7 @@ var Mappings = Module("mappings", { iterate: function (mode) { let seen = {}; - for (let map in iterAll(values(this._user[mode]), values(this._main[mode]))) + for (let map in iter(values(this._user[mode]), values(this._main[mode]))) if (!set.add(seen, map.name)) yield map; }, @@ -448,6 +451,7 @@ var Mappings = Module("mappings", { ] : []; } }; + window.userMappings = userMappings; function userMappings() { let seen = {}; for (let [, stack] in Iterator(mappings._user)) @@ -579,7 +583,7 @@ var Mappings = Module("mappings", { ] }); - forEach(modes.mainModes, function (mode) { + iter.forEach(modes.mainModes, function (mode) { if (mode.char && !commands.get(mode.char + "listkeys", true)) dactyl.addUsageCommand({ __proto__: args, diff --git a/common/content/marks.js b/common/content/marks.js index 2ca47045..332530a3 100644 --- a/common/content/marks.js +++ b/common/content/marks.js @@ -29,12 +29,9 @@ var Marks = Module("marks", { * @property {Array} Returns all marks, both local and URL, in a sorted * array. */ - get all() { - let lmarks = array(Iterator(this._localMarks.get(this.localURI) || {})); - let umarks = array(Iterator(this._urlMarks)).array; - - return lmarks.concat(umarks).sort(function (a, b) String.localeCompare(a[0], b[0])); - }, + get all() iter(this._localMarks.get(this.localURI) || {}, + this._urlMarks + ).sort(function (a, b) String.localeCompare(a[0], b[0])), get localURI() buffer.focusedFrame.document.documentURI, diff --git a/common/content/options.js b/common/content/options.js index 401b1569..0ffd92bd 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -459,7 +459,7 @@ var Option = Class("Option", { testValues: { regexpmap: function (vals, validator) vals.every(function (re) validator(re.result)), stringlist: function (vals, validator) vals.every(validator, this), - stringmap: function (vals, validator) array(values(vals)).every(validator, this) + stringmap: function (vals, validator) values(vals).every(validator, this) }, dequote: function (value) { diff --git a/common/modules/base.jsm b/common/modules/base.jsm index f4bf503a..874d2cbf 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -332,7 +332,7 @@ function keys(obj) { * @param {object} obj The object to inspect. * @returns {Generator} */ -function values(obj) { +function values(obj) iter(function values() { if (isinstance(obj, ["Generator", "Iterator"])) for (let k in obj) yield k; @@ -340,31 +340,10 @@ function values(obj) { for (var k in obj) if (hasOwnProperty.call(obj, k)) yield obj[k]; -} +}()); -/** - * Iterates over an iterable object and calls a callback for each - * element. - * - * @param {object} iter The iterator. - * @param {function} fn The callback. - * @param {object} self The this object for *fn*. - */ -function forEach(iter, fn, self) { - for (let val in iter) - fn.call(self, val); -} - -/** - * Iterates over each iterable argument in turn, yielding each value. - * - * @returns {Generator} - */ -function iterAll() { - for (let i = 0; i < arguments.length; i++) - for (let j in Iterator(arguments[i])) - yield j; -} +var forEach = deprecated("Please use iter.forEach instead", function forEach() iter.forEach.apply(iter, arguments)); +var iterAll = deprecated("Please use iter instead", function iterAll() iter.apply(null, arguments)); /** * Utility for managing sets of strings. Given an array, returns an @@ -429,87 +408,6 @@ set.remove = function (set, key) { return res; } -/** - * Iterates over an arbitrary object. The following iterators types are - * supported, and work as a user would expect: - * - * • nsIDOMNodeIterator - * • mozIStorageStatement - * - * Additionally, the following array-like objects yield a tuple of the - * form [index, element] for each contained element: - * - * • nsIDOMHTMLCollection - * • nsIDOMNodeList - * - * and the following likewise yield one element of the form - * [name, element] for each contained element: - * - * • nsIDOMNamedNodeMap - * - * Duck typing is implemented for the any other type. If the object - * contains the "enumerator" property, iter is called on that. If the - * property is a function, it is called first. If it contains the - * property "getNext" along with either "hasMoreItems" or "hasMore", it - * is iterated over appropriately. - * - * For all other cases, this function behaves exactly like the Iterator - * function. - * - * @param {object} obj - * @returns {Generator} - */ -function iter(obj) { - let res = Iterator(obj); - if (ctypes && ctypes.CData && obj instanceof ctypes.CData) { - while (obj.constructor instanceof ctypes.PointerType) - obj = obj.contents; - if (obj.constructor instanceof ctypes.ArrayType) - res = array.iterItems(obj); - else if (obj.constructor instanceof ctypes.StructType) - res = (function () { - for (let prop in values(obj.constructor.fields)) - yield let ([name, type] = Iterator(prop).next()) [name, obj[name]]; - })(); - else - return iter({}); - } - else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList])) - res = array.iterItems(obj); - else if (obj instanceof Ci.nsIDOMNamedNodeMap) - res = (function () { - for (let i = 0; i < obj.length; i++) - yield [obj.name, obj]; - })(); - else if (obj instanceof Ci.mozIStorageStatement) - res = (function (obj) { - while (obj.executeStep()) - yield obj.row; - obj.reset(); - })(obj); - else if ("getNext" in obj) { - if ("hasMoreElements" in obj) - res = (function () { - while (obj.hasMoreElements()) - yield obj.getNext(); - })(); - else if ("hasMore" in obj) - res = (function () { - while (obj.hasMore()) - yield obj.getNext(); - })(); - } - else if ("enumerator" in obj) { - if (callable(obj.enumerator)) - return iter(obj.enumerator()); - return iter(obj.enumerator); - } - res.__noSuchMethod__ = function __noSuchMethod__(meth, args) - let (ary = array(this)) - ary[meth] ? ary[meth].apply(ary, args) : ary.__noSuchMethod__(meth, args); - return res; -} - /** * Returns true if both arguments are functions and * (targ() instanceof src) would also return true. @@ -889,7 +787,7 @@ Class.prototype = { memoize(Class.prototype, "closure", function () { const self = this; function closure(fn) function () fn.apply(self, arguments); - for (let k in iterAll(properties(this), properties(this, true))) + for (let k in iter(properties(this), properties(this, true))) if (!this.__lookupGetter__(k) && callable(this[k])) closure[k] = closure(this[k]); return closure; @@ -910,8 +808,8 @@ function XPCOM(interfaces, superClass) { Cc["@dactyl.googlecode.com/base/xpc-interface-shim"].createInstance()); let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update( - array([k, v === undefined || callable(v) ? function stub() null : v] - for ([k, v] in Iterator(shim))).toObject(), + iter.toObject([k, v === undefined || callable(v) ? function stub() null : v] + for ([k, v] in Iterator(shim))), { QueryInterface: XPCOMUtils.generateQI(interfaces) })); shim = interfaces = null; return res; @@ -1121,6 +1019,197 @@ function UTF8(str) { function octal(decimal) parseInt(decimal, 8); +/** + * Iterates over an arbitrary object. The following iterators types are + * supported, and work as a user would expect: + * + * • nsIDOMNodeIterator + * • mozIStorageStatement + * + * Additionally, the following array-like objects yield a tuple of the + * form [index, element] for each contained element: + * + * • nsIDOMHTMLCollection + * • nsIDOMNodeList + * + * and the following likewise yield one element of the form + * [name, element] for each contained element: + * + * • nsIDOMNamedNodeMap + * + * Duck typing is implemented for the any other type. If the object + * contains the "enumerator" property, iter is called on that. If the + * property is a function, it is called first. If it contains the + * property "getNext" along with either "hasMoreItems" or "hasMore", it + * is iterated over appropriately. + * + * For all other cases, this function behaves exactly like the Iterator + * function. + * + * @param {object} obj + * @returns {Generator} + */ +function iter(obj) { + let args = arguments; + let res = Iterator(obj); + + if (isinstance(args, ["Iterator", "Generator"])) + ; + else if (args.length > 1) + res = (function () { + for (let i = 0; i < args.length; i++) + for (let j in Iterator(args[i])) + yield j; + })(); + else if (ctypes && ctypes.CData && obj instanceof ctypes.CData) { + while (obj.constructor instanceof ctypes.PointerType) + obj = obj.contents; + if (obj.constructor instanceof ctypes.ArrayType) + res = array.iterItems(obj); + else if (obj.constructor instanceof ctypes.StructType) + res = (function () { + for (let prop in values(obj.constructor.fields)) + yield let ([name, type] = Iterator(prop).next()) [name, obj[name]]; + })(); + else + return iter({}); + } + else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList])) + res = array.iterItems(obj); + else if (obj instanceof Ci.nsIDOMNamedNodeMap) + res = (function () { + for (let i = 0; i < obj.length; i++) + yield [obj.name, obj]; + })(); + else if (obj instanceof Ci.mozIStorageStatement) + res = (function (obj) { + while (obj.executeStep()) + yield obj.row; + obj.reset(); + })(obj); + else if ("getNext" in obj) { + if ("hasMoreElements" in obj) + res = (function () { + while (obj.hasMoreElements()) + yield obj.getNext(); + })(); + else if ("hasMore" in obj) + res = (function () { + while (obj.hasMore()) + yield obj.getNext(); + })(); + } + else if ("enumerator" in obj) { + if (callable(obj.enumerator)) + return iter(obj.enumerator()); + return iter(obj.enumerator); + } + res.__noSuchMethod__ = function __noSuchMethod__(meth, args) { + if (meth in iter) + var res = iter[meth].apply(iter, [this].concat(args)); + else + res = let (ary = array(this)) + ary[meth] ? ary[meth].apply(ary, args) : ary.__noSuchMethod__(meth, args); + if (isinstance(res, ["Iterator", "Generator"])) + return iter(res); + return res; + }; + return res; +} +update(iter, { + toArray: function toArray(iter) array(iter).array, + + // See array.prototype for API docs. + toObject: function toObject(iter) { + let obj = {}; + for (let [k, v] in iter) + obj[k] = v; + return obj; + }, + + compact: function compact(iter) (item for (item in iter) if (item != null)), + + every: function every(iter, pred, self) { + pred = pred || util.identity; + for (let elem in iter) + if (!pred.call(self, elem)) + return false; + return true; + }, + some: function every(iter, pred, self) { + pred = pred || util.identity; + for (let elem in iter) + if (pred.call(self, elem)) + return true; + return false; + }, + + filter: function filter(iter, pred, self) { + for (let elem in iter) + if (pred.call(self, elem)) + yield elem; + }, + + /** + * Iterates over an iterable object and calls a callback for each + * element. + * + * @param {object} iter The iterator. + * @param {function} fn The callback. + * @param {object} self The this object for *fn*. + */ + forEach: function forEach(iter, func, self) { + for (let val in iter) + func.call(self, val); + }, + + /** + * Returns the array that results from applying *func* to each property of + * *obj*. + * + * @param {Object} obj + * @param {function} func + * @returns {Array} + */ + map: function map(iter, func, self) { + for (let i in iter) + yield func.call(self, i); + }, + + /** + * Returns the nth member of the given array that matches the + * given predicate. + */ + nth: function nth(iter, pred, n, self) { + for (let elem in iter) + if (pred.call(self, elem) && n-- === 0) + return elem; + return undefined; + }, + + uniq: function uniq(iter) { + let seen = {}; + for (let item in iter) + if (!set.add(seen, item)) + yield item; + }, + + /** + * Zips the contents of two arrays. The resulting array is the length of + * ary1, with any shortcomings of ary2 replaced with null strings. + * + * @param {Array} ary1 + * @param {Array} ary2 + * @returns {Array} + */ + zip: function zip(iter1, iter2) { + try { + yield [iter1.next(), iter2.next()]; + } + catch (e if e instanceof StopIteration) {} + } +}); + /** * Array utility methods. */ @@ -1138,6 +1227,8 @@ var array = Class("array", Array, { var res = array[meth].apply(null, [this.array].concat(args)); if (isArray(res)) return array(res); + if (isinstance(res, ["Iterator", "Generator"])) + return iter(res); return res; }, array: ary, diff --git a/common/modules/sanitizer.jsm b/common/modules/sanitizer.jsm index f2b1e4ff..6cc7ffe8 100644 --- a/common/modules/sanitizer.jsm +++ b/common/modules/sanitizer.jsm @@ -211,7 +211,9 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef addItem: function addItem(name, params) { this.itemMap[name] = update(this.itemMap[name] || Item(name), - array([k, v] for ([k, v] in Iterator(params)) if (!callable(v))).toObject()); + iter.toObject([k, v] + for ([k, v] in Iterator(params)) + if (!callable(v)))); let names = set([name].concat(params.contains || []).map(function (e) "clear-" + e)); if (params.action) @@ -315,7 +317,7 @@ var Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakRef deny: 2, session: 8 }, - UNPERMS: Class.memoize(function () array.toObject([[v, k] for ([k, v] in Iterator(this.PERMS))])), + UNPERMS: Class.memoize(function () iter(this.PERMS).map(Array.reverse).toObject()), COMMANDS: { unset: "Unset", allow: "Allowed", diff --git a/common/modules/util.jsm b/common/modules/util.jsm index cbd74705..96567914 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -793,20 +793,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), .map(function (node) "//" + node).join(" | "); }, - /** - * Returns the array that results from applying *func* to each property of - * *obj*. - * - * @param {Object} obj - * @param {function} func - * @returns {Array} - */ - map: function map(obj, func) { - let ary = []; - for (let i in Iterator(obj)) - ary.push(func(i)); - return ary; - }, + map: deprecated("Please use iter.map instead", function map(obj, fn, self) iter(obj).map(fn, self).toArray()), /** * Converts a URI string into a URI object.