*** empty log message ***
[m17n/m17n-lib-cs.git] / MInputMethod.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Reflection;
5 using System.IO;
6 using System.Xml;
7
8 using M17N;
9 using M17N.Core;
10 using M17N.Input;
11
12 using Xex = System.Xml.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     private static MSymbol Mat_minus_zero = "@-0";
42
43     private static Xex.Symbol Qmap = "map";
44     private static Xex.Symbol Qrule = "rule";
45     private static Xex.Symbol Qkeyseq = "keyseq";
46     private static Xex.Symbol Qprogn = "progn";
47     private static Xex.Symbol Qcatch = "catch";
48     private static Xex.Symbol Qinsert = "insert";
49     private static Xex.Symbol Qinsert_candidates = "insert-candidates";
50     private static Xex.Symbol Qchar_at = "char-at";
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 MSymbol name;
545
546       private Marker (MSymbol name)
547         {
548           this.name = name;
549         }
550
551       public abstract int Position (Context ic);
552
553       public virtual void Mark (Context ic)
554         {
555           throw new Exception ("Can't set predefined marker: " + name);
556         }
557       public virtual int CharAt (Context ic)
558         {
559           return ic.preedit[Position (ic)];
560         }
561
562       public override string ToString () { return name.Name; }
563
564       public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
565       {
566         return Get ((MSymbol) node.InnerText);
567       }
568
569       public class Named : Marker
570       {
571         public Named (MSymbol name) : base (name) { }
572
573         public override int Position (Context ic)
574         {
575           MPlist p =  ic.marker_positions.Find (name);
576           return (p == null ? 0 : p.Integer);
577         }
578
579         public override void Mark (Context ic)
580         {
581           ic.marker_positions.Put (name, ic.cursor_pos);
582         }
583       }
584      
585       public class Predefined : Marker
586       {
587         char tag;
588
589         public Predefined (MSymbol 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 (MSymbol 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 (MSymbol 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<MSymbol,Predefined> predefined_markers;
670
671       static Marker ()
672       {
673         predefined_markers = new Dictionary<MSymbol, Predefined> ();
674         MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]" };
675         foreach (MSymbol s in symlist)
676           predefined_markers[s] = new Predefined (s);
677       }
678
679       public static Marker Get (MSymbol name)
680       {
681         string str = name.Name;
682         if (str[0] == '@')
683           {
684             Predefined pred;
685             if (predefined_markers.TryGetValue (name, out pred))
686               return pred;
687             if (str.Length == 1)
688               throw new Exception ("Invalid marker name: " + name);
689             if (Char.IsDigit (str[1]))
690               return new PredefinedAbsolute (name);
691             if (str.Length == 2 || name == Mat_minus_zero
692                 || ! (str[1] == '-' || str[1] == '+'))
693               throw new Exception ("Invalid marker name: " + name);
694             return new PredefinedSurround (name);
695           }
696         return new Named (name);
697       }
698     }
699       
700     internal class Candidates
701     {
702       private class Block
703       {
704         public int Index;
705         public object Data;
706
707         public Block (int index, Xex.Term term)
708         {
709           Index = index;
710           if (term.IsStr)
711             Data = (MText) term.Strval;
712           else
713             {
714               MPlist plist = new MPlist ();
715               MPlist p = plist;
716               foreach (Xex.Term t in term.Listval)
717                 p = p.Add (MSymbol.mtext, (MText) t.Strval);
718               Data = plist;
719             }
720         }
721
722         public Block (int index, MPlist plist)
723         {
724           Index = index;
725           if (plist.IsMText)
726             Data = plist.Text;
727           else if (plist.IsPlist)
728             Data = plist.Plist;
729           else
730             throw new Exception ("Invalid candidate: " + plist);
731         }
732
733         public int Count
734         {
735           get { return (Data is MText
736                         ? ((MText) Data).Length
737                         : ((MPlist) Data).Count); }
738         }
739
740         public object this[int i]
741         {
742           get {
743             if (Data is MText) return ((MText) Data)[i];
744             return  ((MPlist) Data)[i];
745           }
746         }
747       }
748
749       private Block[] blocks;
750       private int row = 0;
751       private int index = 0;
752       public object[] group;
753
754       private bool IsFixed { get { return group != null; } }
755       private int Total {
756         get {
757           Block last = blocks[blocks.Length - 1];
758           return last.Index + last.Count; }
759       }
760
761       public int Column {
762         get { return (IsFixed ? index % group.Length
763                       : index - blocks[row].Index); }
764       }
765
766       public object Group {
767         get { return (IsFixed ? group : blocks[row].Data); }
768       }
769
770       public int GroupLength
771       {
772         get {
773           if (IsFixed)
774             {
775               int nitems = group.Length;
776               int start = index - (index % nitems);
777               int total = Total;
778               return (start + nitems <= total ? nitems : total - start);
779             }
780           return blocks[row].Count;
781         }
782       }
783
784       public object Current {
785         get {
786           return (IsFixed ? group[index % group.Length]
787                   : blocks[row][index - blocks[row].Index]);
788         }
789       }
790
791       public Candidates (MPlist list, int column)
792       {
793         int nblocks = list.Count;
794
795         blocks = new Block[nblocks];
796         for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
797           start += (blocks[i] = new Block (index, list)).Count;
798         if (column > 0)
799           group = new object[column];
800       }
801
802       public Candidates (Xex.Term[] candidates, int column)
803       {
804         int nblocks = candidates.Length;
805
806         blocks = new Block[nblocks];
807         for (int i = 0, start = 0; i < nblocks; i++)
808           start += (blocks[i] = new Block (index, candidates[i])).Count;
809         if (column > 0)
810           group = new object[column];
811       }
812
813       public static void Detach (Context ic)
814       {
815         ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates);
816         ic.candidates = null;
817         ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
818                        | CandidateAll);
819       }
820
821       // Fill the array "group" by candidates stating from INDEX.
822       // INDEX must be a multiple of "column".  Set NTIMES to the
823       // number of valid candidates in "group".  Update "block" if
824       // necessary.  Return "group".
825
826       private int fill_group (int start)
827       {
828         int nitems = group.Length;
829         int r = row;
830         Block b = blocks[r];
831
832         if (start < b.Index)
833           while (start < b.Index)
834             b = blocks[--r];
835         else
836           while (start >= b.Index + b.Count)
837             b = blocks[++r];
838         row = r;
839
840         int count = b.Count;
841         start -= b.Index;
842         for (int i = 0; i < nitems; i++, start++)
843           {
844             if (start >= count)
845               {
846                 r++;
847                 if (r == blocks.Length)
848                   return i;
849                 b = blocks[r];
850                 count = b.Count;
851                 start = 0;
852               }
853             group[i] = b[start];
854           }
855         return nitems;
856       }
857
858       // Update "row" to what contains the first candidate of
859       // the previous candidate-group, update "current_index", and
860       // update "group" if necessary.  Return the previous
861       // candidate-group.  Set NITEMS to the number of valid
862       // candidates contained in that group.
863
864       public int PrevGroup ()
865       {
866         int nitems;
867         int col = Column;
868
869         if (IsFixed)
870           {
871             nitems = group.Length;
872             if ((index -= col + nitems) < 0)
873               index = (Total / nitems) * nitems;
874             nitems = fill_group (index);
875           }
876         else
877           {
878             row = row > 0 ? row-- : blocks.Length - 1;
879             nitems = blocks[row].Count;
880             index = blocks[row].Index;
881           }
882         index += col < nitems ? col : nitems - 1;
883         return nitems;
884       }
885
886       public int NextGroup ()
887       {
888         int nitems;
889         int col = Column;
890
891         if (IsFixed)
892           {
893             nitems = group.Length;
894             if ((index += nitems - col) >= Total)
895               index = 0;
896             nitems = fill_group (index);
897           }
898         else
899           {
900             row = row < blocks.Length - 1 ? row + 1 : 0;
901             nitems = blocks[row].Count;
902             index = blocks[row].Count;
903           }
904         index += col < nitems ? col : nitems - 1;
905         return nitems;
906       }
907
908       public void Prev ()
909       {
910         int col = Column;
911
912         if (col == 0)
913           {
914             int nitems = PrevGroup ();
915             index += col < nitems - 1 ? col : nitems - 1;
916           }
917         else
918           index--;
919       }
920
921       public void Next ()
922       {
923         int col = Column;
924         int nitems = GroupLength;
925
926         if (col == nitems - 1)
927           {
928             nitems = NextGroup ();
929             index -= Column;
930           }
931         else
932           index++;
933       }
934
935       public void First ()
936       {
937         index -= Column;
938       }
939
940       public void Last ()
941       {
942         index += GroupLength - (Column + 1);
943       }
944
945       public void Select (int col)
946       {
947         int maxcol = GroupLength - 1;
948         if (col > maxcol)
949           col = maxcol;
950         index = index - Column + col;
951       }
952     }
953
954     internal class Selector : Xex.TermValue
955     {
956       static new Dictionary<MSymbol, Selector> selectors;
957
958       static Selector ()
959         {
960           selectors = new Dictionary<MSymbol, Selector> ();
961           MSymbol[] symlist = new MSymbol[] { "@<", "@=", "@>", "@-", "@+",
962                                               "@[", "@]" };
963           foreach (MSymbol s in symlist)
964             selectors[s] = new Selector (s);
965           selectors["@first"] = new Selector ('<');
966           selectors["@current"] = new Selector ('=');
967           selectors["@last"] = new Selector ('>');
968           selectors["@previous"] = new Selector ('-');
969           selectors["@next"] = new Selector ('+');
970           selectors["@previous-candidate-change"] = new Selector ('[');
971           selectors["@next-candidate-change"] = new Selector (']');
972         }
973
974       private char tag;
975
976       private Selector (MSymbol sym) { tag = sym.Name[1]; }
977
978       private Selector (char tag) { this.tag = tag; }
979
980       public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
981       {
982         return Get ((MSymbol) node.InnerText);
983       }
984
985       public static Xex.TermValue Get (MSymbol name)
986       {
987         Selector selector;
988         if (! selectors.TryGetValue (name, out selector))
989           throw new Exception ("Invalid selector name: " + name);
990         return selector;
991       }
992
993       public void Select (Candidates candidates)
994       {
995         switch (tag)
996           {
997           case '<': candidates.First (); break;
998           case '>': candidates.Last (); break;
999           case '-': candidates.Prev (); break;
1000           case '+': candidates.Next (); break;
1001           case '[': candidates.PrevGroup (); break;
1002           case ']': candidates.NextGroup (); break;
1003           default: break;
1004           }
1005       }
1006     }
1007
1008     internal class Map
1009     {
1010       public MSymbol name;
1011       public List<Entry> entries = new List<Entry> ();
1012
1013       public Map (MSymbol name) { this.name = name; }
1014
1015       public class Entry
1016       {
1017         public KeySeq keyseq;
1018         public Xex.Term[] actions;
1019
1020         public Entry (Xex.Domain domain, KeySeq keyseq, Xex.Term[] actions)
1021         {
1022           this.keyseq = keyseq;
1023           this.actions = actions;
1024         }
1025       }
1026
1027       public override string ToString ()
1028       {
1029         string str = "(" + name;
1030         foreach (Entry e in entries)
1031           str += " " + e.keyseq.ToString ();
1032         return str + ")";
1033       }
1034     }
1035
1036     internal class Keymap
1037     {
1038       public Dictionary<Key, Keymap> submaps;
1039       public Xex.Term[] map_actions, branch_actions;
1040
1041       public Keymap () { }
1042
1043       public void Add (KeySeq keys, int index, 
1044                        Xex.Term[] map_actions, Xex.Term[] branch_actions)
1045       {
1046         if (index == keys.keyseq.Count)
1047           {
1048             this.map_actions = map_actions;
1049             this.branch_actions = branch_actions;
1050           }
1051         else
1052           {
1053             Key key = keys.keyseq[index];
1054             Keymap sub = null;
1055
1056             if (submaps == null)
1057               submaps = new Dictionary<Key, Keymap> ();
1058             else
1059               submaps.TryGetValue (key, out sub);
1060             if (sub == null)
1061               submaps[key] = sub = new Keymap ();
1062             sub.Add (keys, index + 1, map_actions, branch_actions);
1063           }
1064       }
1065
1066       public void AddMap (Map map, Xex.Term[] branch_actions)
1067       {
1068         foreach (Map.Entry entry in map.entries)
1069           Add (entry.keyseq, 0, entry.actions, branch_actions);
1070       }
1071
1072       public Keymap Lookup (KeySeq keys, ref int index)
1073       {
1074         Keymap sub;
1075
1076         if (index < keys.keyseq.Count
1077             && submaps != null
1078             && submaps.TryGetValue (keys.keyseq[index], out sub))
1079           {
1080             index++;
1081             return sub.Lookup (keys, ref index);
1082           }
1083         return this;
1084       }
1085
1086       private void describe (MText mt, KeySeq keyseq)
1087       {
1088         if (map_actions != null || branch_actions != null)
1089           {
1090             if (mt.Length > 0)
1091               mt.Cat (" ");
1092             mt.Cat ('(').Cat (keyseq.ToString ());
1093             if (map_actions != null)
1094               foreach (Xex.Term term in map_actions)
1095                 mt.Cat (' ').Cat (term.ToString ());
1096             if (branch_actions != null)
1097               foreach (Xex.Term term in branch_actions)
1098                 mt.Cat (' ').Cat (term.ToString ());
1099             mt.Cat (')');
1100           }
1101         if (submaps != null)
1102           foreach (KeyValuePair<Key, Keymap> kv in submaps)
1103             {
1104               keyseq.keyseq.Add (kv.Key);
1105               kv.Value.describe (mt, keyseq);
1106               keyseq.keyseq.RemoveAt (keyseq.keyseq.Count - 1);
1107             }
1108       }
1109
1110       public override string ToString ()
1111       {
1112         MText mt = "";
1113         KeySeq keyseq = new KeySeq ();
1114
1115         describe (mt, keyseq);
1116         return (string) mt;
1117       }
1118     }
1119
1120     internal class State
1121     {
1122       public Xex.Symbol name;
1123       public MText title;
1124       public Xex.Term[] enter_actions, fallback_actions;
1125       public Keymap keymap = new Keymap ();
1126
1127       public State (Xex.Symbol name, MText title)
1128       {
1129         this.name = name;
1130         this.title = title;
1131       }
1132
1133       public State (MInputMethod im, XmlNode node)
1134       {
1135         this.name = node.Attributes[Qsname].Value;
1136         XmlAttribute attr = node.Attributes[Qtitle];
1137         if (attr != null)
1138           title = (MText) attr.Value;
1139         else
1140           title = im.title;
1141         keymap = new Keymap ();
1142         for (node = node.FirstChild; node != null; node = node.NextSibling)
1143           {
1144             if (node.Name == Qstate_hook)
1145               enter_actions = Xex.ParseTerms (im.domain, node.FirstChild);
1146             else if (node.Name == Qcatch_all_branch)
1147               fallback_actions = Xex.ParseTerms (im.domain, node.FirstChild);
1148             else if (node.Name == Qbranch)
1149               {
1150                 MSymbol mapname = node.Attributes[Qmname].Value;
1151                 Map map;
1152                 if (im.maps.TryGetValue (mapname, out map))
1153                   keymap.AddMap (map, Xex.ParseTerms (im.domain,
1154                                                       node.FirstChild));
1155                 else
1156                   throw new Exception ("Unknown map: " + mapname);
1157               }
1158           }
1159       }
1160
1161       public State (MInputMethod im, MPlist plist)
1162       {
1163         if (! plist.IsSymbol)
1164           throw new Exception ("Invalid state: " + plist);
1165         this.name = plist.Symbol.Name;
1166         plist = plist.next;
1167         if (plist.IsMText)
1168           {
1169             title = plist.Text;
1170             plist = plist.next;
1171           }
1172         else
1173           title = im.title;
1174         keymap = new Keymap (); 
1175         for (; ! plist.IsEmpty; plist = plist.next)
1176           {
1177             if (! plist.IsPlist)
1178               throw new Exception ("Invalid branch: " + plist);
1179             MPlist p = plist.Plist;
1180             if (! p.IsSymbol)
1181               throw new Exception ("Invalid branch: " + p);
1182             MSymbol mapname = p.Symbol;
1183             if (mapname == MSymbol.t)
1184               enter_actions = im.parse_actions (p.next, false);
1185             else if (mapname == MSymbol.nil)
1186               fallback_actions = im.parse_actions (p.next, false);
1187             else
1188               {
1189                 Map map;
1190                 if (im.maps.TryGetValue (mapname, out map))
1191                   keymap.AddMap (map, im.parse_actions (p.next, false));
1192                 else
1193                   throw new Exception ("Unknown map: " + mapname);
1194               }
1195             }
1196       }
1197
1198       public override string ToString ()
1199       {
1200         MText mt = "(" + name;
1201
1202         if (title != null)
1203           mt.Cat (" \"" + title + "\"");
1204         mt.Cat (keymap.ToString ());
1205         return (string) mt + ")";
1206       }
1207     }
1208
1209     // Instance members
1210     internal Xex.Domain domain = new Xex.Domain (im_domain, null);
1211
1212     protected LoadStatus load_status = LoadStatus.None;
1213     protected MDatabase.Tag tag;
1214     private MDatabase mdb;
1215
1216     private MText description;
1217     internal MText title;
1218     internal Command[] commands;
1219     internal Xex.Symbol[] var_names;
1220     internal Dictionary<MSymbol, Plugin> plugins;
1221     internal Dictionary<MSymbol, Map> maps;
1222     internal Dictionary<Xex.Symbol, State> states;
1223     internal State initial_state;
1224
1225     static MInputMethod ()
1226     {
1227       im_domain.DefTerm ("keyseq", KeySeq.parser);
1228       im_domain.DefTerm ("marker", Marker.parser);
1229       im_domain.DefTerm ("selector", Selector.parser);
1230
1231       im_domain.DefSubr (Finsert, "insert", false, 1, 1);
1232       im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, -1);
1233       im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
1234       im_domain.DefSubr (Fselect, "select", false, 1, 1);
1235       im_domain.DefSubr (Fshow, "show", false, 0, 0);
1236       im_domain.DefSubr (Fhide, "hide", false, 0, 0);
1237       im_domain.DefSubr (Fmove, "move", false, 1, 1);
1238       im_domain.DefSubr (Fmark, "mark", false, 1, 1);
1239       im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
1240       im_domain.DefSubr (Fpop, "pop", false, 0, 0);
1241       im_domain.DefSubr (Fundo, "undo", false, 0, 1);
1242       im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
1243       im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
1244       im_domain.DefSubr (Fshift, "shift", false, 1, 1);
1245       im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
1246       im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
1247       im_domain.DefSubr (Fkey_count, "key-count", false, 1, 1);
1248       im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag",
1249                          false, 0, 0);
1250
1251       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
1252       List<MDatabase> list = MDatabase.List (tag);
1253       M17n.DebugPrint ("Found {0} input methods\n", list.Count);
1254       foreach (MDatabase mdb in list)
1255         im_table[mdb.tag] = new MInputMethod (mdb.tag);
1256     }
1257
1258     // Constructor
1259     private MInputMethod (MDatabase.Tag tag)
1260     {
1261       this.tag = tag;
1262     }
1263
1264     // Instance Properties
1265     public MSymbol Language { get { return tag[1]; } }
1266     public MSymbol Name { get { return tag[2]; } }
1267     public MSymbol SubName { get { return tag[3]; } }
1268
1269     public bool Info (out MText description,
1270                       out MText title,
1271                       out Xex.Variable[] variables,
1272                       out Command[] commands)
1273     {
1274       if ((load_status & LoadStatus.Header) != LoadStatus.Header
1275           && ! load_header ())
1276         {
1277           description = null;
1278           title = null;
1279           variables = null;
1280           commands = null;
1281           return false;
1282         }
1283       description = this.description;
1284       title = this.title;
1285       if (var_names == null)
1286         variables = null;
1287       else
1288         {
1289           variables = new Xex.Variable[var_names.Length];
1290           int i = 0;
1291           foreach (Xex.Symbol name in var_names)
1292             variables[i++] = domain.GetVar (name, false);
1293         }
1294       commands = this.commands;
1295       return true;
1296     }
1297
1298     public static MInputMethod Find (MSymbol language, MSymbol name)
1299     {
1300       return Find (language, name, MSymbol.nil);
1301     }
1302
1303     public static MInputMethod Find (MSymbol language, MSymbol name,
1304                                      MSymbol subname)
1305     {
1306       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
1307                                              name, subname);
1308       MInputMethod im;
1309
1310       return (im_table.TryGetValue (tag, out im) ? im : null);
1311     }
1312
1313     private bool Open ()
1314     {
1315       return ((load_status == LoadStatus.Full) || load_body ());
1316     }
1317
1318     public static MInputMethod[] List ()
1319     {
1320       MInputMethod[] array = new MInputMethod[im_table.Count];
1321       int i = 0;
1322
1323       foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
1324         array[i++] = kv.Value;
1325       return array;
1326     }
1327
1328     private bool load_header ()
1329     {
1330       mdb = MDatabase.Find (tag);
1331       if (mdb == null)
1332         return false;
1333       mdb.name_table = Xex.Symbol.Table;
1334       try {
1335         MSymbol format = mdb.Format;
1336
1337         if (format == MSymbol.plist)
1338           load ((MPlist) mdb.Load (Mmap), false);
1339         else
1340           {
1341             XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list);
1342             load (doc.DocumentElement, false);
1343           }
1344       } catch (Exception e) {
1345         Console.WriteLine ("{0}\n", e);
1346         load_status = LoadStatus.Error;
1347         return false;
1348       }
1349       load_status |= LoadStatus.Header;
1350       return true;
1351     }
1352
1353     private bool load_body ()
1354     {
1355       mdb = MDatabase.Find (tag);
1356       if (mdb == null)
1357         return false;
1358       mdb.name_table = Xex.Symbol.Table;
1359       try {
1360         object obj = mdb.Load ();
1361         if (obj is MPlist)
1362           load ((MPlist) obj, true);
1363         else
1364           load ((XmlDocument) obj, true);
1365       } catch (Exception e) {
1366         Console.WriteLine (e);
1367         load_status = LoadStatus.Error;
1368         return false;
1369       }
1370       load_status = LoadStatus.Full;
1371       return true;
1372     }
1373
1374     private void add_default_state ()
1375     {
1376       Xex.Symbol Qinit = "init";
1377       State state = new State (Qinit, title);
1378       foreach (KeyValuePair<MSymbol, Map>kv in maps)
1379         state.keymap.AddMap (kv.Value, null);
1380       states[Qinit] = initial_state = state;
1381     }
1382
1383     private void load (MPlist plist, bool full)
1384     {
1385       maps = new Dictionary<MSymbol, Map> ();
1386       states = new Dictionary<Xex.Symbol, State> ();
1387
1388       for (; ! plist.IsEmpty; plist = plist.next)
1389         if (plist.IsPlist)
1390           {
1391             MPlist pl = plist.Plist;
1392             if (pl.IsSymbol)
1393               {
1394                 MSymbol sym = pl.Symbol;
1395
1396                 pl = pl.next;
1397                 if (sym == Mdescription)
1398                   description = parse_description (pl);
1399                 else if (sym == Mtitle)
1400                   {
1401                     if (pl.IsMText)
1402                       title = pl.Text;
1403                   }
1404                 else if (sym == Mvariable)
1405                   parse_variables (pl);
1406                 else if (sym == Mcommand)
1407                   parse_commands (pl);
1408                 else if (full)
1409                   {
1410                     if (sym == Mmodule)
1411                       parse_plugins (pl);
1412                     else if (sym == Minclude)
1413                       parse_include (pl);
1414                     else if (sym == Mmacro)
1415                       parse_macros (pl);
1416                     else if (sym == Mmap)
1417                       parse_maps (pl);
1418                     else if (sym == Mstate)
1419                       parse_states (pl);
1420                   }
1421               }
1422           }
1423       if (description == null)
1424         description = (MText) "No description";
1425       if (title == null)
1426         title = new MText (tag[2].Name);
1427       if (commands == null)
1428         commands = new Command[0];
1429       if (! full)
1430         return;
1431       if (states.Count == 0)
1432         add_default_state ();
1433     }
1434
1435     private void load (XmlNode node, bool full)
1436     {
1437       bool skip_header = load_status == LoadStatus.Header;
1438
1439       maps = new Dictionary<MSymbol, Map> ();
1440       states = new Dictionary<Xex.Symbol, State> ();
1441
1442       if (node.NodeType == XmlNodeType.Document)
1443         node = node.FirstChild;
1444       while (node.NodeType != XmlNodeType.Element)
1445         node = node.NextSibling;
1446       for (node = node.FirstChild; node != null; node = node.NextSibling)
1447         {
1448           if (node.NodeType != XmlNodeType.Element)
1449             continue;
1450           if (! skip_header)
1451             {
1452               if (node.Name == "description")
1453                 description = parse_description (node);
1454               else if (node.Name == "title")
1455                 title = parse_title (node);
1456               else if (node.Name == "variable-list")
1457                 parse_variables (node);
1458               else if (node.Name == "command-list")
1459                 parse_commands (node);
1460             }
1461           else if (full)
1462             {
1463               if (node.Name == "module-list")
1464                 parse_plugins (node);
1465               else if (node.Name == "macro-list")
1466                 parse_macros (node);
1467               else if (node.Name == "map-list")
1468                 parse_maps (node);
1469               else if (node.Name == "state-list")
1470                 parse_states (node);
1471             }
1472         }
1473       if (description == null)
1474         description = (MText) "No description";
1475       if (title == null)
1476         title = new MText (tag[2].Name);
1477       if (commands == null)
1478         commands = new Command[0];
1479       if (! full)
1480         return;
1481       if (states.Count == 0)
1482         add_default_state ();
1483     }
1484
1485     private static MText parse_description (MPlist plist)
1486     {
1487       if (plist.IsMText)
1488         return plist.Text;
1489       if (plist.IsPlist)
1490         {
1491           plist = plist.Plist;
1492           if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
1493               && plist.next.IsMText)
1494             return plist.next.Text;
1495         }
1496       return null;
1497     }
1498
1499     private static MText parse_description (XmlNode node)
1500     {
1501       if (node.HasChildNodes)
1502         node = node.FirstChild;
1503       return node.InnerText;
1504     }
1505
1506     private static MText parse_title (XmlNode node)
1507     {
1508       return node.InnerText;
1509     }
1510
1511     private void new_variable (Xex.Symbol name, string desc, int val,
1512                                MPlist pl, Xex.Variable vari)
1513     {
1514       int[] range;
1515
1516       if (pl.IsEmpty)
1517         range = null;
1518       else
1519         {
1520           int nrange = pl.Count;
1521           range = new int[nrange * 2];
1522           for (int i = 0; i < nrange; i++)
1523             {
1524               if (pl.IsPlist)
1525                 {
1526                   MPlist p = pl.Plist;
1527
1528                   if (! p.IsInteger || ! p.next.IsInteger)
1529                     throw new Exception ("Invalid range: " + p);
1530                   range[i * 2] = p.Integer;
1531                   range[i * 2 + 1] = p.next.Integer;
1532                 }
1533               else if (pl.IsInteger)
1534                 range[i * 2] = range[i * 2 + 1] = pl.Integer;
1535               else
1536                 throw new Exception ("Invalid range: " + pl);
1537             }
1538         }
1539       if (vari == null)
1540         domain.Defvar (new Xex.Variable.Int (name, desc, val, range));
1541       else
1542         {
1543           Xex.Term term = new Xex.Term (val);
1544           vari.Value = term;
1545           vari.DefaultValue = term;
1546           vari.Range = range;
1547         }
1548     }
1549
1550     private void new_variable (Xex.Symbol name, string desc, MText val,
1551                                MPlist pl, Xex.Variable vari)
1552     {
1553       string[] range;
1554
1555       if (pl.IsEmpty)
1556         range = null;
1557       else
1558         {
1559           range = new string[pl.Count * 2];
1560           for (int i = 0; i < range.Length; i++)
1561             {
1562               if (pl.IsMText)
1563                 range[i] = (string) pl.Text;
1564               else
1565                 throw new Exception ("Invalid range: " + pl);
1566             }
1567         }
1568       if (vari == null)
1569         domain.Defvar (new Xex.Variable.Str (name, desc, (string) val, range));
1570       else
1571         {
1572           Xex.Term term = new Xex.Term ((string) val);
1573           vari.Value = term;
1574           vari.DefaultValue = term;
1575           vari.Range = range;
1576         }
1577     }
1578
1579     private void new_variable (Xex.Symbol name, string desc, MSymbol val,
1580                                MPlist pl, Xex.Variable vari)
1581     {
1582       Xex.Symbol[] range;
1583       Xex.Symbol sym = val.Name;
1584
1585       if (pl.IsEmpty)
1586         range = null;
1587       else
1588         {
1589           range = new Xex.Symbol[pl.Count * 2];
1590           for (int i = 0; i < range.Length; i++)
1591             {
1592               if (pl.IsSymbol)
1593                 range[i] = pl.Symbol.Name;
1594               else
1595                 throw new Exception ("Invalid range: " + pl);
1596             }
1597         }
1598       if (vari == null)
1599         domain.Defvar (new Xex.Variable.Sym (name, desc, sym, range));
1600       else
1601         {
1602           Xex.Term term = new Xex.Term (sym);
1603           vari.Value = term;
1604           vari.DefaultValue = term;
1605           vari.Range = range;
1606         }
1607     }
1608
1609     private Xex.Variable get_global_var (Xex.Symbol name)
1610     {
1611       if (im_global == null || this != im_global)
1612         {
1613           tag = new MDatabase.Tag (Minput_method, MSymbol.t, MSymbol.nil,
1614                                    "global");
1615           im_global = im_table[tag];
1616           if (! im_global.Open ())
1617             throw new Exception ("Failed to load global"); 
1618         }
1619       return im_global.domain.GetVar (name, false);
1620     }
1621
1622     private void parse_variables (MPlist plist)
1623     {
1624       var_names = new Xex.Symbol[plist.Count];
1625
1626       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1627         {
1628           if (! plist.IsPlist || ! plist.Plist.IsSymbol)
1629             throw new Exception ("Invalid variable: " + plist);
1630
1631           MPlist p = plist.Plist;
1632           Xex.Symbol name = (Xex.Symbol) p.Symbol.Name;
1633           var_names[i] = name;
1634           p = p.next;
1635           string desc = (string) parse_description (p);
1636           Xex.Variable vari = get_global_var (name);
1637           if (vari != null)
1638             domain.Defvar (vari);
1639           if (desc != null)
1640             p = p.next;
1641           if (! p.IsEmpty)
1642             {
1643               if (p.IsInteger)
1644                 new_variable (name, desc, p.Integer, p.next, vari);
1645               else if (p.IsMText)
1646                 new_variable (name, desc, p.Text, p.next, vari);
1647               else if (p.IsSymbol)
1648                 new_variable (name, desc, p.Symbol, p.next, vari);
1649               else
1650                 throw new Exception ("Invalid variable type: " + p.val);
1651             }
1652         }
1653     }
1654
1655     private void parse_variables (XmlNode node)
1656     {
1657       XmlNodeList node_list = node.ChildNodes;
1658
1659       var_names = new Xex.Symbol[node_list.Count];
1660       for (int i = 0; i < node_list.Count; i++)
1661         {
1662           Xex.Symbol name = node_list[i].Attributes[0].Value;
1663           Xex.Variable vari = get_global_var (name);
1664           if (vari != null)
1665             domain.Defvar (vari);
1666           domain.Defvar (node_list[i]);
1667           var_names[i] = name;
1668         }
1669     }
1670
1671     private void parse_commands (MPlist plist)
1672     {
1673       commands = new Command[plist.Count];
1674
1675       for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1676         if (plist.IsPlist && plist.Plist.IsSymbol)
1677           commands[i++] = new Command (plist.Plist);
1678     }
1679
1680     private void parse_commands (XmlNode node)
1681     {
1682       XmlNodeList node_list = node.ChildNodes;
1683
1684       commands = new Command[node_list.Count];
1685       for (int i = 0; i < node_list.Count; i++)
1686         {
1687           if (node_list[i].NodeType == XmlNodeType.Element)
1688             commands[i] = new Command (node_list[i]);
1689         }
1690     }
1691
1692     private void parse_plugins (MPlist plist)
1693     {
1694       plugins = new Dictionary<MSymbol, Plugin> ();
1695
1696       for (; ! plist.IsEmpty; plist = plist.Next)
1697         {
1698           MPlist p = plist.Plist;
1699           MSymbol sym = p.Symbol;
1700           Plugin plugin = new Plugin (sym.Name);
1701
1702           for (p = p.next; ! p.IsEmpty; p = p.next)
1703             {
1704               Xex.Function func = new PluginMethod (plugin, p.Symbol.Name);
1705               domain.Defun (func);
1706             }
1707         }
1708     }
1709
1710     private void parse_plugins (XmlNode node)
1711     {
1712       plugins = new Dictionary<MSymbol, Plugin> ();
1713
1714       foreach (XmlNode n in node.ChildNodes)
1715         {
1716           Plugin plugin = new Plugin (n.Attributes[0].Value);
1717           foreach (XmlNode nn in n.ChildNodes)
1718             {
1719               Xex.Function func = new PluginMethod (plugin,
1720                                                     nn.Attributes[0].Value);
1721               domain.Defun (func);
1722             }
1723         }
1724     }
1725
1726     private void parse_macros (XmlNode node)
1727     {
1728       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1729         if (nn.NodeType == XmlNodeType.Element)
1730           domain.Defun (nn, true);
1731       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1732         if (nn.NodeType == XmlNodeType.Element)
1733           domain.Defun (nn, false);
1734     }
1735
1736     private void parse_maps (XmlNode node)
1737     {
1738       for (node = node.FirstChild; node != null; node = node.NextSibling)
1739         if (node.Name == Qmap)
1740           {
1741             MSymbol name = node.Attributes[0].Value;
1742             Map map = new Map (name);
1743             maps[name] = map;
1744             for (XmlNode nd = node.FirstChild; nd != null; nd = nd.NextSibling)
1745               if (nd.Name == Qrule)
1746                 {
1747                   XmlNode n = nd.FirstChild;
1748                   if (n.Name != Qkeyseq)
1749                     continue;
1750                   KeySeq keyseq = (KeySeq) KeySeq.parser (domain, n);
1751                   Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling);
1752                   map.entries.Add (new Map.Entry (domain, keyseq, actions));
1753                 }
1754           }
1755     }
1756
1757     private void parse_states (MPlist plist)
1758     {
1759       for (; ! plist.IsEmpty; plist = plist.next)
1760         if (plist.IsPlist)
1761           {
1762             State state = new State (this, plist.Plist);
1763             states[state.name] = state;     
1764             if (initial_state == null)
1765               initial_state = state;
1766           }
1767     }
1768
1769     private void parse_states (XmlNode node)
1770     {
1771       for (node = node.FirstChild; node != null; node = node.NextSibling)
1772         if (node.Name == Qstate)
1773           {
1774             State state = new State (this, node);
1775             states[state.name] = state;
1776             if (initial_state == null)
1777               initial_state = state;
1778           }
1779     }
1780
1781     private void parse_include (MPlist plist)
1782     {
1783       if (! plist.IsPlist)
1784         return;
1785       MPlist p = plist.Plist;
1786       MSymbol language, name, subname;
1787       language = p.Symbol;
1788       p = p.next;
1789       if (! p.IsSymbol)
1790         name = subname = MSymbol.nil;
1791       else
1792         {
1793           name = p.Symbol;
1794           p = p.next;
1795           if (! p.IsSymbol)
1796             subname = MSymbol.nil;
1797           else
1798             subname = p.Symbol;
1799         }
1800
1801       MInputMethod im = MInputMethod.Find (language, name, subname);
1802       if (im == null)
1803         return;
1804       if (! im.Open ())
1805         return;
1806       plist = plist.next;
1807       if (! plist.IsSymbol)
1808         return;
1809       MSymbol target_type = plist.Symbol;
1810       plist = plist.next;
1811       MSymbol target_name = MSymbol.nil;
1812       if (plist.IsSymbol)
1813         target_name = plist.Symbol;
1814       if (target_type == Mmacro)
1815         {
1816           if (target_name == MSymbol.nil)
1817             im.domain.CopyFunc (domain);
1818           else
1819             im.domain.CopyFunc (domain, (Xex.Symbol) target_name.Name);
1820         }
1821       else if (target_type == Mmap)
1822         {
1823           if (target_name == MSymbol.nil)
1824             {
1825               foreach (KeyValuePair<MSymbol, Map> kv in im.maps)
1826                 maps[kv.Key] = kv.Value;
1827             }
1828           else
1829             {
1830               Map map;
1831               if (im.maps.TryGetValue (target_name, out map))
1832                 maps[target_name] = map;
1833             }
1834         }
1835       else if (target_type == Mstate)
1836         {
1837           if (target_name == MSymbol.nil)
1838             {
1839               foreach (KeyValuePair<Xex.Symbol, State> kv in im.states)
1840                 states[kv.Key] = kv.Value;
1841             }
1842           else
1843             {
1844               Xex.Symbol state_name = target_name.Name;
1845               State state;
1846               if (im.states.TryGetValue (state_name, out state))
1847                 states[state_name] = state;
1848             }
1849         }
1850     }
1851
1852     private Xex.Term parse_cond (MPlist plist)
1853     {
1854       Xex.Term[] args = new Xex.Term[plist.Count];
1855
1856       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1857         {
1858           if (! plist.IsPlist)
1859             throw new Exception ("Invalid cond args: " + plist);
1860           MPlist p = plist.Plist;
1861           List<Xex.Term> arg = new List<Xex.Term> (parse_actions (p, false));
1862           args[i] = new Xex.Term (arg);
1863         }
1864       return new Xex.Term (domain, Qcond, args);
1865     }
1866
1867     private Xex.Term parse_insert (MPlist plist)
1868     {
1869       Xex.Term[] args;
1870       Xex.Term arg;
1871       if (plist.IsSymbol)
1872         arg = new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
1873       else if (plist.IsMText)
1874         arg = new Xex.Term ((string) plist.Text);
1875       else if (plist.IsInteger)
1876         arg = new Xex.Term (plist.Integer);
1877       else if (plist.IsPlist)
1878         {
1879           MPlist pl = plist.Plist;
1880
1881           args = new Xex.Term[pl.Count];
1882           int i;
1883           for (i = 0; ! pl.IsEmpty; i++, pl = pl.next)
1884             {
1885               if (pl.IsMText)
1886                 args[i] = new Xex.Term ((string) pl.Text);
1887               else if (pl.IsPlist)
1888                 {
1889                   List<Xex.Term> list = new List<Xex.Term> ();
1890                   for (MPlist p = pl.Plist; ! p.IsEmpty; p = p.next)
1891                     {
1892                       if (p.IsMText)
1893                         list.Add (new Xex.Term ((string) p.Text));
1894                       else
1895                         throw new Exception ("Invalid candidates: " + p);
1896                     }                 
1897                 }
1898               else
1899                 throw new Exception ("Invalid candidates: " + pl);
1900             }
1901           return new Xex.Term (domain, Qinsert_candidates, args);
1902         }
1903       else
1904         throw new Exception ("Invalid arg to insert: " + plist);
1905       args = new Xex.Term[1];
1906       args[0] = arg;
1907       return new Xex.Term (domain, Qinsert, args);
1908     }
1909
1910     private Xex.Term parse_select (MPlist plist)
1911     {
1912       Xex.Term[] args = new Xex.Term[1];
1913       if (plist.IsInteger)
1914         args[0] = new Xex.Term (plist.Integer);
1915       else if (! plist.IsSymbol)
1916         throw new Exception ("Invalid arg to select: " + plist);
1917       else if (plist.Symbol.Name[0] == '@')
1918         args[0] = new Xex.Term (Selector.Get (plist.Symbol));
1919       else
1920         args[0] = new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
1921       return new Xex.Term (domain, Qselect, args);
1922     }
1923
1924     private Xex.Term parse_funcall_with_marker (MPlist plist, Xex.Symbol func)
1925     {
1926       Xex.Term[] args = new Xex.Term[1];
1927       if (plist.IsInteger && func != Qmark)
1928         args[0] = new Xex.Term (plist.Integer);
1929       else if (plist.IsSymbol)
1930         args[0] = new Xex.Term (Marker.Get (plist.Symbol));
1931       else
1932         throw new Exception ("Invalid arg to " + func + ": " + plist);
1933       return new Xex.Term (domain, func, args);
1934     }
1935
1936     private Xex.Term parse_char_at (MSymbol name)
1937     {
1938       Xex.Term[] args = new Xex.Term[1];
1939       args[0] = new Xex.Term (Marker.Get (name));
1940       return new Xex.Term (domain, Qchar_at, args);
1941     }
1942
1943     private Xex.Term parse_shift (MPlist plist)
1944     {
1945       Xex.Term[] args = new Xex.Term[1];
1946       if (! plist.IsSymbol)
1947         throw new Exception ("Invalid arg to shift: " + plist);
1948       args[0] = new Xex.Term ((Xex.Symbol) plist.Symbol.Name);
1949       return new Xex.Term (domain, Qshift, args);
1950     }
1951
1952     private Xex.Term parse_action (MPlist plist, bool as_funarg)
1953     {
1954       if (plist.IsPlist)
1955         {
1956           MPlist p = plist.Plist;
1957               
1958           if (p.IsMText || p.IsPlist)
1959             return parse_insert (plist);
1960           if (! p.IsSymbol)
1961             throw new Exception ("Invalid action: " + p);
1962           MSymbol sym = p.Symbol;
1963           Xex.Symbol name = sym.Name;
1964           p = p.next;
1965           if (name == Qcond)
1966             return parse_cond (p);
1967           if (name == Qinsert)
1968             return parse_insert (p);
1969           if (name == Qselect)
1970             return parse_select (p);
1971           if (name == Qdelete || name == Qmove || name == Qmark)
1972             return parse_funcall_with_marker (p, name);
1973           if (name == Qshift)
1974             return parse_shift (p);
1975           if (((string) name)[0] == '@')
1976             return parse_char_at (sym);
1977           if (name == Qset || name == Qadd || name == Qsub
1978                    || name == Qmul || name == Qdiv)
1979             {
1980               if (! p.IsSymbol)
1981                 throw new Exception ("Invalid action: " + p);
1982               Xex.Symbol varname = p.Symbol.Name;
1983               Xex.Term[] args = new Xex.Term[1];
1984               args[0] = parse_action (p.next, true);
1985               return new Xex.Term (domain, name, varname, args);
1986             }
1987           else
1988             {
1989               if (name == Qeq)
1990                 name = Qeqeq;
1991               if (p.IsEmpty)
1992                 return new Xex.Term (domain, name, null);
1993               else
1994                 return new Xex.Term (domain, name, parse_actions (p, true));
1995             }
1996         }
1997       else if (plist.IsSymbol)
1998         return new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name);
1999       else if (plist.IsMText)
2000         return (as_funarg ? new Xex.Term ((string) plist.Text)
2001                 : parse_insert (plist));
2002       else if (plist.IsInteger)
2003         return (as_funarg ? new Xex.Term (plist.Integer)
2004                 : parse_insert (plist));
2005       else
2006         throw new Exception ("Invalid action: " + plist);
2007     }
2008
2009     private Xex.Term[] parse_actions (MPlist plist, bool as_funarg)
2010     {
2011       Xex.Term[] terms = new Xex.Term[plist.Count];
2012
2013       for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
2014         terms[i] = parse_action (plist, as_funarg);
2015       return terms;
2016     }
2017
2018     private void parse_macros (MPlist plist)
2019     {
2020       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
2021         if (pl.IsPlist)
2022           {
2023             MPlist p = pl.Plist;
2024
2025             if (! p.IsSymbol)
2026               continue;
2027             domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null, null, true);
2028           }
2029       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
2030         if (pl.IsPlist)
2031           {
2032             MPlist p = pl.Plist;
2033
2034             if (! p.IsSymbol)
2035               continue;
2036             domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null,
2037                           parse_actions (p.next, false), false);
2038           }
2039     }
2040
2041     private void parse_maps (MPlist plist)
2042     {
2043       for (; ! plist.IsEmpty; plist = plist.next)
2044         if (plist.IsPlist)
2045           {
2046             MPlist pl = plist.Plist;
2047           
2048             if (! pl.IsSymbol)
2049               continue;
2050             Map map = new Map (pl.Symbol);
2051             maps[pl.Symbol] = map;
2052             for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
2053               {
2054                 if (! pl.IsPlist)
2055                   continue;
2056                 MPlist p = pl.Plist;
2057                 KeySeq keys;
2058                 if (p.IsMText)
2059                   keys = new KeySeq (p.Text);
2060                 else if (p.IsPlist)
2061                   keys = new KeySeq (p.Plist);
2062                 else
2063                   continue;
2064                 p = p.next;
2065                 Xex.Term[] actions
2066                   = p.IsEmpty ? null : parse_actions (p, false);
2067                 map.entries.Add (new Map.Entry (domain, keys, actions));
2068               }
2069           }
2070     }
2071
2072     private static Xex.Term Finsert (Xex.Domain domain, Xex.Variable vari,
2073                                      Xex.Term[] args)
2074     {
2075       if (args[0].IsInt)
2076         ((Context) domain.context).insert (args[0].Intval);
2077       else
2078         ((Context) domain.context).insert (args[0].Strval);
2079       return args[0];
2080     }
2081
2082     private static Xex.Term Finsert_candidates (Xex.Domain domain,
2083                                                 Xex.Variable vari,
2084                                                 Xex.Term[] args)
2085     {
2086       Context ic = (Context) domain.context;
2087       Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size, false);
2088       int column = (v == null ? 0 : v.Value.Intval);
2089
2090       ic.insert_candidates (new Candidates (args, column));
2091       return args[0];
2092     }
2093
2094     private static Xex.Term Fchar_at (Xex.Domain domain, Xex.Variable vari,
2095                                       Xex.Term[] args)
2096     {
2097       Context ic = (Context) domain.context;
2098       Marker m = (Marker) args[0].Objval;
2099
2100       return new Xex.Term (m.CharAt (ic));
2101     }
2102
2103     private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
2104                                      Xex.Term[] args)
2105     {
2106       Context ic = (Context) domain.context;
2107       int pos;
2108
2109       if (args[0].IsInt)
2110         pos = args[0].Intval;
2111       else
2112         {
2113           Marker m = (Marker) args[0].Objval;
2114           pos = m.Position (ic);
2115         }
2116       return new Xex.Term (ic.delete (pos));
2117     }
2118
2119     private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
2120                                      Xex.Term[] args)
2121     {
2122       Candidates can = ((Context) domain.context).candidates;
2123
2124       if (can != null)
2125         {
2126           if (args[0].IsInt)
2127             can.Select (args[0].Intval);
2128           else
2129             ((Selector) args[0].Objval).Select (can);
2130         }
2131       return args[0];
2132     }
2133
2134     private static Xex.Term Fshow (Xex.Domain domain, Xex.Variable vari,
2135                                    Xex.Term[] args)
2136     {
2137       ((Context) domain.context).show ();
2138       return Tnil;
2139     }
2140
2141     private static Xex.Term Fhide (Xex.Domain domain, Xex.Variable vari,
2142                                    Xex.Term[] args)
2143     {
2144       ((Context) domain.context).hide ();
2145       return Tnil;
2146     }
2147
2148     private static Xex.Term Fmove (Xex.Domain domain, Xex.Variable vari,
2149                                    Xex.Term[] args)
2150     {
2151       Context ic = (Context) domain.context;
2152       int pos = (args[0].IsInt ? args[0].Intval
2153                  : ((Marker) args[0].Objval).Position (ic));
2154       ic.move (pos);
2155       return args[0];
2156     }
2157
2158     private static Xex.Term Fmark (Xex.Domain domain, Xex.Variable vari,
2159                                    Xex.Term[] args)
2160     {
2161       Marker m = (Marker) args[0].Objval;
2162       m.Mark ((Context) domain.context);
2163       return args[0];
2164     }
2165
2166     private static Xex.Term Fpushback (Xex.Domain domain, Xex.Variable vari,
2167                                        Xex.Term[] args)
2168     {
2169       Context ic = (Context) domain.context;
2170
2171       if (args[0].IsInt)
2172         ic.pushback (args[0].Intval);
2173       else if (args[0].IsStr)
2174         ic.pushback (new KeySeq (args[0].Strval));
2175       else
2176         ic.pushback ((KeySeq) args[0].Objval);
2177       return args[0];
2178     }
2179
2180     private static Xex.Term Fpop (Xex.Domain domain, Xex.Variable vari,
2181                                   Xex.Term[] args)
2182     {
2183       ((Context) domain.context).pop ();
2184       return Tnil;
2185     }
2186
2187     private static Xex.Term Fundo (Xex.Domain domain, Xex.Variable vari,
2188                                    Xex.Term[] args)
2189     {
2190       int n = args.Length == 0 ? -2 : args[0].Intval;
2191       ((Context) domain.context).undo (n);
2192       return Tnil;
2193     }
2194
2195     private static Xex.Term Fcommit (Xex.Domain domain, Xex.Variable vari,
2196                                      Xex.Term[] args)
2197     {
2198       ((Context) domain.context).commit ();
2199       return Tnil;
2200     }
2201
2202     private static Xex.Term Funhandle (Xex.Domain domain, Xex.Variable vari,
2203                                        Xex.Term[] args)
2204     {
2205       ((Context) domain.context).commit ();
2206       args = new Xex.Term[2];
2207       args[0] = args[1] = Tcatch_tag;
2208       return Xex.Fthrow (domain, vari, args);
2209     }
2210
2211     private static Xex.Term Fshift (Xex.Domain domain, Xex.Variable vari,
2212                                     Xex.Term[] args)
2213     {
2214       Context ic = (Context) domain.context;
2215       State state;
2216       if (ic.im.states.TryGetValue (args[0].Symval, out state))
2217         ((Context) domain.context).shift (state);
2218       else
2219         throw new Exception ("Unknown state: " + args[0].Symval);
2220       return args[0];
2221     }
2222
2223     private static Xex.Term Fshiftback (Xex.Domain domain, Xex.Variable vari,
2224                                         Xex.Term[] args)
2225     {
2226       ((Context) domain.context).shift (null);
2227       return Tnil;
2228     }
2229
2230     private static Xex.Term Fkey_count (Xex.Domain domain, Xex.Variable vari,
2231                                         Xex.Term[] args)
2232     {
2233       return new Xex.Term (((Context) domain.context).key_head);
2234     }
2235
2236     private static Xex.Term Fsurrounding_flag (Xex.Domain domain,
2237                                                Xex.Variable vari,
2238                                                Xex.Term[] args)
2239     {
2240       return new Xex.Term (GetSurroundingText == null ? 0 : 1);
2241     }
2242
2243     public override string ToString ()
2244     {
2245       this.Open ();
2246       string str = (String.Format ("({0} (title \"{1}\")", tag, title));
2247       if (commands != null)
2248         {
2249           str += " (commands";
2250           foreach (Command cmd in commands)
2251             str += " " + cmd;
2252           str += ")";
2253         }
2254       if (var_names != null)
2255         {
2256           str += " (variables";
2257           foreach (Xex.Symbol var in var_names)
2258             str += " " + var;
2259           str += ")";
2260         }
2261       if (plugins != null)
2262         {
2263           str += " (modules";
2264           foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
2265             str += " " + kv.Value;
2266           str += ")";
2267         }
2268       str += " (maps";
2269       foreach (KeyValuePair<MSymbol, Map> kv in maps)
2270         str += " " + kv.Value;
2271       str += ") (states";
2272       foreach (KeyValuePair<Xex.Symbol, State> kv in states)
2273         {
2274           str += " (" + kv.Key + " " + kv.Value.keymap + ")";
2275         }
2276       return str + "))";
2277     }
2278
2279     public class Context
2280     {
2281       internal MInputMethod im;
2282       internal Xex.Domain domain;
2283       private bool active;
2284
2285       private MText status;
2286       private MText produced = new MText ();
2287       internal MText preedit = new MText ();
2288       internal int cursor_pos;
2289       internal MPlist marker_positions = new MPlist ();
2290
2291       internal Candidates candidates;
2292       private int candidate_from, candidate_to;
2293       private bool candidate_show;
2294       public bool CandidateShow { get { return candidate_show; } }
2295
2296       private State state, prev_state;
2297       private MText state_preedit = new MText ();
2298       private int state_key_head;
2299       private object state_var_values, state_initial_var_values;
2300       private int state_pos;
2301
2302       private Keymap keymap;
2303       // Sequence of input keys.
2304       internal KeySeq keys = new KeySeq ();
2305       // Index into KEYS specifying the next key to handle.
2306       internal int key_head;
2307
2308       internal MText preceding_text = new MText ();
2309       internal MText following_text = new MText ();
2310
2311       // Set to false before calling the method 'handle_key', and set
2312       // to true when some key is unhandled.
2313       private bool key_unhandled;
2314
2315       // The unhandled key.  It has the meaning only when
2316       // 'key_unhandled' is true.
2317       private Key unhandled_key;
2318
2319       internal ChangedStatus changed;
2320
2321       private void set_cursor (string prefix, int pos)
2322       {
2323         cursor_pos = pos;
2324       }
2325
2326       internal void reset ()
2327       {
2328         status = im.initial_state.title;
2329         produced.Del ();
2330         preedit.Del ();
2331
2332         set_cursor ("reset", 0);
2333         marker_positions.Clear ();
2334         candidates = null;
2335         candidate_show = false;
2336
2337         state = im.initial_state;
2338         prev_state = null;
2339         state_preedit.Del ();
2340         state_key_head = 0;
2341         state_var_values = state_initial_var_values;
2342         state_pos = 0;
2343
2344         keymap = im.initial_state.keymap;
2345         keys.keyseq.Clear ();
2346
2347         preceding_text.Del ();
2348         following_text.Del ();
2349
2350         changed = ChangedStatus.None;
2351       }
2352
2353       static Xex.Term[] catch_args = new Xex.Term[2];
2354
2355       private bool take_actions (Xex.Term[] actions)
2356       {
2357         catch_args[0] = Tcatch_tag;
2358         catch_args[1]= new Xex.Term (domain, Qprogn, actions);
2359         Xex.Term term = new Xex.Term (domain, Qcatch, catch_args);
2360         term = term.Eval (domain);
2361         return (! term.IsSymbol || term.Symval != Tcatch_tag.Symval);
2362       }
2363
2364       static MPlist callback_arg = new MPlist ();
2365
2366       private bool get_surrounding_text (int len)
2367       {
2368         if (len < 0 ? -len <= preceding_text.Length
2369             : len <= following_text.Length)
2370           return true;
2371         if (GetSurroundingText == null)
2372           return false;
2373         callback_arg.Set (MSymbol.integer, len);
2374         if (! GetSurroundingText (this, callback_arg)
2375             || ! callback_arg.IsMText)
2376           return false;
2377         if (len < 0)
2378           {
2379             preceding_text = callback_arg.Text;
2380             return (-len <= preceding_text.Length);
2381           }
2382         following_text = callback_arg.Text;
2383         return (len <= following_text.Length);
2384       }
2385
2386       internal int GetSurroundingChar (int pos)
2387       {
2388         if (! get_surrounding_text (pos < 0 ? pos : pos + 1))
2389           return 0;
2390         if (pos < 0)
2391           return preceding_text[preceding_text.Length + pos];
2392         return following_text[pos];
2393       } 
2394
2395       private void adjust_markers (int from, int to, object inserted)
2396       {
2397         int ins = (inserted == null ? 0
2398                    : inserted is int ? 1
2399                    : ((MText) inserted).Length);
2400         int diff = ins - (to - from);
2401
2402         for (MPlist p = marker_positions; ! p.IsEmpty; p = p.next)
2403           {
2404             int pos = p.Integer;
2405             if (pos > from)
2406               p.Set (p.Key, pos >= to ? pos + diff : from);
2407           }
2408         if (cursor_pos >= to)
2409           set_cursor ("adjust", cursor_pos + diff);
2410         else if (cursor_pos > from)
2411           set_cursor ("adjust", 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         set_cursor ("update-candidate", candidate_to);
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             set_cursor ("move", 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_replace (0, preedit.Length, null);
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         keymap = state.keymap;
2635       }
2636
2637       public Context (MInputMethod im)
2638       {
2639         if (im.load_status != LoadStatus.Full
2640             && ! im.Open ())
2641           throw new Exception ("Openging " + im.tag + " failed");
2642         this.im = im;
2643         domain = new Xex.Domain (im.domain, this);
2644         state_initial_var_values = domain.SaveValues ();
2645         reset ();
2646         active = true;
2647         if (PreeditChanged != null)
2648           {
2649             callback_arg.Set (MSymbol.mtext, preedit);
2650             PreeditChanged (this, callback_arg);
2651           }
2652         if (StatusChanged != null)
2653           {
2654             callback_arg.Set (MSymbol.mtext, status);
2655             StatusChanged (this, callback_arg);
2656           }
2657       }
2658
2659       public ChangedStatus Changed { get { return changed; } }
2660
2661       internal object GetCandidates (out int column)
2662       {
2663         column = 0;
2664         if (cursor_pos == 0)
2665           return null;
2666         Candidates candidates
2667           = (Candidates) preedit.GetProp (cursor_pos - 1, Mcandidates);
2668         if (candidates == null)
2669           return null;
2670         column = candidates.Column;
2671         return candidates.Current;
2672       }
2673
2674       private void save_state ()
2675       {
2676         state_var_values = domain.SaveValues ();
2677         state_preedit.Del ();
2678         state_preedit.Ins (0, preedit);
2679         state_key_head = key_head;
2680         state_pos = cursor_pos;
2681       }
2682
2683       private void restore_state ()
2684       {
2685         domain.RestoreValues (state_var_values);
2686         preedit.Del ();
2687         preedit.Ins (0, state_preedit);
2688         set_cursor ("restore", state_pos);
2689       }
2690
2691       private bool handle_key ()
2692       {
2693         Console.Write ("\nHandle ({0}[{1}]) in {2}",
2694                        keys, key_head, state.name);
2695
2696         Keymap sub = keymap.Lookup (keys, ref key_head);
2697
2698         if (sub != keymap)
2699           {
2700             restore_state ();
2701             keymap = sub;
2702             if (keymap.map_actions != null)
2703               {
2704                 if (! take_actions (keymap.map_actions))
2705                   return false;
2706               }
2707             else if (keymap.submaps != null)
2708               {
2709                 for (int i = state_key_head; i < key_head; i++)
2710                   preedit_replace (cursor_pos, cursor_pos,
2711                                    keys.keyseq[i].ToChar ());
2712               }
2713             if (keymap.submaps == null)
2714               {
2715                 if (keymap.branch_actions != null)
2716                   {
2717                     if (! take_actions (keymap.branch_actions))
2718                       return false;
2719                   }
2720                 if (keymap != state.keymap)
2721                   shift (state);
2722               }
2723           }
2724         else
2725           {
2726             State current_state = state;
2727
2728             if (keymap.branch_actions != null)
2729               {
2730                 if (! take_actions (keymap.branch_actions))
2731                   return false;
2732               }
2733             if (state == current_state)
2734               {
2735                 if (state == im.initial_state
2736                     && key_head < keys.keyseq.Count)
2737                   return false;
2738                 if (keymap != state.keymap)
2739                   shift (state);
2740                 else if (keymap.branch_actions == null)
2741                   shift (im.initial_state);
2742               }
2743           }
2744         return true;
2745       }
2746
2747       public bool Toggle ()
2748       {
2749         active = ! active;
2750         return active;
2751       }
2752
2753       public bool UnhandledKey (out Key key)
2754       {
2755         key = unhandled_key;
2756         return key_unhandled;
2757       }
2758
2759       public MText Preedit { get { return preedit; } }
2760       public MText Produced { get { return produced; } }
2761
2762       // Return value:
2763       //   true: All keys are handled and there's no text to commit.
2764       //   false: Some key is left unhandled or there's a text to
2765       //      commit.  The caller should refer to UnhandledKey and
2766       //      Produced.
2767
2768       public bool Filter (Key key)
2769       {
2770         if (! active)
2771           {
2772             key_unhandled = true;
2773             unhandled_key = key;
2774             return false;
2775           }
2776         if (key == Key.Reload)
2777           return true;
2778         changed = ChangedStatus.None;
2779         produced.Del ();
2780         preceding_text.Del ();
2781         following_text.Del ();
2782
2783         key_unhandled = false;
2784         keys.keyseq.Add (key);
2785         int count = 0;
2786         while (key_head < keys.keyseq.Count)
2787           {
2788             if (! handle_key ())
2789               {
2790                 unhandled_key = keys.keyseq[key_head++];
2791                 key_unhandled = true;
2792                 break;
2793               }
2794             if (++count == 10)
2795               break;
2796           }
2797         keys.keyseq.RemoveRange (0, key_head);
2798         key_head = 0;
2799
2800         if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
2801             && PreeditChanged != null)
2802           {
2803             callback_arg.Set (MSymbol.mtext, preedit);
2804             PreeditChanged (this, callback_arg);
2805           }
2806         if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
2807             && StatusChanged != null)
2808           {
2809             callback_arg.Set (MSymbol.mtext, status);
2810             StatusChanged (this, callback_arg);
2811           }
2812         if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
2813             && CandidateChanged != null)
2814           {
2815             CandidateChanged (this, callback_arg);
2816           }
2817
2818         Console.Write ("\nPreedit(\"{0}\"/{1}), Produced({2})",
2819                        preedit, cursor_pos, produced);
2820
2821         return (! key_unhandled && produced.Length == 0);
2822       }
2823     }
2824   }
2825 }