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