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