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