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