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