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