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