*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
index 9618135..0670f99 100644 (file)
@@ -138,10 +138,11 @@ namespace M17N.Input
         = new Dictionary<string, KeyModifier> ();
        private static uint keysym_base = 0x200000;
        private static uint char_mask = ~((uint) KeyModifier.All);
-       public static Key Reload;
+       public static readonly Key Reload;
 
        static Key ()
        {
+        keysyms["null"] = 0x00;
         keysyms["bs"] = keysyms["backspace"] = 0x08;
         keysyms["tab"] = 0x09;
         keysyms["lf"] = keysyms["linefeed"] = 0x10;
@@ -161,8 +162,7 @@ namespace M17N.Input
         keymodifiers["altgr"] = KeyModifier.AltGr;
         keymodifiers["super"] = KeyModifier.Super;
         keymodifiers["hyper"] = KeyModifier.Hyper;
-        Reload = new Key (keysym_base);
-        keysyms["-reload"] = keysym_base++;
+        Reload = new Key ((MSymbol) "-reload");
        }
 
        private static uint decode_keysym (MSymbol keysym)
@@ -312,7 +312,7 @@ namespace M17N.Input
 
        public int ToChar ()
        {
-        return (int) (key & 0x1FFFFF);
+        return (key & 0x3FFFFF) <= 0x1FFFFF ? (int) (key & 0x1FFFFF) : -1;
        }
 
        public override string ToString ()
@@ -321,7 +321,7 @@ namespace M17N.Input
         MText mt = null;
         if (c < 0x20)
           foreach (KeyValuePair<string, uint> kv in keysyms)
-            if ((uint) c == kv.Value)
+            if ((key & 0x3FFFFF) == kv.Value)
               {
                 mt = kv.Key;
                 break;
@@ -352,6 +352,9 @@ namespace M17N.Input
 
      internal class KeySeq : Xex.TermValue
      {
+       private static Xex.Symbol name = "keyseq";
+       public static Xex.Symbol Name { get { return name; } }
+
        public List<Key> keyseq = new List<Key> ();
 
        public override Xex.TermValue Clone ()
@@ -393,7 +396,7 @@ namespace M17N.Input
               if (list[i].IsInt)
                 keyseq.Add (new Key (list[i].Intval));
               else if (list[i].IsStr)
-                keyseq.Add (new Key (list[i].Strval));
+                keyseq.Add (new Key (list[i].Strval.ToString ()));
               else if (list[i].IsSymbol)
                 keyseq.Add (new Key ((string) list[i].Symval));
               else
@@ -401,13 +404,33 @@ namespace M17N.Input
             }
         }
 
-       public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
+       public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
         {
-          Xex.Term term = new Xex.Term (domain, node.FirstChild).Eval (domain);
-          return (term.IsStr ? new KeySeq ((MText) term.Strval)
+          Xex.Term term = Xex.Parse (domain, node.FirstChild);
+          term = Xex.Eval (domain, term);
+          return (term.IsStr ? new KeySeq ((MText) term.Strval.ToString ())
                   : new KeySeq (term.Listval));
         }
 
+       public override bool Equals (object obj)
+       {
+        KeySeq ks = obj as KeySeq;
+        if (ks == null || ks.keyseq.Count != keyseq.Count)
+          return false;
+        for (int i = 0; i < keyseq.Count; i++)
+          if (keyseq[i] != ks.keyseq[i])
+            return false;
+        return true;
+       }
+
+       public override int GetHashCode ()
+       {
+        int code = 0;
+        for (int i = 0; i < keyseq.Count; i++)
+          code ^= keyseq[i].GetHashCode ();
+        return code;
+       }
+
        public override string ToString ()
        {
         MText mt;
@@ -468,7 +491,7 @@ namespace M17N.Input
             if (node.Name == "description")
               description = parse_description (node);
             else if (node.Name == "keyseq")
-              keys.Add ((KeySeq) KeySeq.parser (null, node));
+              keys.Add ((KeySeq) KeySeq.Parser (null, node));
           }
        }
 
@@ -519,7 +542,7 @@ namespace M17N.Input
        object[] parameters = new object[2];
 
        public PluginMethod (Plugin plugin, string name)
-        : base ((Xex.Symbol) name, 0, -1)
+        : base ((Xex.Symbol) name, false, 0, -1)
         {
           this.plugin = plugin;
         }
@@ -530,8 +553,8 @@ namespace M17N.Input
         args = (Xex.Term[]) args.Clone ();
         for (int i = 0; i < args.Length; i++)
           {
-            args[i] = args[i].Eval (domain);
-            if (domain.Thrown)
+            args[i] = Xex.Eval (domain, args[i]);
+            if (domain.Thrown ())
               return args[i];
           }
         if (method_info == null)
@@ -544,18 +567,21 @@ namespace M17N.Input
 
      internal abstract class Marker : Xex.TermValue
      {
-       private MSymbol name;
+       private static Xex.Symbol name = "marker";
+       public static Xex.Symbol Name { get { return name; } }
 
-       private Marker (MSymbol name)
+       private MSymbol mname;
+
+       private Marker (MSymbol mname)
         {
-          this.name = name;
+          this.mname = mname;
         }
 
        public abstract int Position (Context ic);
 
        public virtual void Mark (Context ic)
         {
-          throw new Exception ("Can't set predefined marker: " + name);
+          throw new Exception ("Can't set predefined marker: " + mname);
         }
        public virtual int CharAt (Context ic)
         {
@@ -567,27 +593,36 @@ namespace M17N.Input
 
        public override string ToString ()
        {
-        return "<marker>" + name.Name + "</marker>";
+        return "<marker>" + mname + "</marker>";
        }
 
-       public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
+       public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
        {
         return Get ((MSymbol) node.InnerText);
        }
 
+       
+       public override bool Equals (object obj)
+       {
+        Marker m = obj as Marker;
+        return (m != null && m.mname == mname);
+       }
+
+       public override int GetHashCode () { return mname.GetHashCode (); }
+
        public class Named : Marker
        {
-        public Named (MSymbol name) : base (name) { }
+        public Named (MSymbol mname) : base (mname) { }
 
         public override int Position (Context ic)
         {
-          MPlist p =  ic.marker_positions.Find (name);
+          MPlist p =  ic.marker_positions.Find (mname);
           return (p == null ? 0 : p.Integer);
         }
 
         public override void Mark (Context ic)
         {
-          ic.marker_positions.Put (name, ic.cursor_pos);
+          ic.marker_positions.Put (mname, ic.cursor_pos);
         }
        }
 
@@ -632,10 +667,10 @@ namespace M17N.Input
        {
         private int pos;
 
-        public PredefinedAbsolute (MSymbol name) : base (name)
+        public PredefinedAbsolute (MSymbol mname) : base (mname)
           {
-            if (! int.TryParse (((string) name).Substring (1), out pos))
-              throw new Exception ("Invalid marker name: " + name);
+            if (! int.TryParse (((string) mname).Substring (1), out pos))
+              throw new Exception ("Invalid marker name: " + mname);
           }
 
         public override int Position (Context ic)
@@ -648,10 +683,10 @@ namespace M17N.Input
        {
         private int distance;
 
-        public PredefinedSurround (MSymbol name) : base (name)
+        public PredefinedSurround (MSymbol mname) : base (mname)
           {
-            if (! int.TryParse (((string) name).Substring (2), out distance))
-              throw new Exception ("Invalid marker name: " + name);
+            if (! int.TryParse (((string) name).Substring (1), out distance))
+              throw new Exception ("Invalid marker name: " + mname);
             if (distance > 0)
               distance--;
           }
@@ -687,24 +722,24 @@ namespace M17N.Input
             = new Predefined (']');
         }
 
-       public static Marker Get (MSymbol name)
+       public static Marker Get (MSymbol mname)
        {
-        string str = name.Name;
+        string str = mname.Name;
         if (str[0] == '@')
           {
             Predefined pred;
-            if (predefineds.TryGetValue (name, out pred))
+            if (predefineds.TryGetValue (mname, out pred))
               return pred;
             if (str.Length == 1)
-              throw new Exception ("Invalid marker name: " + name);
+              throw new Exception ("Invalid marker name: " + mname);
             if (Char.IsDigit (str[1]))
-              return new PredefinedAbsolute (name);
-            if (str.Length == 2 || name == Mat_minus_zero
+              return new PredefinedAbsolute (mname);
+            if (str.Length == 2 || mname == Mat_minus_zero
                 || ! (str[1] == '-' || str[1] == '+'))
-              throw new Exception ("Invalid marker name: " + name);
-            return new PredefinedSurround (name);
+              throw new Exception ("Invalid marker name: " + mname);
+            return new PredefinedSurround (mname);
           }
-        return new Named (name);
+        return new Named (mname);
        }
      }
 
@@ -719,13 +754,13 @@ namespace M17N.Input
         {
           Index = index;
           if (term.IsStr)
-            Data = (MText) term.Strval;
+            Data = (MText) term.Strval.ToString ();
           else
             {
               MPlist plist = new MPlist ();
               MPlist p = plist;
               foreach (Xex.Term t in term.Listval)
-                p = p.Add (MSymbol.mtext, (MText) t.Strval);
+                p = p.Add (MSymbol.mtext, (MText) t.Strval.ToString ());
               Data = plist;
             }
         }
@@ -992,19 +1027,22 @@ namespace M17N.Input
 
     internal class Selector : Xex.TermValue
     {
-      static new Dictionary<MSymbol, Selector> selectors;
+      private static Xex.Symbol name = "selector";
+      public static Xex.Symbol Name { get { return name; } }
+
+      static Dictionary<MSymbol, Selector> selectors;
 
       static Selector ()
        {
          selectors = new Dictionary<MSymbol, Selector> ();
-         selectors ["@<"] = selectors["@first"] = new Selector ('<');
-         selectors ["@="] = selectors["@current"] = new Selector ('=');
-         selectors ["@>"] = selectors["@last"] = new Selector ('>');
-         selectors ["@-"] = selectors["@previous"] = new Selector ('-');
-         selectors ["@+"] = selectors["@next"] = new Selector ('+');
-         selectors ["@["] = selectors["@previous-candidate-change"]
+         selectors["@<"] = selectors["@first"] = new Selector ('<');
+         selectors["@="] = selectors["@current"] = new Selector ('=');
+         selectors["@>"] = selectors["@last"] = new Selector ('>');
+         selectors["@-"] = selectors["@previous"] = new Selector ('-');
+         selectors["@+"] = selectors["@next"] = new Selector ('+');
+         selectors["@["] = selectors["@previous-candidate-change"]
            = new Selector ('[');
-         selectors ["@]"] = selectors["@next-candidate-change"]
+         selectors["@]"] = selectors["@next-candidate-change"]
            = new Selector (']');
        }
 
@@ -1014,7 +1052,7 @@ namespace M17N.Input
 
       private Selector (char tag) { this.tag = tag; }
 
-      public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
+      public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
       {
        return Get ((MSymbol) node.InnerText);
       }
@@ -1026,6 +1064,19 @@ namespace M17N.Input
          throw new Exception ("Invalid selector name: " + name);
        return selector;
       }
+
+      public override bool Equals (object obj)
+      {
+       Selector s = obj as Selector;
+       return (s != null && s.tag == tag);
+      }
+
+      public override int GetHashCode () { return (int) tag; }
+
+      public override string ToString ()
+      {
+       return "<selector>@" + tag + "</selector>";
+      }
     }
 
     internal class Map
@@ -1056,6 +1107,31 @@ namespace M17N.Input
       }
     }
 
+    protected class Action
+    {
+      private Xex.Term action;
+
+      public Action (Xex.Domain domain, Xex.Term[] terms)
+      {
+       Xex.Term[] args = new Xex.Term[terms.Length];
+       args[0] = Tcatch_tag;
+       for (int i = 0; i < terms.Length; i++)
+         args[i + 1] = terms[i];
+       action = new Xex.Term (domain, Qcatch, args);
+      }
+
+      public bool Run (Xex.Domain domain)
+      {
+       Xex.Term result = Xex.Eval (domain, action);
+       if (result.IsError)
+         {
+           ((Context) domain.context).Error = result.ToString ();
+           return false;
+         }
+       return (result != Tcatch_tag);
+      }
+    }
+
     internal class Keymap
     {
       public Dictionary<Key, Keymap> submaps;
@@ -1165,16 +1241,16 @@ namespace M17N.Input
        for (node = node.FirstChild; node != null; node = node.NextSibling)
          {
            if (node.Name == Qstate_hook)
-             enter_actions = Xex.ParseTerms (im.domain, node.FirstChild);
+             enter_actions = Xex.Parse (im.domain, node.FirstChild, null);
            else if (node.Name == Qcatch_all_branch)
-             fallback_actions = Xex.ParseTerms (im.domain, node.FirstChild);
+             fallback_actions = Xex.Parse (im.domain, node.FirstChild, null);
            else if (node.Name == Qbranch)
              {
                MSymbol mapname = node.Attributes[Qmname].Value;
                Map map;
                if (im.maps.TryGetValue (mapname, out map))
-                 keymap.AddMap (map, Xex.ParseTerms (im.domain,
-                                                     node.FirstChild));
+                 keymap.AddMap (map, Xex.Parse (im.domain, node.FirstChild,
+                                                null));
                else
                  throw new Exception ("Unknown map: " + mapname);
              }
@@ -1246,9 +1322,9 @@ namespace M17N.Input
 
     static MInputMethod ()
     {
-      im_domain.DefTerm ("keyseq", KeySeq.parser);
-      im_domain.DefTerm ("marker", Marker.parser);
-      im_domain.DefTerm ("selector", Selector.parser);
+      im_domain.DefType (typeof (KeySeq));
+      im_domain.DefType (typeof (Marker));
+      im_domain.DefType (typeof (Selector));
 
       im_domain.DefSubr (Finsert, "insert", false, 1, 1);
       im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, -1);
@@ -1312,7 +1388,7 @@ namespace M17N.Input
          variables = new Xex.Variable[var_names.Length];
          int i = 0;
          foreach (Xex.Symbol name in var_names)
-           variables[i++] = domain.GetVar (name, false);
+           variables[i++] = domain.GetVar (name);
        }
       commands = this.commands;
       return true;
@@ -1543,7 +1619,7 @@ namespace M17N.Input
          if (! im_global.Open ())
            throw new Exception ("Failed to load global"); 
        }
-      return im_global.domain.GetVar (name, false);
+      return im_global.domain.GetVar (name);
     }
 
     private void parse_variables (MPlist plist)
@@ -1651,7 +1727,7 @@ namespace M17N.Input
          Xex.Variable vari = get_global_var (name);
          if (vari != null)
            domain.Defvar (vari);
-         domain.Defvar (node_list[i]);
+         Xex.Parse (domain, node_list[i]);
          var_names[i] = name;
        }
     }
@@ -1739,17 +1815,13 @@ namespace M17N.Input
     private void parse_macros (XmlNode node)
     {
       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
-       if (nn.NodeType == XmlNodeType.Element)
-       {
-         if (nn.Name == Xex.Qdefun)
-           domain.Defun (nn, true);
-         else if (nn.Name == Qxi_include)
+       if (nn.NodeType == XmlNodeType.Element && nn.Name == Qxi_include)
+         {
            parse_include (nn);
-       }
-      for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
-       if (nn.NodeType == XmlNodeType.Element
-           && nn.Name == Xex.Qdefun)
-         domain.Defun (nn, false);
+           nn = nn.PreviousSibling;
+           node.RemoveChild (nn.NextSibling);
+         }
+      Xex.Parse (domain, node.FirstChild, null);
     }
 
     private void parse_maps (XmlNode node)
@@ -1768,8 +1840,9 @@ namespace M17N.Input
                    XmlNode n = nd.FirstChild;
                    if (n.Name != Qkeyseq)
                      continue;
-                   KeySeq keyseq = (KeySeq) KeySeq.parser (domain, n);
-                   Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling);
+                   KeySeq keyseq = (KeySeq) KeySeq.Parser (domain, n);
+                   n = n.NextSibling;
+                   Xex.Term[] actions = Xex.Parse (domain, n, null);
                    map.entries.Add (new Map.Entry (domain, keyseq, actions));
                  }
            }
@@ -2065,17 +2138,16 @@ namespace M17N.Input
            MPlist p = pl.Plist;
            if (! p.IsSymbol)
              continue;
-           domain.Defun ((Xex.Symbol) p.Symbol.Name, null, null, true);
+           domain.Defun ((Xex.Symbol) p.Symbol.Name, 0, 0, null, null);
          }
       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
        if (pl.IsPlist)
          {
            MPlist p = pl.Plist;
-
            if (! p.IsSymbol)
              continue;
-           domain.Defun ((Xex.Symbol) p.Symbol.Name, null,
-                         parse_actions (p.next, false), false);
+           domain.Defun ((Xex.Symbol) p.Symbol.Name, 0, 0, null,
+                         parse_actions (p.next, false));
          }
     }
 
@@ -2116,7 +2188,8 @@ namespace M17N.Input
       if (args[0].IsInt)
        ((Context) domain.context).insert (args[0].Intval, null);
       else
-       ((Context) domain.context).insert ((MText) args[0].Strval, null);
+       ((Context) domain.context).insert ((MText) args[0].Strval.ToString (),
+                                          null);
       return args[0];
     }
 
@@ -2125,8 +2198,8 @@ namespace M17N.Input
                                                Xex.Term[] args)
     {
       Context ic = (Context) domain.context;
-      Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size, false);
-      int column = (v == null ? 0 : v.Value.Intval);
+      Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size);
+      int column = v == null ? 0 : v.Value.Intval;
       Candidates candidates = new Candidates (args, column);
       object candidate = candidates.Current;
 
@@ -2228,7 +2301,7 @@ namespace M17N.Input
       if (args[0].IsInt)
        ic.pushback (args[0].Intval);
       else if (args[0].IsStr)
-       ic.pushback (new KeySeq (args[0].Strval));
+       ic.pushback (new KeySeq (args[0].Strval.ToString ()));
       else
        ic.pushback ((KeySeq) args[0].Objval);
       return args[0];
@@ -2260,9 +2333,7 @@ namespace M17N.Input
                                       Xex.Term[] args)
     {
       ((Context) domain.context).commit ();
-      args = new Xex.Term[2];
-      args[0] = args[1] = Tcatch_tag;
-      return Xex.Fthrow (domain, vari, args);
+      return Xex.Fthrow (domain, vari, new Xex.Term[1] { Tcatch_tag });
     }
 
     private static Xex.Term Fshift (Xex.Domain domain, Xex.Variable vari,
@@ -2379,6 +2450,12 @@ namespace M17N.Input
 
       internal ChangedStatus changed;
 
+      private string error_message;
+      public string Error {
+       get { return error_message; }
+       set { error_message = value; }
+      }
+
       private void set_cursor (string prefix, int pos)
       {
        cursor_pos = pos;
@@ -2419,7 +2496,7 @@ namespace M17N.Input
        catch_args[0] = Tcatch_tag;
        catch_args[1]= new Xex.Term (domain, Qprogn, actions);
        Xex.Term term = new Xex.Term (domain, Qcatch, catch_args);
-       term = term.Eval (domain);
+       term = Xex.Eval (domain, term);
        return (! term.IsSymbol || term.Symval != Tcatch_tag.Symval);
       }
 
@@ -2519,6 +2596,7 @@ namespace M17N.Input
              {
                if (DelSurroundingText != null)
                  {
+                   Console.WriteLine ("deleting the prev {0} chars", - pos);
                    callback_arg.Set (MSymbol.integer, pos);
                    if (DelSurroundingText (this, callback_arg))
                      {
@@ -2540,6 +2618,8 @@ namespace M17N.Input
              {
                if (DelSurroundingText != null)
                  {
+                   Console.WriteLine ("deleting the next {0} chars",
+                                      pos - preedit.Length);
                    callback_arg.Set (MSymbol.integer, pos - preedit.Length);
                    if (DelSurroundingText (this, callback_arg))
                      {
@@ -2630,9 +2710,12 @@ namespace M17N.Input
 
       internal void commit ()
       {
-       Candidates.Detach (this);
-       produced.Cat (preedit);
-       preedit_replace (0, preedit.Length, null, null);
+       if (preedit.Length > 0)
+         {
+           Candidates.Detach (this);
+           produced.Cat (preedit);
+           preedit_replace (0, preedit.Length, null, null);
+         }
       }
 
       internal void shift (State state)
@@ -2674,7 +2757,7 @@ namespace M17N.Input
       {
        if (im.load_status != LoadStatus.Full
            && ! im.Open ())
-         throw new Exception ("Openging " + im.tag + " failed");
+         throw new Exception ("Opening " + im.tag + " failed");
        this.im = im;
        domain = new Xex.Domain ("context", im.domain, this);
        initial_state = (State) im.states.Val;
@@ -2727,8 +2810,7 @@ namespace M17N.Input
 
       private bool handle_key ()
       {
-       Console.WriteLine ("{0}:key='{1}'", state.name,
-                          new MText (keys.keyseq[key_head].ToChar ()));
+       Console.WriteLine ("{0}:key='{1}'", state.name, keys.keyseq[key_head]);
        Keymap sub = keymap.Lookup (keys, ref key_head);
 
        if (sub != keymap)
@@ -2852,6 +2934,34 @@ namespace M17N.Input
          }
        return (! key_unhandled && produced.Length == 0);
       }
+
+      public bool Filter ()
+      {
+       changed = ChangedStatus.None;
+       produced.Del ();
+       preceding_text.Del ();
+       following_text.Del ();
+
+       commit ();
+       if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
+           && PreeditChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, preedit);
+           PreeditChanged (this, callback_arg);
+         }
+       if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
+           && StatusChanged != null)
+         {
+           callback_arg.Set (MSymbol.mtext, status);
+           StatusChanged (this, callback_arg);
+         }
+       if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
+           && CandidateChanged != null)
+         {
+           CandidateChanged (this, callback_arg);
+         }
+       return (produced.Length == 0);
+      }
     }
 
     public class Session
@@ -2882,6 +2992,7 @@ namespace M17N.Input
       private bool del_surrounding_text (Context ic, MPlist args)
       {
        int pos = this.pos + args.Integer;
+       Console.WriteLine ("del-surround: {0}-{1}", this.pos, pos);
        if (pos < this.pos)
          {
            mt.Del (pos, this.pos);
@@ -2892,25 +3003,37 @@ namespace M17N.Input
        return true;
       }
 
-      public bool HandleKey (Key key)
+      public bool HandleKey (ref Key key)
       {
-       bool result = ic.Filter (key);
-         
-       if (! result)
+       if (! ic.Filter (key))
          {
            MText produced = ic.Produced;
            mt.Ins (pos, produced);
            pos += produced.Length;
-           if (ic.UnhandledKey (out key))
+           Key unhandled;
+           if (ic.UnhandledKey (out unhandled))
              {
-               mt.Ins (pos, key.ToChar ());
-               pos++;
+               key = unhandled;
+               return false;
              }
          }
+       return true;
+      }
+
+      public bool Close ()
+      {
+       bool result = ic.Filter ();
+       if (! result)
+         {
+           mt.Ins (pos, ic.Produced);
+           pos += ic.Produced.Length;
+         }
+       ic = null;
+       mt = null;
        return result;
       }
 
-      public int CurrentPos { get { return pos; } }
+      public int CurrentPos { get { return pos; } set { pos = value; } }
       public MText Preedit { get { return ic.Preedit; } }
     }
   }