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