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