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