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