2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Reflection;
14 public class MInputMethod
17 public delegate bool Callback (MInputContext ic, MPlist args);
20 public static Callback PreeditStart, PreeditDone, PreeditDraw;
21 public static Callback StatusStart, StatusDone, StatusDraw;
22 public static Callback CandidateStart, CandidateDone, CandidateDraw;
23 public static Callback SetSpot;
24 public static Callback Toggle;
25 public static Callback Reset;
26 public static Callback GetSurroundingText;
27 public static Callback DeleteSurroundingText;
29 internal static MExpression.Domain domain = new MExpression.Domain (null);
30 private static MSymbol Minput_method = "input-method";
31 private static MSymbol Mdescription = "description";
32 private static MSymbol Mvariable = "variable";
33 private static MSymbol Mcommand = "command";
34 private static MSymbol Mmodule = "module";
35 private static MSymbol Mmodule_list = "module-list";
36 private static MSymbol Mtitle = "title";
37 private static MSymbol Minclude = "include";
38 private static MSymbol Mmacro = "macro";
39 private static MSymbol Mmacro_list = "macro-list";
40 private static MSymbol Mmap = "map";
41 private static MSymbol Mmap_list = "map-list";
42 private static MSymbol Mstate = "state";
43 private static MSymbol Mstate_list = "state-list";
44 internal static MSymbol Mcandidates = "candidates";
45 private static MSymbol Minsert = "insert";
46 private static MSymbol Mdelete = "delete";
47 private static MSymbol Mmove = "move";
48 private static MSymbol Mmark = "mark";
49 private static MSymbol Mmarker = "marker";
50 private static MSymbol Madd = "add";
51 private static MSymbol Msub = "sub";
52 private static MSymbol Mmul = "mul";
53 private static MSymbol Mdiv = "div";
54 private static MSymbol Mif = "if";
55 private static MSymbol Mcond = "cond";
56 private static MSymbol Mchar_at = "char-at";
57 private static MSymbol Msurrounding_text_p = "surrounding-text-p";
58 private static MSymbol Mpushback = "pushback";
59 private static MSymbol Mkeyseq = "keyseq";
61 private static Dictionary<MDatabase.Tag, MInputMethod> im_table
62 = new Dictionary<MDatabase.Tag, MInputMethod> ();
65 private class Exception : System.Exception
69 public Exception (string msg) : base (msg)
74 public Exception (string fmt, params object[] args)
75 : base (String.Format (fmt, args))
80 public Exception (string msg, bool error) : base (msg)
87 private enum LoadStatus
97 public enum KeyModifier
100 Shift_L = 0x00400000,
101 Shift_R = 0x00800000,
103 Control_L = 0x01000000,
104 Control_R = 0x02000000,
105 Control = 0x03000000,
120 private static Dictionary<string, uint> keysyms
121 = new Dictionary<string, uint> ();
122 private static Dictionary<string, KeyModifier> keymodifiers
123 = new Dictionary<string, KeyModifier> ();
124 private static uint keysym_base = 0x200000;
125 private static uint char_mask = ~((uint) KeyModifier.All);
129 keysyms["bs"] = keysyms["backspace"] = 0x08;
130 keysyms["tab"] = 0x09;
131 keysyms["lf"] = keysyms["linefeed"] = 0x10;
132 keysyms["cr"] = keysyms["return"] = keysyms["enter"] = 0x13;
133 keysyms["esc"] = keysyms["escape"] = 0x1B;
134 keysyms["spc"] = keysyms["space"] = 0x20;
135 keysyms["del"] = keysyms["delete"] = 0x7F;
136 keymodifiers["shift-l"] = KeyModifier.Shift_L;
137 keymodifiers["shift-r"] = KeyModifier.Shift_R;
138 keymodifiers["shift"] = KeyModifier.Shift;
139 keymodifiers["control-l"] = KeyModifier.Control_L;
140 keymodifiers["control-r"] = KeyModifier.Control_R;
141 keymodifiers["control"] = KeyModifier.Control;
142 keymodifiers["alt-l"] = KeyModifier.Alt_L;
143 keymodifiers["alt-r"] = KeyModifier.Alt_R;
144 keymodifiers["alt"] = KeyModifier.Alt;
145 keymodifiers["altgr"] = KeyModifier.AltGr;
146 keymodifiers["super"] = KeyModifier.Super;
147 keymodifiers["hyper"] = KeyModifier.Hyper;
150 private static uint decode_keysym (MSymbol keysym)
153 string name = keysym.Name;
155 if (name.Length == 1)
157 name = name.ToLower ();
158 if (! keysyms.TryGetValue (name, out key))
159 keysyms[name] = key = keysym_base++;
163 private static uint combine_modifiers (uint c, KeyModifier modifiers)
165 if (c < 0x7F && c != 0x20)
167 if ((modifiers & KeyModifier.Shift) != KeyModifier.None
168 && Char.IsLower ((char) c))
170 modifiers &= ~KeyModifier.Shift;
171 c = Char.ToUpper ((char) c);
173 if ((modifiers & KeyModifier.Control) != KeyModifier.None)
175 modifiers &= ~KeyModifier.Control;
179 return c | (uint) modifiers;
187 public Key (uint c, KeyModifier modifiers)
189 key = combine_modifiers (c, modifiers);
192 public Key (MSymbol keysym, KeyModifier modifiers)
194 key = combine_modifiers (decode_keysym (keysym), modifiers);
197 public Key (MSymbol keysym)
199 string str = keysym.Name;
200 int len = str.Length;
202 KeyModifier modifiers = KeyModifier.None;
204 for (i = 0; i + 2 < len && str[i + 1] == '-'; i += 2)
207 modifiers |= KeyModifier.Shift;
208 else if (str[i] == 'C')
209 modifiers |= KeyModifier.Control;
210 else if (str[i] == 'A')
211 modifiers |= KeyModifier.Alt;
212 else if (str[i] == 'G')
213 modifiers |= KeyModifier.AltGr;
214 else if (str[i] == 's')
215 modifiers |= KeyModifier.Super;
216 else if (str[i] == 'H')
217 modifiers |= KeyModifier.Hyper;
220 key = combine_modifiers (str[i], modifiers);
222 key = combine_modifiers (decode_keysym (keysym), modifiers);
225 public Key (MPlist plist)
227 KeyModifier modifiers = KeyModifier.None;
230 for (p = plist; ! p.IsEmpty; p = p.next)
234 if (! p.next.IsEmpty)
235 throw new Exception ("Invalid Key: " + plist);
238 else if (! p.IsSymbol)
239 throw new Exception ("Invalid Key: " + plist);
242 string name = p.Symbol.Name.ToLower ();
245 if (! keymodifiers.TryGetValue (name, out m))
250 if (p.IsEmpty || ! p.next.IsEmpty)
251 throw new Exception ("Invalid Key: " + plist);
253 key = combine_modifiers ((uint) p.Integer, modifiers);
255 key = combine_modifiers (decode_keysym (p.Symbol), modifiers);
258 public bool HasModifier
260 get { return ((key & (uint) KeyModifier.All) != 0); }
263 public bool Match (Key k)
267 if ((k.key & char_mask) != (key & char_mask))
269 KeyModifier m1 = ((KeyModifier) key) & KeyModifier.All;
270 KeyModifier m2 = ((KeyModifier) k.key) & KeyModifier.All;
271 return (((m1 & KeyModifier.Shift) == (m2 & KeyModifier.Shift)
272 || ((m1 & KeyModifier.Shift) == KeyModifier.Shift
273 && (m2 & KeyModifier.Shift) != KeyModifier.None))
274 && ((m1 & KeyModifier.Control) == (m2 & KeyModifier.Control)
275 || ((m1 & KeyModifier.Control) == KeyModifier.Control
276 && (m2 & KeyModifier.Control) != KeyModifier.None))
277 && ((m1 & KeyModifier.Alt) == (m2 & KeyModifier.Alt)
278 || ((m1 & KeyModifier.Alt) == KeyModifier.Alt
279 && (m2 & KeyModifier.Alt) != KeyModifier.None))
280 && ((m1 & KeyModifier.High) == (m2 & KeyModifier.High)));
283 public override string ToString ()
285 string str = Char.ToString ((char) key);
286 KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
288 if (m != KeyModifier.None)
290 if ((m & KeyModifier.Shift) != KeyModifier.None)
292 if ((m & KeyModifier.Control) != KeyModifier.None)
294 if ((m & KeyModifier.Alt) != KeyModifier.None)
296 if ((m & KeyModifier.AltGr) != KeyModifier.None)
298 if ((m & KeyModifier.Super) != KeyModifier.None)
300 if ((m & KeyModifier.Hyper) != KeyModifier.None)
307 public class KeySeq : List<Key>
309 public KeySeq () : base () { }
311 public KeySeq (MPlist plist) : base ()
313 foreach (MPlist p in plist)
316 this.Add (new Key (p.Symbol));
317 else if (p.IsInteger)
318 this.Add (new Key ((char) p.Integer));
320 this.Add (new Key (p.Plist));
322 throw new Exception ("Invalid Key Sequence: " + plist);
326 public KeySeq (MText mt) : base ()
328 for (int i = 0; i < mt.Length; i++)
329 this.Add (new Key ((uint) mt[i]));
332 private static uint parse_integer (string str)
334 if (Char.IsDigit (str[0]))
336 if (str[0] == '0' && str.Length > 2 && str[1] == 'x')
339 for (int idx = 2; idx < str.Length; idx++)
342 if (c >= '0' && c <= '9')
343 i = i * 16 + (c - '0');
344 else if (c >= 'A' && c <= 'F')
345 i = i * 16 + 10 + (c - 'A');
346 else if (c >= 'a' && c <= 'f')
347 i = i * 16 + 10 + (c - 'a');
353 return UInt32.Parse (str);
355 else if (str[0] == '?')
360 public KeySeq (XmlNode node) : base ()
362 XmlAttributeCollection acol = node.Attributes;
365 if (acol != null && (n = acol["keys"]) != null)
367 foreach (char c in n.Value)
368 this.Add (new Key ((uint) c));
371 for (node = node.FirstChild; node != null; node = node.NextSibling)
373 if (node.Name == "key-event")
374 this.Add (new Key ((MSymbol) node.InnerText));
376 this.Add (new Key (parse_integer (node.InnerText)));
380 public override string ToString ()
384 foreach (Key key in this)
388 foreach (Key k in this)
389 str += " " + k.ToString ();
393 foreach (Key key in this)
394 str += key.ToString ();
399 public class Variable
402 public MText description;
405 public object[] candidates;
407 public Variable (MPlist p)
411 description = parse_description (p);
412 if (description == null)
413 description = new MText ("No description");
416 type = (p.IsMText ? typeof (MText)
417 : p.IsInteger ? typeof (int)
418 : p.IsSymbol ? typeof (MSymbol)
422 candidates = new object[p.Count];
423 for (int i = 0; ! p.IsEmpty; i++, p = p.next)
424 candidates[i] = p.val;
427 private static Type parse_value (XmlNode node, out object value)
429 string typename = node.Attributes["type"].Value;
432 if (typename == "integer")
435 if (! Int32.TryParse (node.InnerText, out i))
440 else if (typename == "string")
442 MText mt = node.InnerText;
444 type = typeof (MText);
446 else if (typename == "symbol")
448 MSymbol sym = node.InnerText;
450 type = typeof (MSymbol);
455 type = typeof (object);
460 public Variable (XmlNode node)
462 name = node.Attributes["id"].Value;
463 for (node = node.FirstChild; node != null; node = node.NextSibling)
464 if (node.NodeType == XmlNodeType.Element)
466 if (node.Name == "description")
467 description = parse_description (node);
468 else if (node.Name == "value")
469 type = parse_value (node, out value);
470 else if (node.Name == "valiable-value-candidate")
472 XmlNodeList n_list = node.ChildNodes;
473 candidates = new object[n_list.Count];
474 for (int i = 0; i < n_list.Count; i++)
477 parse_value (n_list[i], out val);
484 public override string ToString ()
486 return ("(" + name + " \"" + (string) description
487 + "\" " + type + " " + value + " " + candidates + ")");
494 public MText description;
495 public List<KeySeq> keys;
497 public Command (MPlist p)
501 description = parse_description (p);
502 if (description == null)
503 description = "No description";
504 keys = new List<KeySeq> ();
505 for (p = p.next; ! p.IsEmpty; p = p.next)
508 keys.Add (new KeySeq (p.Text));
510 keys.Add (new KeySeq (p.Plist));
514 public Command (XmlNode node)
516 name = node.Attributes["id"].Value;
517 keys = new List<KeySeq> ();
518 for (node = node.FirstChild; node != null; node = node.NextSibling)
520 if (node.Name == "description")
521 description = parse_description (node);
522 else if (node.Name == "keyseq")
523 keys.Add (new KeySeq (node));
527 public override string ToString ()
529 string str = "(" + name + " \"" + (string) description;
530 foreach (KeySeq keyseq in keys)
536 internal class Plugin
539 public Assembly assembly;
540 public MPlist methods;
542 public override string ToString ()
544 string str = "(" + name;
545 for (MPlist p = methods; ! p.IsEmpty; p = p.next)
554 public Dictionary<Key, Map> submaps;
555 public MExpression actions;
557 public void Add (KeySeq keys, int index, MExpression actions)
562 submaps = new Dictionary<Key, Map> ();
564 submaps.TryGetValue (keys[index], out sub);
567 Key key = keys[index];
568 submaps[key] = sub = new Map ();
570 if (index + 1 < keys.Count)
571 sub.Add (keys, index + 1, actions);
573 this.actions = actions;
576 public MExpression Lookup (KeySeq keys, int index)
580 if (index + 1 == keys.Count)
582 if (submaps.TryGetValue (keys[index], out sub))
583 return sub.Lookup (keys, index + 1);
587 private void describe (MText mt, KeySeq keyseq)
589 if (keyseq.Count > 0)
591 mt.Cat (" (").Cat (keyseq.ToString ());
593 mt.Cat (' ').Cat (actions.ToString ());
597 foreach (KeyValuePair<Key, Map> kv in submaps)
600 kv.Value.describe (mt, keyseq);
601 keyseq.RemoveAt (keyseq.Count - 1);
605 public override string ToString ()
607 MText mt = "(" + name.Name;
608 KeySeq keyseq = new KeySeq ();
610 describe (mt, keyseq);
620 public MPlist branches = new MPlist ();
622 public State (MSymbol name)
627 public override string ToString ()
629 MText mt = "(" + name.Name;
632 mt.Cat (" \"" + title + "\"");
633 for (MPlist p = branches; ! p.IsEmpty; p = p.next)
634 mt.Cat (" (" + p.Key + " " + (MExpression) p.Val + ")");
635 return (string) mt + ")";
640 internal MExpression.Domain local_domain;
642 private LoadStatus load_status = LoadStatus.None;
643 private MDatabase.Tag tag;
644 private MDatabase mdb;
646 private MText description;
647 internal MText title;
648 internal Command[] commands;
649 internal Variable[] variables;
650 internal Dictionary<MSymbol, Plugin> plugins;
651 internal MPlist bindings;
652 internal Dictionary<MSymbol, Map> maps;
653 internal MPlist states;
655 static MInputMethod ()
657 domain.Defun ("insert", insert, 1, 1);
658 domain.Defun ("candidates", insert_candidates, 1, -1);
659 domain.Defun ("delete", delete, 1, 1);
660 domain.Defun ("select", select, 1, 1);
661 domain.Defun ("show", show, 0, 0);
662 domain.Defun ("hide", hide, 0, 0);
663 domain.Defun ("move", move, 1, 1);
664 domain.Defun ("mark", mark, 1, 1, true);
665 domain.Defun ("pushback", pushback, 1, 1);
666 domain.Defun ("pop", pop, 0, 0);
667 domain.Defun ("undo", undo, 0, 1);
668 domain.Defun ("commit", commit, 0, 0);
669 domain.Defun ("unhandle", unhandle, 0, 0);
670 domain.Defun ("shift", shift, 1, 1, true);
671 domain.Defun ("call", call, 2, -1, true);
672 // Pseudo functions to make arguments of special objects.
673 domain.Defun ("marker", marker, 1, 1, true);
674 domain.Defun ("char-at", char_at, 1, 1, true);
675 domain.Defun ("keyseq", keyseq, 1, -1, true);
677 MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
678 List<MDatabase> list = MDatabase.List (tag);
679 M17n.DebugPrint ("Found {0} input methods\n", list.Count);
680 foreach (MDatabase mdb in list)
681 im_table[mdb.tag] = new MInputMethod (mdb.tag);
685 private MInputMethod (MDatabase.Tag tag)
690 // Instance Properties
691 public MSymbol Language { get { return tag[1]; } }
692 public MSymbol Name { get { return tag[2]; } }
693 public MSymbol SubName { get { return tag[3]; } }
695 public bool Info (out MText description, out MText title,
696 out Variable[] variables, out Command[] commands)
698 if ((load_status & LoadStatus.Header) != LoadStatus.Header
707 description = this.description;
709 variables = this.variables;
710 commands = this.commands;
714 public static MInputMethod Find (MSymbol language, MSymbol name)
716 return Find (language, name, MSymbol.nil);
719 public static MInputMethod Find (MSymbol language, MSymbol name,
722 MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
726 return (im_table.TryGetValue (tag, out im) ? im : null);
731 return ((load_status == LoadStatus.Full) || load_body ());
734 public static MInputMethod[] List ()
736 MInputMethod[] array = new MInputMethod[im_table.Count];
739 foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
740 array[i++] = kv.Value;
744 private bool load_header ()
746 mdb = MDatabase.Find (tag);
750 MSymbol format = mdb.Format;
752 if (format == MSymbol.plist)
753 load ((MPlist) mdb.Load (Mmap), false);
756 XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list);
757 load (doc.DocumentElement, false);
759 } catch (Exception e) {
760 Console.WriteLine ("{0}\n", e);
761 load_status = LoadStatus.Error;
764 load_status |= LoadStatus.Header;
768 private bool load_body ()
770 local_domain = new MExpression.Domain (domain, null);
771 mdb = MDatabase.Find (tag);
775 object obj = mdb.Load ();
777 load ((MPlist) obj, true);
779 load ((XmlDocument) obj, true);
780 } catch (Exception e) {
781 Console.WriteLine (e);
782 load_status = LoadStatus.Error;
785 load_status = LoadStatus.Full;
789 private void load (MPlist plist, bool full)
791 maps = new Dictionary<MSymbol, Map> ();
792 states = new MPlist ();
794 for (; ! plist.IsEmpty; plist = plist.next)
797 MPlist pl = plist.Plist;
800 MSymbol sym = pl.Symbol;
803 if (sym == Mdescription)
805 description = parse_description (pl);
806 if (description == null)
807 description = new MText ("No description");
809 else if (sym == Mtitle)
814 else if (sym == Mvariable)
815 parse_variables (pl);
816 else if (sym == Mcommand)
822 else if (sym == Minclude)
824 else if (sym == Mmacro)
826 else if (sym == Mmap)
828 else if (sym == Mstate)
833 if (description == null)
834 description = (MText) "No description";
836 title = new MText (tag[2].Name);
837 if (variables == null)
838 variables = new Variable[0];
839 if (commands == null)
840 commands = new Command[0];
845 State state = new State ((MSymbol) "init");
846 plist = new MPlist ();
847 foreach (KeyValuePair<MSymbol, Map>kv in maps)
848 state.branches.Add (kv.Key, new MExpression (plist, local_domain));
849 states.Add (state.name, state);
853 private void load (XmlNode node, bool full)
855 bool skip_header = load_status == LoadStatus.Header;
857 maps = new Dictionary<MSymbol, Map> ();
858 states = new MPlist ();
860 if (node.NodeType == XmlNodeType.Document)
861 node = node.FirstChild;
862 while (node.NodeType != XmlNodeType.Element)
863 node = node.NextSibling;
864 for (node = node.FirstChild; node != null; node = node.NextSibling)
866 if (node.NodeType != XmlNodeType.Element)
870 if (node.Name == "description")
871 description = parse_description (node);
872 else if (node.Name == "title")
873 title = parse_title (node);
874 else if (node.Name == "variable-list")
875 parse_variables (node);
876 else if (node.Name == "command-list")
877 parse_commands (node);
881 if (node.Name == "module-list")
882 parse_plugins (node);
883 else if (node.Name == "macro-list")
885 else if (node.Name == "map-list")
887 else if (node.Name == "state-list")
891 if (description == null)
892 description = (MText) "No description";
894 title = new MText (tag[2].Name);
895 if (variables == null)
896 variables = new Variable[0];
897 if (commands == null)
898 commands = new Command[0];
903 State state = new State ((MSymbol) "init");
904 MPlist plist = new MPlist ();
905 foreach (KeyValuePair<MSymbol, Map>kv in maps)
906 state.branches.Add (kv.Key, new MExpression (plist, local_domain));
907 states.Add (state.name, state);
911 private static void transform (MPlist plist)
913 for (; ! plist.IsEmpty; plist = plist.next)
917 MPlist p = new MPlist ();
918 p.Add (MSymbol.symbol, Minsert);
919 p.Add (MSymbol.mtext, plist.Text);
920 plist.Set (MSymbol.plist, p);
922 else if (plist.IsInteger)
924 MPlist p = new MPlist ();
925 p.Add (MSymbol.symbol, Minsert);
926 p.Add (MSymbol.integer, plist.Integer);
927 plist.Set (MSymbol.plist, p);
929 else if (plist.IsPlist)
931 MPlist pl = plist.Plist;
935 if (pl.Symbol == Madd)
936 pl.Set (MSymbol.symbol, (MSymbol) "+=");
937 else if (pl.Symbol == Msub)
938 pl.Set (MSymbol.symbol, (MSymbol) "-=");
939 else if (pl.Symbol == Mmul)
940 pl.Set (MSymbol.symbol, (MSymbol) "*=");
941 else if (pl.Symbol == Mdiv)
942 pl.Set (MSymbol.symbol, (MSymbol) "/=");
943 else if (pl.Symbol == Minsert)
945 // (insert (CANDIDATES ...))
946 // => (candidates CANDIDATES ...)
949 pl.Set (MSymbol.symbol, Mcandidates);
952 pl.Set (p.key, p.val);
953 for (p = p.next; ! p.IsEmpty; p = p.next);
954 pl.Add (p.key, p.val);
957 else if (pl.Symbol == Mif)
963 else if (pl.Symbol == Mcond)
965 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
976 else if (pl.Symbol == Mdelete
977 || pl.Symbol == Mmove
978 || pl.Symbol == Mmark)
983 MSymbol sym = pl.Symbol;
984 MPlist p = new MPlist ();
985 p.Add (MSymbol.symbol, Mmarker);
986 p.Add (MSymbol.symbol, sym);
987 pl.Set (MSymbol.plist, p);
990 else if (pl.Symbol == Mpushback)
994 pl.Plist.Push (MSymbol.symbol, Mkeyseq);
999 // (CANDIDATES ...) => (candidates CANDIDATES ...)
1000 pl.Push (MSymbol.symbol, Mcandidates);
1003 else if (plist.IsSymbol)
1005 MSymbol sym = plist.Symbol;
1007 if (sym.Name.Length >= 3
1008 && sym.Name[0] == '@'
1009 && (sym.Name[1] == '-' || sym.Name[1] == '+'))
1011 int pos = int.Parse (sym.Name.Substring (1));
1012 MPlist p = new MPlist ();
1016 p.Add (MSymbol.symbol, Msurrounding_text_p);
1020 if (sym.Name[1] == '+')
1022 p.Add (MSymbol.symbol, Mchar_at);
1023 p.Add (MSymbol.integer, pos);
1025 plist.Set (MSymbol.plist, p);
1031 private static MText parse_description (MPlist plist)
1037 plist = plist.Plist;
1038 if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
1039 && plist.next.IsMText)
1040 return plist.next.Text;
1045 private static MText parse_description (XmlNode node)
1047 if (node.HasChildNodes)
1048 node = node.FirstChild;
1049 return node.InnerText;
1052 private static MText parse_title (XmlNode node)
1054 return node.InnerText;
1057 private void parse_variables (MPlist plist)
1059 variables = new Variable[plist.Count];
1061 for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1062 if (plist.IsPlist && plist.Plist.IsSymbol)
1063 variables[i++] = new Variable (plist.Plist);
1066 private void parse_variables (XmlNode node)
1068 XmlNodeList node_list = node.ChildNodes;
1070 variables = new Variable[node_list.Count];
1071 for (int i = 0; i < node_list.Count; i++)
1072 if (node_list[i].NodeType == XmlNodeType.Element)
1073 variables[i] = new Variable (node_list[i]);
1076 private void parse_commands (MPlist plist)
1078 commands = new Command[plist.Count];
1080 for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1081 if (plist.IsPlist && plist.Plist.IsSymbol)
1082 commands[i++] = new Command (plist.Plist);
1085 private void parse_commands (XmlNode node)
1087 XmlNodeList node_list = node.ChildNodes;
1089 commands = new Command[node_list.Count];
1090 for (int i = 0; i < node_list.Count; i++)
1092 if (node_list[i].NodeType == XmlNodeType.Element)
1093 commands[i] = new Command (node_list[i]);
1097 private void parse_plugins (MPlist plist)
1099 plugins = new Dictionary<MSymbol, Plugin> ();
1101 for (; ! plist.IsEmpty; plist = plist.Next)
1103 MPlist p = plist.Plist;
1104 MSymbol sym = p.Symbol;
1105 Plugin plugin = new Plugin ();
1107 plugin.name = sym.Name;
1108 plugin.methods = new MPlist ();
1109 for (p = p.next; ! p.IsEmpty; p = p.next)
1110 plugin.methods.Add (p.Symbol, null);
1111 plugins.Add (sym, plugin);
1115 private void parse_plugins (XmlNode node)
1117 plugins = new Dictionary<MSymbol, Plugin> ();
1119 foreach (XmlNode n in node.ChildNodes)
1121 Plugin plugin = new Plugin ();
1122 plugin.name = n.Attributes["id"].Value;
1123 plugin.methods = new MPlist ();
1124 foreach (XmlNode nn in n.ChildNodes)
1125 plugin.methods.Add ((MSymbol) nn.Attributes["id"].Value,
1127 plugins.Add (plugin.name, plugin);
1131 private void parse_macros (XmlNode node)
1133 for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1134 if (nn.NodeType == XmlNodeType.Element
1135 && nn.Name == "xi:include")
1137 XmlNode n = nn.FirstChild.FirstChild;
1138 MSymbol language = n.InnerText;
1140 MSymbol name = n.InnerText;
1142 MSymbol subname = (n != null ? n.InnerText : MSymbol.nil);
1143 n = n.ParentNode.NextSibling;
1144 MSymbol section = n.InnerText;
1146 MSymbol id = (n != null ? n.InnerText : MSymbol.nil);
1148 MInputMethod im = MInputMethod.Find (language, name, subname);
1149 if (im == null || ! im.Open ())
1151 if (id == MSymbol.nil)
1152 im.local_domain.CopyFunc (local_domain);
1154 im.local_domain.CopyFunc (local_domain, id);
1156 for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1157 if (nn.NodeType == XmlNodeType.Element
1158 && nn.Name != "xi:include")
1159 local_domain.Defun ((MSymbol) node.GetAttribute ("id"));
1160 for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1161 if (nn.NodeType == XmlNodeType.Element
1162 && nn.Name != "xi:include")
1163 local_domain.Defun ((MSymbol) node.GetAttribute ("id"), null,
1167 private void parse_maps (XmlNode node)
1171 private void parse_states (XmlNode node)
1175 private void parse_include (MPlist plist)
1177 if (! plist.IsPlist)
1179 MPlist p = plist.Plist;
1180 MSymbol language, name, subname;
1181 language = p.Symbol;
1184 name = subname = MSymbol.nil;
1190 subname = MSymbol.nil;
1195 MInputMethod im = MInputMethod.Find (language, name, subname);
1201 if (! plist.IsSymbol)
1203 MSymbol target_type = plist.Symbol;
1205 MSymbol target_name = MSymbol.nil;
1207 target_name = plist.Symbol;
1208 if (target_type == Mmacro)
1210 if (target_name == MSymbol.nil)
1211 im.local_domain.CopyFunc (local_domain);
1213 im.local_domain.CopyFunc (local_domain, target_name);
1215 else if (target_type == Mmap)
1217 if (target_name == MSymbol.nil)
1219 foreach (KeyValuePair<MSymbol, Map> kv in im.maps)
1220 maps[kv.Key] = kv.Value;
1225 if (im.maps.TryGetValue (target_name, out map))
1226 maps[target_name] = map;
1229 else if (target_type == Mstate)
1231 if (target_name == MSymbol.nil)
1233 for (p = im.states; ! p.IsEmpty; p = p.next)
1234 states.Add (p.key, p.val);
1238 object state = im.states.Get (target_name);
1240 states.Add (target_name, state);
1245 private void parse_macros (MPlist plist)
1247 for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1250 MPlist p = pl.Plist;
1254 local_domain.Defun (p.Symbol, null, null);
1256 for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1259 MPlist p = pl.Plist;
1264 local_domain.Defun (p.Symbol, null, p.next);
1268 private void parse_maps (MPlist plist)
1270 for (; ! plist.IsEmpty; plist = plist.next)
1273 MPlist pl = plist.Plist;
1277 Map map = new Map ();
1278 map.name = pl.Symbol;
1279 maps[map.name] = map;
1280 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1284 MPlist p = pl.Plist;
1287 keys = new KeySeq (p.Text);
1289 keys = new KeySeq (p.Plist);
1296 MExpression expr = new MExpression (p, local_domain);
1297 map.Add (keys, 0, expr);
1302 private void parse_states (MPlist plist)
1304 for (; ! plist.IsEmpty; plist = plist.next)
1307 MPlist pl = plist.Plist;
1318 State state = new State (pl.Symbol);
1319 state.title = title;
1321 states = new MPlist ();
1322 states.Add (state.name, state);
1323 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1327 MPlist p = pl.Plist;
1330 MSymbol map_name = p.Symbol;
1333 state.branches.Add (map_name,
1334 new MExpression (p, local_domain));
1339 private static object insert (MExpression[] args, MExpression.Domain domain)
1341 ((MInputContext) domain.context).insert (args[0].Val);
1346 private static object insert_candidates (MExpression[] args,
1347 MExpression.Domain domain)
1349 ((MInputContext) domain.context).insert_candidates ((MPlist) args[0].Val);
1354 private static object marker (MExpression[] args, MExpression.Domain domain)
1356 MSymbol sym = (MSymbol) args[0].Args[0].Val;
1358 return ((MInputContext) domain.context).marker (sym);
1361 private static object char_at (MExpression[] args,
1362 MExpression.Domain domain)
1364 return ((MInputContext) domain.context).char_at ((int) args[0].Val);
1367 private static object delete (MExpression[] args, MExpression.Domain domain)
1369 ((MInputContext) domain.context).delete ((int) args[0].Val);
1373 private static object select (MExpression[] args, MExpression.Domain domain)
1375 MInputContext ic = (MInputContext) domain.context;
1376 object val = args[0].Val;
1379 ic.select ((int) val);
1381 ic.select ((MSymbol) val);
1385 private static object show (MExpression[] args, MExpression.Domain domain)
1387 ((MInputContext) domain.context).show ();
1392 private static object hide (MExpression[] args, MExpression.Domain domain)
1394 ((MInputContext) domain.context).hide ();
1399 private static object move (MExpression[] args, MExpression.Domain domain)
1401 ((MInputContext) domain.context).move ((int) args[0].Val);
1406 private static object mark (MExpression[] args, MExpression.Domain domain)
1408 MSymbol sym = (MSymbol) args[0].Val;
1410 ((MInputContext) domain.context).mark (sym);
1414 private static object keyseq (MExpression[] args, MExpression.Domain domain)
1416 MPlist p = new MPlist ();
1418 for (int i = 0; i < args.Length; i++)
1419 p.Add (MSymbol.symbol, (MSymbol) args[i].Val);
1420 return new KeySeq (p);
1423 private static object pushback (MExpression[] args,
1424 MExpression.Domain domain)
1426 MInputContext ic = (MInputContext) domain.context;
1427 object val = args[0].Val;
1430 ic.pushback ((int) val);
1431 else if (val is MText)
1432 ic.pushback (new KeySeq ((MText) val));
1433 else if (val is KeySeq)
1434 ic.pushback ((KeySeq) val);
1436 throw new Exception ("Invalid keyseq: " + val);
1440 private static object pop (MExpression[] args, MExpression.Domain domain)
1442 ((MInputContext) domain.context).pop ();
1446 private static object undo (MExpression[] args, MExpression.Domain domain)
1448 int n = args.Length == 0 ? -2 : (int) args[0].Val;
1449 ((MInputContext) domain.context).undo (n);
1453 private static object commit (MExpression[] args, MExpression.Domain domain)
1455 ((MInputContext) domain.context).commit ();
1459 private static object unhandle (MExpression[] args,
1460 MExpression.Domain domain)
1462 ((MInputContext) domain.context).commit ();
1466 private static object shift (MExpression[] args, MExpression.Domain domain)
1468 MSymbol sym = (MSymbol) args[0].Args[0].Val;
1470 ((MInputContext) domain.context).shift (sym);
1474 private static object call (MExpression[] args, MExpression.Domain domain)
1476 MSymbol module = (MSymbol) args[0].Args[0].Val;
1477 MSymbol method = (MSymbol) args[1].Args[0].Val;
1478 MPlist arglist = new MPlist ();
1480 for (int i = 2; i < args.Length; i++)
1482 object val = args[i].Eval (domain);
1485 arglist.Add (MSymbol.integer, val);
1486 else if (val is MSymbol)
1487 arglist.Add (MSymbol.symbol, val);
1488 else if (val is MText)
1489 arglist.Add (MSymbol.mtext, val);
1490 else if (val is MPlist)
1491 arglist.Add (MSymbol.plist, val);
1493 throw new Exception ("Invalid argument to {0}/{1}: {2}",
1494 module, method, val);
1496 return ((MInputContext) domain.context).call (module, method, arglist);
1499 public override string ToString ()
1501 string str = (String.Format ("({0} (title \"{1}\")", tag, title));
1502 if (commands != null)
1504 str += " (commands";
1505 foreach (Command cmd in commands)
1509 if (variables != null)
1511 str += " (variables";
1512 foreach (Variable var in variables)
1516 if (plugins != null)
1519 foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
1520 str += " " + kv.Value;
1524 foreach (KeyValuePair<MSymbol, Map> kv in maps)
1525 str += " " + kv.Value;
1527 foreach (MPlist p in states)
1533 public class MInputContext
1535 internal static MSymbol Mcandidates_group_size = "candidates-group-size";
1536 private static MSymbol Mat_less_than = "@<";
1537 private static MSymbol Mat_greater_than = "@>";
1538 private static MSymbol Mat_minus = "@-";
1539 private static MSymbol Mat_plus = "@+";
1540 private static MSymbol Mat_open_square_bracket = "@[";
1541 private static MSymbol Mat_close_square_bracket = "@]";
1543 public MInputMethod im;
1544 private MText produced;
1545 private bool active;
1546 private MText status;
1547 private bool status_changed;
1548 private MText preedit;
1549 private bool preedit_changed;
1550 private int cursor_pos;
1551 private bool cursor_pos_changed;
1552 private Candidates candidates;
1553 private MPlist candidate_group;
1554 private int candidate_index;
1555 private int candidate_from, candidate_to;
1556 private bool candidate_show;
1557 private bool candidate_changed;
1559 private Stack<MInputMethod.State> states;
1560 internal MInputMethod.KeySeq keys;
1561 private int key_head;
1562 private int state_key_head;
1563 private MPlist state_boundary;
1564 private int commit_key_head;
1565 private MText state_preedit;
1566 private int state_pos;
1567 internal MPlist markers = new MPlist ();
1568 private MPlist vars;
1569 private MPlist vars_saved;
1570 internal MText preceding_text = new MText ();
1571 internal MText following_text = new MText ();
1572 private bool key_unhandled;
1574 internal MExpression.Domain domain;
1576 public MInputContext (MInputMethod im)
1579 domain = new MExpression.Domain (im.local_domain, this);
1580 states = new Stack<MInputMethod.State> ();
1581 states.Push ((MInputMethod.State) im.states.val);
1582 keys = new MInputMethod.KeySeq ();
1585 private void adjust_markers (int from, int to, object inserted)
1587 int ins = (inserted == null ? 0
1588 : inserted is int ? 1
1589 : ((MText) inserted).Length);
1590 int diff = ins - (to - from);
1592 for (MPlist plist = markers; ! plist.IsEmpty; plist = plist.next)
1594 int pos = plist.Integer;
1598 plist.val = pos + diff;
1603 if (cursor_pos >= to)
1605 else if (cursor_pos > from)
1609 private void preedit_replace (int from, int to, int c)
1611 preedit.Del (from, to);
1612 preedit.Ins (from, c);
1613 adjust_markers (from, to, c);
1616 private void preedit_replace (int from, int to, MText mt)
1618 preedit[from, to] = mt;
1619 adjust_markers (from, to, mt);
1622 internal void insert (object arg)
1625 preedit_replace (cursor_pos, cursor_pos, (int) arg);
1627 preedit_replace (cursor_pos, cursor_pos, (MText) arg);
1628 preedit_changed = true;
1629 cursor_pos_changed = true;
1632 private class Candidates
1639 public Block (int index, MPlist plist)
1650 get { return (Data is MText
1651 ? ((MText) Data).Length
1652 : ((MPlist) Data).Count); }
1655 public object this[int i]
1658 if (Data is MText) return ((MText) Data)[i];
1659 return ((MPlist) Data)[i];
1664 private Block[] blocks;
1665 private int row = 0;
1666 private int index = 0;
1667 public object[] group;
1669 private bool IsFixed { get { return group != null; } }
1672 Block last = blocks[blocks.Length - 1];
1673 return last.Index + last.Count; }
1677 get { return (IsFixed ? index % group.Length
1678 : index - blocks[row].Index); }
1681 public object Group {
1682 get { return (IsFixed ? group : blocks[row].Data); }
1685 public int GroupLength
1690 int nitems = group.Length;
1691 int start = index - (index % nitems);
1693 return (start + nitems <= total ? nitems : total - start);
1695 return blocks[row].Count;
1699 public object Current {
1701 return (IsFixed ? group[index % group.Length]
1702 : blocks[row][index - blocks[row].Index]);
1706 public Candidates (MPlist list, int column)
1708 int nblocks = list.Count;
1710 blocks = new Block[nblocks];
1711 for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
1712 start += (blocks[i] = new Block (index, list)).Count;
1714 group = new object[column];
1717 public static void Detach (MInputContext ic)
1719 ic.preedit.PopProp (0, ic.preedit.Length, MInputMethod.Mcandidates);
1720 ic.candidates = null;
1721 ic.preedit_changed = true;
1722 ic.cursor_pos_changed = true;
1723 ic.candidate_changed = true;
1726 // Fill the array "group" by candidates stating from INDEX.
1727 // INDEX must be a multiple of "column". Set NTIMES to the
1728 // number of valid candidates in "group". Update "block" if
1729 // necessary. Return "group".
1731 private int fill_group (int start)
1733 int nitems = group.Length;
1735 Block b = blocks[r];
1737 if (start < b.Index)
1738 while (start < b.Index)
1741 while (start >= b.Index + b.Count)
1745 int count = b.Count;
1747 for (int i = 0; i < nitems; i++, start++)
1752 if (r == blocks.Length)
1758 group[i] = b[start];
1763 // Update "row" to what contains the first candidate of
1764 // the previous candidate-group, update "current_index", and
1765 // update "group" if necessary. Return the previous
1766 // candidate-group. Set NITEMS to the number of valid
1767 // candidates contained in that group.
1769 public int PrevGroup ()
1776 nitems = group.Length;
1777 if ((index -= col + nitems) < 0)
1778 index = (Total / nitems) * nitems;
1779 nitems = fill_group (index);
1783 row = row > 0 ? row-- : blocks.Length - 1;
1784 nitems = blocks[row].Count;
1785 index = blocks[row].Index;
1787 index += col < nitems ? col : nitems - 1;
1791 public int NextGroup ()
1798 nitems = group.Length;
1799 if ((index += nitems - col) >= Total)
1801 nitems = fill_group (index);
1805 row = row < blocks.Length - 1 ? row + 1 : 0;
1806 nitems = blocks[row].Count;
1807 index = blocks[row].Count;
1809 index += col < nitems ? col : nitems - 1;
1819 int nitems = PrevGroup ();
1820 index += col < nitems - 1 ? col : nitems - 1;
1829 int nitems = GroupLength;
1831 if (col == nitems - 1)
1833 nitems = NextGroup ();
1840 public void First ()
1847 index += GroupLength - (Column + 1);
1850 public void Select (int col)
1852 int maxcol = GroupLength - 1;
1855 index = index - Column + col;
1859 private void update_candidate ()
1861 object candidate = candidates.Current;
1863 if (candidate is MText)
1865 preedit_replace (candidate_from, candidate_to, (MText) candidate);
1866 candidate_to = candidate_from + ((MText) candidate).Length;
1870 preedit_replace (candidate_from, candidate_to, (int) candidate);
1871 candidate_to = candidate_from + 1;
1873 preedit.PushProp (candidate_from, candidate_to,
1874 MInputMethod.Mcandidates, this);
1875 cursor_pos = candidate_from;
1876 preedit_changed = true;
1877 cursor_pos_changed = true;
1878 candidate_changed = true;
1881 internal void insert_candidates (MPlist list)
1885 if (domain.IsBound (Mcandidates_group_size))
1887 object val = domain.GetValue (Mcandidates_group_size);
1891 candidates = new Candidates (list, column);
1892 candidate_from = candidate_to = cursor_pos;
1893 update_candidate ();
1896 internal void select (int n)
1898 if (candidates != null)
1900 candidates.Select (n);
1901 update_candidate ();
1905 internal void select (MSymbol sym)
1907 if (candidates != null)
1909 if (sym == Mat_less_than)
1910 candidates.First ();
1911 else if (sym == Mat_greater_than)
1913 else if (sym == Mat_minus)
1915 else if (sym == Mat_plus)
1917 else if (sym == Mat_open_square_bracket)
1918 candidates.PrevGroup ();
1919 else if (sym == Mat_close_square_bracket)
1920 candidates.NextGroup ();
1924 internal int marker (MSymbol sym)
1926 int pos = cursor_pos;
1928 if (sym.Name.Length == 2 && sym.Name[0] == '@')
1930 switch (sym.Name[0])
1932 case '<': pos = 0; break;
1933 case '>': pos = preedit.Length; break;
1934 case '-': pos = cursor_pos - 1; break;
1935 case '+': pos = cursor_pos + 1; break;
1940 preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
1947 if (cursor_pos < preedit.Length - 1)
1950 preedit.FindProp (MInputMethod.Mcandidates, pos,
1954 pos = preedit.Length;
1957 if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
1962 else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
1964 pos = int.Parse (sym.Name.Substring (2));
1968 object val = markers.Get (sym);
1976 internal int char_at (int pos)
1983 if (preceding_text.Length < -pos)
1985 MPlist plist = new MPlist ();
1986 plist.Push (MSymbol.integer, pos);
1987 if (MInputMethod.GetSurroundingText != null
1988 && MInputMethod.GetSurroundingText (this, plist)
1990 && preceding_text.Length < plist.Text.Length)
1991 preceding_text = plist.Text;
1993 c = (-pos < preceding_text.Length
1994 ? preceding_text[preceding_text.Length + pos] : -1);
1996 else if (pos >= 0 && pos < preedit.Length)
2000 pos -= preedit.Length;
2001 if (pos >= following_text.Length)
2003 MPlist plist = new MPlist ();
2004 plist.Push (MSymbol.integer, pos + 1);
2005 if (MInputMethod.GetSurroundingText != null
2006 && MInputMethod.GetSurroundingText (this, plist)
2008 && following_text.Length < plist.Text.Length)
2009 following_text = plist.Text;
2011 c = (pos < following_text.Length ? following_text[pos] : -1);
2016 internal void delete (int pos)
2018 if (pos < cursor_pos)
2019 preedit_replace (pos, cursor_pos, null);
2021 preedit_replace (cursor_pos, pos, null);
2022 preedit_changed = true;
2023 cursor_pos_changed = true;
2026 internal void show ()
2028 candidate_show = true;
2029 candidate_changed = true;
2032 internal void hide ()
2034 candidate_show = false;
2035 candidate_changed = true;
2038 internal void move (int pos)
2042 else if (pos > preedit.Length)
2043 pos = preedit.Length;
2044 if (pos != cursor_pos)
2047 preedit_changed = true;
2051 internal void mark (MSymbol sym)
2053 MPlist slot = markers.Find (sym);
2056 markers.Push (sym, cursor_pos);
2058 slot.val = cursor_pos;
2061 internal void pushback (int n)
2074 if (key_head > keys.Count)
2075 key_head = keys.Count;
2079 internal void pushback (MInputMethod.KeySeq keyseq)
2083 if (key_head < keys.Count)
2084 keys.RemoveRange (key_head, keys.Count - key_head);
2085 for (int i = 0; i < keyseq.Count; i++)
2086 keys.Add (keyseq[i]);
2089 internal void pop ()
2091 if (key_head < keys.Count)
2092 keys.RemoveRange (key_head, 1);
2095 internal void undo (int n)
2098 keys.RemoveRange (keys.Count + n, - n);
2100 keys.RemoveRange (n, keys.Count - n);
2104 internal void commit ()
2106 produced.Cat (preedit);
2108 preedit_changed = true;
2111 internal void shift (MSymbol sym)
2113 MInputMethod.State state;
2115 if (sym == MSymbol.t)
2117 if (states.Count > 1)
2118 state = states.Pop ();
2120 state = states.Peek ();
2124 state = (MInputMethod.State) im.states.Get (sym);
2126 throw new Exception ("Unknown state: " + state.name);
2129 state = states.Pop ();
2130 if (state == (MInputMethod.State) im.states.val)
2137 state_key_head = key_head;
2138 state_pos = cursor_pos;
2139 state_preedit = preedit.Dup ();
2140 if (state != states.Peek ())
2142 states.Push (state);
2143 state_boundary = domain.SetBoundary ();
2144 status = state.title;
2147 status_changed = true;
2148 MExpression on_entry
2149 = (MExpression) state.branches.Get (MSymbol.t);
2150 if (on_entry != null)
2151 on_entry.Eval (domain);
2156 internal bool call (MSymbol module, MSymbol method, MPlist arglist)
2158 MInputMethod.Plugin plugin;
2160 if (! im.plugins.TryGetValue (module, out plugin))
2162 if (plugin.assembly == null)
2167 assembly = Assembly.LoadFrom (module.Name + ".dll");
2171 Type t = assembly.GetType ("Plugin");
2172 for (MPlist p = plugin.methods; ! p.IsEmpty; p = p.next)
2173 p.Set (p.key, t.GetMethod (p.key.Name));
2176 MethodInfo method_info = (MethodInfo) plugin.methods.Get (method);
2177 if (method_info == null)
2179 object[] method_arg = new object[1];
2180 method_arg[0] = arglist;
2181 bool result = (bool) method_info.Invoke (null, method_arg);
2184 if (! arglist.IsEmpty)
2185 (new MExpression (arglist, domain)).Eval (domain);
2189 internal void reset ()
2192 state_preedit.Del ();
2196 key_head = commit_key_head = 0;
2198 states.Push ((MInputMethod.State) im.states.Val);
2203 internal object GetCandidates (out int column)
2206 if (cursor_pos == 0)
2208 Candidates candidates
2209 = (Candidates) preedit.GetProp (cursor_pos - 1,
2210 MInputMethod.Mcandidates);
2211 if (candidates == null)
2213 column = candidates.Column;
2214 return candidates.Current;
2217 internal void HandleKey ()
2219 MInputMethod.State state = states.Peek ();