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