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