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