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