]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/base.jsm
Import 1.0b7.1 supporting Firefox up to 8.*
[dactyl.git] / common / modules / base.jsm
index 13bd9a03e93fcd3b88a5400ba38061e5b25bf08a..d07ba1230732b78e0f69eb944b84e8017c91f3fc 100644 (file)
@@ -37,65 +37,83 @@ if (!Object.create)
     };
 if (!Object.defineProperty)
     Object.defineProperty = function defineProperty(obj, prop, desc) {
-        let value = desc.value;
-        if ("value" in desc)
-            if (desc.writable && !__lookupGetter__.call(obj, prop)
-                              && !__lookupSetter__.call(obj, prop))
-                try {
-                    obj[prop] = value;
+        try {
+            let value = desc.value;
+            if ("value" in desc)
+                if (desc.writable && !__lookupGetter__.call(obj, prop)
+                                  && !__lookupSetter__.call(obj, prop))
+                    try {
+                        obj[prop] = value;
+                    }
+                    catch (e if e instanceof TypeError) {}
+                else {
+                    objproto.__defineGetter__.call(obj, prop, function () value);
+                    if (desc.writable)
+                        objproto.__defineSetter__.call(obj, prop, function (val) { value = val; });
                 }
-                catch (e if e instanceof TypeError) {}
-            else {
-                objproto.__defineGetter__.call(obj, prop, function () value);
-                if (desc.writable)
-                    objproto.__defineSetter__.call(obj, prop, function (val) { value = val; });
-            }
 
-        if ("get" in desc)
-            objproto.__defineGetter__.call(obj, prop, desc.get);
-        if ("set" in desc)
-            objproto.__defineSetter__.call(obj, prop, desc.set);
+            if ("get" in desc)
+                objproto.__defineGetter__.call(obj, prop, desc.get);
+            if ("set" in desc)
+                objproto.__defineSetter__.call(obj, prop, desc.set);
+        }
+        catch (e) {
+            throw e.stack ? e : Error(e);
+        }
     };
 if (!Object.defineProperties)
     Object.defineProperties = function defineProperties(obj, props) {
         for (let [k, v] in Iterator(props))
             Object.defineProperty(obj, k, v);
-    }
+    };
 if (!Object.freeze)
     Object.freeze = function freeze(obj) {};
+if (!Object.getPropertyDescriptor)
+    Object.getPropertyDescriptor = function getPropertyDescriptor(obj, prop) {
+        try {
+            let desc = {
+                configurable: true,
+                enumerable: propertyIsEnumerable.call(obj, prop)
+            };
+            var get = __lookupGetter__.call(obj, prop),
+                set = __lookupSetter__.call(obj, prop);
+            if (!get && !set) {
+                desc.value = obj[prop];
+                desc.writable = true;
+            }
+            if (get)
+                desc.get = get;
+            if (set)
+                desc.set = set;
+            return desc;
+        }
+        catch (e) {
+            throw e.stack ? e : Error(e);
+        }
+    };
 if (!Object.getOwnPropertyDescriptor)
     Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) {
-        if (!hasOwnProperty.call(obj, prop))
-            return undefined;
-        let desc = {
-            configurable: true,
-            enumerable: propertyIsEnumerable.call(obj, prop)
-        };
-        var get = __lookupGetter__.call(obj, prop),
-            set = __lookupSetter__.call(obj, prop);
-        if (!get && !set) {
-            desc.value = obj[prop];
-            desc.writable = true;
-        }
-        if (get)
-            desc.get = get;
-        if (set)
-            desc.set = set;
-        return desc;
+        if (hasOwnProperty.call(obj, prop))
+            return Object.getPropertyDescriptor(obj, prop);
     };
 if (!Object.getOwnPropertyNames)
     Object.getOwnPropertyNames = function getOwnPropertyNames(obj, _debugger) {
-        // This is an ugly and unfortunately necessary hack.
-        if (hasOwnProperty.call(obj, "__iterator__")) {
-            var oldIter = obj.__iterator__;
-            delete obj.__iterator__;
+        try {
+            // This is an ugly and unfortunately necessary hack.
+            if (hasOwnProperty.call(obj, "__iterator__")) {
+                var oldIter = obj.__iterator__;
+                delete obj.__iterator__;
+            }
+            let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))];
+            if (oldIter !== undefined) {
+                obj.__iterator__ = oldIter;
+                res.push("__iterator__");
+            }
+            return res;
         }
-        let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))];
-        if (oldIter !== undefined) {
-            obj.__iterator__ = oldIter;
-            res.push("__iterator__");
+        catch (e) {
+            throw e.stack ? e : Error(e);
         }
-        return res;
     };
 if (!Object.getPrototypeOf)
     Object.getPrototypeOf = function getPrototypeOf(obj) obj.__proto__;
@@ -127,6 +145,7 @@ function defineModule(name, params, module) {
             use[mod].push(module);
         }
     currentModule = module;
+    module.startTime = Date.now();
 }
 
 defineModule.loadLog = [];
@@ -148,7 +167,6 @@ defineModule.dump = function dump_() {
                .replace(/^./gm, name + ": $&"));
 }
 defineModule.modules = [];
-defineModule.times = { all: 0 };
 defineModule.time = function time(major, minor, func, self) {
     let time = Date.now();
     if (typeof func !== "function")
@@ -161,13 +179,7 @@ defineModule.time = function time(major, minor, func, self) {
         loaded.util && util.reportError(e);
     }
 
-    let delta = Date.now() - time;
-    defineModule.times.all += delta;
-    defineModule.times[major] = (defineModule.times[major] || 0) + delta;
-    if (minor) {
-        defineModule.times[":" + minor] = (defineModule.times[":" + minor] || 0) + delta;
-        defineModule.times[major + ":" + minor] = (defineModule.times[major + ":" + minor] || 0) + delta;
-    }
+    JSMLoader.times.add(major, minor, Date.now() - time);
     return res;
 }
 
@@ -185,8 +197,10 @@ function require(obj, name, from) {
         if (arguments.length === 1)
             [obj, name] = [{}, obj];
 
+        let caller = Components.stack.caller;
+
         if (!loaded[name])
-            defineModule.loadLog.push((from || "require") + ": loading " + name + (obj.NAME ? " into " + obj.NAME : ""));
+            defineModule.loadLog.push((from || "require") + ": loading " + name + " into " + (obj.NAME || caller.filename + ":" + caller.lineNumber));
 
         JSMLoader.load(name + ".jsm", obj);
         return obj;
@@ -196,7 +210,7 @@ function require(obj, name, from) {
         if (loaded.util)
             util.reportError(e);
         else
-            defineModule.dump("    " + (e.filename || e.fileName) + ":" + e.lineNumber + ": " + e +"\n");
+            defineModule.dump("    " + (e.filename || e.fileName) + ":" + e.lineNumber + ": " + e + "\n");
     }
 }
 
@@ -204,10 +218,10 @@ defineModule("base", {
     // sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/  "\2",/p' base.jsm | sort | fmt
     exports: [
         "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable",
-        "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper",
+        "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper",
         "array", "bind", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule",
         "deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject",
-        "isString", "isSubclass", "iter", "iterAll", "iterOwnProperties","keys", "memoize", "octal",
+        "isString", "isSubclass", "iter", "iterAll", "iterOwnProperties", "keys", "memoize", "octal",
         "properties", "require", "set", "update", "values", "withCallerGlobal"
     ],
     use: ["config", "services", "util"]
@@ -259,7 +273,7 @@ function properties(obj, prototypes, debugger_) {
     try {
         if ("dactylPropertyNames" in obj && !prototypes)
             for (let key in values(obj.dactylPropertyNames))
-                if (key in obj && !set.add(seen, key))
+                if (key in obj && !Set.add(seen, key))
                     yield key;
     }
     catch (e) {}
@@ -274,7 +288,7 @@ function properties(obj, prototypes, debugger_) {
             iter = (prop.name.stringValue for (prop in values(debuggerProperties(obj))));
 
         for (let key in iter)
-            if (!prototypes || !set.add(seen, key) && obj != orig)
+            if (!prototypes || !Set.add(seen, key) && obj != orig)
                 yield key;
     }
 }
@@ -292,7 +306,8 @@ function deprecated(alternative, fn) {
     let name, func = callable(fn) ? fn : function () this[fn].apply(this, arguments);
 
     function deprecatedMethod() {
-        let obj = this.className             ? this.className + "#" :
+        let obj = !this                      ? "" :
+                  this.className             ? this.className + "#" :
                   this.constructor.className ? this.constructor.className + "#" :
                       "";
 
@@ -307,17 +322,16 @@ function deprecated(alternative, fn) {
 }
 deprecated.warn = function warn(func, name, alternative, frame) {
     if (!func.seenCaller)
-        func.seenCaller = set([
+        func.seenCaller = Set([
             "resource://dactyl" + JSMLoader.suffix + "/javascript.jsm",
             "resource://dactyl" + JSMLoader.suffix + "/util.jsm"
         ]);
 
     frame = frame || Components.stack.caller.caller;
     let filename = util.fixURI(frame.filename || "unknown");
-    if (!set.add(func.seenCaller, filename))
-        util.dactyl(func).warn(
-            util.urlPath(filename) + ":" + frame.lineNumber + ": " +
-            name + " is deprecated: Please use " + alternative + " instead");
+    if (!Set.add(func.seenCaller, filename))
+        util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":")
+                                   + require("messages")._("warn.deprecated", name, alternative));
 }
 
 /**
@@ -359,7 +373,7 @@ var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments))
  * @param {[string]} ary @optional
  * @returns {object}
  */
-function set(ary) {
+function Set(ary) {
     let obj = {};
     if (ary)
         for (let val in values(ary))
@@ -374,7 +388,7 @@ function set(ary) {
  * @param {string} key The key to add.
  * @returns boolean
  */
-set.add = curry(function set_add(set, key) {
+Set.add = curry(function set_add(set, key) {
     let res = this.has(set, key);
     set[key] = true;
     return res;
@@ -386,7 +400,7 @@ set.add = curry(function set_add(set, key) {
  * @param {string} key The key to check.
  * @returns {boolean}
  */
-set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) &&
+Set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) &&
                                            propertyIsEnumerable.call(set, key));
 /**
  * Returns a new set containing the members of the first argument which
@@ -395,7 +409,7 @@ set.has = curry(function set_has(set, key) hasOwnProperty.call(set, key) &&
  * @param {object} set The set.
  * @returns {object}
  */
-set.subtract = function set_subtract(set) {
+Set.subtract = function set_subtract(set) {
     set = update({}, set);
     for (let i = 1; i < arguments.length; i++)
         for (let k in keys(arguments[i]))
@@ -410,12 +424,23 @@ set.subtract = function set_subtract(set) {
  * @param {string} key The key to remove.
  * @returns boolean
  */
-set.remove = curry(function set_remove(set, key) {
+Set.remove = curry(function set_remove(set, key) {
     let res = set.has(set, key);
     delete set[key];
     return res;
 });
 
+function set() {
+    deprecated.warn(set, "set", "Set");
+    return Set.apply(this, arguments);
+}
+Object.keys(Set).forEach(function (meth) {
+    set[meth] = function proxy() {
+        deprecated.warn(proxy, "set." + meth, "Set." + meth);
+        return Set[meth].apply(Set, arguments);
+    };
+});
+
 /**
  * Curries a function to the given number of arguments. Each
  * call of the resulting function returns a new function. When
@@ -464,9 +489,13 @@ function curry(fn, length, self, acc) {
 }
 
 if (curry.bind)
-    var bind = function bind(func) func.bind.apply(func, Array.slice(arguments, bind.length));
+    var bind = function bind(meth, self) let (func = callable(meth) ? meth : self[meth])
+        func.bind.apply(func, Array.slice(arguments, 1));
 else
     var bind = function bind(func, self) {
+        if (!callable(func))
+            func = self[func];
+
         let args = Array.slice(arguments, bind.length);
         return function bound() func.apply(self, args.concat(Array.slice(arguments)));
     };
@@ -582,7 +611,7 @@ function call(fn) {
  */
 function memoize(obj, key, getter) {
     if (arguments.length == 1) {
-        obj = update({}, obj);
+        obj = update({ __proto__: obj.__proto__ }, obj);
         for (let prop in Object.getOwnPropertyNames(obj)) {
             let get = __lookupGetter__.call(obj, prop);
             if (get)
@@ -591,17 +620,22 @@ function memoize(obj, key, getter) {
         return obj;
     }
 
-    Object.defineProperty(obj, key, {
-        configurable: true,
-        enumerable: true,
+    try {
+        Object.defineProperty(obj, key, {
+            configurable: true,
+            enumerable: true,
 
-        get: function g_replaceProperty() (
-            Class.replaceProperty(this.instance || this, key, null),
-            Class.replaceProperty(this.instance || this, key, getter.call(this, key))),
+            get: function g_replaceProperty() (
+                Class.replaceProperty(this.instance || this, key, null),
+                Class.replaceProperty(this.instance || this, key, getter.call(this, key))),
 
-        set: function s_replaceProperty(val)
-            Class.replaceProperty(this.instance || this, key, val)
-    });
+            set: function s_replaceProperty(val)
+                Class.replaceProperty(this.instance || this, key, val)
+        });
+    }
+    catch (e) {
+        obj[key] = getter.call(obj, key);
+    }
 }
 
 let sandbox = Cu.Sandbox(this);
@@ -648,12 +682,14 @@ function update(target) {
 
             if (typeof desc.value === "function" && target.__proto__) {
                 let func = desc.value.wrapped || desc.value;
-                func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]);
-                func.superapply = function superapply(self, args)
-                    let (meth = Object.getPrototypeOf(target)[k])
-                        meth && meth.apply(self, args);
-                func.supercall = function supercall(self)
-                    func.superapply(self, Array.slice(arguments, 1));
+                if (!func.superapply) {
+                    func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]);
+                    func.superapply = function superapply(self, args)
+                        let (meth = Object.getPrototypeOf(target)[k])
+                            meth && meth.apply(self, args);
+                    func.supercall = function supercall(self)
+                        func.superapply(self, Array.slice(arguments, 1));
+                }
             }
             try {
                 Object.defineProperty(target, k, desc);
@@ -696,18 +732,28 @@ function Class() {
     if (callable(args[0]))
         superclass = args.shift();
 
-    var Constructor = eval(String.replace(<![CDATA[
-        (function constructor(PARAMS) {
+    if (loaded.util && util.haveGecko("6.0a1")) // Bug 657418.
+        var Constructor = function Constructor() {
             var self = Object.create(Constructor.prototype, {
                 constructor: { value: Constructor },
             });
             self.instance = self;
             var res = self.init.apply(self, arguments);
             return res !== undefined ? res : self;
-        })]]>,
-        "constructor", (name || superclass.className).replace(/\W/g, "_"))
-            .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]
-                                                       .replace(/\b(self|res|Constructor)\b/g, "$1_")));
+        };
+    else
+        var Constructor = eval(String.replace(<![CDATA[
+            (function constructor(PARAMS) {
+                var self = Object.create(Constructor.prototype, {
+                    constructor: { value: Constructor },
+                });
+                self.instance = self;
+                var res = self.init.apply(self, arguments);
+                return res !== undefined ? res : self;
+            })]]>,
+            "constructor", (name || superclass.className).replace(/\W/g, "_"))
+                .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]
+                                                           .replace(/\b(self|res|Constructor)\b/g, "$1_")));
 
     Constructor.className = name || superclass.className || superclass.name;
 
@@ -735,19 +781,19 @@ function Class() {
 }
 
 if (Cu.getGlobalForObject)
-    Class.objectGlobal = function (caller) {
+    Class.objectGlobal = function (object) {
         try {
-            return Cu.getGlobalForObject(caller);
+            return Cu.getGlobalForObject(object);
         }
         catch (e) {
             return null;
         }
     };
 else
-    Class.objectGlobal = function (caller) {
-        while (caller.__parent__)
-            caller = caller.__parent__;
-        return caller;
+    Class.objectGlobal = function (object) {
+        while (object.__parent__)
+            object = object.__parent__;
+        return object;
     };
 
 /**
@@ -791,7 +837,7 @@ Class.extend = function extend(subclass, superclass, overrides) {
  *
  * @param {function(string)} getter The function which returns the
  *      property's value.
- * @return {Class.Property}
+ * @returns {Class.Property}
  */
 Class.memoize = function memoize(getter, wait)
     Class.Property({
@@ -883,7 +929,48 @@ Class.prototype = {
             util.trapErrors(callback, self);
         }
         return services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT);
-    }
+    },
+
+    /**
+     * Updates this instance with the properties of the given objects.
+     * Like the update function, but with special semantics for
+     * localized properties.
+     */
+    update: function update() {
+        let self = this;
+        // XXX: Duplication.
+
+        for (let i = 0; i < arguments.length; i++) {
+            let src = arguments[i];
+            Object.getOwnPropertyNames(src || {}).forEach(function (k) {
+                let desc = Object.getOwnPropertyDescriptor(src, k);
+                if (desc.value instanceof Class.Property)
+                    desc = desc.value.init(k, this) || desc.value;
+
+                if (typeof desc.value === "function") {
+                    let func = desc.value.wrapped || desc.value;
+                    if (!func.superapply) {
+                        func.__defineGetter__("super", function () Object.getPrototypeOf(self)[k]);
+                        func.superapply = function superapply(self, args)
+                            let (meth = Object.getPrototypeOf(self)[k])
+                                meth && meth.apply(self, args);
+                        func.supercall = function supercall(self)
+                            func.superapply(self, Array.slice(arguments, 1));
+                    }
+                }
+
+                try {
+                    if ("value" in desc && (k in this.localizedProperties || k in this.magicalProperties))
+                        this[k] = desc.value;
+                    else
+                        Object.defineProperty(this, k, desc);
+                }
+                catch (e) {}
+            }, this);
+        }
+    },
+
+    magicalProperties: {}
 };
 Class.makeClosure = function makeClosure() {
     const self = this;
@@ -946,7 +1033,9 @@ var ErrorBase = Class("ErrorBase", Error, {
     level: 2,
     init: function EB_init(message, level) {
         level = level || 0;
-        update(this, Error(message))
+        let error = Error(message);
+        update(this, error)
+        this.stack = error.stack;
         this.message = message;
 
         let frame = Components.stack;
@@ -956,7 +1045,8 @@ var ErrorBase = Class("ErrorBase", Error, {
         }
         this.fileName = frame.filename;
         this.lineNumber = frame.lineNumber;
-    }
+    },
+    toString: function () String(this.message)
 });
 
 /**
@@ -1368,7 +1458,7 @@ update(iter, {
     uniq: function uniq(iter) {
         let seen = {};
         for (let item in iter)
-            if (!set.add(seen, item))
+            if (!Set.add(seen, item))
                 yield item;
     },
 
@@ -1423,7 +1513,7 @@ var array = Class("array", Array, {
      * as such:
      *    [["a", "b"], ["c", "d"]] -> { a: "b", c: "d" }
      *
-     * @param {Array[]} assoc
+     * @param {[Array]} assoc
      * @... {string} 0 - Key
      * @...          1 - Value
      */