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