*** 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 namespace M17N.Input
13 {
14   public class MInputMethod
15   {
16     // Delegaes
17     public delegate bool Callback (MInputContext ic, MPlist args);
18
19     // Class members
20     public static Callback PreeditStart, PreeditDone, PreeditDraw;
21     public static Callback StatusStart, StatusDone, StatusDraw;
22     public static Callback CandidateStart, CandidateDone, CandidateDraw;
23     public static Callback SetSpot;
24     public static Callback Toggle;
25     public static Callback Reset;
26     public static Callback GetSurroundingText;
27     public static Callback DeleteSurroundingText;
28
29     internal static MExpression.Domain domain = new MExpression.Domain (null);
30     private static MSymbol Minput_method = "input-method";
31     private static MSymbol Mdescription = "description";
32     private static MSymbol Mvariable = "variable";
33     private static MSymbol Mcommand = "command";
34     private static MSymbol Mmodule = "module";
35     private static MSymbol Mmodule_list = "module-list";
36     private static MSymbol Mtitle = "title";
37     private static MSymbol Minclude = "include";
38     private static MSymbol Mmacro = "macro";
39     private static MSymbol Mmacro_list = "macro-list";
40     private static MSymbol Mmap = "map";
41     private static MSymbol Mmap_list = "map-list";
42     private static MSymbol Mstate = "state";
43     private static MSymbol Mstate_list = "state-list";
44     internal static MSymbol Mcandidates = "candidates";
45     private static MSymbol Minsert = "insert";
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 Madd = "add";
51     private static MSymbol Msub = "sub";
52     private static MSymbol Mmul = "mul";
53     private static MSymbol Mdiv = "div";
54     private static MSymbol Mif = "if";
55     private static MSymbol Mcond = "cond";
56     private static MSymbol Mchar_at = "char-at";
57     private static MSymbol Msurrounding_text_p = "surrounding-text-p";
58     private static MSymbol Mpushback = "pushback"; 
59     private static MSymbol Mkeyseq = "keyseq"; 
60
61     private static Dictionary<MDatabase.Tag, MInputMethod> im_table
62       = new Dictionary<MDatabase.Tag, MInputMethod> ();
63
64     // Sub classes
65     private class Exception : System.Exception
66     {
67       bool error;
68
69       public Exception (string msg) : base (msg)
70         {
71           error = true;
72         }
73
74       public Exception (string fmt, params object[] args)
75         : base (String.Format (fmt, args))
76         {
77           error = true;
78         }
79
80       public Exception (string msg, bool error) : base (msg)
81         {
82           this.error = error;
83         }
84     }
85
86     [FlagsAttribute]
87     private enum LoadStatus
88     {
89       None =   0x00,
90       Header = 0x01,
91       Body =   0x02,
92       Full =   0x03,
93       Error =  0x04,
94     };
95
96     [FlagsAttribute]
97     public enum KeyModifier
98       {
99         None =      0x00000000,
100         Shift_L =   0x00400000,
101         Shift_R =   0x00800000,
102         Shift =     0x00C00000,
103         Control_L = 0x01000000,
104         Control_R = 0x02000000,
105         Control   = 0x03000000,
106         Alt_L =     0x04000000,
107         Alt_R =     0x08000000,
108         Alt =       0x0C000000,
109         AltGr =     0x10000000,
110         Super =     0x20000000,
111         Hyper =     0x40000000,
112         High =      0x70000000,
113         All =       0x7FC00000,
114       };
115
116     public struct Key
117     {
118       internal uint key;
119
120       private static Dictionary<string, uint> keysyms
121         = new Dictionary<string, uint> ();
122       private static Dictionary<string, KeyModifier> keymodifiers
123         = new Dictionary<string, KeyModifier> ();
124       private static uint keysym_base = 0x200000;
125       private static uint char_mask = ~((uint) KeyModifier.All);
126
127       static Key ()
128       {
129         keysyms["bs"] = keysyms["backspace"] = 0x08;
130         keysyms["tab"] = 0x09;
131         keysyms["lf"] = keysyms["linefeed"] = 0x10;
132         keysyms["cr"] = keysyms["return"] = keysyms["enter"] = 0x13;
133         keysyms["esc"] = keysyms["escape"] = 0x1B;
134         keysyms["spc"] = keysyms["space"] = 0x20;
135         keysyms["del"] = keysyms["delete"] = 0x7F;
136         keymodifiers["shift-l"] = KeyModifier.Shift_L;
137         keymodifiers["shift-r"] = KeyModifier.Shift_R;
138         keymodifiers["shift"] = KeyModifier.Shift;
139         keymodifiers["control-l"] = KeyModifier.Control_L;
140         keymodifiers["control-r"] = KeyModifier.Control_R;
141         keymodifiers["control"] = KeyModifier.Control;
142         keymodifiers["alt-l"] = KeyModifier.Alt_L;
143         keymodifiers["alt-r"] = KeyModifier.Alt_R;
144         keymodifiers["alt"] = KeyModifier.Alt;
145         keymodifiers["altgr"] = KeyModifier.AltGr;
146         keymodifiers["super"] = KeyModifier.Super;
147         keymodifiers["hyper"] = KeyModifier.Hyper;
148       }
149
150       private static uint decode_keysym (MSymbol keysym)
151       {
152         uint key;
153         string name = keysym.Name;
154
155         if (name.Length == 1)
156           return name[0];
157         name = name.ToLower ();
158         if (! keysyms.TryGetValue (name, out key))
159           keysyms[name] = key = keysym_base++;
160         return key;
161       }
162
163       private static uint combine_modifiers (uint c, KeyModifier modifiers)
164       {
165         if (c < 0x7F && c != 0x20)
166           {
167             if ((modifiers & KeyModifier.Shift) != KeyModifier.None
168                 && Char.IsLower ((char) c))
169               {
170                 modifiers &= ~KeyModifier.Shift;
171                 c = Char.ToUpper ((char) c);
172               }
173             if ((modifiers & KeyModifier.Control) != KeyModifier.None)
174               {
175                 modifiers &= ~KeyModifier.Control;
176                 c &= 0x1F;
177               }
178           }     
179         return c | (uint) modifiers;
180       }
181
182       public Key (uint c)
183       {
184         key = c;
185       }
186
187       public Key (uint c, KeyModifier modifiers)
188       {
189         key = combine_modifiers (c, modifiers);
190       }
191
192       public Key (MSymbol keysym, KeyModifier modifiers)
193       {
194         key = combine_modifiers (decode_keysym (keysym), modifiers);
195       }
196
197       public Key (MSymbol keysym)
198       {
199         string str = keysym.Name;
200         int len = str.Length;
201         int i;
202         KeyModifier modifiers = KeyModifier.None;
203
204         for (i = 0; i + 2 < len && str[i + 1] == '-'; i += 2)
205           {
206             if (str[i] == 'S')
207               modifiers |= KeyModifier.Shift;
208             else if (str[i] == 'C')
209               modifiers |= KeyModifier.Control;
210             else if (str[i] == 'A')
211               modifiers |= KeyModifier.Alt;
212             else if (str[i] == 'G')
213               modifiers |= KeyModifier.AltGr;
214             else if (str[i] == 's')
215               modifiers |= KeyModifier.Super;
216             else if (str[i] == 'H')
217               modifiers |= KeyModifier.Hyper;
218           }
219         if (i + 1 == len)
220           key = combine_modifiers (str[i], modifiers);
221         else
222           key = combine_modifiers (decode_keysym (keysym), modifiers);
223       }
224
225       public Key (MPlist plist)
226       {
227         KeyModifier modifiers = KeyModifier.None;
228         MPlist p;
229
230         for (p = plist; ! p.IsEmpty; p = p.next)
231           {
232             if (p.IsInteger)
233               {
234                 if (! p.next.IsEmpty)
235                   throw new Exception ("Invalid Key: " + plist);
236                 break;
237               }
238             else if (! p.IsSymbol)
239               throw new Exception ("Invalid Key: " + plist);
240             else
241               {
242                 string name = p.Symbol.Name.ToLower ();
243                 KeyModifier m;
244                 
245                 if (! keymodifiers.TryGetValue (name, out m))
246                   break;
247                 modifiers |= m;
248               }
249           }
250         if (p.IsEmpty || ! p.next.IsEmpty)
251           throw new Exception ("Invalid Key: " + plist);
252         if (p.IsInteger)
253           key = combine_modifiers ((uint) p.Integer, modifiers);
254         else
255           key = combine_modifiers (decode_keysym (p.Symbol), modifiers);
256       }
257
258       public bool HasModifier
259       {
260         get { return ((key & (uint) KeyModifier.All) != 0); }
261       }
262
263       public bool Match (Key k)
264       {
265         if (k.key == key)
266           return true;
267         if ((k.key & char_mask) != (key & char_mask))
268           return false;
269         KeyModifier m1 = ((KeyModifier) key) & KeyModifier.All;
270         KeyModifier m2 = ((KeyModifier) k.key) & KeyModifier.All;
271         return (((m1 & KeyModifier.Shift) == (m2 & KeyModifier.Shift)
272                  || ((m1 & KeyModifier.Shift) == KeyModifier.Shift
273                      && (m2 & KeyModifier.Shift) != KeyModifier.None))
274                 && ((m1 & KeyModifier.Control) == (m2 & KeyModifier.Control)
275                     || ((m1 & KeyModifier.Control) == KeyModifier.Control
276                         && (m2 & KeyModifier.Control) != KeyModifier.None))
277                 && ((m1 & KeyModifier.Alt) == (m2 & KeyModifier.Alt)
278                     || ((m1 & KeyModifier.Alt) == KeyModifier.Alt
279                         && (m2 & KeyModifier.Alt) != KeyModifier.None))
280                 && ((m1 & KeyModifier.High) == (m2 & KeyModifier.High)));
281       }
282
283       public override string ToString ()
284       {
285         string str = Char.ToString ((char) key);
286         KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
287
288         if (m != KeyModifier.None)
289           {
290             if ((m & KeyModifier.Shift) != KeyModifier.None)
291               str = "S-" + str;
292             if ((m & KeyModifier.Control) != KeyModifier.None)
293               str = "C-" + str;
294             if ((m & KeyModifier.Alt) != KeyModifier.None)
295               str = "A-" + str;
296             if ((m & KeyModifier.AltGr) != KeyModifier.None)
297               str = "G-" + str;
298             if ((m & KeyModifier.Super) != KeyModifier.None)
299               str = "s-" + str;
300             if ((m & KeyModifier.Hyper) != KeyModifier.None)
301               str = "H-" + str;
302           }
303         return str;
304       }
305     }
306
307     public class KeySeq : List<Key>
308     {
309       public KeySeq () : base () { }
310
311       public KeySeq (MPlist plist) : base ()
312       {
313         foreach (MPlist p in plist)
314           {
315             if (p.IsSymbol)
316               this.Add (new Key (p.Symbol));
317             else if (p.IsInteger)
318               this.Add (new Key ((char) p.Integer));
319             else if (p.IsPlist)
320               this.Add (new Key (p.Plist));
321             else
322               throw new Exception ("Invalid Key Sequence: " + plist);
323           }
324       }
325
326       public KeySeq (MText mt) : base ()
327       {
328         for (int i = 0; i < mt.Length; i++)
329           this.Add (new Key ((uint) mt[i]));
330       }
331
332       private static uint parse_integer (string str)
333       {
334         if (Char.IsDigit (str[0]))
335           {
336             if (str[0] == '0' && str.Length > 2 && str[1] == 'x')
337               {
338                 uint i = 0;
339                 for (int idx = 2; idx < str.Length; idx++)
340                   {
341                     uint c = str[idx];
342                     if (c >= '0' && c <= '9')
343                       i = i * 16 + (c - '0');
344                     else if (c >= 'A' && c <= 'F')
345                       i = i * 16 + 10 + (c - 'A');
346                     else if (c >= 'a' && c <= 'f')
347                       i = i * 16 + 10 + (c - 'a');
348                     else
349                       break;
350                   }
351                 return i;
352               }
353             return UInt32.Parse (str);
354           }
355         else if (str[0] == '?')
356           return str[1];
357         return 0;
358       }
359
360       public KeySeq (XmlNode node) : base ()
361         {
362           XmlAttributeCollection acol = node.Attributes;
363           XmlNode n;
364
365           if (acol != null && (n = acol["keys"]) != null)
366             {
367               foreach (char c in  n.Value)
368                 this.Add (new Key ((uint) c));
369             }
370
371           for (node = node.FirstChild; node != null; node = node.NextSibling)
372             {
373               if (node.Name == "key-event")
374                 this.Add (new Key ((MSymbol) node.InnerText));
375               else
376                 this.Add (new Key (parse_integer (node.InnerText)));
377             }
378         }
379
380       public override string ToString ()
381       {
382         string str;
383
384         foreach (Key key in this)
385           if (key.HasModifier)
386             {
387               str = "(keyseq";
388               foreach (Key k in this)
389                 str += " " + k.ToString ();
390               return str + ")";
391             }
392         str = "\"";
393         foreach (Key key in this)               
394           str += key.ToString ();
395         return str + "\"";
396       }
397     }
398
399     public class Variable
400     {
401       public MSymbol name;
402       public MText description;
403       public Type type;
404       public object value;
405       public object[] candidates;
406
407       public Variable (MPlist p)
408       {
409         name = p.Symbol;
410         p = p.Next;
411         description = parse_description (p);
412         if (description == null)
413           description = new MText ("No description");
414         else
415           p = p.next;
416         type = (p.IsMText ? typeof (MText)
417                 : p.IsInteger ? typeof (int)
418                 : p.IsSymbol ? typeof (MSymbol)
419                 : typeof (object));
420         value = p.val;
421         p = p.next;
422         candidates = new object[p.Count];
423         for (int i = 0; ! p.IsEmpty; i++, p = p.next)
424           candidates[i] = p.val;
425       }
426
427       private static Type parse_value (XmlNode node, out object value)
428       {
429         string typename = node.Attributes["type"].Value;
430         Type type;
431
432         if (typename == "integer")
433           {
434             int i;
435             if (! Int32.TryParse (node.InnerText, out i))
436               i = 0;
437             value = i;
438             type = typeof (int);
439           }
440         else if (typename == "string")
441           {
442             MText mt = node.InnerText;
443             value = mt;
444             type = typeof (MText);
445           }
446         else if (typename == "symbol")
447           {
448             MSymbol sym = node.InnerText;
449             value = sym;
450             type = typeof (MSymbol);
451           }
452         else
453           {
454             value = null;
455             type = typeof (object);
456           }
457         return type;
458       }
459
460       public Variable (XmlNode node)
461       {
462         name = node.Attributes["id"].Value;
463         for (node = node.FirstChild; node != null; node = node.NextSibling)
464           if (node.NodeType == XmlNodeType.Element)
465             {
466               if (node.Name == "description")
467                 description = parse_description (node);
468               else if (node.Name == "value")
469                 type = parse_value (node, out value);
470               else if (node.Name == "valiable-value-candidate")
471                 {
472                   XmlNodeList n_list = node.ChildNodes;
473                   candidates = new object[n_list.Count];
474                   for (int i = 0; i < n_list.Count; i++)
475                     {
476                       object val;
477                       parse_value (n_list[i], out val);
478                       candidates[i] = val;
479                     }
480                 }
481             }
482       }
483
484       public override string ToString ()
485       {
486         return ("(" + name + " \"" + (string) description
487                 + "\" " + type + " " + value + " " + candidates + ")");
488       }
489     }
490
491     public class Command
492     {
493       public MSymbol name;
494       public MText description;
495       public List<KeySeq> keys;
496
497       public Command (MPlist p)
498       {
499         name = p.Symbol;
500         p = p.Next;
501         description = parse_description (p);
502         if (description == null)
503           description = "No description";
504         keys = new List<KeySeq> ();
505         for (p = p.next; ! p.IsEmpty; p = p.next)
506           {
507             if (p.IsMText)
508               keys.Add (new KeySeq (p.Text));
509             else if (p.IsPlist)
510               keys.Add (new KeySeq (p.Plist));
511           }
512       }
513
514       public Command (XmlNode node)
515       {
516         name = node.Attributes["id"].Value;
517         keys = new List<KeySeq> ();
518         for (node = node.FirstChild; node != null; node = node.NextSibling)
519           {
520             if (node.Name == "description")
521               description = parse_description (node);
522             else if (node.Name == "keyseq")
523               keys.Add (new KeySeq (node));
524           }
525       }
526
527       public override string ToString ()
528       {
529         string str = "(" + name + " \"" + (string) description;
530         foreach (KeySeq keyseq in keys)
531           str += " " + keyseq;
532         return str + ")";
533       }
534     }
535
536     internal class Plugin
537     {
538       public string name;
539       public Assembly assembly;
540       public MPlist methods;
541
542       public override string ToString ()
543       {
544         string str = "(" + name;
545         for (MPlist p = methods; ! p.IsEmpty; p = p.next)
546           str += " " + p.key;
547         return str + ")";
548       }
549     }
550
551     internal class Map
552     {
553       public MSymbol name;
554       public Dictionary<Key, Map> submaps;
555       public MExpression actions;
556
557       public void Add (KeySeq keys, int index, MExpression actions)
558       {
559         Map sub = null;
560
561         if (submaps == null)
562           submaps = new Dictionary<Key, Map> ();
563         else
564           submaps.TryGetValue (keys[index], out sub);
565         if (sub == null)
566           {
567             Key key = keys[index];
568             submaps[key] = sub = new Map ();
569           }
570         if (index + 1 < keys.Count)
571           sub.Add (keys, index + 1, actions);
572         else
573           this.actions = actions;
574       }
575
576       public MExpression Lookup (KeySeq keys, int index)
577       {
578         Map sub;
579
580         if (index + 1 == keys.Count)
581           return actions;
582         if (submaps.TryGetValue (keys[index], out sub))
583           return sub.Lookup (keys, index + 1);
584         return null;
585       }
586
587       private void describe (MText mt, KeySeq keyseq)
588       {
589         if (keyseq.Count > 0)
590           {
591             mt.Cat (" (").Cat (keyseq.ToString ());
592             if (actions != null)
593               mt.Cat (' ').Cat (actions.ToString ());
594             mt.Cat (')');           
595           }
596         if (submaps != null)
597           foreach (KeyValuePair<Key, Map> kv in submaps)
598             {
599               keyseq.Add (kv.Key);
600               kv.Value.describe (mt, keyseq);
601               keyseq.RemoveAt (keyseq.Count - 1);
602             }
603       }
604
605       public override string ToString ()
606       {
607         MText mt = "(" + name.Name;
608         KeySeq keyseq = new KeySeq ();
609
610         describe (mt, keyseq);
611         mt.Cat (')');
612         return (string) mt;
613       }
614     }
615
616     internal class State
617     {
618       public MSymbol name;
619       public MText title;
620       public MPlist branches = new MPlist ();
621
622       public State (MSymbol name)
623       {
624         this.name = name;
625       }
626
627       public override string ToString ()
628       {
629         MText mt = "(" + name.Name;
630
631         if (title != null)
632           mt.Cat (" \"" + title + "\"");
633         for (MPlist p = branches; ! p.IsEmpty; p = p.next)
634           mt.Cat (" (" + p.Key + " " + (MExpression) p.Val + ")");
635         return (string) mt + ")";
636       }
637     }
638
639     // Instance members
640     internal MExpression.Domain local_domain;
641
642     private LoadStatus load_status = LoadStatus.None;
643     private MDatabase.Tag tag;
644     private MDatabase mdb;
645
646     private MText description;
647     internal MText title;
648     internal Command[] commands;
649     internal Variable[] variables;
650     internal Dictionary<MSymbol, Plugin> plugins;
651     internal MPlist bindings;
652     internal Dictionary<MSymbol, Map> maps;
653     internal MPlist states;
654
655     static MInputMethod ()
656     {
657       domain.Defun ("insert", insert, 1, 1);
658       domain.Defun ("candidates", insert_candidates, 1, -1);
659       domain.Defun ("delete", delete, 1, 1);
660       domain.Defun ("select", select, 1, 1);
661       domain.Defun ("show", show, 0, 0);
662       domain.Defun ("hide", hide, 0, 0);
663       domain.Defun ("move", move, 1, 1);
664       domain.Defun ("mark", mark, 1, 1, true);
665       domain.Defun ("pushback", pushback, 1, 1);
666       domain.Defun ("pop", pop, 0, 0);
667       domain.Defun ("undo", undo, 0, 1);
668       domain.Defun ("commit", commit, 0, 0);
669       domain.Defun ("unhandle", unhandle, 0, 0);
670       domain.Defun ("shift", shift, 1, 1, true);
671       domain.Defun ("call", call, 2, -1, true);
672       // Pseudo functions to make arguments of special objects.
673       domain.Defun ("marker", marker, 1, 1, true);
674       domain.Defun ("char-at", char_at, 1, 1, true);
675       domain.Defun ("keyseq", keyseq, 1, -1, true);
676
677       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
678       List<MDatabase> list = MDatabase.List (tag);
679       M17n.DebugPrint ("Found {0} input methods\n", list.Count);
680       foreach (MDatabase mdb in list)
681         im_table[mdb.tag] = new MInputMethod (mdb.tag);
682     }
683
684     // Constructor
685     private MInputMethod (MDatabase.Tag tag)
686     {
687       this.tag = tag;
688     }
689
690     // Instance Properties
691     public MSymbol Language { get { return tag[1]; } }
692     public MSymbol Name { get { return tag[2]; } }
693     public MSymbol SubName { get { return tag[3]; } }
694
695     public bool Info (out MText description, out MText title,
696                       out Variable[] variables, out Command[] commands)
697     {
698       if ((load_status & LoadStatus.Header) != LoadStatus.Header
699           && ! load_header ())
700         {
701           description = null;
702           title = null;
703           variables = null;
704           commands = null;
705           return false;
706         }
707       description = this.description;
708       title = this.title;
709       variables = this.variables;
710       commands = this.commands;
711       return true;
712     }
713
714     public static MInputMethod Find (MSymbol language, MSymbol name)
715     {
716       return Find (language, name, MSymbol.nil);
717     }
718
719     public static MInputMethod Find (MSymbol language, MSymbol name,
720                                      MSymbol subname)
721     {
722       MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
723                                              name, subname);
724       MInputMethod im;
725
726       return (im_table.TryGetValue (tag, out im) ? im : null);
727     }
728
729     public bool Open ()
730     {
731       return ((load_status == LoadStatus.Full) || load_body ());
732     }
733
734     public static MInputMethod[] List ()
735     {
736       MInputMethod[] array = new MInputMethod[im_table.Count];
737       int i = 0;
738
739       foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
740         array[i++] = kv.Value;
741       return array;
742     }
743
744     private bool load_header ()
745     {
746       mdb = MDatabase.Find (tag);
747       if (mdb == null)
748         return false;
749       try {
750         MSymbol format = mdb.Format;
751
752         if (format == MSymbol.plist)
753           load ((MPlist) mdb.Load (Mmap), false);
754         else
755           {
756             XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list);
757             load (doc.DocumentElement, false);
758           }
759       } catch (Exception e) {
760         Console.WriteLine ("{0}\n", e);
761         load_status = LoadStatus.Error;
762         return false;
763       }
764       load_status |= LoadStatus.Header;
765       return true;
766     }
767
768     private bool load_body ()
769     {
770       local_domain = new MExpression.Domain (domain, null);
771       mdb = MDatabase.Find (tag);
772       if (mdb == null)
773         return false;
774       try {
775         object obj = mdb.Load ();
776         if (obj is MPlist)
777           load ((MPlist) obj, true);
778         else
779           load ((XmlDocument) obj, true);
780       } catch (Exception e) {
781         Console.WriteLine (e);
782         load_status = LoadStatus.Error;
783         return false;
784       }
785       load_status = LoadStatus.Full;
786       return true;
787     }
788
789     private void load (MPlist plist, bool full)
790     {
791       maps = new Dictionary<MSymbol, Map> ();
792       states = new MPlist ();
793
794       for (; ! plist.IsEmpty; plist = plist.next)
795         if (plist.IsPlist)
796           {
797             MPlist pl = plist.Plist;
798             if (pl.IsSymbol)
799               {
800                 MSymbol sym = pl.Symbol;
801
802                 pl = pl.next;
803                 if (sym == Mdescription)
804                   {
805                     description = parse_description (pl);
806                     if (description == null)
807                       description = new MText ("No description");
808                   }
809                 else if (sym == Mtitle)
810                   {
811                     if (pl.IsMText)
812                       title = pl.Text;
813                   }
814                 else if (sym == Mvariable)
815                   parse_variables (pl);
816                 else if (sym == Mcommand)
817                   parse_commands (pl);
818                 else if (full)
819                   {
820                     if (sym == Mmodule)
821                       parse_plugins (pl);
822                     else if (sym == Minclude)
823                       parse_include (pl);
824                     else if (sym == Mmacro)
825                       parse_macros (pl);
826                     else if (sym == Mmap)
827                       parse_maps (pl);
828                     else if (sym == Mstate)
829                       parse_states (pl);
830                   }
831               }
832           }
833       if (description == null)
834         description = (MText) "No description";
835       if (title == null)
836         title = new MText (tag[2].Name);
837       if (variables == null)
838         variables = new Variable[0];
839       if (commands == null)
840         commands = new Command[0];
841       if (! full)
842         return;
843       if (states.IsEmpty)
844         {
845           State state = new State ((MSymbol) "init");
846           plist = new MPlist ();
847           foreach (KeyValuePair<MSymbol, Map>kv in maps)
848             state.branches.Add (kv.Key, new MExpression (plist, local_domain));
849           states.Add (state.name, state);
850         }
851     }
852
853     private void load (XmlNode node, bool full)
854     {
855       bool skip_header = load_status == LoadStatus.Header;
856
857       maps = new Dictionary<MSymbol, Map> ();
858       states = new MPlist ();
859
860       if (node.NodeType == XmlNodeType.Document)
861         node = node.FirstChild;
862       while (node.NodeType != XmlNodeType.Element)
863         node = node.NextSibling;
864       for (node = node.FirstChild; node != null; node = node.NextSibling)
865         {
866           if (node.NodeType != XmlNodeType.Element)
867             continue;
868           if (! skip_header)
869             {
870               if (node.Name == "description")
871                 description = parse_description (node);
872               else if (node.Name == "title")
873                 title = parse_title (node);
874               else if (node.Name == "variable-list")
875                 parse_variables (node);
876               else if (node.Name == "command-list")
877                 parse_commands (node);
878             }
879           else if (full)
880             {
881               if (node.Name == "module-list")
882                 parse_plugins (node);
883               else if (node.Name == "macro-list")
884                 parse_macros (node);
885               else if (node.Name == "map-list")
886                 parse_maps (node);
887               else if (node.Name == "state-list")
888                 parse_states (node);
889             }
890         }
891       if (description == null)
892         description = (MText) "No description";
893       if (title == null)
894         title = new MText (tag[2].Name);
895       if (variables == null)
896         variables = new Variable[0];
897       if (commands == null)
898         commands = new Command[0];
899       if (! full)
900         return;
901       if (states.IsEmpty)
902         {
903           State state = new State ((MSymbol) "init");
904           MPlist plist = new MPlist ();
905           foreach (KeyValuePair<MSymbol, Map>kv in maps)
906             state.branches.Add (kv.Key, new MExpression (plist, local_domain));
907           states.Add (state.name, state);
908         }
909     }
910
911     private static void transform (MPlist plist)
912     {
913       for (; ! plist.IsEmpty; plist = plist.next)
914         {
915           if (plist.IsMText)
916             {
917               MPlist p = new MPlist ();
918               p.Add (MSymbol.symbol, Minsert);
919               p.Add (MSymbol.mtext, plist.Text);
920               plist.Set (MSymbol.plist, p);
921             }
922           else if (plist.IsInteger)
923             {
924               MPlist p = new MPlist ();
925               p.Add (MSymbol.symbol, Minsert);
926               p.Add (MSymbol.integer, plist.Integer);
927               plist.Set (MSymbol.plist, p);
928             }
929           else if (plist.IsPlist)
930             {
931               MPlist pl = plist.Plist;
932
933               if (pl.IsSymbol)
934                 {
935                   if (pl.Symbol == Madd)
936                     pl.Set (MSymbol.symbol, (MSymbol) "+=");
937                   else if (pl.Symbol == Msub)
938                     pl.Set (MSymbol.symbol, (MSymbol) "-=");
939                   else if (pl.Symbol == Mmul)
940                     pl.Set (MSymbol.symbol, (MSymbol) "*=");
941                   else if (pl.Symbol == Mdiv)
942                     pl.Set (MSymbol.symbol, (MSymbol) "/=");
943                   else if (pl.Symbol == Minsert)
944                     {
945                       // (insert (CANDIDATES ...))
946                       //   => (candidates CANDIDATES ...)
947                       if (pl.next.IsPlist)
948                         {
949                           pl.Set (MSymbol.symbol, Mcandidates);
950                           pl = pl.next;
951                           MPlist p = pl.Plist;
952                           pl.Set (p.key, p.val);
953                           for (p = p.next; ! p.IsEmpty; p = p.next);
954                           pl.Add (p.key, p.val);
955                         }
956                     }
957                   else if (pl.Symbol == Mif)
958                     {
959                       pl = pl.next;
960                       if (! pl.IsEmpty)
961                         transform (pl.next);
962                     }
963                   else if (pl.Symbol == Mcond)
964                     {
965                       for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
966                         if (pl.IsPlist)
967                           {
968                             MPlist p = pl.Plist;
969
970                             if (p.IsPlist)
971                               transform (p);
972                             else
973                               transform (p.next);
974                           }
975                     }
976                   else if (pl.Symbol == Mdelete
977                            || pl.Symbol == Mmove
978                            || pl.Symbol == Mmark)
979                     {
980                       pl = pl.next;
981                       if (pl.IsSymbol)
982                         {
983                           MSymbol sym = pl.Symbol;
984                           MPlist p = new MPlist ();
985                           p.Add (MSymbol.symbol, Mmarker);
986                           p.Add (MSymbol.symbol, sym);
987                           pl.Set (MSymbol.plist, p);
988                         }
989                     }
990                   else if (pl.Symbol == Mpushback)
991                     {
992                       pl = pl.next;
993                       if (pl.IsPlist)
994                         pl.Plist.Push (MSymbol.symbol, Mkeyseq);
995                     }
996                 }
997               else if (pl.IsMText)
998                 {
999                   // (CANDIDATES ...) => (candidates CANDIDATES ...)
1000                   pl.Push (MSymbol.symbol, Mcandidates);
1001                 }
1002             }
1003           else if (plist.IsSymbol)
1004             {
1005               MSymbol sym = plist.Symbol;
1006
1007               if (sym.Name.Length >= 3
1008                   && sym.Name[0] == '@'
1009                   && (sym.Name[1] == '-' || sym.Name[1] == '+'))
1010                 {
1011                   int pos = int.Parse (sym.Name.Substring (1));
1012                   MPlist p = new MPlist ();
1013
1014                   if (pos == 0)
1015                     {
1016                       p.Add (MSymbol.symbol, Msurrounding_text_p);
1017                     }
1018                   else
1019                     {
1020                       if (sym.Name[1] == '+')
1021                         pos--;
1022                       p.Add (MSymbol.symbol, Mchar_at);
1023                       p.Add (MSymbol.integer, pos);
1024                     }
1025                   plist.Set (MSymbol.plist, p);
1026                 }
1027             }
1028         }
1029     }
1030
1031     private static MText parse_description (MPlist plist)
1032     {
1033       if (plist.IsMText)
1034         return plist.Text;
1035       if (plist.IsPlist)
1036         {
1037           plist = plist.Plist;
1038           if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
1039               && plist.next.IsMText)
1040             return plist.next.Text;
1041         }
1042       return null;
1043     }
1044
1045     private static MText parse_description (XmlNode node)
1046     {
1047       if (node.HasChildNodes)
1048         node = node.FirstChild;
1049       return node.InnerText;
1050     }
1051
1052     private static MText parse_title (XmlNode node)
1053     {
1054       return node.InnerText;
1055     }
1056
1057     private void parse_variables (MPlist plist)
1058     {
1059       variables = new Variable[plist.Count];
1060
1061       for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1062         if (plist.IsPlist && plist.Plist.IsSymbol)
1063           variables[i++] = new Variable (plist.Plist);
1064     }
1065
1066     private void parse_variables (XmlNode node)
1067     {
1068       XmlNodeList node_list = node.ChildNodes;
1069
1070       variables = new Variable[node_list.Count];
1071       for (int i = 0; i < node_list.Count; i++)
1072         if (node_list[i].NodeType == XmlNodeType.Element)
1073           variables[i] = new Variable (node_list[i]);
1074     }
1075
1076     private void parse_commands (MPlist plist)
1077     {
1078       commands = new Command[plist.Count];
1079
1080       for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1081         if (plist.IsPlist && plist.Plist.IsSymbol)
1082           commands[i++] = new Command (plist.Plist);
1083     }
1084
1085     private void parse_commands (XmlNode node)
1086     {
1087       XmlNodeList node_list = node.ChildNodes;
1088
1089       commands = new Command[node_list.Count];
1090       for (int i = 0; i < node_list.Count; i++)
1091         {
1092           if (node_list[i].NodeType == XmlNodeType.Element)
1093             commands[i] = new Command (node_list[i]);
1094         }
1095     }
1096
1097     private void parse_plugins (MPlist plist)
1098     {
1099       plugins = new Dictionary<MSymbol, Plugin> ();
1100
1101       for (; ! plist.IsEmpty; plist = plist.Next)
1102         {
1103           MPlist p = plist.Plist;
1104           MSymbol sym = p.Symbol;
1105           Plugin plugin = new Plugin ();
1106
1107           plugin.name = sym.Name;
1108           plugin.methods = new MPlist ();
1109           for (p = p.next; ! p.IsEmpty; p = p.next)
1110             plugin.methods.Add (p.Symbol, null);
1111           plugins.Add (sym, plugin);
1112         }
1113     }
1114
1115     private void parse_plugins (XmlNode node)
1116     {
1117       plugins = new Dictionary<MSymbol, Plugin> ();
1118
1119       foreach (XmlNode n in node.ChildNodes)
1120         {
1121           Plugin plugin = new Plugin ();
1122           plugin.name = n.Attributes["id"].Value;
1123           plugin.methods = new MPlist ();
1124           foreach (XmlNode nn in n.ChildNodes)
1125             plugin.methods.Add ((MSymbol) nn.Attributes["id"].Value,
1126                                 null);
1127           plugins.Add (plugin.name, plugin);
1128         }
1129     }
1130
1131     private void parse_macros (XmlNode node)
1132     {
1133       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1134         if (nn.NodeType == XmlNodeType.Element
1135             && nn.Name == "xi:include")
1136           {
1137             XmlNode n = nn.FirstChild.FirstChild;
1138             MSymbol language = n.InnerText;
1139             n = n.NextSibling;
1140             MSymbol name = n.InnerText;
1141             n = n.NextSibling;
1142             MSymbol subname = (n != null ? n.InnerText : MSymbol.nil);
1143             n = n.ParentNode.NextSibling;
1144             MSymbol section = n.InnerText;
1145             n = n.NextSibling;
1146             MSymbol id = (n != null ? n.InnerText : MSymbol.nil);
1147
1148             MInputMethod im = MInputMethod.Find (language, name, subname);
1149             if (im == null || ! im.Open ())
1150               continue;
1151             if (id == MSymbol.nil)
1152               im.local_domain.CopyFunc (local_domain);
1153             else
1154               im.local_domain.CopyFunc (local_domain, id);
1155           }
1156       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1157         if (nn.NodeType == XmlNodeType.Element
1158             && nn.Name != "xi:include")
1159           local_domain.Defun ((MSymbol) node.GetAttribute ("id"));
1160       for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1161         if (nn.NodeType == XmlNodeType.Element
1162             && nn.Name != "xi:include")
1163           local_domain.Defun ((MSymbol) node.GetAttribute ("id"), null,
1164                               nn.FirstChild);
1165     }
1166
1167     private void parse_maps (XmlNode node)
1168     {
1169     }
1170
1171     private void parse_states (XmlNode node)
1172     {
1173     }
1174
1175     private void parse_include (MPlist plist)
1176     {
1177       if (! plist.IsPlist)
1178         return;
1179       MPlist p = plist.Plist;
1180       MSymbol language, name, subname;
1181       language = p.Symbol;
1182       p = p.next;
1183       if (! p.IsSymbol)
1184         name = subname = MSymbol.nil;
1185       else
1186         {
1187           name = p.Symbol;
1188           p = p.next;
1189           if (! p.IsSymbol)
1190             subname = MSymbol.nil;
1191           else
1192             subname = p.Symbol;
1193         }
1194
1195       MInputMethod im = MInputMethod.Find (language, name, subname);
1196       if (im == null)
1197         return;
1198       if (! im.Open ())
1199         return;
1200       plist = plist.next;
1201       if (! plist.IsSymbol)
1202         return;
1203       MSymbol target_type = plist.Symbol;
1204       plist = plist.next;
1205       MSymbol target_name = MSymbol.nil;
1206       if (plist.IsSymbol)
1207         target_name = plist.Symbol;
1208       if (target_type == Mmacro)
1209         {
1210           if (target_name == MSymbol.nil)
1211             im.local_domain.CopyFunc (local_domain);
1212           else
1213             im.local_domain.CopyFunc (local_domain, target_name);
1214         }
1215       else if (target_type == Mmap)
1216         {
1217           if (target_name == MSymbol.nil)
1218             {
1219               foreach (KeyValuePair<MSymbol, Map> kv in im.maps)
1220                 maps[kv.Key] = kv.Value;
1221             }
1222           else
1223             {
1224               Map map;
1225               if (im.maps.TryGetValue (target_name, out map))
1226                 maps[target_name] = map;
1227             }
1228         }
1229       else if (target_type == Mstate)
1230         {
1231           if (target_name == MSymbol.nil)
1232             {
1233               for (p = im.states; ! p.IsEmpty; p = p.next)
1234                 states.Add (p.key, p.val);
1235             }
1236           else
1237             {
1238               object state = im.states.Get (target_name);
1239               if (state != null)
1240                 states.Add (target_name, state);
1241             }
1242         }
1243     }
1244
1245     private void parse_macros (MPlist plist)
1246     {
1247       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1248         if (pl.IsPlist)
1249           {
1250             MPlist p = pl.Plist;
1251
1252             if (! p.IsSymbol)
1253               continue;
1254             local_domain.Defun (p.Symbol, null, null);
1255           }
1256       for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1257         if (pl.IsPlist)
1258           {
1259             MPlist p = pl.Plist;
1260
1261             if (! p.IsSymbol)
1262               continue;
1263             transform (p.next);
1264             local_domain.Defun (p.Symbol, null, p.next);
1265           }
1266     }
1267
1268     private void parse_maps (MPlist plist)
1269     {
1270       for (; ! plist.IsEmpty; plist = plist.next)
1271         if (plist.IsPlist)
1272           {
1273             MPlist pl = plist.Plist;
1274           
1275             if (! pl.IsSymbol)
1276               continue;
1277             Map map = new Map ();
1278             map.name = pl.Symbol;
1279             maps[map.name] = map;
1280             for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1281               {
1282                 if (! pl.IsPlist)
1283                   continue;
1284                 MPlist p = pl.Plist;
1285                 KeySeq keys;
1286                 if (p.IsMText)
1287                   keys = new KeySeq (p.Text);
1288                 else if (p.IsPlist)
1289                   keys = new KeySeq (p.Plist);
1290                 else
1291                   continue;
1292                 p = p.next;
1293                 if (p.IsEmpty)
1294                   continue;
1295                 transform (p);
1296                 MExpression expr = new MExpression (p, local_domain);
1297                 map.Add (keys, 0, expr);
1298               }
1299           }
1300     }
1301
1302     private void parse_states (MPlist plist)
1303     {
1304       for (; ! plist.IsEmpty; plist = plist.next)
1305         if (plist.IsPlist)
1306           {
1307             MPlist pl = plist.Plist;
1308             MText title = null;
1309           
1310             if (pl.IsMText)
1311               {
1312                 title = pl.Text;
1313                 pl = pl.next;
1314               }
1315             if (! pl.IsSymbol)
1316               continue;
1317
1318             State state = new State (pl.Symbol);
1319             state.title = title;
1320             if (states == null)
1321               states = new MPlist ();
1322             states.Add (state.name, state);
1323             for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1324               {
1325                 if (! pl.IsPlist)
1326                   continue;
1327                 MPlist p = pl.Plist;
1328                 if (! p.IsSymbol)
1329                   continue;
1330                 MSymbol map_name = p.Symbol;
1331                 p = p.next;
1332                 transform (p);
1333                 state.branches.Add (map_name,
1334                                     new MExpression (p, local_domain));
1335               }
1336           }
1337     }
1338
1339     private static object insert (MExpression[] args, MExpression.Domain domain)
1340     {
1341       ((MInputContext) domain.context).insert (args[0].Val);
1342
1343       return true;
1344     }
1345
1346     private static object insert_candidates (MExpression[] args,
1347                                              MExpression.Domain domain)
1348     {
1349       ((MInputContext) domain.context).insert_candidates ((MPlist) args[0].Val);
1350
1351       return true;
1352     }
1353
1354     private static object marker (MExpression[] args, MExpression.Domain domain)
1355     {
1356       MSymbol sym = (MSymbol) args[0].Args[0].Val;
1357
1358       return ((MInputContext) domain.context).marker (sym);
1359     }
1360
1361     private static object char_at (MExpression[] args,
1362                                    MExpression.Domain domain)
1363     {
1364       return ((MInputContext) domain.context).char_at ((int) args[0].Val);
1365     }
1366
1367     private static object delete (MExpression[] args, MExpression.Domain domain)
1368     {
1369       ((MInputContext) domain.context).delete ((int) args[0].Val);
1370       return true;
1371     }
1372
1373     private static object select (MExpression[] args, MExpression.Domain domain)
1374     {
1375       MInputContext ic = (MInputContext) domain.context;
1376       object val = args[0].Val;
1377
1378       if (val is int)
1379         ic.select ((int) val);
1380       else
1381         ic.select ((MSymbol) val);
1382       return true;
1383     }
1384
1385     private static object show (MExpression[] args, MExpression.Domain domain)
1386     {
1387       ((MInputContext) domain.context).show ();
1388
1389       return true;
1390     }
1391
1392     private static object hide (MExpression[] args, MExpression.Domain domain)
1393     {
1394       ((MInputContext) domain.context).hide ();
1395
1396       return true;
1397     }
1398
1399     private static object move (MExpression[] args, MExpression.Domain domain)
1400     {
1401       ((MInputContext) domain.context).move ((int) args[0].Val);
1402
1403       return true;
1404     }
1405
1406     private static object mark (MExpression[] args, MExpression.Domain domain)
1407     {
1408       MSymbol sym = (MSymbol) args[0].Val;
1409
1410       ((MInputContext) domain.context).mark (sym);
1411       return true;
1412     }
1413
1414     private static object keyseq (MExpression[] args, MExpression.Domain domain)
1415     {
1416       MPlist p = new MPlist ();
1417
1418       for (int i = 0; i < args.Length; i++)
1419         p.Add (MSymbol.symbol, (MSymbol) args[i].Val);
1420       return new KeySeq (p);
1421     }
1422
1423     private static object pushback (MExpression[] args,
1424                                     MExpression.Domain domain)
1425     {
1426       MInputContext ic = (MInputContext) domain.context;
1427       object val = args[0].Val;
1428
1429       if (val is int)
1430         ic.pushback ((int) val);
1431       else if (val is MText)
1432         ic.pushback (new KeySeq ((MText) val));
1433       else if (val is KeySeq)
1434         ic.pushback ((KeySeq) val);
1435       else
1436         throw new Exception ("Invalid keyseq: " + val);
1437       return true;
1438     }
1439
1440     private static object pop (MExpression[] args, MExpression.Domain domain)
1441     {
1442       ((MInputContext) domain.context).pop ();
1443       return true;
1444     }
1445
1446     private static object undo (MExpression[] args, MExpression.Domain domain)
1447     {
1448       int n = args.Length == 0 ? -2 : (int) args[0].Val;
1449       ((MInputContext) domain.context).undo (n);
1450       return true;
1451     }
1452
1453     private static object commit (MExpression[] args, MExpression.Domain domain)
1454     {
1455       ((MInputContext) domain.context).commit ();
1456       return true;
1457     }
1458
1459     private static object unhandle (MExpression[] args,
1460                                     MExpression.Domain domain)
1461     {
1462       ((MInputContext) domain.context).commit ();
1463       return false;
1464     }
1465
1466     private static object shift (MExpression[] args, MExpression.Domain domain)
1467     {
1468       MSymbol sym = (MSymbol) args[0].Args[0].Val;
1469
1470       ((MInputContext) domain.context).shift (sym);
1471       return true;
1472     }
1473
1474     private static object call (MExpression[] args, MExpression.Domain domain)
1475     {
1476       MSymbol module = (MSymbol) args[0].Args[0].Val;
1477       MSymbol method = (MSymbol) args[1].Args[0].Val;
1478       MPlist arglist = new MPlist ();
1479
1480       for (int i = 2; i < args.Length; i++)
1481         {
1482           object val = args[i].Eval (domain);
1483
1484           if (val is int)
1485             arglist.Add (MSymbol.integer, val);
1486           else if (val is MSymbol)
1487             arglist.Add (MSymbol.symbol, val);
1488           else if (val is MText)
1489             arglist.Add (MSymbol.mtext, val);
1490           else if (val is MPlist)
1491             arglist.Add (MSymbol.plist, val);
1492           else
1493             throw new Exception ("Invalid argument to {0}/{1}: {2}",
1494                                  module, method, val);
1495         }
1496       return ((MInputContext) domain.context).call (module, method, arglist);
1497     }
1498
1499     public override string ToString ()
1500     {
1501       string str = (String.Format ("({0} (title \"{1}\")", tag, title));
1502       if (commands != null)
1503         {
1504           str += " (commands";
1505           foreach (Command cmd in commands)
1506             str += " " + cmd;
1507           str += ")";
1508         }
1509       if (variables != null)
1510         {
1511           str += " (variables";
1512           foreach (Variable var in variables)
1513             str += " " + var;
1514           str += ")";
1515         }
1516       if (plugins != null)
1517         {
1518           str += " (modules";
1519           foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
1520             str += " " + kv.Value;
1521           str += ")";
1522         }
1523       str += " (maps";
1524       foreach (KeyValuePair<MSymbol, Map> kv in maps)
1525         str += " " + kv.Value;
1526       str += ") (states";
1527       foreach (MPlist p in states)
1528         str += " " + p.val;
1529       return str + "))";
1530     }
1531   }
1532
1533   public class MInputContext
1534   {
1535     internal static MSymbol Mcandidates_group_size = "candidates-group-size";
1536     private static MSymbol Mat_less_than = "@<";
1537     private static MSymbol Mat_greater_than = "@>";
1538     private static MSymbol Mat_minus = "@-";
1539     private static MSymbol Mat_plus = "@+";
1540     private static MSymbol Mat_open_square_bracket = "@[";
1541     private static MSymbol Mat_close_square_bracket = "@]";
1542
1543     public MInputMethod im;
1544     private MText produced;
1545     private bool active;
1546     private MText status;
1547     private bool status_changed;
1548     private MText preedit;
1549     private bool preedit_changed;
1550     private int cursor_pos;
1551     private bool cursor_pos_changed;
1552     private Candidates candidates;
1553     private MPlist candidate_group;
1554     private int candidate_index;
1555     private int candidate_from, candidate_to;
1556     private bool candidate_show;
1557     private bool candidate_changed;
1558
1559     private Stack<MInputMethod.State> states;
1560     internal MInputMethod.KeySeq keys;
1561     private int key_head;
1562     private int state_key_head;
1563     private MPlist state_boundary;
1564     private int commit_key_head;
1565     private MText state_preedit;
1566     private int state_pos;
1567     internal MPlist markers = new MPlist ();
1568     private MPlist vars;
1569     private MPlist vars_saved;
1570     internal MText preceding_text = new MText ();
1571     internal MText following_text = new MText ();
1572     private bool key_unhandled;
1573
1574     internal MExpression.Domain domain;
1575
1576     public MInputContext (MInputMethod im)
1577     {
1578       this.im = im;
1579       domain = new MExpression.Domain (im.local_domain, this);
1580       states = new Stack<MInputMethod.State> ();
1581       states.Push ((MInputMethod.State) im.states.val);
1582       keys = new MInputMethod.KeySeq ();
1583     }
1584
1585     private void adjust_markers (int from, int to, object inserted)
1586     {
1587       int ins = (inserted == null ? 0
1588                  : inserted is int ? 1
1589                  : ((MText) inserted).Length);
1590       int diff = ins - (to - from);
1591
1592       for (MPlist plist = markers; ! plist.IsEmpty; plist = plist.next)
1593         {
1594           int pos = plist.Integer;
1595           if (pos > from)
1596             {
1597               if (pos >= to)
1598                 plist.val = pos + diff;
1599               else
1600                 plist.val = from;
1601             }
1602         }
1603       if (cursor_pos >= to)
1604         cursor_pos += diff;
1605       else if (cursor_pos > from)
1606         cursor_pos = from;
1607     }
1608
1609     private void preedit_replace (int from, int to, int c)
1610     {
1611       preedit.Del (from, to);
1612       preedit.Ins (from, c);
1613       adjust_markers (from, to, c);
1614     }
1615
1616     private void preedit_replace (int from, int to, MText mt)
1617     {
1618       preedit[from, to] = mt;
1619       adjust_markers (from, to, mt);
1620     }
1621
1622     internal void insert (object arg)
1623     {
1624       if (arg is int)
1625         preedit_replace (cursor_pos, cursor_pos, (int) arg);
1626       else
1627         preedit_replace (cursor_pos, cursor_pos, (MText) arg);
1628       preedit_changed = true;
1629       cursor_pos_changed = true;
1630     }
1631
1632     private class Candidates
1633     {
1634       private class Block
1635       {
1636         public int Index;
1637         public object Data;
1638
1639         public Block (int index, MPlist plist)
1640         {
1641           Index = index;
1642           if (plist.IsMText)
1643             Data = plist.Text;
1644           else
1645             Data = plist.Plist;
1646         }
1647
1648         public int Count
1649         {
1650           get { return (Data is MText
1651                         ? ((MText) Data).Length
1652                         : ((MPlist) Data).Count); }
1653         }
1654
1655         public object this[int i]
1656         {
1657           get {
1658             if (Data is MText) return ((MText) Data)[i];
1659             return  ((MPlist) Data)[i];
1660           }
1661         }
1662       }
1663
1664       private Block[] blocks;
1665       private int row = 0;
1666       private int index = 0;
1667       public object[] group;
1668
1669       private bool IsFixed { get { return group != null; } }
1670       private int Total {
1671         get {
1672           Block last = blocks[blocks.Length - 1];
1673           return last.Index + last.Count; }
1674       }
1675
1676       public int Column {
1677         get { return (IsFixed ? index % group.Length
1678                       : index - blocks[row].Index); }
1679       }
1680
1681       public object Group {
1682         get { return (IsFixed ? group : blocks[row].Data); }
1683       }
1684
1685       public int GroupLength
1686       {
1687         get {
1688           if (IsFixed)
1689             {
1690               int nitems = group.Length;
1691               int start = index - (index % nitems);
1692               int total = Total;
1693               return (start + nitems <= total ? nitems : total - start);
1694             }
1695           return blocks[row].Count;
1696         }
1697       }
1698
1699       public object Current {
1700         get {
1701           return (IsFixed ? group[index % group.Length]
1702                   : blocks[row][index - blocks[row].Index]);
1703         }
1704       }
1705
1706       public Candidates (MPlist list, int column)
1707       {
1708         int nblocks = list.Count;
1709
1710         blocks = new Block[nblocks];
1711         for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
1712           start += (blocks[i] = new Block (index, list)).Count;
1713         if (column > 0)
1714           group = new object[column];
1715       }
1716
1717       public static void Detach (MInputContext ic)
1718       {
1719         ic.preedit.PopProp (0, ic.preedit.Length, MInputMethod.Mcandidates);
1720         ic.candidates = null;
1721         ic.preedit_changed = true;
1722         ic.cursor_pos_changed = true;
1723         ic.candidate_changed = true;
1724       }
1725
1726       // Fill the array "group" by candidates stating from INDEX.
1727       // INDEX must be a multiple of "column".  Set NTIMES to the
1728       // number of valid candidates in "group".  Update "block" if
1729       // necessary.  Return "group".
1730
1731       private int fill_group (int start)
1732       {
1733         int nitems = group.Length;
1734         int r = row;
1735         Block b = blocks[r];
1736
1737         if (start < b.Index)
1738           while (start < b.Index)
1739             b = blocks[--r];
1740         else
1741           while (start >= b.Index + b.Count)
1742             b = blocks[++r];
1743         row = r;
1744
1745         int count = b.Count;
1746         start -= b.Index;
1747         for (int i = 0; i < nitems; i++, start++)
1748           {
1749             if (start >= count)
1750               {
1751                 r++;
1752                 if (r == blocks.Length)
1753                   return i;
1754                 b = blocks[r];
1755                 count = b.Count;
1756                 start = 0;
1757               }
1758             group[i] = b[start];
1759           }
1760         return nitems;
1761       }
1762
1763       // Update "row" to what contains the first candidate of
1764       // the previous candidate-group, update "current_index", and
1765       // update "group" if necessary.  Return the previous
1766       // candidate-group.  Set NITEMS to the number of valid
1767       // candidates contained in that group.
1768
1769       public int PrevGroup ()
1770       {
1771         int nitems;
1772         int col = Column;
1773
1774         if (IsFixed)
1775           {
1776             nitems = group.Length;
1777             if ((index -= col + nitems) < 0)
1778               index = (Total / nitems) * nitems;
1779             nitems = fill_group (index);
1780           }
1781         else
1782           {
1783             row = row > 0 ? row-- : blocks.Length - 1;
1784             nitems = blocks[row].Count;
1785             index = blocks[row].Index;
1786           }
1787         index += col < nitems ? col : nitems - 1;
1788         return nitems;
1789       }
1790
1791       public int NextGroup ()
1792       {
1793         int nitems;
1794         int col = Column;
1795
1796         if (IsFixed)
1797           {
1798             nitems = group.Length;
1799             if ((index += nitems - col) >= Total)
1800               index = 0;
1801             nitems = fill_group (index);
1802           }
1803         else
1804           {
1805             row = row < blocks.Length - 1 ? row + 1 : 0;
1806             nitems = blocks[row].Count;
1807             index = blocks[row].Count;
1808           }
1809         index += col < nitems ? col : nitems - 1;
1810         return nitems;
1811       }
1812
1813       public void Prev ()
1814       {
1815         int col = Column;
1816
1817         if (col == 0)
1818           {
1819             int nitems = PrevGroup ();
1820             index += col < nitems - 1 ? col : nitems - 1;
1821           }
1822         else
1823           index--;
1824       }
1825
1826       public void Next ()
1827       {
1828         int col = Column;
1829         int nitems = GroupLength;
1830
1831         if (col == nitems - 1)
1832           {
1833             nitems = NextGroup ();
1834             index -= Column;
1835           }
1836         else
1837           index++;
1838       }
1839
1840       public void First ()
1841       {
1842         index -= Column;
1843       }
1844
1845       public void Last ()
1846       {
1847         index += GroupLength - (Column + 1);
1848       }
1849
1850       public void Select (int col)
1851       {
1852         int maxcol = GroupLength - 1;
1853         if (col > maxcol)
1854           col = maxcol;
1855         index = index - Column + col;
1856       }
1857     }
1858
1859     private void update_candidate ()
1860     {
1861       object candidate = candidates.Current;
1862
1863       if (candidate is MText)
1864         {
1865           preedit_replace (candidate_from, candidate_to, (MText) candidate);
1866           candidate_to = candidate_from + ((MText) candidate).Length;
1867         }
1868       else
1869         {
1870           preedit_replace (candidate_from, candidate_to, (int) candidate);
1871           candidate_to = candidate_from + 1;
1872         }
1873       preedit.PushProp (candidate_from, candidate_to,
1874                         MInputMethod.Mcandidates, this);
1875       cursor_pos = candidate_from;
1876       preedit_changed = true;
1877       cursor_pos_changed = true;
1878       candidate_changed = true;
1879     }
1880
1881     internal void insert_candidates (MPlist list)
1882     {
1883       int column = 0;
1884
1885       if (domain.IsBound (Mcandidates_group_size))
1886         {
1887           object val = domain.GetValue (Mcandidates_group_size);
1888           if (val is int)
1889             column = (int) val;
1890         }
1891       candidates = new Candidates (list, column);
1892       candidate_from = candidate_to = cursor_pos;
1893       update_candidate ();
1894     }
1895
1896     internal void select (int n)
1897     {
1898       if (candidates != null)
1899         {
1900           candidates.Select (n);
1901           update_candidate ();
1902         }
1903     }
1904
1905     internal void select (MSymbol sym)
1906     {
1907       if (candidates != null)
1908         {
1909           if (sym == Mat_less_than)
1910             candidates.First ();
1911           else if (sym == Mat_greater_than)
1912             candidates.Last ();
1913           else if (sym == Mat_minus)
1914             candidates.Prev ();
1915           else if (sym == Mat_plus)
1916             candidates.Next ();
1917           else if (sym == Mat_open_square_bracket)
1918             candidates.PrevGroup ();
1919           else if (sym == Mat_close_square_bracket)
1920             candidates.NextGroup ();
1921         }
1922     }
1923
1924     internal int marker (MSymbol sym)
1925     {
1926       int pos = cursor_pos;
1927
1928       if (sym.Name.Length == 2 && sym.Name[0] == '@')
1929         {
1930           switch (sym.Name[0])
1931             {
1932             case '<': pos = 0; break;
1933             case '>': pos = preedit.Length; break;
1934             case '-': pos = cursor_pos - 1; break;
1935             case '+': pos = cursor_pos + 1; break;
1936             case '[':
1937               if (pos > 0)
1938                 {
1939                   int to;
1940                   preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
1941                                     out pos, out to);
1942                 }
1943               else
1944                 pos = 0;
1945               break;
1946             case ']':
1947               if (cursor_pos < preedit.Length - 1)
1948                 {
1949                   int from;
1950                   preedit.FindProp (MInputMethod.Mcandidates, pos,
1951                                     out from, out pos);
1952                 }
1953               else
1954                 pos = preedit.Length;
1955               break;
1956             default:
1957               if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
1958                 pos = sym.Name[0];
1959               break;
1960             }
1961         }
1962       else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
1963         {
1964           pos = int.Parse (sym.Name.Substring (2));
1965         }
1966       else
1967         {
1968           object val = markers.Get (sym);
1969
1970           if (val is int)
1971             pos = (int) val;
1972         }
1973       return pos;
1974     }
1975
1976     internal int char_at (int pos)
1977     {
1978       int c;
1979
1980       pos += cursor_pos;
1981       if (pos < 0)
1982         {
1983           if (preceding_text.Length < -pos)
1984             {
1985               MPlist plist = new MPlist ();
1986               plist.Push (MSymbol.integer, pos);
1987               if (MInputMethod.GetSurroundingText != null
1988                   && MInputMethod.GetSurroundingText (this, plist)
1989                   && plist.IsMText
1990                   && preceding_text.Length < plist.Text.Length)
1991                 preceding_text = plist.Text;
1992             }
1993           c = (-pos < preceding_text.Length
1994                ? preceding_text[preceding_text.Length + pos] : -1);
1995         }
1996       else if (pos >= 0 && pos < preedit.Length)
1997         c = preedit[pos];
1998       else
1999         {
2000           pos -= preedit.Length;
2001           if (pos >= following_text.Length)
2002             {
2003               MPlist plist = new MPlist ();
2004               plist.Push (MSymbol.integer, pos + 1);
2005               if (MInputMethod.GetSurroundingText != null
2006                   && MInputMethod.GetSurroundingText (this, plist)
2007                   && plist.IsMText
2008                   && following_text.Length < plist.Text.Length)
2009                 following_text = plist.Text;
2010             }
2011           c = (pos < following_text.Length ? following_text[pos] : -1);
2012         }
2013       return c;
2014     }
2015
2016     internal void delete (int pos)
2017     {
2018       if (pos < cursor_pos)
2019         preedit_replace (pos, cursor_pos, null);
2020       else
2021         preedit_replace (cursor_pos, pos, null);
2022       preedit_changed = true;
2023       cursor_pos_changed = true;
2024     }
2025
2026     internal void show ()
2027     {
2028       candidate_show = true;
2029       candidate_changed = true;
2030     }
2031
2032     internal void hide ()
2033     {
2034       candidate_show = false;
2035       candidate_changed = true;
2036     }
2037
2038     internal void move (int pos)
2039     {
2040       if (pos < 0)
2041         pos = 0;
2042       else if (pos > preedit.Length)
2043         pos = preedit.Length;
2044       if (pos != cursor_pos)
2045         {
2046           cursor_pos = pos;
2047           preedit_changed = true;
2048         }
2049     }
2050
2051     internal void mark (MSymbol sym)
2052     {
2053       MPlist slot = markers.Find (sym);
2054
2055       if (slot == null)
2056         markers.Push (sym, cursor_pos);
2057       else
2058         slot.val = cursor_pos;
2059     }
2060
2061     internal void pushback (int n)
2062     {
2063       if (n > 0)
2064         {
2065           key_head -= n;
2066           if (key_head < 0)
2067             key_head = 0;
2068         }
2069       else if (n == 0)
2070         key_head = 0;
2071       else
2072         {
2073           key_head = - n;
2074           if (key_head > keys.Count)
2075             key_head = keys.Count;
2076         }
2077     }
2078
2079     internal void pushback (MInputMethod.KeySeq keyseq)
2080     {
2081       if (key_head > 0)
2082         key_head--;
2083       if (key_head < keys.Count)
2084         keys.RemoveRange (key_head, keys.Count - key_head);
2085       for (int i = 0; i < keyseq.Count; i++)
2086         keys.Add (keyseq[i]);
2087     }
2088
2089     internal void pop ()
2090     {
2091       if (key_head < keys.Count)
2092         keys.RemoveRange (key_head, 1);
2093     }
2094
2095     internal void undo (int n)
2096     {
2097       if (n < 0)
2098         keys.RemoveRange (keys.Count + n, - n);
2099       else
2100         keys.RemoveRange (n, keys.Count  - n);
2101       reset ();
2102     }
2103
2104     internal void commit ()
2105     {
2106       produced.Cat (preedit);
2107       preedit.Del ();
2108       preedit_changed = true;
2109     }
2110
2111     internal void shift (MSymbol sym)
2112     {
2113       MInputMethod.State state;
2114
2115       if (sym == MSymbol.t)
2116         {
2117           if (states.Count > 1)
2118             state = states.Pop ();
2119           else
2120             state = states.Peek ();
2121         }
2122       else
2123         {
2124           state = (MInputMethod.State) im.states.Get (sym);
2125           if (state == null)
2126             throw new Exception ("Unknown state: " + state.name);
2127         }
2128       if (state == null)
2129         state = states.Pop ();
2130       if (state == (MInputMethod.State) im.states.val)
2131         {
2132           commit ();
2133           reset ();
2134         }
2135       else
2136         {
2137           state_key_head = key_head;
2138           state_pos = cursor_pos;
2139           state_preedit = preedit.Dup ();
2140           if (state != states.Peek ())
2141             {
2142               states.Push (state);
2143               state_boundary = domain.SetBoundary ();
2144               status = state.title;
2145               if (status == null)
2146                 status = im.title;
2147               status_changed = true;
2148               MExpression on_entry
2149                 = (MExpression) state.branches.Get (MSymbol.t);
2150               if (on_entry != null)
2151                 on_entry.Eval (domain);
2152             }
2153         }
2154     }
2155
2156     internal bool call (MSymbol module, MSymbol method, MPlist arglist)
2157     {
2158       MInputMethod.Plugin plugin;
2159
2160       if (! im.plugins.TryGetValue (module, out plugin))
2161         return false;
2162       if (plugin.assembly == null)
2163         {
2164           Assembly assembly;
2165
2166           try {
2167             assembly = Assembly.LoadFrom (module.Name + ".dll");
2168           } catch {
2169             return false;
2170           }
2171           Type t = assembly.GetType ("Plugin");
2172           for (MPlist p = plugin.methods; ! p.IsEmpty; p = p.next)
2173             p.Set (p.key, t.GetMethod (p.key.Name));
2174         }
2175
2176       MethodInfo method_info = (MethodInfo) plugin.methods.Get (method);
2177       if (method_info == null)
2178         return false;
2179       object[] method_arg = new object[1];
2180       method_arg[0] = arglist;
2181       bool result = (bool) method_info.Invoke (null, method_arg);
2182       if (! result)
2183         return false;
2184       if (! arglist.IsEmpty)
2185         (new MExpression (arglist, domain)).Eval (domain);
2186       return true;
2187     }
2188
2189     internal void reset ()
2190     {
2191       preedit.Del ();
2192       state_preedit.Del ();
2193       produced.Del ();
2194       markers.Clear ();
2195       cursor_pos = 0;
2196       key_head = commit_key_head = 0;
2197       states.Clear ();
2198       states.Push ((MInputMethod.State) im.states.Val);
2199       state_key_head = 0;
2200       state_pos = 0;
2201     }
2202
2203     internal object GetCandidates (out int column)
2204     {
2205       column = 0;
2206       if (cursor_pos == 0)
2207         return null;
2208       Candidates candidates
2209         = (Candidates) preedit.GetProp (cursor_pos - 1,
2210                                         MInputMethod.Mcandidates);
2211       if (candidates == null)
2212         return null;
2213       column = candidates.Column;
2214       return candidates.Current;
2215     }
2216
2217     internal void HandleKey ()
2218     {
2219       MInputMethod.State state = states.Peek ();
2220
2221       
2222     }
2223   }
2224 }