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