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