*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Reflection;
5 using System.IO;
6 using System.Xml;
7
8 using M17N;
9 using M17N.Core;
10 using M17N.Input;
11
12 using Xex = System.Xml.Xexpression;
13
14 namespace M17N.Input
15 {
16   public class MInputMethod
17   {
18     // Delegaes
19     public delegate bool Callback (Context ic, MPlist args);
20
21     internal static Xex.Domain im_domain
22       = new Xex.Domain ("input-method", null);
23     private static MSymbol Minput_method = "input-method";
24     private static MSymbol Mdescription = "description";
25     private static MSymbol Mvariable = "variable";
26     private static MSymbol Mcommand = "command";
27     private static MSymbol Mmodule = "module";
28     private static MSymbol Mtitle = "title";
29     private static MSymbol Minclude = "include";
30     private static MSymbol Mmacro = "macro";
31     private static MSymbol Mmap = "map";
32     private static MSymbol Mmap_list = "map-list";
33     private static MSymbol Mstate = "state";
34     internal static MSymbol Mcandidates = "candidates";
35     private static MSymbol Mat_minus_zero = "@-0";
36     private static MSymbol Matat = "@@";
37
38     private static Xex.Symbol Qxi_include = "xi:include";
39     private static Xex.Symbol Qmap = "map";
40     private static Xex.Symbol Qrule = "rule";
41     private static Xex.Symbol Qkeyseq = "keyseq";
42     private static Xex.Symbol Qprogn = "progn";
43     private static Xex.Symbol Qcatch = "catch";
44     private static Xex.Symbol Qinsert = "insert";
45     private static Xex.Symbol Qinsert_candidates = "insert-candidates";
46     private static Xex.Symbol Qchar_at = "char-at";
47     private static Xex.Symbol Qselect = "select";
48     private static Xex.Symbol Qdelete = "delete";
49     private static Xex.Symbol Qshift = "shift";
50     private static Xex.Symbol Qmove = "move";
51     private static Xex.Symbol Qmark = "mark";
52     private static Xex.Symbol Qset = "set";
53     private static Xex.Symbol Qadd = "add";
54     private static Xex.Symbol Qsub = "sub";
55     private static Xex.Symbol Qmul = "mul";
56     private static Xex.Symbol Qdiv = "div";
57     private static Xex.Symbol Qcond = "cond";
58     private static Xex.Symbol Qsname = "sname";
59     private static Xex.Symbol Qmname = "mname";
60     private static Xex.Symbol Qstate_hook = "state-hook";
61     private static Xex.Symbol Qcatch_all_branch = "catch-all-branch";
62     private static Xex.Symbol Qbranch = "branch";
63     private static Xex.Symbol Qstate = "state";
64     private static Xex.Symbol Qtitle = "title";
65     private static Xex.Symbol Qeq = "=";
66     private static Xex.Symbol Qeqeq = "==";
67     private static Xex.Symbol Qhide = "hide";
68     private static Xex.Symbol Qhide_candidates = "hide-candidates";
69     private static Xex.Symbol Qshow = "show";
70     private static Xex.Symbol Qshow_candidates = "show-candidates";
71     private static Xex.Symbol Qkey_count = "key-count";
72     private static Xex.Symbol Qsurrounding_text_flag = "surrounding-text-flag";
73     private static Xex.Symbol Qcandidates_group_size = "candidates-group-size";
74
75     private static Xex.Term Tnil = new Xex.Term ((Xex.Symbol) "nil");
76     private static Xex.Term Tcatch_tag = new Xex.Term ((Xex.Symbol) "@mimtag");
77
78     private static Dictionary<MDatabase.Tag, MInputMethod> im_table
79       = new Dictionary<MDatabase.Tag, MInputMethod> ();
80
81     internal static MInputMethod im_global = null;
82
83     [FlagsAttribute]
84     protected enum LoadStatus
85     {
86       None =   0x00,
87       Header = 0x01,
88       Body =   0x02,
89       Full =   0x03,
90       Error =  0x04,
91     };
92
93     [FlagsAttribute]
94     public enum ChangedStatus
95     {
96       None =            0x00,
97       StateTitle =      0x01,
98       PreeditText =     0x02,
99       CursorPos =       0x04,
100       CandidateList =   0x08,
101       CandidateIndex =  0x10,
102       CandidateShow =   0x20,
103       Preedit =         PreeditText | CursorPos,
104       Candidate =       CandidateList | CandidateIndex | CandidateShow,
105     }
106
107     private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList
108                                                  | ChangedStatus.CandidateIndex
109                                                  | ChangedStatus.CandidateShow);
110
111      [FlagsAttribute]
112      public enum KeyModifier
113        {
114          None =      0x00000000,
115          Shift_L =   0x00400000,
116          Shift_R =   0x00800000,
117          Shift =     0x00C00000,
118          Control_L = 0x01000000,
119          Control_R = 0x02000000,
120          Control   = 0x03000000,
121          Alt_L =     0x04000000,
122          Alt_R =     0x08000000,
123          Alt =       0x0C000000,
124          AltGr =     0x10000000,
125          Super =     0x20000000,
126          Hyper =     0x40000000,
127          High =      0x70000000,
128          All =       0x7FC00000,
129        };
130
131      public struct Key
132      {
133        internal uint key;
134
135        private static Dictionary<string, uint> keysyms
136          = new Dictionary<string, uint> ();
137        private static Dictionary<string, KeyModifier> keymodifiers
138          = new Dictionary<string, KeyModifier> ();
139        private static uint keysym_base = 0x200000;
140        private static uint char_mask = ~((uint) KeyModifier.All);
141        public static readonly Key Reload;
142
143        static Key ()
144        {
145          keysyms["null"] = 0x00;
146          keysyms["bs"] = keysyms["backspace"] = 0x08;
147          keysyms["tab"] = 0x09;
148          keysyms["lf"] = keysyms["linefeed"] = 0x10;
149          keysyms["cr"] = keysyms["return"] = keysyms["enter"] = 0x13;
150          keysyms["esc"] = keysyms["escape"] = 0x1B;
151          keysyms["spc"] = keysyms["space"] = 0x20;
152          keysyms["del"] = keysyms["delete"] = 0x7F;
153          keymodifiers["shift-l"] = KeyModifier.Shift_L;
154          keymodifiers["shift-r"] = KeyModifier.Shift_R;
155          keymodifiers["shift"] = KeyModifier.Shift;
156          keymodifiers["control-l"] = KeyModifier.Control_L;
157          keymodifiers["control-r"] = KeyModifier.Control_R;
158          keymodifiers["control"] = KeyModifier.Control;
159          keymodifiers["alt-l"] = KeyModifier.Alt_L;
160          keymodifiers["alt-r"] = KeyModifier.Alt_R;
161          keymodifiers["alt"] = KeyModifier.Alt;
162          keymodifiers["altgr"] = KeyModifier.AltGr;
163          keymodifiers["super"] = KeyModifier.Super;
164          keymodifiers["hyper"] = KeyModifier.Hyper;
165          Reload = new Key ((MSymbol) "-reload");
166        }
167
168        private static uint decode_keysym (MSymbol keysym)
169        {
170          uint key;
171          string name = keysym.Name;
172
173          if (name.Length == 1)
174            return name[0];
175          name = name.ToLower ();
176          if (! keysyms.TryGetValue (name, out key))
177            keysyms[name] = key = keysym_base++;
178          return key;
179        }
180
181        private static uint combine_modifiers (uint c, KeyModifier modifiers)
182        {
183          if (c < 0x7F && c != 0x20)
184            {
185              if ((modifiers & KeyModifier.Shift) != KeyModifier.None
186                  && Char.IsLower ((char) c))
187                {
188                  modifiers &= ~KeyModifier.Shift;
189                  c = Char.ToUpper ((char) c);
190                }
191              if ((modifiers & KeyModifier.Control) != KeyModifier.None)
192                {
193                  modifiers &= ~KeyModifier.Control;
194                  c &= 0x1F;
195                }
196            }    
197          return c | (uint) modifiers;
198        }
199
200        public Key (uint c) { key = c; }
201        public Key (int c) { key = (uint) c; }
202
203        public Key (uint c, KeyModifier modifiers)
204        {
205          key = combine_modifiers (c, modifiers);
206        }
207
208        public Key (MSymbol keysym, KeyModifier modifiers)
209        {
210          key = combine_modifiers (decode_keysym (keysym), modifiers);
211        }
212
213        public Key (MSymbol keysym)
214        {
215          string str = keysym.Name;
216          int len = str.Length;
217          int i;
218          KeyModifier modifiers = KeyModifier.None;
219
220          for (i = 0; i + 2 < len && str[i + 1] == '-'; i += 2)
221            {
222              if (str[i] == 'S')
223                modifiers |= KeyModifier.Shift;
224              else if (str[i] == 'C')
225                modifiers |= KeyModifier.Control;
226              else if (str[i] == 'A')
227                modifiers |= KeyModifier.Alt;
228              else if (str[i] == 'G')
229                modifiers |= KeyModifier.AltGr;
230              else if (str[i] == 's')
231                modifiers |= KeyModifier.Super;
232              else if (str[i] == 'H')
233                modifiers |= KeyModifier.Hyper;
234            }
235          if (i + 1 == len)
236            key = combine_modifiers (str[i], modifiers);
237          else
238            key = combine_modifiers (decode_keysym (keysym), modifiers);
239        }
240
241        public Key (MPlist plist)
242        {
243          KeyModifier modifiers = KeyModifier.None;
244          MPlist p;
245
246          for (p = plist; ! p.IsEmpty; p = p.next)
247            {
248              if (p.IsInteger)
249                {
250                  if (! p.next.IsEmpty)
251                    throw new Exception ("Invalid Key: " + plist);
252                  break;
253                }
254              else if (! p.IsSymbol)
255                throw new Exception ("Invalid Key: " + plist);
256              else
257                {
258                  string name = p.Symbol.Name.ToLower ();
259                  KeyModifier m;
260
261                  if (! keymodifiers.TryGetValue (name, out m))
262                    break;
263                  modifiers |= m;
264                }
265            }
266          if (p.IsEmpty || ! p.next.IsEmpty)
267            throw new Exception ("Invalid Key: " + plist);
268          if (p.IsInteger)
269            key = combine_modifiers ((uint) p.Integer, modifiers);
270          else
271            key = combine_modifiers (decode_keysym (p.Symbol), modifiers);
272        }
273
274        public bool HasModifier
275        {
276          get { return ((key & (uint) KeyModifier.All) != 0); }
277        }
278
279        public static bool operator== (Key k1, Key k2)
280          {
281            return k1.key == k2.key;
282          }
283
284        public static bool operator!= (Key k1, Key k2)
285          {
286            return k1.key != k2.key;
287          }
288
289        public override bool Equals (object o) { return key == ((Key) o).key; }
290
291        public override int GetHashCode () { return (int) key; }
292
293        public bool Match (Key k)
294        {
295          if (k.key == key)
296            return true;
297          if ((k.key & char_mask) != (key & char_mask))
298            return false;
299          KeyModifier m1 = ((KeyModifier) key) & KeyModifier.All;
300          KeyModifier m2 = ((KeyModifier) k.key) & KeyModifier.All;
301          return (((m1 & KeyModifier.Shift) == (m2 & KeyModifier.Shift)
302                   || ((m1 & KeyModifier.Shift) == KeyModifier.Shift
303                       && (m2 & KeyModifier.Shift) != KeyModifier.None))
304                  && ((m1 & KeyModifier.Control) == (m2 & KeyModifier.Control)
305                      || ((m1 & KeyModifier.Control) == KeyModifier.Control
306                          && (m2 & KeyModifier.Control) != KeyModifier.None))
307                  && ((m1 & KeyModifier.Alt) == (m2 & KeyModifier.Alt)
308                      || ((m1 & KeyModifier.Alt) == KeyModifier.Alt
309                          && (m2 & KeyModifier.Alt) != KeyModifier.None))
310                  && ((m1 & KeyModifier.High) == (m2 & KeyModifier.High)));
311        }
312
313        public int ToChar ()
314        {
315          return (key & 0x3FFFFF) <= 0x1FFFFF ? (int) (key & 0x1FFFFF) : -1;
316        }
317
318        public override string ToString ()
319        {
320          int c = ToChar ();
321          MText mt = null;
322          if (c < 0x20)
323            foreach (KeyValuePair<string, uint> kv in keysyms)
324              if ((key & 0x3FFFFF) == kv.Value)
325                {
326                  mt = kv.Key;
327                  break;
328                }
329          if (mt == null)
330            mt = new MText (c);
331
332          KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
333
334          if (m != KeyModifier.None)
335            {
336              if ((m & KeyModifier.Shift) != KeyModifier.None)
337                mt.Ins (0, "S-");
338              if ((m & KeyModifier.Control) != KeyModifier.None)
339                mt.Ins (0, "C-");
340              if ((m & KeyModifier.Alt) != KeyModifier.None)
341                mt.Ins (0, "A-");
342              if ((m & KeyModifier.AltGr) != KeyModifier.None)
343                mt.Ins (0, "G-");
344              if ((m & KeyModifier.Super) != KeyModifier.None)
345                mt.Ins (0, "s-");
346              if ((m & KeyModifier.Hyper) != KeyModifier.None)
347                mt.Ins (0, "H-");
348            }
349          return (string) mt;
350        }
351      }
352
353      internal class KeySeq : Xex.TermValue
354      {
355        private static Xex.Symbol name = "keyseq";
356        public static Xex.Symbol Name { get { return name; } }
357
358        public List<Key> keyseq = new List<Key> ();
359
360        public override Xex.TermValue Clone ()
361        {
362          KeySeq ks = new KeySeq ();
363          ks.keyseq.InsertRange (0, keyseq);
364          return ks;
365        }
366
367        public KeySeq () { }
368
369        public KeySeq (MPlist plist)
370        {
371          foreach (MPlist p in plist)
372            {
373              if (p.IsSymbol)
374                keyseq.Add (new Key (p.Symbol));
375              else if (p.IsInteger)
376                keyseq.Add (new Key ((char) p.Integer));
377              else if (p.IsPlist)
378                keyseq.Add (new Key (p.Plist));
379              else
380                throw new Exception ("Invalid Key Sequence: " + plist);
381            }
382        }
383
384        public KeySeq (MText mt) : base ()
385        {
386          for (int i = 0; i < mt.Length; i++)
387            keyseq.Add (new Key ((uint) mt[i]));
388        }
389
390        public KeySeq (List<Xex.Term> list)
391          {
392            int len = list.Count;
393
394            for (int i = 0; i < len; i++)
395              {
396                if (list[i].IsInt)
397                  keyseq.Add (new Key (list[i].Intval));
398                else if (list[i].IsStr)
399                  keyseq.Add (new Key (list[i].Strval));
400                else if (list[i].IsSymbol)
401                  keyseq.Add (new Key ((string) list[i].Symval));
402                else
403                  throw new Exception ("Invalid key: " + list[i]);
404              }
405          }
406
407        public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
408          {
409            Xex.Term term = new Xex.Term (domain, node.FirstChild).Eval (domain);
410            return (term.IsStr ? new KeySeq ((MText) term.Strval)
411                    : new KeySeq (term.Listval));
412          }
413
414        public override bool Equals (object obj)
415        {
416          KeySeq ks = obj as KeySeq;
417          if (ks == null || ks.keyseq.Count != keyseq.Count)
418            return false;
419          for (int i = 0; i < keyseq.Count; i++)
420            if (keyseq[i] != ks.keyseq[i])
421              return false;
422          return true;
423        }
424
425        public override int GetHashCode ()
426        {
427          int code = 0;
428          for (int i = 0; i < keyseq.Count; i++)
429            code ^= keyseq[i].GetHashCode ();
430          return code;
431        }
432
433        public override string ToString ()
434        {
435          MText mt;
436          foreach (Key key in keyseq)
437            if (key.HasModifier || key.ToChar () < 0x20)
438              {
439                mt = "(";
440                foreach (Key k in keyseq)
441                  {
442                    if (mt.Length > 1)
443                      mt.Cat (' ');
444                    mt.Cat (k.ToString ());
445                  }
446                return (string) mt.Cat (")");
447              }
448          mt = "\"";
449          foreach (Key k in keyseq)              
450            {
451              int c = k.ToChar ();
452
453              if (c == '\\' || c == '"')
454                mt.Cat ('\\');
455              mt.Cat (c);
456            }        
457          return (string) mt.Cat ("\"");
458        }
459      }
460
461      public class Command
462      {
463        public MSymbol name;
464        public MText description;
465        internal List<KeySeq> keys;
466
467        public Command (MPlist p)
468        {
469          name = p.Symbol;
470          p = p.Next;
471          description = parse_description (p);
472          if (description == null)
473            description = "No description";
474          keys = new List<KeySeq> ();
475          for (p = p.next; ! p.IsEmpty; p = p.next)
476            {
477              if (p.IsMText)
478                keys.Add (new KeySeq (p.Text));
479              else if (p.IsPlist)
480                keys.Add (new KeySeq (p.Plist));
481            }
482        }
483
484        public Command (XmlNode node)
485        {
486          name = node.Attributes[0].Value;
487          keys = new List<KeySeq> ();
488          for (node = node.FirstChild; node != null; node = node.NextSibling)
489            {
490              if (node.Name == "description")
491                description = parse_description (node);
492              else if (node.Name == "keyseq")
493                keys.Add ((KeySeq) KeySeq.Parser (null, node));
494            }
495        }
496
497        public override string ToString ()
498        {
499          string str = "(" + name + " \"" + (string) description;
500          foreach (KeySeq keyseq in keys)
501            str += " " + keyseq;
502          return str + ")";
503        }
504      }
505
506      internal class Plugin
507      {
508        private string name;
509        private Assembly assembly;
510        private Type plugin_type;
511
512        public Plugin (string name)
513        {
514          this.name = name;
515        }
516
517        public MethodInfo GetMethod (Xex.Symbol name)
518        {
519          if (assembly == null)
520            {
521              assembly = Assembly.LoadFrom (name + ".dll");
522              plugin_type = assembly.GetType ("M17n.MInputMethod.Plugin");
523            }
524
525          MethodInfo info = plugin_type.GetMethod ((string) name);
526          if (info == null)
527            throw new Exception ("Invalid plugin method: " + name);
528          return info;
529        }
530
531        public override string ToString ()
532        {
533          return String.Format ("(module {0}", name);
534        }
535      }
536
537      internal class PluginMethod : Xex.Function
538      {
539        private Plugin plugin;
540        private MethodInfo method_info;
541        object[] parameters = new object[2];
542
543        public PluginMethod (Plugin plugin, string name)
544          : base ((Xex.Symbol) name, 0, -1)
545          {
546            this.plugin = plugin;
547          }
548
549        public override Xex.Term Call (Xex.Domain domain, Xex.Variable vari,
550                                       Xex.Term[] args)
551        {
552          args = (Xex.Term[]) args.Clone ();
553          for (int i = 0; i < args.Length; i++)
554            {
555              args[i] = args[i].Eval (domain);
556              if (domain.Thrown)
557                return args[i];
558            }
559          if (method_info == null)
560            method_info = plugin.GetMethod (name);
561          parameters[0] = domain.context;
562          parameters[1] = args;
563          return (Xex.Term) method_info.Invoke (null, parameters);
564        }
565      }
566
567      internal abstract class Marker : Xex.TermValue
568      {
569        private static Xex.Symbol name = "marker";
570        public static Xex.Symbol Name { get { return name; } }
571
572        private MSymbol mname;
573
574        private Marker (MSymbol mname)
575          {
576            this.mname = mname;
577          }
578
579        public abstract int Position (Context ic);
580
581        public virtual void Mark (Context ic)
582          {
583            throw new Exception ("Can't set predefined marker: " + mname);
584          }
585        public virtual int CharAt (Context ic)
586          {
587            int pos = Position (ic);
588
589            return ((pos >= 0 && pos < ic.preedit.Length) ? ic.preedit[pos]
590                    : -1);
591          }
592
593        public override string ToString ()
594        {
595          return "<marker>" + mname + "</marker>";
596        }
597
598        public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
599        {
600          return Get ((MSymbol) node.InnerText);
601        }
602
603        
604        public override bool Equals (object obj)
605        {
606          Marker m = obj as Marker;
607          return (m != null && m.mname == mname);
608        }
609
610        public override int GetHashCode () { return mname.GetHashCode (); }
611
612        public class Named : Marker
613        {
614          public Named (MSymbol mname) : base (mname) { }
615
616          public override int Position (Context ic)
617          {
618            MPlist p =  ic.marker_positions.Find (mname);
619            return (p == null ? 0 : p.Integer);
620          }
621
622          public override void Mark (Context ic)
623          {
624            ic.marker_positions.Put (mname, ic.cursor_pos);
625          }
626        }
627
628        public class Predefined : Marker
629        {
630          char tag;
631
632          public Predefined (char tag) : base ("@" + tag) { this.tag = tag; }
633
634          public override int Position (Context ic)
635          {
636            switch (tag) {
637            case '<': return 0;
638            case '>': return ic.preedit.Length;
639            case '-': return ic.cursor_pos - 1;
640            case '+': return ic.cursor_pos + 1;
641            case '[':
642              if (ic.cursor_pos > 0)
643                {
644                  int pos = ic.cursor_pos;
645                  int to;
646                  ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to);
647                  return pos;
648                }
649              return 0;
650            case ']':
651              if (ic.cursor_pos < ic.preedit.Length - 1)
652                {
653                  int pos = ic.cursor_pos;
654                  int from;
655                  ic.preedit.FindProp (Mcandidates, pos, out from, out pos);
656                  return pos;
657                }
658              return ic.preedit.Length;
659            default:
660              return tag - '0';
661            }
662          }
663        }
664
665        public class PredefinedAbsolute : Marker
666        {
667          private int pos;
668
669          public PredefinedAbsolute (MSymbol mname) : base (mname)
670            {
671              if (! int.TryParse (((string) mname).Substring (1), out pos))
672                throw new Exception ("Invalid marker name: " + mname);
673            }
674
675          public override int Position (Context ic)
676          {
677            return (pos < ic.preedit.Length ? pos : ic.preedit.Length);
678          }
679        }
680
681        public class PredefinedSurround : Marker
682        {
683          private int distance;
684
685          public PredefinedSurround (MSymbol mname) : base (mname)
686            {
687              if (! int.TryParse (((string) name).Substring (1), out distance))
688                throw new Exception ("Invalid marker name: " + mname);
689              if (distance > 0)
690                distance--;
691            }
692
693          public override int Position (Context ic)
694          {
695            return ic.cursor_pos + distance;
696          }
697
698          public override int CharAt (Context ic)
699            {
700              int pos = ic.cursor_pos + distance;
701              if (pos < 0)
702                return ic.GetSurroundingChar (pos);
703              else if (pos >= ic.preedit.Length)
704                return ic.GetSurroundingChar (pos - ic.preedit.Length);
705              return ic.preedit[pos];
706            }
707        }
708
709        static internal Dictionary<MSymbol,Predefined> predefineds;
710
711        static Marker ()
712          {
713            predefineds = new Dictionary<MSymbol, Predefined> ();
714            predefineds ["@<"] = predefineds["@first"] = new Predefined ('<');
715            predefineds ["@>"] = predefineds["@last"] = new Predefined ('>');
716            predefineds ["@-"] = predefineds["@previous"] = new Predefined ('-');
717            predefineds ["@+"] = predefineds["@next"] = new Predefined ('+');
718            predefineds ["@["] = predefineds["@previous-candidate-change"]
719              = new Predefined ('[');
720            predefineds ["@]"] = predefineds["@next-candidate-change"]
721              = new Predefined (']');
722          }
723
724        public static Marker Get (MSymbol mname)
725        {
726          string str = mname.Name;
727          if (str[0] == '@')
728            {
729              Predefined pred;
730              if (predefineds.TryGetValue (mname, out pred))
731                return pred;
732              if (str.Length == 1)
733                throw new Exception ("Invalid marker name: " + mname);
734              if (Char.IsDigit (str[1]))
735                return new PredefinedAbsolute (mname);
736              if (str.Length == 2 || mname == Mat_minus_zero
737                  || ! (str[1] == '-' || str[1] == '+'))
738                throw new Exception ("Invalid marker name: " + mname);
739              return new PredefinedSurround (mname);
740            }
741          return new Named (mname);
742        }
743      }
744
745      internal class Candidates
746      {
747        private class Block
748        {
749          public int Index;
750          public object Data;
751
752          public Block (int index, Xex.Term term)
753          {
754            Index = index;
755            if (term.IsStr)
756              Data = (MText) term.Strval;
757            else
758              {
759                MPlist plist = new MPlist ();
760                MPlist p = plist;
761                foreach (Xex.Term t in term.Listval)
762                  p = p.Add (MSymbol.mtext, (MText) t.Strval);
763                Data = plist;
764              }
765          }
766
767          public Block (int index, MPlist plist)
768          {
769            Index = index;
770            if (plist.IsMText)
771              Data = plist.Text;
772            else if (plist.IsPlist)
773              Data = plist.Plist;
774            else
775              throw new Exception ("Invalid candidate: " + plist);
776          }
777
778          public int Count
779          {
780            get { return (Data is MText
781                          ? ((MText) Data).Length
782                          : ((MPlist) Data).Count); }
783          }
784
785          public object this[int i]
786          {
787            get {
788              if (Data is MText) return ((MText) Data)[i];
789              return  ((MPlist) Data)[i];
790            }
791          }
792        }
793
794        private Block[] blocks;
795        private int row = 0;
796        private int index = 0;
797        public object[] group;
798
799        private bool IsFixed { get { return group != null; } }
800        private int Total {
801          get {
802            Block last = blocks[blocks.Length - 1];
803            return last.Index + last.Count; }
804        }
805
806        public int Column {
807          get { return (IsFixed ? index % group.Length
808                        : index - blocks[row].Index); }
809        }
810
811        public object Group {
812          get { return (IsFixed ? group : blocks[row].Data); }
813        }
814
815        public int GroupLength
816        {
817          get {
818            if (IsFixed)
819              {
820                int nitems = group.Length;
821                int start = index - (index % nitems);
822                int total = Total;
823                return (start + nitems <= total ? nitems : total - start);
824              }
825            return blocks[row].Count;
826          }
827        }
828
829        public object Current {
830          get {
831            return (IsFixed ? group[index % group.Length]
832                    : blocks[row][index - blocks[row].Index]);
833          }
834        }
835
836        public Candidates (MPlist list, int column)
837        {
838          int nblocks = list.Count;
839
840          blocks = new Block[nblocks];
841          for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
842            start += (blocks[i] = new Block (index, list)).Count;
843          if (column > 0)
844            {
845              group = new object[column];
846              fill_group (0);
847            }
848        }
849
850        public Candidates (Xex.Term[] candidates, int column)
851        {
852          int nblocks = candidates.Length;
853
854          blocks = new Block[nblocks];
855          for (int i = 0, start = 0; i < nblocks; i++)
856            start += (blocks[i] = new Block (index, candidates[i])).Count;
857          if (column > 0)
858            {
859              group = new object[column];
860              fill_group (0);
861            }
862        }
863
864        public static void Detach (Context ic)
865        {
866          ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates);
867          ic.candidates = null;
868          ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
869                         | CandidateAll);
870        }
871
872        // Fill the array "group" by candidates stating from START.
873        // START must be a multiple of "column".  Return the number of
874        // valid candidates in "group".
875
876        private int fill_group (int start)
877        {
878          int nitems = group.Length;
879          int r = row;
880          Block b = blocks[r];
881
882          if (start < b.Index)
883            while        (start < b.Index)
884              b = blocks[--r];
885          else
886            while        (start >= b.Index + b.Count)
887              b = blocks[++r];
888          row = r;
889
890          int count = b.Count;
891          start -= b.Index;
892          for (int i = 0; i < nitems; i++, start++)
893            {
894              if (start >= count)
895                {
896                  r++;
897                  if (r == blocks.Length)
898                    return i;
899                  b = blocks[r];
900                  count = b.Count;
901                  start = 0;
902                }
903              group[i] = b[start];
904            }
905          return nitems;
906        }
907
908        // Update "row" to what contains the first candidate of
909        // the previous candidate-group, update "current_index", and
910        // update "group" if necessary.  Return the previous
911        // candidate-group.  Set NITEMS to the number of valid
912        // candidates contained in that group.
913
914        public int PrevGroup ()
915        {
916          int nitems;
917          int col = Column;
918
919          if (IsFixed)
920            {
921              nitems = group.Length;
922              if ((index -= col + nitems) < 0)
923                index = (Total / nitems) * nitems;
924              nitems = fill_group (index);
925            }
926          else
927            {
928              row = row > 0 ? row-- : blocks.Length - 1;
929              nitems = blocks[row].Count;
930              index = blocks[row].Index;
931            }
932          index += col < nitems ? col : nitems - 1;
933          return nitems;
934        }
935
936        public int NextGroup ()
937        {
938          int nitems;
939          int col = Column;
940
941          if (IsFixed)
942            {
943              nitems = group.Length;
944              if ((index += nitems - col) >= Total)
945                index = 0;
946              nitems = fill_group (index);
947            }
948          else
949            {
950              row = row < blocks.Length - 1 ? row + 1 : 0;
951              nitems = blocks[row].Count;
952              index = blocks[row].Count;
953            }
954          index += col < nitems ? col : nitems - 1;
955          return nitems;
956        }
957
958        public void Prev ()
959        {
960          int col = Column;
961
962          if (col == 0)
963            {
964              int nitems = PrevGroup ();
965              index += col < nitems - 1 ? col : nitems - 1;
966            }
967          else
968            index--;
969        }
970
971        public void Next ()
972        {
973          int col = Column;
974          int nitems = GroupLength;
975
976          if (col == nitems - 1)
977            {
978              nitems = NextGroup ();
979              index -= Column;
980            }
981          else
982            index++;
983        }
984
985        public void First ()
986        {
987          index -= Column;
988        }
989
990        public void Last ()
991        {
992          index += GroupLength - (Column + 1);
993        }
994
995        public object Select (int col)
996        {
997          int maxcol = GroupLength - 1;
998          if (col > maxcol)
999            col = maxcol;
1000          index = index - Column + col;
1001          return Current;
1002        }
1003
1004        public object Select (Selector selector)
1005        {
1006          switch (selector.Tag)
1007            {
1008            case '<': First (); break;
1009            case '>': Last (); break;
1010            case '-': Prev (); break;
1011            case '+': Next (); break;
1012            case '[': PrevGroup (); break;
1013            case ']': NextGroup (); break;
1014            default: break;
1015            }
1016          return Current;
1017        }
1018
1019        public override string ToString ()
1020        {
1021          return (String.Format ("<candidates row={0} col={1}>", row, index)
1022                  + Group
1023                  + "</candidates>");
1024        }
1025      }
1026
1027     internal class Selector : Xex.TermValue
1028     {
1029       private static Xex.Symbol name = "selector";
1030       public static Xex.Symbol Name { get { return name; } }
1031
1032       static new Dictionary<MSymbol, Selector> selectors;
1033
1034       static Selector ()
1035         {
1036           selectors = new Dictionary<MSymbol, Selector> ();
1037           selectors ["@<"] = selectors["@first"] = new Selector ('<');
1038           selectors ["@="] = selectors["@current"] = new Selector ('=');
1039           selectors ["@>"] = selectors["@last"] = new Selector ('>');
1040           selectors ["@-"] = selectors["@previous"] = new Selector ('-');
1041           selectors ["@+"] = selectors["@next"] = new Selector ('+');
1042           selectors ["@["] = selectors["@previous-candidate-change"]
1043             = new Selector ('[');
1044           selectors ["@]"] = selectors["@next-candidate-change"]
1045             = new Selector (']');
1046         }
1047
1048       private readonly char tag;
1049
1050       public char Tag { get { return tag; } }
1051
1052       private Selector (char tag) { this.tag = tag; }
1053
1054       public static Xex.TermValue Parser (Xex.Domain domain, XmlNode node)
1055       {
1056         return Get ((MSymbol) node.InnerText);
1057       }
1058
1059       public static Xex.TermValue Get (MSymbol name)
1060       {
1061         Selector selector;
1062         if (! selectors.TryGetValue (name, out selector))
1063           throw new Exception ("Invalid selector name: " + name);
1064         return selector;
1065       }
1066
1067       public override bool Equals (object obj)
1068       {
1069         Selector s = obj as Selector;
1070         return (s != null && s.tag == tag);
1071       }
1072
1073       public override int GetHashCode () { return (int) tag; }
1074
1075       public override string ToString ()
1076       {
1077         return "<selector>@" + tag + "</selector>";
1078       }
1079     }
1080
1081     internal class Map
1082     {
1083       public MSymbol name;
1084       public List<Entry> entries = new List<Entry> ();
1085
1086       public Map (MSymbol name) { this.name = name; }
1087
1088       public class Entry
1089       {
1090         public KeySeq keyseq;
1091         public Xex.Term[] actions;
1092
1093         public Entry (Xex.Domain domain, KeySeq keyseq, Xex.Term[] actions)
1094         {
1095           this.keyseq = keyseq;
1096           this.actions = actions;
1097         }
1098       }
1099
1100       public override string ToString ()
1101       {
1102         string str = "(" + name;
1103         foreach (Entry e in entries)
1104           str += " " + e.keyseq.ToString ();
1105         return str + ")";
1106       }
1107     }
1108
1109     protected class Action
1110     {
1111       private Xex.Term action;
1112
1113       public Action (Xex.Domain domain, Xex.Term[] terms)
1114       {
1115         Xex.Term[] args = new Xex.Term[terms.Length];
1116         args[0] = Tcatch_tag;
1117         for (int i = 0; i < terms.Length; i++)
1118           args[i + 1] = terms[i];
1119         action = new Xex.Term (domain, Qcatch, args);
1120       }
1121
1122       public bool Run (Xex.Domain domain)
1123       {
1124         Xex.Term result = action.Eval (domain);
1125         if (result.IsError)
1126           {
1127             ((Context) domain.context).Error = result.ToString ();
1128             return false;
1129           }
1130         return (result != Tcatch_tag);
1131       }
1132     }
1133
1134     internal class Keymap
1135     {
1136       public Dictionary<Key, Keymap> submaps;
1137       public Xex.Term[] map_actions, branch_actions;
1138
1139       public Keymap () { }
1140
1141       public void Add (KeySeq keys, int index, 
1142                        Xex.Term[] map_actions, Xex.Term[] branch_actions)
1143       {
1144         if (index == keys.keyseq.Count)
1145           {
1146             this.map_actions = map_actions;
1147             this.branch_actions = branch_actions;
1148           }
1149         else
1150           {
1151             Key key = keys.keyseq[index];
1152             Keymap sub = null;
1153
1154             if (submaps == null)
1155               submaps = new Dictionary<Key, Keymap> ();
1156             else
1157               submaps.TryGetValue (key, out sub);
1158             if (sub == null)
1159               submaps[key] = sub = new Keymap ();
1160             sub.Add (keys, index + 1, map_actions, branch_actions);
1161           }
1162       }
1163
1164       public void AddMap (Map map, Xex.Term[] branch_actions)
1165       {
1166         foreach (Map.Entry entry in map.entries)
1167           Add (entry.keyseq, 0, entry.actions, branch_actions);
1168       }
1169
1170       public Keymap Lookup (KeySeq keys, ref int index)
1171       {
1172         Keymap sub;
1173
1174         if (index < keys.keyseq.Count
1175             && submaps != null
1176             && submaps.TryGetValue (keys.keyseq[index], out sub))
1177           {
1178             index++;
1179             return sub.Lookup (keys, ref index);
1180           }
1181         return this;
1182       }
1183
1184       private void describe (MText mt, KeySeq keyseq)
1185       {
1186         if (map_actions != null || branch_actions != null)
1187           {
1188             if (mt.Length > 0)
1189               mt.Cat (" ");
1190             mt.Cat ('(').Cat (keyseq.ToString ());
1191             if (map_actions != null)
1192               foreach (Xex.Term term in map_actions)
1193                 mt.Cat (' ').Cat (term.ToString ());
1194             if (branch_actions != null)
1195               foreach (Xex.Term term in branch_actions)
1196                 mt.Cat (' ').Cat (term.ToString ());
1197             mt.Cat (')');
1198           }
1199         if (submaps != null)
1200           foreach (KeyValuePair<Key, Keymap> kv in submaps)
1201             {
1202               keyseq.keyseq.Add (kv.Key);
1203               kv.Value.describe (mt, keyseq);
1204               keyseq.keyseq.RemoveAt (keyseq.keyseq.Count - 1);
1205             }
1206       }
1207
1208       public override string ToString ()
1209       {
1210         MText mt = "";
1211         KeySeq keyseq = new KeySeq ();
1212
1213         describe (mt, keyseq);
1214         return (string) mt;
1215       }
1216     }
1217
1218     internal class State
1219     {
1220       public MSymbol name;
1221       public MText title;
1222       public Xex.Term[] enter_actions, fallback_actions;
1223       public Keymap keymap = new Keymap ();
1224
1225       public State (MSymbol name, MText title)
1226       {
1227         this.name = name;
1228         this.title = title;
1229       }
1230
1231       public State (MInputMethod im, XmlNode node)
1232       {
1233         this.name = node.Attributes[Qsname].Value;
1234         XmlAttribute attr = node.Attributes[Qtitle];
1235         if (attr != null)
1236           title = (MText) attr.Value;
1237         else
1238           title = im.title;
1239         keymap = new Keymap ();
1240         for (node = node.FirstChild; node != null; node = node.NextSibling)
1241           {
1242             if (node.Name == Qstate_hook)
1243               enter_actions = Xex.ParseTerms (im.domain, node.FirstChild);
1244             else if (node.Name == Qcatch_all_branch)
1245               fallback_actions = Xex.ParseTerms (im.domain, node.FirstChild);
1246             else if (node.Name == Qbranch)
1247               {
1248                 MSymbol mapname = node.Attributes[Qmname].Value;
1249                 Map map;
1250                 if (im.maps.TryGetValue (mapname, out map))
1251                   keymap.AddMap (map, Xex.ParseTerms (im.domain,
1252                                                       node.FirstChild));
1253                 else
1254                   throw new Exception ("Unknown map: " + mapname);
1255               }
1256           }
1257       }
1258
1259       public State (MInputMethod im, MPlist plist)
1260       {
1261         if (! plist.IsSymbol)
1262           throw new Exception ("Invalid state: " + plist);
1263         this.name = plist.Symbol;
1264         plist = plist.next;
1265         if (plist.IsMText)
1266           {
1267             title = plist.Text;
1268             plist = plist.next;
1269           }
1270         else
1271           title = im.title;
1272         keymap = new Keymap (); 
1273         for (; ! plist.IsEmpty; plist = plist.next)
1274           {
1275             if (! plist.IsPlist)
1276               throw new Exception ("Invalid branch: " + plist);
1277             MPlist p = plist.Plist;
1278             if (! p.IsSymbol)
1279               throw new Exception ("Invalid branch: " + p);
1280             MSymbol mapname = p.Symbol;
1281             if (mapname == MSymbol.t)
1282               enter_actions = im.parse_actions (p.next, false);
1283             else if (mapname == MSymbol.nil)
1284               fallback_actions = im.parse_actions (p.next, false);
1285             else
1286               {
1287                 Map map;
1288                 if (im.maps.TryGetValue (mapname, out map))
1289                   keymap.AddMap (map, im.parse_actions (p.next, false));
1290                 else
1291                   throw new Exception ("Unknown map: " + mapname);
1292               }
1293             }
1294       }
1295
1296       public override string ToString ()
1297       {
1298         MText mt = "(" + name;
1299
1300         if (title != null)
1301           mt.Cat (" \"" + title + "\"");
1302         mt.Cat (keymap.ToString ());
1303         return (string) mt + ")";
1304       }
1305     }
1306
1307     // Instance members
1308     internal Xex.Domain domain;
1309
1310     protected LoadStatus load_status = LoadStatus.None;
1311     protected MDatabase.Tag tag;
1312     private MDatabase mdb;
1313
1314     private MText description;
1315     internal MText title;
1316     internal Command[] commands;
1317     internal Xex.Symbol[] var_names;
1318     internal Dictionary<MSymbol, Plugin> plugins;
1319     internal Dictionary<MSymbol, Map> maps;
1320     internal MPlist states;
1321
1322     static MInputMethod ()
1323     {
1324       im_domain.DefType (typeof (KeySeq));
1325       im_domain.DefType (typeof (Marker));
1326       im_domain.DefType (typeof (Selector));
1327
1328       im_domain.DefSubr (Finsert, "insert", false, 1, 1);
1329       im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, -1);
1330       im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
1331       im_domain.DefSubr (Fselect, "select", false, 1, 1);
1332       im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0);
1333       im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
1334       im_domain.DefSubr (Fmove, "move", false, 1, 1);
1335       im_domain.DefSubr (Fmark, "mark", false, 1, 1);
1336       im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
1337       im_domain.DefSubr (Fpop, "pop", false, 0, 0);
1338       im_domain.DefSubr (Fundo, "undo", false, 0, 1);
1339       im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
1340       im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
1341       im_domain.DefSubr (Fshift, "shift", false, 1, 1);
1342       im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
1343       im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
1344       im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
1345       im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag",
1346                          false, 0, 0);
1347
1348       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
1349       List<MDatabase> list = MDatabase.List (tag);
1350       M17n.DebugPrint ("Found {0} input methods\n", list.Count);
1351       foreach (MDatabase mdb in list)
1352         im_table[mdb.tag] = new MInputMethod (mdb.tag);
1353     }
1354
1355     // Constructor
1356     private MInputMethod (MDatabase.Tag tag)
1357     {
1358       this.tag = tag;
1359       domain = new Xex.Domain (tag[1].Name, im_domain, null);
1360     }
1361
1362     // Instance Properties
1363     public MSymbol Language { get { return tag[1]; } }
1364     public MSymbol Name { get { return tag[2]; } }
1365     public MSymbol SubName { get { return tag[3]; } }
1366
1367     public bool Info (out MText description,
1368                       out MText title,
1369                       out Xex.Variable[] variables,
1370                       out Command[] commands)
1371     {
1372       if ((load_status & LoadStatus.Header) != LoadStatus.Header
1373           && ! load_header ())
1374         {
1375           description = null;
1376           title = null;
1377           variables = null;
1378           commands = null;
1379           return false;
1380         }
1381       description = this.description;
1382       title = this.title;
1383       if (var_names == null)
1384         variables = null;
1385       else
1386         {
1387           variables = new Xex.Variable[var_names.Length];
1388           int i = 0;
1389           foreach (Xex.Symbol name in var_names)
1390             variables[i++] = domain.GetVar (name, false);
1391         }
1392       commands = this.commands;
1393       return true;
1394     }
1395
1396     public static MInputMethod Find (MSymbol language, MSymbol name)
1397     {
1398       return Find (language, name, MSymbol.nil);
1399     }
1400
1401     public static MInputMethod Find (MSymbol language, MSymbol name,
1402                                      MSymbol subname)
1403     {
1404       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
1405                                              name, subname);
1406       MInputMethod im;
1407
1408       return (im_table.TryGetValue (tag, out im) ? im : null);
1409     }
1410
1411     private bool Open ()
1412     {
1413       return ((load_status == LoadStatus.Full) || load_body ());
1414     }
1415
1416     public static MInputMethod[] List ()
1417     {
1418       MInputMethod[] array = new MInputMethod[im_table.Count];
1419       int i = 0;
1420
1421       foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
1422         array[i++] = kv.Value;
1423       return array;
1424     }
1425
1426     private bool load_header ()
1427     {
1428       mdb = MDatabase.Find (tag);
1429       if (mdb == null)
1430         return false;
1431       try {
1432         if (mdb.Format == MSymbol.plist)
1433           load (mdb.Load (Mmap), false);
1434         else
1435           {
1436             XmlDocument doc = new XmlDocument (Xex.Symbol.NameTable);
1437             if (! mdb.Load (doc, Mmap_list))
1438               throw new Exception ("Load error" + mdb.tag);
1439             load (doc.DocumentElement, false);
1440           }
1441       } catch (Exception e) {
1442         Console.WriteLine ("{0}\n", e);
1443         load_status = LoadStatus.Error;
1444         return false;
1445       }
1446       load_status |= LoadStatus.Header;
1447       return true;
1448     }
1449
1450     private bool load_body ()
1451     {
1452       mdb = MDatabase.Find (tag);
1453       if (mdb == null)
1454         return false;
1455       try {
1456         if (mdb.Format == MSymbol.plist)
1457           load (mdb.Load (), true);
1458         else
1459           {
1460             XmlDocument doc = new XmlDocument (Xex.Symbol.NameTable);
1461             if (! mdb.Load (doc))
1462               throw new Exception ("Load error" + mdb.tag);
1463             load (doc.DocumentElement, true);
1464           }
1465       } catch (Exception e) {
1466         Console.WriteLine (e);
1467         load_status = LoadStatus.Error;
1468         return false;
1469       }
1470       load_status = LoadStatus.Full;
1471       return true;
1472     }
1473
1474     private void add_default_state ()
1475     {
1476       MSymbol Qinit = "init";
1477       State state = new State (Qinit, title);
1478       foreach (KeyValuePair<MSymbol, Map>kv in maps)
1479         state.keymap.AddMap (kv.Value, null);
1480       states.Add (Qinit, state);
1481     }
1482
1483     private void load (MPlist plist, bool full)
1484     {
1485       maps = new Dictionary<MSymbol, Map> ();
1486       states = new MPlist ();
1487
1488       for (; ! plist.IsEmpty; plist = plist.next)
1489         if (plist.IsPlist)
1490           {
1491             MPlist pl = plist.Plist;
1492             if (pl.IsSymbol)
1493               {
1494                 MSymbol sym = pl.Symbol;
1495
1496                 pl = pl.next;
1497                 if (sym == Mdescription)
1498                   description = parse_description (pl);
1499                 else if (sym == Mtitle)
1500                   {
1501                     if (pl.IsMText)
1502                       title = pl.Text;
1503                   }
1504                 else if (sym == Mvariable)
1505                   parse_variables (pl);
1506                 else if (sym == Mcommand)
1507                   parse_commands (pl);
1508                 else if (full)
1509                   {
1510                     if (sym == Mmodule)
1511                       parse_plugins (pl);
1512                     else if (sym == Minclude)
1513                       parse_include (pl);
1514                     else if (sym == Mmacro)
1515                       parse_macros (pl);
1516                     else if (sym == Mmap)
1517                       parse_maps (pl);
1518                     else if (sym == Mstate)
1519                       parse_states (pl);
1520                   }
1521               }
1522           }
1523       if (description == null)
1524         description = (MText) "No description";
1525       if (title == null)
1526         title = new MText (tag[2].Name);
1527       if (commands == null)
1528         commands = new Command[0];
1529       if (! full)
1530         return;
1531       if (states.IsEmpty)
1532         add_default_state ();
1533     }
1534
1535     private void load (XmlNode node, bool full)
1536     {
1537       bool skip_header = load_status == LoadStatus.Header;
1538
1539       maps = new Dictionary<MSymbol, Map> ();
1540       states = new MPlist ();
1541
1542       if (node.NodeType == XmlNodeType.Document)
1543         node = node.FirstChild;
1544       while (node.NodeType != XmlNodeType.Element)
1545         node = node.NextSibling;
1546       for (node = node.FirstChild; node != null; node = node.NextSibling)
1547         {
1548           if (node.NodeType != XmlNodeType.Element)
1549             continue;
1550           if (! skip_header)
1551             {
1552               if (node.Name == "description")
1553                 description = parse_description (node);
1554               else if (node.Name == "title")
1555                 title = parse_title (node);
1556               else if (node.Name == "variable-list")
1557                 parse_variables (node);
1558               else if (node.Name == "command-list")
1559                 parse_commands (node);
1560             }
1561           if (full)
1562             {
1563               if (node.Name == "module-list")
1564                 parse_plugins (node);
1565               else if (node.Name == "macro-list")
1566                 parse_macros (node);
1567               else if (node.Name == "map-list")
1568                 parse_maps (node);
1569               else if (node.Name == "state-list")
1570                 parse_states (node);
1571             }
1572         }
1573       if (description == null)
1574         description = (MText) "No description";
1575       if (title == null)
1576         title = new MText (tag[2].Name);
1577       if (commands == null)
1578         commands = new Command[0];
1579       if (! full)
1580         return;
1581       if (states.IsEmpty)
1582         add_default_state ();
1583     }
1584
1585     private static MText parse_description (MPlist plist)
1586     {
1587       if (plist.IsMText)
1588         return plist.Text;
1589       if (plist.IsPlist)
1590         {
1591           plist = plist.Plist;
1592           if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
1593               && plist.next.IsMText)
1594             return plist.next.Text;
1595         }
1596       return null;
1597     }
1598
1599     private static MText parse_description (XmlNode node)
1600     {
1601       if (node.HasChildNodes)
1602         node = node.FirstChild;
1603       return node.InnerText;
1604     }
1605
1606     private static MText parse_title (XmlNode node)
1607     {
1608       return node.InnerText;
1609     }
1610
1611     private Xex.Variable get_global_var (Xex.Symbol name)
1612     {
1613       if (im_global == null || this != im_global)
1614         {
1615           MDatabase.Tag tag =
1616             new MDatabase.Tag (Minput_method, MSymbol.t, MSymbol.nil, "global");
1617           im_global = im_table[tag];
1618           if (! im_global.Open ())
1619             throw new Exception ("Failed to load global"); 
1620         }
1621       return im_global.domain.GetVar (name, false);
1622     }
1623
1624     private void parse_variables (MPlist plist)
1625     {
1626       var_names = new Xex.Symbol[plist.Count];
1627
1628       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1629         {
1630           if (! plist.IsPlist || ! plist.Plist.IsSymbol)
1631             throw new Exception ("Invalid variable: " + plist);
1632
1633           MPlist p = plist.Plist;
1634           Xex.Symbol name = (Xex.Symbol) p.Symbol.Name;
1635           var_names[i] = name;
1636           p = p.next;
1637           MText mt = parse_description (p);
1638           string desc = mt == null ? null : (string) mt;
1639           if (! p.IsEmpty)
1640             p = p.next;
1641           Xex.Variable vari = get_global_var (name);
1642           if (vari != null)
1643             domain.Defvar (vari);
1644           if (p.IsInteger)
1645             {
1646               int n = p.Integer;
1647               int[] range = null;
1648
1649               p = p.Next;
1650               if (! p.IsEmpty)
1651                 {
1652                   int nrange = p.Count;
1653                   range = new int[nrange * 2];
1654                   for (int j = 0; j < nrange; j++)
1655                     {
1656                       if (p.IsPlist)
1657                         {
1658                           MPlist p0 = p.Plist;
1659
1660                           if (! p0.IsInteger || ! p0.next.IsInteger)
1661                             throw new Exception ("Invalid range: " + p0);
1662                           range[j * 2] = p0.Integer;
1663                           range[j * 2 + 1] = p0.next.Integer;
1664                         }
1665                       else if (p.IsInteger)
1666                         range[j * 2] = range[j * 2 + 1] = p.Integer;
1667                       else
1668                         throw new Exception ("Invalid range: " + p);
1669                     }
1670                 }
1671               domain.DefvarInt (name, n, desc, range);
1672             }
1673           else if (p.IsMText)
1674             {
1675               string str = (string) p.Text;
1676               string[] range = null;
1677
1678               p = p.next;
1679               if (! p.IsEmpty)
1680                 {
1681                   range = new string[p.Count];
1682                   for (int j = 0; j < range.Length; j++)
1683                     {
1684                       if (p.IsMText)
1685                         range[j] = (string) p.Text;
1686                       else
1687                         throw new Exception ("Invalid range: " + p);
1688                     }
1689                 }
1690               domain.DefvarStr (name, str, desc, range);
1691             }
1692           else if (p.IsSymbol)
1693             {
1694               Xex.Symbol sym = p.Symbol.Name;
1695               Xex.Symbol[] range;
1696
1697               p = p.next;
1698               if (p.IsEmpty)
1699                 range = null;
1700               else
1701                 {
1702                   range = new Xex.Symbol[p.Count];
1703                   for (int j = 0; j < range.Length; j++)
1704                     {
1705                       if (p.IsSymbol)
1706                         range[j] = p.Symbol.Name;
1707                       else
1708                         throw new Exception ("Invalid range: " + p);
1709                     }
1710                 }
1711               domain.DefvarSym (name, sym, desc, range);
1712             }
1713           else if (! p.IsEmpty)
1714             throw new Exception ("Invalid variable type: " + p.val);
1715         }
1716     }
1717
1718     private void parse_variables (XmlNode node)
1719     {
1720       XmlNodeList node_list = node.ChildNodes;
1721
1722       var_names = new Xex.Symbol[node_list.Count];
1723       for (int i = 0; i < node_list.Count; i++)
1724         {
1725           Xex.Symbol name = node_list[i].Attributes[0].Value;
1726           Xex.Variable vari = get_global_var (name);
1727           if (vari != null)
1728             domain.Defvar (vari);
1729           domain.Defvar (node_list[i]);
1730           var_names[i] = name;
1731         }
1732     }
1733
1734     private void parse_commands (MPlist plist)
1735     {
1736       commands = new Command[plist.Count];
1737
1738       for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1739         if (plist.IsPlist && plist.Plist.IsSymbol)
1740           commands[i++] = new Command (plist.Plist);
1741     }
1742
1743     private void parse_commands (XmlNode node)
1744     {
1745       XmlNodeList node_list = node.ChildNodes;
1746
1747       commands = new Command[node_list.Count];
1748       for (int i = 0; i < node_list.Count; i++)
1749         {
1750           if (node_list[i].NodeType == XmlNodeType.Element)
1751             commands[i] = new Command (node_list[i]);
1752         }
1753     }
1754
1755     private void parse_plugins (MPlist plist)
1756     {
1757       plugins = new Dictionary<MSymbol, Plugin> ();
1758
1759       for (; ! plist.IsEmpty; plist = plist.Next)
1760         {
1761           MPlist p = plist.Plist;
1762           MSymbol sym = p.Symbol;
1763           Plugin plugin = new Plugin (sym.Name);
1764
1765           for (p = p.next; ! p.IsEmpty; p = p.next)
1766             {
1767               Xex.Function func = new PluginMethod (plugin, p.Symbol.Name);
1768               domain.Defun (func);
1769             }
1770         }
1771     }
1772
1773     private void parse_plugins (XmlNode node)
1774     {
1775       plugins = new Dictionary<MSymbol, Plugin> ();
1776
1777       foreach (XmlNode n in node.ChildNodes)
1778         {
1779           Plugin plugin = new Plugin (n.Attributes[0].Value);
1780           foreach (XmlNode nn in n.ChildNodes)
1781             {
1782               Xex.Function func = new PluginMethod (plugin,
1783                                                     nn.Attributes[0].Value);
1784               domain.Defun (func);
1785             }
1786         }
1787     }
1788
1789     private void parse_include (XmlNode node)
1790     {
1791       XmlNode n;
1792       MSymbol language, name, subname;
1793       MSymbol part, section;
1794       node = node.FirstChild;
1795       n = node.FirstChild;
1796       language = n.InnerText;
1797       n = n.NextSibling;
1798       name = n.InnerText;
1799       n = n.NextSibling;      
1800       if (n != null)
1801         subname = n.InnerText;
1802       else
1803         subname = MSymbol.nil;
1804       node = node.NextSibling;
1805       part = node.InnerText;
1806       node = node.NextSibling;
1807       if (node != null)
1808         section = node.InnerText;
1809       else
1810         section = MSymbol.nil;
1811       include_part (language, name, subname, part, section);
1812     }
1813
1814     private void parse_macros (XmlNode node)
1815     {
1816       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1817         if (nn.NodeType == XmlNodeType.Element)
1818         {
1819           if (nn.Name == Xex.Qdefun)
1820             domain.Defun (nn, true);
1821           else if (nn.Name == Qxi_include)
1822             parse_include (nn);
1823         }
1824       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1825         if (nn.NodeType == XmlNodeType.Element
1826             && nn.Name == Xex.Qdefun)
1827           domain.Defun (nn, false);
1828     }
1829
1830     private void parse_maps (XmlNode node)
1831     {
1832       for (node = node.FirstChild; node != null; node = node.NextSibling)
1833         {
1834           if (node.Name == Qmap)
1835             {
1836               MSymbol name = node.Attributes[0].Value;
1837               Map map = new Map (name);
1838               maps[name] = map;
1839               for (XmlNode nd = node.FirstChild; nd != null;
1840                    nd = nd.NextSibling)
1841                 if (nd.Name == Qrule)
1842                   {
1843                     XmlNode n = nd.FirstChild;
1844                     if (n.Name != Qkeyseq)
1845                       continue;
1846                     KeySeq keyseq = (KeySeq) KeySeq.Parser (domain, n);
1847                     Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling);
1848                     map.entries.Add (new Map.Entry (domain, keyseq, actions));
1849                   }
1850             }
1851           else if (node.Name == Qxi_include)
1852             parse_include (node);
1853         }
1854     }
1855
1856     private void parse_states (MPlist plist)
1857     {
1858       for (; ! plist.IsEmpty; plist = plist.next)
1859         if (plist.IsPlist)
1860           {
1861             State state = new State (this, plist.Plist);
1862             states.Add (state.name, state);         
1863           }
1864     }
1865
1866     private void parse_states (XmlNode node)
1867     {
1868       for (node = node.FirstChild; node != null; node = node.NextSibling)
1869         {
1870           if (node.Name == Qstate)
1871             {
1872               State state = new State (this, node);
1873               states.Add (state.name, state);
1874             }
1875           else if (node.Name == Qxi_include)
1876             parse_include (node);
1877         }
1878     }
1879
1880     private void include_part (MSymbol language, MSymbol name, MSymbol subname,
1881                                MSymbol part, MSymbol section)
1882     {
1883       MInputMethod im = MInputMethod.Find (language, name, subname);
1884       if (im == null)
1885         return;
1886       if (! im.Open ())
1887         return;
1888       if (part == Mmacro)
1889         {
1890           if (section == MSymbol.nil)
1891             im.domain.CopyFunc (domain);
1892           else
1893             im.domain.CopyFunc (domain, (Xex.Symbol) section.Name);
1894         }
1895       else if (part == Mmap)
1896         {
1897           if (section == MSymbol.nil)
1898             {
1899               foreach (KeyValuePair<MSymbol, Map> kv in im.maps)
1900                 maps[kv.Key] = kv.Value;
1901             }
1902           else
1903             {
1904               Map map;
1905               if (im.maps.TryGetValue (section, out map))
1906                 maps[section] = map;
1907             }
1908         }
1909       else if (part == Mstate)
1910         {
1911           if (section == MSymbol.nil)
1912             {
1913               for (MPlist p = im.states; ! p.IsEmpty; p = p.next)
1914                 states.Add (p.Key, p.Val);
1915             }
1916           else
1917             {
1918               MSymbol state_name = (string) section.Name;
1919               State state = (State) im.states.Get (state_name);
1920               if (state != null)
1921                 states.Add (state.name, state);
1922             }
1923         }
1924     }
1925
1926     private void parse_include (MPlist plist)
1927     {
1928       if (! plist.IsPlist)
1929         return;
1930       MPlist p = plist.Plist;
1931       MSymbol language, name, subname;
1932       language = p.Symbol;
1933       p = p.next;
1934       if (! p.IsSymbol)
1935         name = subname = MSymbol.nil;
1936       else
1937         {
1938           name = p.Symbol;
1939           p = p.next;
1940           if (! p.IsSymbol)
1941             subname = MSymbol.nil;
1942           else
1943             subname = p.Symbol;
1944         }
1945       plist = plist.next;
1946       if (! plist.IsSymbol)
1947         return;
1948       MSymbol part = plist.Symbol;
1949       plist = plist.next;
1950       MSymbol section = MSymbol.nil;
1951       if (plist.IsSymbol)
1952         section = plist.Symbol;
1953       include_part (language, name, subname, part, section);
1954     }
1955
1956     private Xex.Term parse_cond (MPlist plist)
1957     {
1958       Xex.Term[] args = new Xex.Term[plist.Count];
1959
1960       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1961         {
1962           if (! plist.IsPlist)
1963             throw new Exception ("Invalid cond args: " + plist);
1964           MPlist p = plist.Plist;
1965           List<Xex.Term> arg = new List<Xex.Term> ();
1966           arg.Add (parse_action (p, true));
1967           for (p = p.next; ! p.IsEmpty; p = p.next)
1968             arg.Add (parse_action (p, false));
1969           args[i] = new Xex.Term (arg);
1970         }
1971       return new Xex.Term (domain, Qcond, args);
1972     }
1973
1974     private Xex.Term parse_insert (MPlist plist)
1975     {
1976       Xex.Term[] args;
1977       Xex.Term arg;
1978       if (plist.IsSymbol)
1979         arg = new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
1980       else if (plist.IsMText)
1981         arg = new Xex.Term ((string) plist.Text);
1982       else if (plist.IsInteger)
1983         arg = new Xex.Term (plist.Integer);
1984       else if (plist.IsPlist)
1985         {
1986           MPlist pl = plist.Plist;
1987
1988           args = new Xex.Term[pl.Count];
1989           int i;
1990           for (i = 0; ! pl.IsEmpty; i++, pl = pl.next)
1991             {
1992               if (pl.IsMText)
1993                 args[i] = new Xex.Term ((string) pl.Text);
1994               else if (pl.IsPlist)
1995                 {
1996                   List<Xex.Term> list = new List<Xex.Term> ();
1997                   for (MPlist p = pl.Plist; ! p.IsEmpty; p = p.next)
1998                     {
1999                       if (p.IsMText)
2000                         list.Add (new Xex.Term ((string) p.Text));
2001                       else
2002                         throw new Exception ("Invalid candidates: " + p);
2003                     }                 
2004                 }
2005               else
2006                 throw new Exception ("Invalid candidates: " + pl);
2007             }
2008           return new Xex.Term (domain, Qinsert_candidates, args);
2009         }
2010       else
2011         throw new Exception ("Invalid arg to insert: " + plist);
2012       args = new Xex.Term[1];
2013       args[0] = arg;
2014       return new Xex.Term (domain, Qinsert, args);
2015     }
2016
2017     private Xex.Term parse_select (MPlist plist)
2018     {
2019       Xex.Term[] args = new Xex.Term[1];
2020       if (plist.IsInteger)
2021         args[0] = new Xex.Term (plist.Integer);
2022       else if (! plist.IsSymbol)
2023         throw new Exception ("Invalid arg to select: " + plist);
2024       else if (plist.Symbol.Name[0] == '@')
2025         args[0] = new Xex.Term (Selector.Get (plist.Symbol));
2026       else
2027         args[0] = new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
2028       return new Xex.Term (domain, Qselect, args);
2029     }
2030
2031     private Xex.Term parse_funcall_with_marker (MPlist plist, Xex.Symbol func)
2032     {
2033       Xex.Term[] args = new Xex.Term[1];
2034       if (plist.IsInteger && func != Qmark)
2035         args[0] = new Xex.Term (plist.Integer);
2036       else if (plist.IsSymbol)
2037         args[0] = new Xex.Term (Marker.Get (plist.Symbol));
2038       else
2039         throw new Exception ("Invalid arg to " + func + ": " + plist);
2040       return new Xex.Term (domain, func, args);
2041     }
2042
2043     private Xex.Term parse_char_at (MSymbol name)
2044     {
2045       Xex.Term[] args = new Xex.Term[1];
2046       args[0] = new Xex.Term (Marker.Get (name));
2047       return new Xex.Term (domain, Qchar_at, args);
2048     }
2049
2050     private Xex.Term parse_shift (MPlist plist)
2051     {
2052       Xex.Term[] args = new Xex.Term[1];
2053       if (! plist.IsSymbol)
2054         throw new Exception ("Invalid arg to shift: " + plist);
2055       args[0] = new Xex.Term ((Xex.Symbol) plist.Symbol.Name);
2056       return new Xex.Term (domain, Qshift, args);
2057     }
2058
2059     private Xex.Term parse_action (MPlist plist, bool as_funarg)
2060     {
2061       if (plist.IsPlist)
2062         {
2063           MPlist p = plist.Plist;
2064               
2065           if (p.IsMText || p.IsPlist)
2066             return parse_insert (plist);
2067           if (! p.IsSymbol)
2068             throw new Exception ("Invalid action: " + p);
2069           MSymbol sym = p.Symbol;
2070           Xex.Symbol name = sym.Name;
2071           p = p.next;
2072           if (name == Qcond)
2073             return parse_cond (p);
2074           if (name == Qinsert)
2075             return parse_insert (p);
2076           if (name == Qselect)
2077             return parse_select (p);
2078           if (name == Qdelete || name == Qmove || name == Qmark)
2079             return parse_funcall_with_marker (p, name);
2080           if (name == Qshift)
2081             return parse_shift (p);
2082           if (name == Qset || name == Qadd || name == Qsub
2083                    || name == Qmul || name == Qdiv)
2084             {
2085               if (! p.IsSymbol)
2086                 throw new Exception ("Invalid action: " + p);
2087               Xex.Symbol varname = p.Symbol.Name;
2088               Xex.Term[] args = new Xex.Term[1];
2089               args[0] = parse_action (p.next, true);
2090               return new Xex.Term (domain, name, varname, args);
2091             }
2092           else
2093             {
2094               if (name == Qeq)
2095                 name = Qeqeq;
2096               else if (name == Qhide)
2097                 name = Qhide_candidates;
2098               else if (name == Qshow)
2099                 name = Qshow_candidates;
2100               if (p.IsEmpty)
2101                 return new Xex.Term (domain, name, null);
2102               else
2103                 return new Xex.Term (domain, name, parse_actions (p, true));
2104             }
2105         }
2106       else if (plist.IsSymbol)
2107         {
2108           if (plist.Symbol == Matat)
2109             return new Xex.Term (domain, Qkey_count, null);
2110           if (plist.Symbol == Mat_minus_zero)
2111             return new Xex.Term (domain, Qsurrounding_text_flag, null);
2112           if (plist.Symbol.Name[0] == '@')
2113             return parse_char_at (plist.Symbol);
2114           return new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
2115         }
2116       else if (plist.IsMText)
2117         return (as_funarg ? new Xex.Term ((string) plist.Text)
2118                 : parse_insert (plist));
2119       else if (plist.IsInteger)
2120         return (as_funarg ? new Xex.Term (plist.Integer)
2121                 : parse_insert (plist));
2122       else
2123         throw new Exception ("Invalid action: " + plist);
2124     }
2125
2126     private Xex.Term[] parse_actions (MPlist plist, bool as_funarg)
2127     {
2128       Xex.Term[] terms = new Xex.Term[plist.Count];
2129
2130       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
2131         terms[i] = parse_action (plist, as_funarg);
2132       return terms;
2133     }
2134
2135     private Xex.Variable[] parse_args (Xex.Domain domain, Xex.Symbol[] args)
2136     {
2137       int nfixed = 0;
2138       int noptional = 0;
2139       int nrest = 0;
2140
2141       if (args.Length > 0)
2142         {
2143           int i = 0;
2144           for (i = 0; i < args.Length; i++, nfixed++)
2145             if (args[i] == Qoptional || args[i] == Qrest)
2146               break;
2147           if (i < args.Length)
2148             {
2149               if (args[i] == Qoptional)
2150                 {
2151                   for (i++; i < args.Length; i++, noptional++)
2152                     if (args[i] == Qrest)
2153                       break;
2154                   if (i < args.Length)
2155                     nrest = 1;
2156                 }
2157             }
2158           min_args = nfixed;
2159           max_args = nfixed + noptional + nrest;
2160           this.args = new Variable[max_args];
2161           int j;
2162           for (i = j = 0; j < this.args.Length; i++)
2163             if (args[i] != Qoptional || args[i] != Qrest)
2164               this.args[j++] = domain.Defvar (args[i]);
2165         }
2166       else
2167         {
2168           min_args = max_args = 0;
2169         }
2170       with_var = false;
2171     }
2172
2173     private void parse_macros (MPlist plist)
2174     {
2175       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
2176         if (pl.IsPlist)
2177           {
2178             MPlist p = pl.Plist;
2179             if (! p.IsSymbol)
2180               continue;
2181             domain.Defun ((Xex.Symbol) p.Symbol.Name, null, null, true);
2182           }
2183       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
2184         if (pl.IsPlist)
2185           {
2186             MPlist p = pl.Plist;
2187
2188             if (! p.IsSymbol)
2189               continue;
2190             domain.Defun ((Xex.Symbol) p.Symbol.Name, null,
2191                           parse_actions (p.next, false), false);
2192           }
2193     }
2194
2195     private void parse_maps (MPlist plist)
2196     {
2197       for (; ! plist.IsEmpty; plist = plist.next)
2198         if (plist.IsPlist)
2199           {
2200             MPlist pl = plist.Plist;
2201           
2202             if (! pl.IsSymbol)
2203               continue;
2204             Map map = new Map (pl.Symbol);
2205             maps[pl.Symbol] = map;
2206             for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
2207               {
2208                 if (! pl.IsPlist)
2209                   continue;
2210                 MPlist p = pl.Plist;
2211                 KeySeq keys;
2212                 if (p.IsMText)
2213                   keys = new KeySeq (p.Text);
2214                 else if (p.IsPlist)
2215                   keys = new KeySeq (p.Plist);
2216                 else
2217                   continue;
2218                 p = p.next;
2219                 Xex.Term[] actions
2220                   = p.IsEmpty ? null : parse_actions (p, false);
2221                 map.entries.Add (new Map.Entry (domain, keys, actions));
2222               }
2223           }
2224     }
2225
2226     private static Xex.Term Finsert (Xex.Domain domain, Xex.Variable vari,
2227                                      Xex.Term[] args)
2228     {
2229       if (args[0].IsInt)
2230         ((Context) domain.context).insert (args[0].Intval, null);
2231       else
2232         ((Context) domain.context).insert ((MText) args[0].Strval, null);
2233       return args[0];
2234     }
2235
2236     private static Xex.Term Finsert_candidates (Xex.Domain domain,
2237                                                 Xex.Variable vari,
2238                                                 Xex.Term[] args)
2239     {
2240       Context ic = (Context) domain.context;
2241       Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size, false);
2242       int column = (v == null ? 0 : v.Value.Intval);
2243       Candidates candidates = new Candidates (args, column);
2244       object candidate = candidates.Current;
2245
2246       if (candidate is MText)
2247         ic.insert ((MText) candidate, candidates);
2248       else
2249         ic.insert ((int) candidate, candidates);
2250       return args[0];
2251     }
2252
2253     private static Xex.Term Fchar_at (Xex.Domain domain, Xex.Variable vari,
2254                                       Xex.Term[] args)
2255     {
2256       Context ic = (Context) domain.context;
2257       Marker m = (Marker) args[0].Objval;
2258
2259       return new Xex.Term (m.CharAt (ic));
2260     }
2261
2262     private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
2263                                      Xex.Term[] args)
2264     {
2265       Context ic = (Context) domain.context;
2266       int pos;
2267
2268       if (args[0].IsInt)
2269         pos = args[0].Intval;
2270       else
2271         {
2272           Marker m = (Marker) args[0].Objval;
2273           pos = m.Position (ic);
2274         }
2275       return new Xex.Term (ic.delete (pos));
2276     }
2277
2278     private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
2279                                      Xex.Term[] args)
2280     {
2281       Context ic = (Context) domain.context;
2282       Candidates can = ic.candidates;
2283
2284       if (can != null)
2285         {
2286           object candidate = can.Current;
2287
2288           if (candidate is MText)
2289             ic.delete (ic.cursor_pos - ((MText) candidate).Length);
2290           else
2291             ic.delete (ic.cursor_pos - 1);
2292           if (args[0].IsInt)
2293             candidate = can.Select (args[0].Intval);
2294           else
2295             candidate = can.Select ((Selector) args[0].Objval);
2296           if (candidate is MText)
2297             ic.insert ((MText) candidate, can);
2298           else
2299             ic.insert ((int) candidate, can);
2300         }
2301       return args[0];
2302     }
2303
2304     private static Xex.Term Fshow (Xex.Domain domain, Xex.Variable vari,
2305                                    Xex.Term[] args)
2306     {
2307       ((Context) domain.context).show ();
2308       return Tnil;
2309     }
2310
2311     private static Xex.Term Fhide (Xex.Domain domain, Xex.Variable vari,
2312                                    Xex.Term[] args)
2313     {
2314       ((Context) domain.context).hide ();
2315       return Tnil;
2316     }
2317
2318     private static Xex.Term Fmove (Xex.Domain domain, Xex.Variable vari,
2319                                    Xex.Term[] args)
2320     {
2321       Context ic = (Context) domain.context;
2322       int pos = (args[0].IsInt ? args[0].Intval
2323                  : ((Marker) args[0].Objval).Position (ic));
2324       ic.move (pos);
2325       return args[0];
2326     }
2327
2328     private static Xex.Term Fmark (Xex.Domain domain, Xex.Variable vari,
2329                                    Xex.Term[] args)
2330     {
2331       Marker m = (Marker) args[0].Objval;
2332       m.Mark ((Context) domain.context);
2333       return args[0];
2334     }
2335
2336     private static Xex.Term Fpushback (Xex.Domain domain, Xex.Variable vari,
2337                                        Xex.Term[] args)
2338     {
2339       Context ic = (Context) domain.context;
2340
2341       if (args[0].IsInt)
2342         ic.pushback (args[0].Intval);
2343       else if (args[0].IsStr)
2344         ic.pushback (new KeySeq (args[0].Strval));
2345       else
2346         ic.pushback ((KeySeq) args[0].Objval);
2347       return args[0];
2348     }
2349
2350     private static Xex.Term Fpop (Xex.Domain domain, Xex.Variable vari,
2351                                   Xex.Term[] args)
2352     {
2353       ((Context) domain.context).pop ();
2354       return Tnil;
2355     }
2356
2357     private static Xex.Term Fundo (Xex.Domain domain, Xex.Variable vari,
2358                                    Xex.Term[] args)
2359     {
2360       int n = args.Length == 0 ? -2 : args[0].Intval;
2361       ((Context) domain.context).undo (n);
2362       return Tnil;
2363     }
2364
2365     private static Xex.Term Fcommit (Xex.Domain domain, Xex.Variable vari,
2366                                      Xex.Term[] args)
2367     {
2368       ((Context) domain.context).commit ();
2369       return Tnil;
2370     }
2371
2372     private static Xex.Term Funhandle (Xex.Domain domain, Xex.Variable vari,
2373                                        Xex.Term[] args)
2374     {
2375       ((Context) domain.context).commit ();
2376       return Xex.Fthrow (domain, vari, new Xex.Term[1] { Tcatch_tag });
2377     }
2378
2379     private static Xex.Term Fshift (Xex.Domain domain, Xex.Variable vari,
2380                                     Xex.Term[] args)
2381     {
2382       Context ic = (Context) domain.context;
2383       MSymbol state_name = (string) args[0].Symval;
2384       State state = (State) ic.im.states.Get (state_name);
2385       if (state == null)
2386         throw new Exception ("Unknown state: " + state_name);
2387       ((Context) domain.context).shift (state);
2388       return args[0];
2389     }
2390
2391     private static Xex.Term Fshiftback (Xex.Domain domain, Xex.Variable vari,
2392                                         Xex.Term[] args)
2393     {
2394       ((Context) domain.context).shift (null);
2395       return Tnil;
2396     }
2397
2398     private static Xex.Term Fkey_count (Xex.Domain domain, Xex.Variable vari,
2399                                         Xex.Term[] args)
2400     {
2401       return new Xex.Term (((Context) domain.context).key_head);
2402     }
2403
2404     private static Xex.Term Fsurrounding_flag (Xex.Domain domain,
2405                                                Xex.Variable vari,
2406                                                Xex.Term[] args)
2407     {
2408       return new Xex.Term (((Context) domain.context).GetSurroundingText == null
2409                            ? -2 : -1);
2410     }
2411
2412     public override string ToString ()
2413     {
2414       this.Open ();
2415       string str = (String.Format ("({0} (title \"{1}\")", tag, title));
2416       if (commands != null)
2417         {
2418           str += " (commands";
2419           foreach (Command cmd in commands)
2420             str += " " + cmd;
2421           str += ")";
2422         }
2423       if (var_names != null)
2424         {
2425           str += " (variables";
2426           foreach (Xex.Symbol var in var_names)
2427             str += " " + var;
2428           str += ")";
2429         }
2430       if (plugins != null)
2431         {
2432           str += " (modules";
2433           foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
2434             str += " " + kv.Value;
2435           str += ")";
2436         }
2437       str += " (maps";
2438       foreach (KeyValuePair<MSymbol, Map> kv in maps)
2439         str += " " + kv.Value;
2440       str += ") (states";
2441       for (MPlist p = states; ! p.IsEmpty; p = p.next)
2442         str += " (" + p.Key + " " + ((State) p.Val).keymap + ")";
2443       return str + "))";
2444     }
2445
2446     public class Context
2447     {
2448       internal MInputMethod im;
2449       internal Xex.Domain domain;
2450       private bool active;
2451
2452       public Callback PreeditChanged;
2453       public Callback StatusChanged;
2454       public Callback CandidateChanged;
2455       public Callback GetSurroundingText;
2456       public Callback DelSurroundingText;
2457
2458       private MText status;
2459       private MText produced = new MText ();
2460       internal MText preedit = new MText ();
2461       internal int cursor_pos;
2462       internal MPlist marker_positions = new MPlist ();
2463
2464       internal Candidates candidates;
2465       private bool candidate_show;
2466       public bool CandidateShow { get { return candidate_show; } }
2467
2468       private State initial_state, state, prev_state;
2469       private MText state_preedit = new MText ();
2470       private int state_key_head;
2471       private object state_var_values, state_initial_var_values;
2472       private int state_pos;
2473
2474       private Keymap keymap;
2475       // Sequence of input keys.
2476       internal KeySeq keys = new KeySeq ();
2477       // Index into KEYS specifying the next key to handle.
2478       internal int key_head;
2479
2480       internal MText preceding_text = new MText ();
2481       internal MText following_text = new MText ();
2482
2483       // Set to false before calling the method 'handle_key', and set
2484       // to true when some key is unhandled.
2485       private bool key_unhandled;
2486
2487       // The unhandled key.  It has the meaning only when
2488       // 'key_unhandled' is true.
2489       private Key unhandled_key;
2490
2491       internal ChangedStatus changed;
2492
2493       private string error_message;
2494       public string Error {
2495         get { return error_message; }
2496         set { error_message = value; }
2497       }
2498
2499       private void set_cursor (string prefix, int pos)
2500       {
2501         cursor_pos = pos;
2502         if (cursor_pos > 0)
2503           candidates = (Candidates) preedit.GetProp (cursor_pos - 1,
2504                                                      Mcandidates);
2505         else
2506           candidates = null;
2507       }
2508
2509       internal void reset ()
2510       {
2511         status = initial_state.title;
2512         produced.Del ();
2513         preedit.Del ();
2514
2515         set_cursor ("reset", 0);
2516         marker_positions.Clear ();
2517         candidates = null;
2518         candidate_show = false;
2519
2520         state = prev_state = null;
2521         state_preedit.Del ();
2522         state_var_values = state_initial_var_values;
2523         state_pos = 0;
2524         shift (initial_state);
2525
2526         preceding_text.Del ();
2527         following_text.Del ();
2528
2529         changed = ChangedStatus.None;
2530       }
2531
2532       static Xex.Term[] catch_args = new Xex.Term[2];
2533
2534       private bool take_actions (Xex.Term[] actions)
2535       {
2536         catch_args[0] = Tcatch_tag;
2537         catch_args[1]= new Xex.Term (domain, Qprogn, actions);
2538         Xex.Term term = new Xex.Term (domain, Qcatch, catch_args);
2539         term = term.Eval (domain);
2540         return (! term.IsSymbol || term.Symval != Tcatch_tag.Symval);
2541       }
2542
2543       static MPlist callback_arg = new MPlist ();
2544
2545       private bool get_surrounding_text (int len)
2546       {
2547         if (len < 0 ? -len <= preceding_text.Length
2548             : len <= following_text.Length)
2549           return true;
2550         if (GetSurroundingText == null)
2551           return false;
2552         callback_arg.Set (MSymbol.integer, len);
2553         if (! GetSurroundingText (this, callback_arg)
2554             || ! callback_arg.IsMText)
2555           return false;
2556         if (len < 0)
2557           {
2558             preceding_text = callback_arg.Text;
2559             return (-len <= preceding_text.Length);
2560           }
2561         following_text = callback_arg.Text;
2562         return (len <= following_text.Length);
2563       }
2564
2565       internal int GetSurroundingChar (int pos)
2566       {
2567         if (! get_surrounding_text (pos < 0 ? pos : pos + 1))
2568           return 0;
2569         if (pos < 0)
2570           return preceding_text[preceding_text.Length + pos];
2571         return following_text[pos];
2572       } 
2573
2574       private void adjust_markers (int from, int to, int inserted)
2575       {
2576         int diff = inserted - (to - from);
2577
2578         for (MPlist p = marker_positions; ! p.IsEmpty; p = p.next)
2579           {
2580             int pos = p.Integer;
2581             if (pos > from)
2582               p.Set (p.Key, pos >= to ? pos + diff : from);
2583           }
2584         if (cursor_pos >= to)
2585           set_cursor ("adjust", cursor_pos + diff);
2586         else if (cursor_pos > from)
2587           set_cursor ("adjust", from);
2588       }
2589
2590       private void preedit_replace (int from, int to, int c,
2591                                     Candidates candidates)
2592       {
2593         preedit.Del (from, to);
2594         preedit.Ins (from, c);
2595         if (candidates != null)
2596           {
2597             preedit.PushProp (from, from + 1, Mcandidates, candidates);
2598             changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
2599                         | CandidateAll);
2600           }
2601         adjust_markers (from, to, 1);
2602       }
2603
2604       private void preedit_replace (int from, int to, MText mt,
2605                                     Candidates candidates)
2606       {
2607         preedit[from, to] = mt;
2608         if (candidates != null)
2609           {
2610             preedit.PushProp (from, from + mt.Length, Mcandidates, candidates);
2611             changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
2612                         | CandidateAll);
2613           }
2614         adjust_markers (from, to, mt == null ? 0 : mt.Length);
2615       }
2616
2617       internal void insert (int c, Candidates candidates)
2618       {
2619         preedit_replace (cursor_pos, cursor_pos, c, candidates);
2620         changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
2621       }
2622
2623       internal void insert (MText mt, Candidates candidates)
2624       {
2625         preedit_replace (cursor_pos, cursor_pos, mt, candidates);
2626         changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
2627       }
2628
2629       internal int delete (int pos)
2630       {
2631         int deleted = pos - cursor_pos;
2632
2633         if (pos < cursor_pos)
2634           {
2635             if (pos < 0)
2636               {
2637                 if (DelSurroundingText != null)
2638                   {
2639                     Console.WriteLine ("deleting the prev {0} chars", - pos);
2640                     callback_arg.Set (MSymbol.integer, pos);
2641                     if (DelSurroundingText (this, callback_arg))
2642                       {
2643                         if (callback_arg.IsInteger)
2644                           deleted = callback_arg.Integer - cursor_pos;
2645                         preceding_text.Del ();
2646                       }
2647                     else
2648                       deleted = - cursor_pos;
2649                   }
2650                 pos = 0;
2651               }
2652             if (pos < cursor_pos)
2653               preedit_replace (pos, cursor_pos, null, null);
2654           }
2655         else
2656           {
2657             if (pos > preedit.Length)
2658               {
2659                 if (DelSurroundingText != null)
2660                   {
2661                     Console.WriteLine ("deleting the next {0} chars",
2662                                        pos - preedit.Length);
2663                     callback_arg.Set (MSymbol.integer, pos - preedit.Length);
2664                     if (DelSurroundingText (this, callback_arg))
2665                       {
2666                         if (callback_arg.IsInteger)
2667                           deleted = callback_arg.Integer - cursor_pos;
2668                         preceding_text.Del ();
2669                       }
2670                     else
2671                       deleted = preedit.Length - cursor_pos;
2672                   }
2673                 pos = preedit.Length;
2674               }
2675             if (pos > cursor_pos)
2676               preedit_replace (cursor_pos, pos, null, null);
2677           }
2678         if (deleted != 0)
2679           changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
2680         return deleted;
2681       }
2682
2683       internal void show ()
2684       {
2685         candidate_show = true;
2686         changed |= ChangedStatus.CandidateShow;
2687       }
2688
2689       internal void hide ()
2690       {
2691         candidate_show = false;
2692         changed |= ChangedStatus.CandidateShow;
2693       }
2694
2695       internal void move (int pos)
2696       {
2697         if (pos < 0)
2698           pos = 0;
2699         else if (pos > preedit.Length)
2700           pos = preedit.Length;
2701         if (pos != cursor_pos)
2702           {
2703             set_cursor ("move", pos);
2704             changed |= ChangedStatus.Preedit;
2705           }
2706       }
2707
2708       internal void pushback (int n)
2709       {
2710         if (n > 0)
2711           {
2712             key_head -= n;
2713             if (key_head < 0)
2714               key_head = 0;
2715           }
2716         else if (n == 0)
2717           key_head = 0;
2718         else
2719           {
2720             key_head = - n;
2721             if (key_head > keys.keyseq.Count)
2722               key_head = keys.keyseq.Count;
2723           }
2724       }
2725
2726       internal void pushback (KeySeq keyseq)
2727       {
2728         if (key_head > 0)
2729           key_head--;
2730         if (key_head < keys.keyseq.Count)
2731           keys.keyseq.RemoveRange (key_head, keys.keyseq.Count - key_head);
2732         for (int i = 0; i < keyseq.keyseq.Count; i++)
2733           keys.keyseq.Add (keyseq.keyseq[i]);
2734       }
2735
2736       internal void pop ()
2737       {
2738         if (key_head < keys.keyseq.Count)
2739           keys.keyseq.RemoveRange (key_head, 1);
2740       }
2741
2742       internal void undo (int n)
2743       {
2744         if (n < 0)
2745           keys.keyseq.RemoveRange (keys.keyseq.Count + n, - n);
2746         else
2747           keys.keyseq.RemoveRange (n, keys.keyseq.Count  - n);
2748         reset ();
2749       }
2750
2751       internal void commit ()
2752       {
2753         if (preedit.Length > 0)
2754           {
2755             Candidates.Detach (this);
2756             produced.Cat (preedit);
2757             preedit_replace (0, preedit.Length, null, null);
2758           }
2759       }
2760
2761       internal void shift (State state)
2762       {
2763         if (state == null)
2764           {
2765             if (prev_state == null)
2766               return;
2767             state = prev_state;
2768           }
2769
2770         if (state == initial_state)
2771           {
2772             commit ();
2773             keys.keyseq.RemoveRange (0, key_head);
2774             key_head = 0;
2775             if (state != this.state)
2776               {
2777                 domain.RestoreValues (state_initial_var_values);
2778                 if (state.enter_actions != null)
2779                   take_actions (state.enter_actions);
2780               }
2781             prev_state = null;
2782           }
2783         else
2784           {
2785             if (state != this.state && state.enter_actions != null)
2786               take_actions (state.enter_actions);
2787             prev_state = this.state;
2788           }
2789         save_state ();
2790         if (this.state == null || this.state.title != state.title)
2791           this.changed |= ChangedStatus.StateTitle;
2792         this.state = state;
2793         keymap = state.keymap;
2794       }
2795
2796       public Context (MInputMethod im)
2797       {
2798         if (im.load_status != LoadStatus.Full
2799             && ! im.Open ())
2800           throw new Exception ("Openging " + im.tag + " failed");
2801         this.im = im;
2802         domain = new Xex.Domain ("context", im.domain, this);
2803         initial_state = (State) im.states.Val;
2804         state_initial_var_values = domain.SaveValues ();
2805         reset ();
2806         active = true;
2807         if (PreeditChanged != null)
2808           {
2809             callback_arg.Set (MSymbol.mtext, preedit);
2810             PreeditChanged (this, callback_arg);
2811           }
2812         if (StatusChanged != null)
2813           {
2814             callback_arg.Set (MSymbol.mtext, status);
2815             StatusChanged (this, callback_arg);
2816           }
2817       }
2818
2819       public ChangedStatus Changed { get { return changed; } }
2820
2821       internal object GetCandidates (out int column)
2822       {
2823         column = 0;
2824         if (cursor_pos == 0)
2825           return null;
2826         Candidates candidates
2827           = (Candidates) preedit.GetProp (cursor_pos - 1, Mcandidates);
2828         if (candidates == null)
2829           return null;
2830         column = candidates.Column;
2831         return candidates.Current;
2832       }
2833
2834       private void save_state ()
2835       {
2836         state_var_values = domain.SaveValues ();
2837         state_preedit.Del ();
2838         state_preedit.Ins (0, preedit);
2839         state_key_head = key_head;
2840         state_pos = cursor_pos;
2841       }
2842
2843       private void restore_state ()
2844       {
2845         domain.RestoreValues (state_var_values);
2846         preedit.Del ();
2847         preedit.Ins (0, state_preedit);
2848         set_cursor ("restore", state_pos);
2849       }
2850
2851       private bool handle_key ()
2852       {
2853         Console.WriteLine ("{0}:key='{1}'", state.name, keys.keyseq[key_head]);
2854         Keymap sub = keymap.Lookup (keys, ref key_head);
2855
2856         if (sub != keymap)
2857           {
2858             restore_state ();
2859             keymap = sub;
2860             if (keymap.map_actions != null)
2861               {
2862                 if (! take_actions (keymap.map_actions))
2863                   return false;
2864               }
2865             else if (keymap.submaps != null)
2866               {
2867                 for (int i = state_key_head; i < key_head; i++)
2868                   preedit_replace (cursor_pos, cursor_pos,
2869                                    keys.keyseq[i].ToChar (), null);
2870               }
2871             if (keymap.submaps == null)
2872               {
2873                 if (keymap.branch_actions != null)
2874                   {
2875                     if (! take_actions (keymap.branch_actions))
2876                       return false;
2877                   }
2878                 if (keymap != state.keymap)
2879                   shift (state);
2880               }
2881           }
2882         else
2883           {
2884             State current_state = state;
2885
2886             if (keymap.branch_actions != null)
2887               {
2888                 if (! take_actions (keymap.branch_actions))
2889                   return false;
2890               }
2891             if (state == current_state)
2892               {
2893                 if (state == initial_state
2894                     && key_head < keys.keyseq.Count)
2895                   return false;
2896                 if (keymap != state.keymap)
2897                   shift (state);
2898                 else if (keymap.branch_actions == null)
2899                   shift (initial_state);
2900               }
2901           }
2902         return true;
2903       }
2904
2905       public bool Toggle ()
2906       {
2907         active = ! active;
2908         return active;
2909       }
2910
2911       public bool UnhandledKey (out Key key)
2912       {
2913         key = unhandled_key;
2914         return key_unhandled;
2915       }
2916
2917       public MText Preedit { get { return preedit; } }
2918       public MText Produced { get { return produced; } }
2919
2920       // Return value:
2921       //   true: All keys are handled and there's no text to commit.
2922       //   false: Some key is left unhandled or there's a text to
2923       //      commit.  The caller should refer to UnhandledKey and
2924       //      Produced.
2925
2926       public bool Filter (Key key)
2927       {
2928         if (! active)
2929           {
2930             key_unhandled = true;
2931             unhandled_key = key;
2932             return false;
2933           }
2934         if (key == Key.Reload)
2935           return true;
2936         changed = ChangedStatus.None;
2937         produced.Del ();
2938         preceding_text.Del ();
2939         following_text.Del ();
2940
2941         key_unhandled = false;
2942         keys.keyseq.Add (key);
2943         int count = 0;
2944         while (key_head < keys.keyseq.Count)
2945           {
2946             if (! handle_key ())
2947               {
2948                 unhandled_key = keys.keyseq[key_head++];
2949                 key_unhandled = true;
2950                 break;
2951               }
2952             if (++count == 10)
2953               break;
2954           }
2955         keys.keyseq.RemoveRange (0, key_head);
2956         key_head = 0;
2957
2958         if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
2959             && PreeditChanged != null)
2960           {
2961             callback_arg.Set (MSymbol.mtext, preedit);
2962             PreeditChanged (this, callback_arg);
2963           }
2964         if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
2965             && StatusChanged != null)
2966           {
2967             callback_arg.Set (MSymbol.mtext, status);
2968             StatusChanged (this, callback_arg);
2969           }
2970         if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
2971             && CandidateChanged != null)
2972           {
2973             CandidateChanged (this, callback_arg);
2974           }
2975         return (! key_unhandled && produced.Length == 0);
2976       }
2977
2978       public bool Filter ()
2979       {
2980         changed = ChangedStatus.None;
2981         produced.Del ();
2982         preceding_text.Del ();
2983         following_text.Del ();
2984
2985         commit ();
2986         if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
2987             && PreeditChanged != null)
2988           {
2989             callback_arg.Set (MSymbol.mtext, preedit);
2990             PreeditChanged (this, callback_arg);
2991           }
2992         if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
2993             && StatusChanged != null)
2994           {
2995             callback_arg.Set (MSymbol.mtext, status);
2996             StatusChanged (this, callback_arg);
2997           }
2998         if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
2999             && CandidateChanged != null)
3000           {
3001             CandidateChanged (this, callback_arg);
3002           }
3003         return (produced.Length == 0);
3004       }
3005     }
3006
3007     public class Session
3008     {
3009       Context ic;
3010       MText mt;
3011       int pos;
3012
3013       public Session (MInputMethod im, MText mt, int pos)
3014       {
3015         ic = new Context (im);
3016         this.mt = mt;
3017         this.pos = pos;
3018         ic.GetSurroundingText = get_surrounding_text;
3019         ic.DelSurroundingText = del_surrounding_text;
3020       }
3021
3022       private bool get_surrounding_text (Context ic, MPlist args)
3023       {
3024         int len = args.Integer;
3025         if (len < 0)
3026           args.Set (MSymbol.mtext, mt[0, pos]);
3027         else
3028           args.Set (MSymbol.mtext, mt[pos, mt.Length]);
3029         return true;
3030       }
3031
3032       private bool del_surrounding_text (Context ic, MPlist args)
3033       {
3034         int pos = this.pos + args.Integer;
3035         Console.WriteLine ("del-surround: {0}-{1}", this.pos, pos);
3036         if (pos < this.pos)
3037           {
3038             mt.Del (pos, this.pos);
3039             this.pos = pos;
3040           }
3041         else
3042           mt.Del (this.pos, pos);
3043         return true;
3044       }
3045
3046       public bool HandleKey (ref Key key)
3047       {
3048         if (! ic.Filter (key))
3049           {
3050             MText produced = ic.Produced;
3051             mt.Ins (pos, produced);
3052             pos += produced.Length;
3053             Key unhandled;
3054             if (ic.UnhandledKey (out unhandled))
3055               {
3056                 key = unhandled;
3057                 return false;
3058               }
3059           }
3060         return true;
3061       }
3062
3063       public bool Close ()
3064       {
3065         bool result = ic.Filter ();
3066         if (! result)
3067           {
3068             mt.Ins (pos, ic.Produced);
3069             pos += ic.Produced.Length;
3070           }
3071         ic = null;
3072         mt = null;
3073         return result;
3074       }
3075
3076       public int CurrentPos { get { return pos; } set { pos = value; } }
3077       public MText Preedit { get { return ic.Preedit; } }
3078     }
3079   }
3080 }