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