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