*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
index da10788..ff6a974 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 ()
@@ -401,13 +404,32 @@ 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)
                   : 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 +490,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));
           }
        }
 
@@ -544,47 +566,62 @@ 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)
         {
-          return ic.preedit[Position (ic)];
+          int pos = Position (ic);
+
+          return ((pos >= 0 && pos < ic.preedit.Length) ? ic.preedit[pos]
+                  : -1);
         }
 
        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);
         }
        }
 
@@ -629,10 +666,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)
@@ -645,10 +682,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--;
           }
@@ -684,24 +721,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);
        }
      }
 
@@ -989,6 +1026,9 @@ namespace M17N.Input
 
     internal class Selector : Xex.TermValue
     {
+      private static Xex.Symbol name = "selector";
+      public static Xex.Symbol Name { get { return name; } }
+
       static new Dictionary<MSymbol, Selector> selectors;
 
       static Selector ()
@@ -1011,7 +1051,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);
       }
@@ -1023,6 +1063,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
@@ -1053,6 +1106,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 = action.Eval (domain);
+       if (result.IsError)
+         {
+           ((Context) domain.context).Error = result.ToString ();
+           return false;
+         }
+       return (result != Tcatch_tag);
+      }
+    }
+
     internal class Keymap
     {
       public Dictionary<Key, Keymap> submaps;
@@ -1243,9 +1321,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);
@@ -1765,7 +1843,7 @@ namespace M17N.Input
                    XmlNode n = nd.FirstChild;
                    if (n.Name != Qkeyseq)
                      continue;
-                   KeySeq keyseq = (KeySeq) KeySeq.parser (domain, n);
+                   KeySeq keyseq = (KeySeq) KeySeq.Parser (domain, n);
                    Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling);
                    map.entries.Add (new Map.Entry (domain, keyseq, actions));
                  }
@@ -2257,9 +2335,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,
@@ -2292,7 +2368,7 @@ namespace M17N.Input
                                               Xex.Term[] args)
     {
       return new Xex.Term (((Context) domain.context).GetSurroundingText == null
-                          ? 0 : 1);
+                          ? -2 : -1);
     }
 
     public override string ToString ()
@@ -2376,6 +2452,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;
@@ -2516,6 +2598,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))
                      {
@@ -2537,6 +2620,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))
                      {
@@ -2627,9 +2712,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)
@@ -2724,6 +2812,7 @@ namespace M17N.Input
 
       private bool handle_key ()
       {
+       Console.WriteLine ("{0}:key='{1}'", state.name, keys.keyseq[key_head]);
        Keymap sub = keymap.Lookup (keys, ref key_head);
 
        if (sub != keymap)
@@ -2847,6 +2936,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
@@ -2877,6 +2994,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);
@@ -2887,25 +3005,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; } }
     }
   }