improvements to Doc.java, corresponding fixes to the reference
[org.ibex.core.git] / src / org / ibex / Ibex.java
index ba80775..d1e3284 100644 (file)
@@ -11,6 +11,7 @@ public final class Ibex extends JS.Cloneable {
 
     // FIXME remove this
     private final JS rr;
+
     public Ibex(Stream rr) { this.rr = bless(rr); }
 
     public JS resolveString(String str, boolean permitAbsolute) throws JSExn {
@@ -27,7 +28,7 @@ public final class Ibex extends JS.Cloneable {
             str = str.substring(str.indexOf('.') + 1);
             ret = (JS)ret.get(path);
         }
-        ret = (JS)ret.get(str);
+        if (!"".equals(str)) ret = (JS)ret.get(str);
         return ret;
     }
 
@@ -63,6 +64,9 @@ public final class Ibex extends JS.Cloneable {
         case "regexp": return METHOD;
         case "ui": return getSub("ui");
         case "ui.font": return getSub("ui.font");
+        case "ui.font.wait": return METHOD;
+        case "ui.font.width": return METHOD;
+        case "ui.font.height": return METHOD;
         case "ui.font.sansserif": return Main.builtin.get("fonts/vera/Vera.ttf");
         case "ui.font.monospace": return Main.builtin.get("fonts/vera/VeraMono.ttf");
         case "ui.font.serif": return Main.builtin.get("fonts/vera/VeraSe.ttf");
@@ -169,6 +173,10 @@ public final class Ibex extends JS.Cloneable {
                         else if (url.startsWith("https://")) return new Stream.HTTP(url);
                         else if (url.startsWith("data:")) return new Stream.ByteArray(Base64.decode(url.substring(5)), null);
                         else if (url.startsWith("utf8:")) return new Stream.ByteArray(url.substring(5).getBytes(), null);
+                        else if (url.startsWith("file:")) {
+                            // FIXME
+                            Platform.fileDialog(url.substring(5), false);
+                        }
                         throw new JSExn("invalid resource specifier " + url);
                     }
                     case "thread.sleep": sleep(JS.toInt(a)); return null;
@@ -190,6 +198,20 @@ public final class Ibex extends JS.Cloneable {
                     case "stream.watch": return new Stream.ProgressWatcher((Stream)a, (JS)b);
                     case "regexp": return new JSRegexp(a, b);
                     //#end
+                case 3:
+                    //#switch(name)
+                    case "ui.font.height": return N(Font.getFont((Stream)a, JS.toInt(b)).textheight((String)c));
+                    case "ui.font.wait":
+                        try {
+                            JS.UnpauseCallback callback = JS.pause();
+                            Font font = Font.getFont((Stream)a, JS.toInt(b));
+                            if (font.rasterizeGlyphs((String)c, null, 0,0,0,0,0,0,0, callback) != -1) Scheduler.add(callback);
+                        } catch (JS.NotPauseableException npe) {
+                            JS.error("can't wait for a font in a foreground thread");
+                        }
+                        return null;
+                    case "ui.font.width": return N(Font.getFont((Stream)a, JS.toInt(b)).textwidth((String)c));
+                    //#end
                     break;
             }
         } catch (RuntimeException e) {
@@ -198,7 +220,7 @@ public final class Ibex extends JS.Cloneable {
             throw new JSExn("invalid argument for ibex object method "+name+"()");
         }
 
-        throw new JSExn("invalid number of arguments for ibex object method "+name+"()");
+        throw new JSExn("invalid number of arguments ("+nargs+") for ibex object method "+name+"()");
     }
 
     public Stream url2res(String url) throws JSExn {
@@ -305,12 +327,17 @@ public final class Ibex extends JS.Cloneable {
     public static class Blessing extends JS.Clone {
         private Ibex ibex;
         private Template t = null;
-        private Object parentkey = null;
-        private Blessing parent = null;
+        public Object parentkey = null;
+        public Blessing parent = null;
+        private Hash cache = new Hash();
         public Blessing(JS.Cloneable clonee, Ibex ibex, Blessing parent, Object parentkey) {
             super(clonee); this.ibex = ibex; this.parentkey = parentkey; this.parent = parent; }
         public Object get(Object key) throws JSExn {
-            return key.equals("") ? ((Object)getStatic()) : (new Blessing((JS.Cloneable)clonee.get(key), ibex, this, key));
+            if (key.equals("")) return ((Object)getStatic());
+            if (cache.get(key) != null) return cache.get(key);
+            Object ret = new Blessing((JS.Cloneable)clonee.get(key), ibex, this, key);
+            cache.put(key, ret);
+            return ret;
         }
         public static Blessing getBlessing(Object o) {
             if (!(o instanceof JS)) return null;
@@ -334,8 +361,7 @@ public final class Ibex extends JS.Cloneable {
         }
         public JSScope getStatic() {
             try {
-                // FIXME background?
-                if (t == null) t = Template.buildTemplate(parentkey + ".ixt", Stream.getInputStream(parent.get(parentkey + ".ixt")), ibex);
+                if (t == null) t = Template.buildTemplate(parentkey + ".t", parent.get(parentkey + ".t"), ibex);
                 return t.staticScope;
             } catch (Exception e) {
                 Log.error(this, e);
@@ -344,9 +370,10 @@ public final class Ibex extends JS.Cloneable {
         }
         public Object call(Object a, Object b, Object c, Object[] rest, int nargs) throws JSExn {
             // GROSS hack
-            if (nargs == 9999) return t;
-            if (nargs != 1) throw new JSExn("FIXME can only call with one arg");
+            if (nargs != 1 && nargs != 9999) throw new JSExn("FIXME can only call with one arg");
             getStatic();
+            if (t == null) throw new JSExn("No such template " + parentkey);
+            if (nargs == 9999) return t;
             t.apply((Box)a);
             return a;
         }