*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
index 918fea5..0128e84 100644 (file)
@@ -12,6 +12,7 @@ using M17N.Input;
 namespace M17N.Input
 {
   using Xex = System.Xml.Expression.Xexpression;
+  using Mim = MInputMethod;
 
   public class MInputMethod
   {
@@ -348,37 +349,28 @@ namespace M17N.Input
        return 0;
       }
 
-      public KeySeq (Xex.Term arg)
+      public KeySeq (List<Xex.Term> list)
        {
-         if (arg.IsStr)
-           {
-             string str = arg.Strval;
+         int len = list.Count;
 
-             for (int i = 0; i < str.Length; i++)
-               keyseq.Add (new Key (str[i]));
-           }
-         else if (arg.IsList)
+         for (int i = 0; i < len; i++)
            {
-             List<Xex.Term> list = arg.Listval;
-             int len = list.Count;
-
-             for (int i = 0; i < len; i++)
-               {
-                 if (list[i].IsInt)
-                   keyseq.Add (new Key (list[i].Intval));
-                 else if (list[i].IsStr)
-                   keyseq.Add (new Key (list[i].Strval));
-                 else if (list[i].IsSymbol)
-                   keyseq.Add (new Key ((string) list[i].Symval));
-                 else
-                   throw new Exception ("Invalid key: " + list[i]);
-               }
+             if (list[i].IsInt)
+               keyseq.Add (new Key (list[i].Intval));
+             else if (list[i].IsStr)
+               keyseq.Add (new Key (list[i].Strval));
+             else if (list[i].IsSymbol)
+               keyseq.Add (new Key ((string) list[i].Symval));
+             else
+               throw new Exception ("Invalid key: " + list[i]);
            }
        }
 
-      public static Xex.TermValue New (Xex.Domain domain, XmlNode node)
+      public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
        {
-         return new KeySeq (new Xex.Term (domain, node.FirstChild));
+         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 string ToString ()
@@ -525,10 +517,7 @@ namespace M17N.Input
            if (node.Name == "description")
              description = parse_description (node);
            else if (node.Name == "keyseq")
-             {
-               KeySeq ks = MInputMethod.KeySeq.New (domain, node);
-               keys.Add (ks);
-             }
+             keys.Add ((KeySeq) KeySeq.parser (null, node));
          }
       }
 
@@ -604,7 +593,7 @@ namespace M17N.Input
 
     internal abstract class Marker : Xex.TermValue
     {
-      MSymbol name;
+      private MSymbol name;
 
       public Marker (MSymbol name)
        {
@@ -614,6 +603,13 @@ namespace M17N.Input
       public abstract int Position (MInputContext ic);
       public abstract void Mark (MInputContext ic);
 
+      public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
+      {
+       MSymbol name = node.InnerText;
+       
+       return Get ((MInputContext) domain.context, name);
+      }
+
       public class Named : Marker
       {
        int pos;
@@ -648,8 +644,7 @@ namespace M17N.Input
              {
                int pos = ic.cursor_pos;
                int to;
-               ic.preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
-                                    out pos, out to);
+               ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to);
                return pos;
              }
            return 0;
@@ -658,8 +653,7 @@ namespace M17N.Input
              {
                int pos = ic.cursor_pos;
                int from;
-               ic.preedit.FindProp (MInputMethod.Mcandidates, pos,
-                                    out from, out pos);
+               ic.preedit.FindProp (Mcandidates, pos, out from, out pos);
                return pos;
              }
            return ic.preedit.Length;
@@ -710,143 +704,471 @@ namespace M17N.Input
       }
     }
       
-    internal class Map
+    internal class Candidates
     {
-      public MSymbol name;
-      public Dictionary<Key, Map> submaps;
-      public Xex.Term actions;
-
-      public void Add (KeySeq keys, int index, Xex.Term actions)
+      private class Block
       {
-       Map sub = null;
+       public int Index;
+       public object Data;
 
-       if (submaps == null)
-         submaps = new Dictionary<Key, Map> ();
-       else
-         submaps.TryGetValue (keys.keyseq[index], out sub);
-       if (sub == null)
-         {
-           Key key = keys.keyseq[index];
-           submaps[key] = sub = new Map ();
+       public Block (int index, Xex.Term term)
+       {
+         Index = index;
+         if (term.IsStr)
+           Data = (MText) term.Strval;
+         else
+           {
+             MPlist plist = new MPlist ();
+             MPlist p = plist;
+             foreach (Xex.Term t in term.Listval)
+               p = p.Add (MSymbol.mtext, (MText) t.Strval);
+             Data = plist;
+           }
+       }
+
+       public Block (int index, MPlist plist)
+       {
+         Index = index;
+         if (plist.IsMText)
+           Data = plist.Text;
+         else if (plist.IsPlist)
+           Data = plist.Plist;
+         else
+           throw new Exception ("Invalid candidate: " + plist);
+       }
+
+       public int Count
+       {
+         get { return (Data is MText
+                       ? ((MText) Data).Length
+                       : ((MPlist) Data).Count); }
+       }
+
+       public object this[int i]
+       {
+         get {
+           if (Data is MText) return ((MText) Data)[i];
+           return  ((MPlist) Data)[i];
          }
-       if (index + 1 < keys.keyseq.Count)
-         sub.Add (keys, index + 1, actions);
-       else
-         this.actions = actions;
+       }
       }
 
-      public Xex.Term Lookup (KeySeq keys, int index)
-      {
-       Map sub;
+      private Block[] blocks;
+      private int row = 0;
+      private int index = 0;
+      public object[] group;
 
-       if (index + 1 == keys.keyseq.Count)
-         return actions;
-       if (submaps.TryGetValue (keys.keyseq[index], out sub))
-         return sub.Lookup (keys, index + 1);
-       return Tnil;
+      private bool IsFixed { get { return group != null; } }
+      private int Total {
+       get {
+         Block last = blocks[blocks.Length - 1];
+         return last.Index + last.Count; }
       }
 
-      private void describe (MText mt, KeySeq keyseq)
+      public int Column {
+       get { return (IsFixed ? index % group.Length
+                     : index - blocks[row].Index); }
+      }
+
+      public object Group {
+       get { return (IsFixed ? group : blocks[row].Data); }
+      }
+
+      public int GroupLength
       {
-       if (keyseq.keyseq.Count > 0)
-         {
-           mt.Cat (" (").Cat (keyseq.ToString ());
-           mt.Cat (' ').Cat (actions.ToString ());
-           mt.Cat (')');           
-         }
-       if (submaps != null)
-         foreach (KeyValuePair<Key, Map> kv in submaps)
+       get {
+         if (IsFixed)
            {
-             keyseq.keyseq.Add (kv.Key);
-             kv.Value.describe (mt, keyseq);
-             keyseq.keyseq.RemoveAt (keyseq.keyseq.Count - 1);
+             int nitems = group.Length;
+             int start = index - (index % nitems);
+             int total = Total;
+             return (start + nitems <= total ? nitems : total - start);
            }
+         return blocks[row].Count;
+       }
       }
 
-      public override string ToString ()
-      {
-       MText mt = "(" + name.Name;
-       KeySeq keyseq = new KeySeq ();
-
-       describe (mt, keyseq);
-       mt.Cat (')');
-       return (string) mt;
+      public object Current {
+       get {
+         return (IsFixed ? group[index % group.Length]
+                 : blocks[row][index - blocks[row].Index]);
+       }
       }
-    }
-
-    internal class State
-    {
-      public MSymbol name;
-      public MText title;
-      public MPlist branches = new MPlist ();
 
-      public State (MSymbol name)
+      public Candidates (MPlist list, int column)
       {
-       this.name = name;
+       int nblocks = list.Count;
+
+       blocks = new Block[nblocks];
+       for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
+         start += (blocks[i] = new Block (index, list)).Count;
+       if (column > 0)
+         group = new object[column];
       }
 
-      public override string ToString ()
+      public Candidates (List<Xex.Term> list, int column)
       {
-       MText mt = "(" + name.Name;
+       int nblocks = list.Count;
 
-       if (title != null)
-         mt.Cat (" \"" + title + "\"");
-       for (MPlist p = branches; ! p.IsEmpty; p = p.next)
-         mt.Cat (" (" + p.Key + " " + (Xex) p.Val + ")");
-       return (string) mt + ")";
+       blocks = new Block[nblocks];
+       for (int i = 0, start = 0; i < nblocks; i++)
+         start += (blocks[i] = new Block (index, list[i])).Count;
+       if (column > 0)
+         group = new object[column];
       }
-    }
 
-    // Instance members
-    internal Xex.Domain domain = new Xex.Domain (im_domain, null);
+      public static void Detach (MInputContext ic)
+      {
+       ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates);
+       ic.candidates = null;
+       ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
+                      | CandidateAll);
+      }
 
-    private LoadStatus load_status = LoadStatus.None;
-    private MDatabase.Tag tag;
-    private MDatabase mdb;
+      // Fill the array "group" by candidates stating from INDEX.
+      // INDEX must be a multiple of "column".  Set NTIMES to the
+      // number of valid candidates in "group".  Update "block" if
+      // necessary.  Return "group".
 
-    private MText description;
-    internal MText title;
-    internal Command[] commands;
-    internal Xex.Symbol[] var_names;
-    internal Dictionary<MSymbol, Plugin> plugins;
-    internal Dictionary<MSymbol, Map> maps;
-    internal MPlist states;
+      private int fill_group (int start)
+      {
+       int nitems = group.Length;
+       int r = row;
+       Block b = blocks[r];
 
-    static MInputMethod ()
-    {
-      im_domain.DefType ("keyseq", KeySeq.New);
+       if (start < b.Index)
+         while (start < b.Index)
+            b = blocks[--r];
+       else
+         while (start >= b.Index + b.Count)
+           b = blocks[++r];
+       row = r;
 
-      im_domain.DefSubr (Finsert, "insert", true, 1, 1);
-      im_domain.DefSubr (Finsert_candidates, "candidates", true, 1, -1);
-      im_domain.DefSubr (Fdelete, "delete", true, 1, 1);
-      im_domain.DefSubr (Fselect, "select", true, 1, 1);
-      im_domain.DefSubr (Fshow, "show", true, 0, 0);
-      im_domain.DefSubr (Fhide, "hide", true, 0, 0);
-      im_domain.DefSubr (Fmove, "move", true, 1, 1);
-      im_domain.DefSubr (Fmark, "mark", true, 1, 1);
-      im_domain.DefSubr (Fpushback, "pushback", true, 1, 1);
-      im_domain.DefSubr (Fpop, "pop", true, 0, 0);
-      im_domain.DefSubr (Fundo, "undo", true, 0, 1);
-      im_domain.DefSubr (Fcommit, "commit", true, 0, 0);
-      im_domain.DefSubr (Funhandle, "unhandle", true, 0, 0);
-      im_domain.DefSubr (Fshift, "shift", true, 1, 1);
-      im_domain.DefSubr (Fmarker, "marker", true, 1, 1);
-      im_domain.DefSubr (Fchar_at, "char-at", true, 1, 1);
+       int count = b.Count;
+       start -= b.Index;
+       for (int i = 0; i < nitems; i++, start++)
+         {
+           if (start >= count)
+             {
+               r++;
+               if (r == blocks.Length)
+                 return i;
+               b = blocks[r];
+               count = b.Count;
+               start = 0;
+             }
+           group[i] = b[start];
+         }
+       return nitems;
+      }
 
-      MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
-      List<MDatabase> list = MDatabase.List (tag);
-      M17n.DebugPrint ("Found {0} input methods\n", list.Count);
-      foreach (MDatabase mdb in list)
-       im_table[mdb.tag] = new MInputMethod (mdb.tag);
-    }
+      // Update "row" to what contains the first candidate of
+      // the previous candidate-group, update "current_index", and
+      // update "group" if necessary.  Return the previous
+      // candidate-group.  Set NITEMS to the number of valid
+      // candidates contained in that group.
 
-    // Constructor
-    private MInputMethod (MDatabase.Tag tag)
-    {
-      this.tag = tag;
-    }
+      public int PrevGroup ()
+      {
+       int nitems;
+       int col = Column;
 
-    // Instance Properties
+       if (IsFixed)
+         {
+           nitems = group.Length;
+           if ((index -= col + nitems) < 0)
+             index = (Total / nitems) * nitems;
+           nitems = fill_group (index);
+         }
+       else
+         {
+           row = row > 0 ? row-- : blocks.Length - 1;
+           nitems = blocks[row].Count;
+           index = blocks[row].Index;
+         }
+       index += col < nitems ? col : nitems - 1;
+       return nitems;
+      }
+
+      public int NextGroup ()
+      {
+       int nitems;
+       int col = Column;
+
+       if (IsFixed)
+         {
+           nitems = group.Length;
+           if ((index += nitems - col) >= Total)
+             index = 0;
+           nitems = fill_group (index);
+         }
+       else
+         {
+           row = row < blocks.Length - 1 ? row + 1 : 0;
+           nitems = blocks[row].Count;
+           index = blocks[row].Count;
+         }
+       index += col < nitems ? col : nitems - 1;
+       return nitems;
+      }
+
+      public void Prev ()
+      {
+       int col = Column;
+
+       if (col == 0)
+         {
+           int nitems = PrevGroup ();
+           index += col < nitems - 1 ? col : nitems - 1;
+         }
+       else
+         index--;
+      }
+
+      public void Next ()
+      {
+       int col = Column;
+       int nitems = GroupLength;
+
+       if (col == nitems - 1)
+         {
+           nitems = NextGroup ();
+           index -= Column;
+         }
+       else
+         index++;
+      }
+
+      public void First ()
+      {
+       index -= Column;
+      }
+
+      public void Last ()
+      {
+       index += GroupLength - (Column + 1);
+      }
+
+      public void Select (int col)
+      {
+       int maxcol = GroupLength - 1;
+       if (col > maxcol)
+         col = maxcol;
+       index = index - Column + col;
+      }
+    }
+
+    internal abstract class Selector : Xex.TermValue
+    {
+      private Selector () { }
+
+      public abstract void Select (Candidates candidates);
+
+      public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
+      {
+       MSymbol name = node.InnerText;
+       Predefined pred;
+
+       if (predefined_selectors.TryGetValue (name, out pred))
+         return pred;
+       if (name.Name[0] == '@')
+         throw new Exception ("Invalid selector name: " + name);
+       int index;
+       if (! Int32.TryParse (node.InnerText, out index))
+         throw new Exception ("Invalid selector name: " + name);
+       return new Numbered (index);
+      }
+
+      public class Numbered : Selector
+      {
+       int index;
+
+       public Numbered (int index) { this.index = index; }
+
+       public override void Select (Candidates can)
+       {
+         if (can != null)
+           can.Select (index);
+       }
+      }
+
+      public class Predefined : Selector
+      {
+       private char tag;
+
+       private Predefined (MSymbol sym) { this.tag = sym.Name[1]; }
+
+       public override void Select (Candidates can)
+       {
+         if (can != null)
+           {
+             if (sym == Mat_less_than)
+               candidates.First ();
+             else if (sym == Mat_greater_than)
+               candidates.Last ();
+             else if (sym == Mat_minus)
+               candidates.Prev ();
+             else if (sym == Mat_plus)
+               candidates.Next ();
+             else if (sym == Mat_open_square_bracket)
+               candidates.PrevGroup ();
+             else if (sym == Mat_close_square_bracket)
+               candidates.NextGroup ();
+           }
+       }
+      }
+
+      static Predefined predefined_selectors;
+
+      static Selector ()
+       {
+         predefined_selectors = new Dictionary<MSymbol, Predefined> ();
+         MSymbol[] symlist = new MSymbol[] { "@<", "@=", "@>", "@-", "@+",
+                                             "@[", "@]" };
+         foreach (MSymbol s in symlist)
+           predefined_markers[s] = new Predefined (s);
+       }
+    }
+
+    internal class Map
+    {
+      public MSymbol name;
+      public Dictionary<Key, Map> submaps;
+      public Xex.Term actions;
+
+      public void Add (KeySeq keys, int index, Xex.Term actions)
+      {
+       Map sub = null;
+
+       if (submaps == null)
+         submaps = new Dictionary<Key, Map> ();
+       else
+         submaps.TryGetValue (keys.keyseq[index], out sub);
+       if (sub == null)
+         {
+           Key key = keys.keyseq[index];
+           submaps[key] = sub = new Map ();
+         }
+       if (index + 1 < keys.keyseq.Count)
+         sub.Add (keys, index + 1, actions);
+       else
+         this.actions = actions;
+      }
+
+      public Xex.Term Lookup (KeySeq keys, int index)
+      {
+       Map sub;
+
+       if (index + 1 == keys.keyseq.Count)
+         return actions;
+       if (submaps.TryGetValue (keys.keyseq[index], out sub))
+         return sub.Lookup (keys, index + 1);
+       return Tnil;
+      }
+
+      private void describe (MText mt, KeySeq keyseq)
+      {
+       if (keyseq.keyseq.Count > 0)
+         {
+           mt.Cat (" (").Cat (keyseq.ToString ());
+           mt.Cat (' ').Cat (actions.ToString ());
+           mt.Cat (')');           
+         }
+       if (submaps != null)
+         foreach (KeyValuePair<Key, Map> kv in submaps)
+           {
+             keyseq.keyseq.Add (kv.Key);
+             kv.Value.describe (mt, keyseq);
+             keyseq.keyseq.RemoveAt (keyseq.keyseq.Count - 1);
+           }
+      }
+
+      public override string ToString ()
+      {
+       MText mt = "(" + name.Name;
+       KeySeq keyseq = new KeySeq ();
+
+       describe (mt, keyseq);
+       mt.Cat (')');
+       return (string) mt;
+      }
+    }
+
+    internal class State
+    {
+      public MSymbol name;
+      public MText title;
+      public MPlist branches = new MPlist ();
+
+      public State (MSymbol name)
+      {
+       this.name = name;
+      }
+
+      public override string ToString ()
+      {
+       MText mt = "(" + name.Name;
+
+       if (title != null)
+         mt.Cat (" \"" + title + "\"");
+       for (MPlist p = branches; ! p.IsEmpty; p = p.next)
+         mt.Cat (" (" + p.Key + " " + (Xex) p.Val + ")");
+       return (string) mt + ")";
+      }
+    }
+
+    // Instance members
+    internal Xex.Domain domain = new Xex.Domain (im_domain, null);
+
+    private LoadStatus load_status = LoadStatus.None;
+    private MDatabase.Tag tag;
+    private MDatabase mdb;
+
+    private MText description;
+    internal MText title;
+    internal Command[] commands;
+    internal Xex.Symbol[] var_names;
+    internal Dictionary<MSymbol, Plugin> plugins;
+    internal Dictionary<MSymbol, Map> maps;
+    internal MPlist states;
+
+    static MInputMethod ()
+    {
+      im_domain.DefTerm ("keyseq", KeySeq.parser);
+      im_domain.DefTerm ("marker", Marker.parser);
+      im_domain.DefTerm ("selector", Selector.parser);
+
+      im_domain.DefSubr (Finsert, "insert", true, 1, 1);
+      im_domain.DefSubr (Finsert_candidates, "candidates", true, 1, -1);
+      im_domain.DefSubr (Fdelete, "delete", true, 1, 1);
+      im_domain.DefSubr (Fselect, "select", true, 1, 1);
+      im_domain.DefSubr (Fshow, "show", true, 0, 0);
+      im_domain.DefSubr (Fhide, "hide", true, 0, 0);
+      im_domain.DefSubr (Fmove, "move", true, 1, 1);
+      im_domain.DefSubr (Fmark, "mark", true, 1, 1);
+      im_domain.DefSubr (Fpushback, "pushback", true, 1, 1);
+      im_domain.DefSubr (Fpop, "pop", true, 0, 0);
+      im_domain.DefSubr (Fundo, "undo", true, 0, 1);
+      im_domain.DefSubr (Fcommit, "commit", true, 0, 0);
+      im_domain.DefSubr (Funhandle, "unhandle", true, 0, 0);
+      im_domain.DefSubr (Fshift, "shift", true, 1, 1);
+      im_domain.DefSubr (Fmarker, "marker", true, 1, 1);
+      im_domain.DefSubr (Fchar_at, "char-at", true, 1, 1);
+
+      MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
+      List<MDatabase> list = MDatabase.List (tag);
+      M17n.DebugPrint ("Found {0} input methods\n", list.Count);
+      foreach (MDatabase mdb in list)
+       im_table[mdb.tag] = new MInputMethod (mdb.tag);
+    }
+
+    // Constructor
+    private MInputMethod (MDatabase.Tag tag)
+    {
+      this.tag = tag;
+    }
+
+    // Instance Properties
     public MSymbol Language { get { return tag[1]; } }
     public MSymbol Name { get { return tag[2]; } }
     public MSymbol SubName { get { return tag[3]; } }
@@ -1703,14 +2025,11 @@ namespace M17N.Input
     }
 
     private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
-                                  Xex.Term[] args)
+                                    Xex.Term[] args)
     {
-      MInputContext ic = (MInputContext) domain.context;
+      Selector sel = (Selector) args[0].Objval;
 
-      if (args[0].IsInt)
-       ic.select (args[0].Intval);
-      else
-       ic.select ((MSymbol) ((string) args[0].Symval));
+      sel.Select (((MInputContext) domain.context).candidates);
       return args[0];
     }
 
@@ -1852,14 +2171,14 @@ namespace M17N.Input
     private MText status;
     internal MText preedit;
     internal int cursor_pos;
-    private Candidates candidates;
+    internal Mim.Candidates candidates;
     private MPlist candidate_group;
     private int candidate_index;
     private int candidate_from, candidate_to;
     private bool candidate_show;
 
-    private Stack<MInputMethod.State> states;
-    internal MInputMethod.KeySeq keys;
+    private Stack<Mim.State> states;
+    internal Mim.KeySeq keys;
     private int key_head;
     private int state_key_head;
     private object state_var_values;
@@ -1896,9 +2215,9 @@ namespace M17N.Input
     {
       this.im = im;
       domain = new Xex.Domain (im.domain, this);
-      states = new Stack<MInputMethod.State> ();
-      states.Push ((MInputMethod.State) im.states.val);
-      keys = new MInputMethod.KeySeq ();
+      states = new Stack<Mim.State> ();
+      states.Push ((Mim.State) im.states.val);
+      keys = new Mim.KeySeq ();
     }
 
     private void adjust_markers (int from, int to, object inserted)
@@ -1947,260 +2266,6 @@ namespace M17N.Input
       changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
     }
 
-    private class Candidates
-    {
-      private class Block
-      {
-       public int Index;
-       public object Data;
-
-       public Block (int index, Xex.Term term)
-       {
-         Index = index;
-         if (term.IsStr)
-           Data = (MText) term.Strval;
-         else
-           {
-             MPlist plist = new MPlist ();
-             MPlist p = plist;
-             foreach (Xex.Term t in term.Listval)
-               p = p.Add (MSymbol.mtext, (MText) t.Strval);
-             Data = plist;
-           }
-       }
-
-       public Block (int index, MPlist plist)
-       {
-         Index = index;
-         if (plist.IsMText)
-           Data = plist.Text;
-         else if (plist.IsPlist)
-           Data = plist.Plist;
-         else
-           throw new Exception ("Invalid candidate: " + plist);
-       }
-
-       public int Count
-       {
-         get { return (Data is MText
-                       ? ((MText) Data).Length
-                       : ((MPlist) Data).Count); }
-       }
-
-       public object this[int i]
-       {
-         get {
-           if (Data is MText) return ((MText) Data)[i];
-           return  ((MPlist) Data)[i];
-         }
-       }
-      }
-
-      private Block[] blocks;
-      private int row = 0;
-      private int index = 0;
-      public object[] group;
-
-      private bool IsFixed { get { return group != null; } }
-      private int Total {
-       get {
-         Block last = blocks[blocks.Length - 1];
-         return last.Index + last.Count; }
-      }
-
-      public int Column {
-       get { return (IsFixed ? index % group.Length
-                     : index - blocks[row].Index); }
-      }
-
-      public object Group {
-       get { return (IsFixed ? group : blocks[row].Data); }
-      }
-
-      public int GroupLength
-      {
-       get {
-         if (IsFixed)
-           {
-             int nitems = group.Length;
-             int start = index - (index % nitems);
-             int total = Total;
-             return (start + nitems <= total ? nitems : total - start);
-           }
-         return blocks[row].Count;
-       }
-      }
-
-      public object Current {
-       get {
-         return (IsFixed ? group[index % group.Length]
-                 : blocks[row][index - blocks[row].Index]);
-       }
-      }
-
-      public Candidates (MPlist list, int column)
-      {
-       int nblocks = list.Count;
-
-       blocks = new Block[nblocks];
-       for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
-         start += (blocks[i] = new Block (index, list)).Count;
-       if (column > 0)
-         group = new object[column];
-      }
-
-      public Candidates (List<Xex.Term> list, int column)
-      {
-       int nblocks = list.Count;
-
-       blocks = new Block[nblocks];
-       for (int i = 0, start = 0; i < nblocks; i++)
-         start += (blocks[i] = new Block (index, list[i])).Count;
-       if (column > 0)
-         group = new object[column];
-      }
-
-      public static void Detach (MInputContext ic)
-      {
-       ic.preedit.PopProp (0, ic.preedit.Length, MInputMethod.Mcandidates);
-       ic.candidates = null;
-       ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
-                      | CandidateAll);
-      }
-
-      // Fill the array "group" by candidates stating from INDEX.
-      // INDEX must be a multiple of "column".  Set NTIMES to the
-      // number of valid candidates in "group".  Update "block" if
-      // necessary.  Return "group".
-
-      private int fill_group (int start)
-      {
-       int nitems = group.Length;
-       int r = row;
-       Block b = blocks[r];
-
-       if (start < b.Index)
-         while (start < b.Index)
-            b = blocks[--r];
-       else
-         while (start >= b.Index + b.Count)
-           b = blocks[++r];
-       row = r;
-
-       int count = b.Count;
-       start -= b.Index;
-       for (int i = 0; i < nitems; i++, start++)
-         {
-           if (start >= count)
-             {
-               r++;
-               if (r == blocks.Length)
-                 return i;
-               b = blocks[r];
-               count = b.Count;
-               start = 0;
-             }
-           group[i] = b[start];
-         }
-       return nitems;
-      }
-
-      // Update "row" to what contains the first candidate of
-      // the previous candidate-group, update "current_index", and
-      // update "group" if necessary.  Return the previous
-      // candidate-group.  Set NITEMS to the number of valid
-      // candidates contained in that group.
-
-      public int PrevGroup ()
-      {
-       int nitems;
-       int col = Column;
-
-       if (IsFixed)
-         {
-           nitems = group.Length;
-           if ((index -= col + nitems) < 0)
-             index = (Total / nitems) * nitems;
-           nitems = fill_group (index);
-         }
-       else
-         {
-           row = row > 0 ? row-- : blocks.Length - 1;
-           nitems = blocks[row].Count;
-           index = blocks[row].Index;
-         }
-       index += col < nitems ? col : nitems - 1;
-       return nitems;
-      }
-
-      public int NextGroup ()
-      {
-       int nitems;
-       int col = Column;
-
-       if (IsFixed)
-         {
-           nitems = group.Length;
-           if ((index += nitems - col) >= Total)
-             index = 0;
-           nitems = fill_group (index);
-         }
-       else
-         {
-           row = row < blocks.Length - 1 ? row + 1 : 0;
-           nitems = blocks[row].Count;
-           index = blocks[row].Count;
-         }
-       index += col < nitems ? col : nitems - 1;
-       return nitems;
-      }
-
-      public void Prev ()
-      {
-       int col = Column;
-
-       if (col == 0)
-         {
-           int nitems = PrevGroup ();
-           index += col < nitems - 1 ? col : nitems - 1;
-         }
-       else
-         index--;
-      }
-
-      public void Next ()
-      {
-       int col = Column;
-       int nitems = GroupLength;
-
-       if (col == nitems - 1)
-         {
-           nitems = NextGroup ();
-           index -= Column;
-         }
-       else
-         index++;
-      }
-
-      public void First ()
-      {
-       index -= Column;
-      }
-
-      public void Last ()
-      {
-       index += GroupLength - (Column + 1);
-      }
-
-      public void Select (int col)
-      {
-       int maxcol = GroupLength - 1;
-       if (col > maxcol)
-         col = maxcol;
-       index = index - Column + col;
-      }
-    }
-
     private void update_candidate ()
     {
       object candidate = candidates.Current;
@@ -2216,7 +2281,7 @@ namespace M17N.Input
          candidate_to = candidate_from + 1;
        }
       preedit.PushProp (candidate_from, candidate_to,
-                       MInputMethod.Mcandidates, this);
+                       Mim.Mcandidates, this);
       cursor_pos = candidate_from;
       changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
                  | CandidateAll);
@@ -2229,7 +2294,7 @@ namespace M17N.Input
 
       if (v != null)
        column = v.Value.Intval;
-      candidates = new Candidates (arg.Listval, column);
+      candidates = new Mim.Candidates (arg.Listval, column);
       candidate_from = candidate_to = cursor_pos;
       update_candidate ();
     }
@@ -2243,25 +2308,6 @@ namespace M17N.Input
        }
     }
 
-    internal void select (MSymbol sym)
-    {
-      if (candidates != null)
-       {
-         if (sym == Mat_less_than)
-           candidates.First ();
-         else if (sym == Mat_greater_than)
-           candidates.Last ();
-         else if (sym == Mat_minus)
-           candidates.Prev ();
-         else if (sym == Mat_plus)
-           candidates.Next ();
-         else if (sym == Mat_open_square_bracket)
-           candidates.PrevGroup ();
-         else if (sym == Mat_close_square_bracket)
-           candidates.NextGroup ();
-       }
-    }
-
     internal int marker (MSymbol sym)
     {
       int pos = cursor_pos;
@@ -2278,7 +2324,7 @@ namespace M17N.Input
              if (pos > 0)
                {
                  int to;
-                 preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
+                 preedit.FindProp (Mim.Mcandidates, pos - 1,
                                    out pos, out to);
                }
              else
@@ -2288,7 +2334,7 @@ namespace M17N.Input
              if (cursor_pos < preedit.Length - 1)
                {
                  int from;
-                 preedit.FindProp (MInputMethod.Mcandidates, pos,
+                 preedit.FindProp (Mim.Mcandidates, pos,
                                    out from, out pos);
                }
              else
@@ -2325,8 +2371,8 @@ namespace M17N.Input
            {
              MPlist plist = new MPlist ();
              plist.Push (MSymbol.integer, pos);
-             if (MInputMethod.GetSurroundingText != null
-                 && MInputMethod.GetSurroundingText (this, plist)
+             if (Mim.GetSurroundingText != null
+                 && Mim.GetSurroundingText (this, plist)
                  && plist.IsMText
                  && preceding_text.Length < plist.Text.Length)
                preceding_text = plist.Text;
@@ -2343,8 +2389,8 @@ namespace M17N.Input
            {
              MPlist plist = new MPlist ();
              plist.Push (MSymbol.integer, pos + 1);
-             if (MInputMethod.GetSurroundingText != null
-                 && MInputMethod.GetSurroundingText (this, plist)
+             if (Mim.GetSurroundingText != null
+                 && Mim.GetSurroundingText (this, plist)
                  && plist.IsMText
                  && following_text.Length < plist.Text.Length)
                following_text = plist.Text;
@@ -2416,7 +2462,7 @@ namespace M17N.Input
        }
     }
 
-    internal void pushback (MInputMethod.KeySeq keyseq)
+    internal void pushback (Mim.KeySeq keyseq)
     {
       if (key_head > 0)
        key_head--;
@@ -2450,7 +2496,7 @@ namespace M17N.Input
 
     internal void shift (MSymbol sym)
     {
-      MInputMethod.State state;
+      Mim.State state;
 
       if (sym == MSymbol.t)
        {
@@ -2461,13 +2507,13 @@ namespace M17N.Input
        }
       else
        {
-         state = (MInputMethod.State) im.states.Get (sym);
+         state = (Mim.State) im.states.Get (sym);
          if (state == null)
            throw new Exception ("Unknown state: " + state.name);
        }
       if (state == null)
        state = states.Pop ();
-      if (state == (MInputMethod.State) im.states.val)
+      if (state == (Mim.State) im.states.val)
        {
          commit ();
          reset ();
@@ -2502,7 +2548,7 @@ namespace M17N.Input
       cursor_pos = 0;
       key_head = commit_key_head = 0;
       states.Clear ();
-      states.Push ((MInputMethod.State) im.states.Val);
+      states.Push ((Mim.State) im.states.Val);
       state_key_head = 0;
       state_pos = 0;
     }
@@ -2512,9 +2558,8 @@ namespace M17N.Input
       column = 0;
       if (cursor_pos == 0)
        return null;
-      Candidates candidates
-       = (Candidates) preedit.GetProp (cursor_pos - 1,
-                                       MInputMethod.Mcandidates);
+      Mim.Candidates candidates
+       = (Mim.Candidates) preedit.GetProp (cursor_pos - 1, Mim.Mcandidates);
       if (candidates == null)
        return null;
       column = candidates.Column;