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