2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Reflection;
14 using Xex = System.Xml.Expression.Xexpression;
15 using Mim = MInputMethod;
17 public class MInputMethod
20 public delegate bool Callback (MInputContext ic, MPlist args);
23 public static Callback PreeditStart, PreeditDone, PreeditDraw;
24 public static Callback StatusStart, StatusDone, StatusDraw;
25 public static Callback CandidateStart, CandidateDone, CandidateDraw;
26 public static Callback SetSpot;
27 public static Callback Toggle;
28 public static Callback Reset;
29 public static Callback GetSurroundingText;
30 public static Callback DeleteSurroundingText;
32 internal static Xex.Domain im_domain = new Xex.Domain (null);
33 private static MSymbol Minput_method = "input-method";
34 private static MSymbol Mdescription = "description";
35 private static MSymbol Mvariable = "variable";
36 private static MSymbol Mcommand = "command";
37 private static MSymbol Mmodule = "module";
38 private static MSymbol Mtitle = "title";
39 private static MSymbol Minclude = "include";
40 private static MSymbol Mmacro = "macro";
41 private static MSymbol Mmap = "map";
42 private static MSymbol Mmap_list = "map-list";
43 private static MSymbol Mstate = "state";
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 Mset = "set";
51 private static MSymbol Madd = "add";
52 private static MSymbol Msub = "sub";
53 private static MSymbol Mmul = "mul";
54 private static MSymbol Mdiv = "div";
55 private static MSymbol Mif = "if";
56 private static MSymbol Mcond = "cond";
57 private static MSymbol Mchar_at = "char-at";
58 private static MSymbol Msurrounding_text_p = "surrounding-text-p";
59 private static MSymbol Mpushback = "pushback";
60 private static MSymbol Mkeyseq = "keyseq";
62 private static Xex.Symbol Nprogn = "progn";
63 private static Xex.Term Tnil = new Xex.Term ((Xex.Symbol) "nil");
64 private static Xex.Term Tcatch_tag = new Xex.Term ((Xex.Symbol) "@mimtag");
66 private static Dictionary<MDatabase.Tag, MInputMethod> im_table
67 = new Dictionary<MDatabase.Tag, MInputMethod> ();
69 internal static MInputMethod im_global = null;
72 private enum LoadStatus
82 public enum KeyModifier
88 Control_L = 0x01000000,
89 Control_R = 0x02000000,
105 private static Dictionary<string, uint> keysyms
106 = new Dictionary<string, uint> ();
107 private static Dictionary<string, KeyModifier> keymodifiers
108 = new Dictionary<string, KeyModifier> ();
109 private static uint keysym_base = 0x200000;
110 private static uint char_mask = ~((uint) KeyModifier.All);
114 keysyms["bs"] = keysyms["backspace"] = 0x08;
115 keysyms["tab"] = 0x09;
116 keysyms["lf"] = keysyms["linefeed"] = 0x10;
117 keysyms["cr"] = keysyms["return"] = keysyms["enter"] = 0x13;
118 keysyms["esc"] = keysyms["escape"] = 0x1B;
119 keysyms["spc"] = keysyms["space"] = 0x20;
120 keysyms["del"] = keysyms["delete"] = 0x7F;
121 keymodifiers["shift-l"] = KeyModifier.Shift_L;
122 keymodifiers["shift-r"] = KeyModifier.Shift_R;
123 keymodifiers["shift"] = KeyModifier.Shift;
124 keymodifiers["control-l"] = KeyModifier.Control_L;
125 keymodifiers["control-r"] = KeyModifier.Control_R;
126 keymodifiers["control"] = KeyModifier.Control;
127 keymodifiers["alt-l"] = KeyModifier.Alt_L;
128 keymodifiers["alt-r"] = KeyModifier.Alt_R;
129 keymodifiers["alt"] = KeyModifier.Alt;
130 keymodifiers["altgr"] = KeyModifier.AltGr;
131 keymodifiers["super"] = KeyModifier.Super;
132 keymodifiers["hyper"] = KeyModifier.Hyper;
135 private static uint decode_keysym (MSymbol keysym)
138 string name = keysym.Name;
140 if (name.Length == 1)
142 name = name.ToLower ();
143 if (! keysyms.TryGetValue (name, out key))
144 keysyms[name] = key = keysym_base++;
148 private static uint combine_modifiers (uint c, KeyModifier modifiers)
150 if (c < 0x7F && c != 0x20)
152 if ((modifiers & KeyModifier.Shift) != KeyModifier.None
153 && Char.IsLower ((char) c))
155 modifiers &= ~KeyModifier.Shift;
156 c = Char.ToUpper ((char) c);
158 if ((modifiers & KeyModifier.Control) != KeyModifier.None)
160 modifiers &= ~KeyModifier.Control;
164 return c | (uint) modifiers;
167 public Key (uint c) { key = c; }
168 public Key (int c) { key = (uint) c; }
170 public Key (uint c, KeyModifier modifiers)
172 key = combine_modifiers (c, modifiers);
175 public Key (MSymbol keysym, KeyModifier modifiers)
177 key = combine_modifiers (decode_keysym (keysym), modifiers);
180 public Key (MSymbol keysym)
182 string str = keysym.Name;
183 int len = str.Length;
185 KeyModifier modifiers = KeyModifier.None;
187 for (i = 0; i + 2 < len && str[i + 1] == '-'; i += 2)
190 modifiers |= KeyModifier.Shift;
191 else if (str[i] == 'C')
192 modifiers |= KeyModifier.Control;
193 else if (str[i] == 'A')
194 modifiers |= KeyModifier.Alt;
195 else if (str[i] == 'G')
196 modifiers |= KeyModifier.AltGr;
197 else if (str[i] == 's')
198 modifiers |= KeyModifier.Super;
199 else if (str[i] == 'H')
200 modifiers |= KeyModifier.Hyper;
203 key = combine_modifiers (str[i], modifiers);
205 key = combine_modifiers (decode_keysym (keysym), modifiers);
208 public Key (MPlist plist)
210 KeyModifier modifiers = KeyModifier.None;
213 for (p = plist; ! p.IsEmpty; p = p.next)
217 if (! p.next.IsEmpty)
218 throw new Exception ("Invalid Key: " + plist);
221 else if (! p.IsSymbol)
222 throw new Exception ("Invalid Key: " + plist);
225 string name = p.Symbol.Name.ToLower ();
228 if (! keymodifiers.TryGetValue (name, out m))
233 if (p.IsEmpty || ! p.next.IsEmpty)
234 throw new Exception ("Invalid Key: " + plist);
236 key = combine_modifiers ((uint) p.Integer, modifiers);
238 key = combine_modifiers (decode_keysym (p.Symbol), modifiers);
241 public bool HasModifier
243 get { return ((key & (uint) KeyModifier.All) != 0); }
246 public bool Match (Key k)
250 if ((k.key & char_mask) != (key & char_mask))
252 KeyModifier m1 = ((KeyModifier) key) & KeyModifier.All;
253 KeyModifier m2 = ((KeyModifier) k.key) & KeyModifier.All;
254 return (((m1 & KeyModifier.Shift) == (m2 & KeyModifier.Shift)
255 || ((m1 & KeyModifier.Shift) == KeyModifier.Shift
256 && (m2 & KeyModifier.Shift) != KeyModifier.None))
257 && ((m1 & KeyModifier.Control) == (m2 & KeyModifier.Control)
258 || ((m1 & KeyModifier.Control) == KeyModifier.Control
259 && (m2 & KeyModifier.Control) != KeyModifier.None))
260 && ((m1 & KeyModifier.Alt) == (m2 & KeyModifier.Alt)
261 || ((m1 & KeyModifier.Alt) == KeyModifier.Alt
262 && (m2 & KeyModifier.Alt) != KeyModifier.None))
263 && ((m1 & KeyModifier.High) == (m2 & KeyModifier.High)));
266 public override string ToString ()
268 string str = Char.ToString ((char) key);
269 KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
271 if (m != KeyModifier.None)
273 if ((m & KeyModifier.Shift) != KeyModifier.None)
275 if ((m & KeyModifier.Control) != KeyModifier.None)
277 if ((m & KeyModifier.Alt) != KeyModifier.None)
279 if ((m & KeyModifier.AltGr) != KeyModifier.None)
281 if ((m & KeyModifier.Super) != KeyModifier.None)
283 if ((m & KeyModifier.Hyper) != KeyModifier.None)
290 public class KeySeq : Xex.TermValue
292 public List<Key> keyseq = new List<Key> ();
294 public override Xex.TermValue Clone ()
296 KeySeq ks = new KeySeq ();
297 ks.keyseq.InsertRange (0, keyseq);
303 public KeySeq (MPlist plist)
305 foreach (MPlist p in plist)
308 keyseq.Add (new Key (p.Symbol));
309 else if (p.IsInteger)
310 keyseq.Add (new Key ((char) p.Integer));
312 keyseq.Add (new Key (p.Plist));
314 throw new Exception ("Invalid Key Sequence: " + plist);
318 public KeySeq (MText mt) : base ()
320 for (int i = 0; i < mt.Length; i++)
321 keyseq.Add (new Key ((uint) mt[i]));
324 private static uint parse_integer (string str)
326 if (Char.IsDigit (str[0]))
328 if (str[0] == '0' && str.Length > 2 && str[1] == 'x')
331 for (int idx = 2; idx < str.Length; idx++)
334 if (c >= '0' && c <= '9')
335 i = i * 16 + (c - '0');
336 else if (c >= 'A' && c <= 'F')
337 i = i * 16 + 10 + (c - 'A');
338 else if (c >= 'a' && c <= 'f')
339 i = i * 16 + 10 + (c - 'a');
345 return UInt32.Parse (str);
347 else if (str[0] == '?')
352 public KeySeq (List<Xex.Term> list)
354 int len = list.Count;
356 for (int i = 0; i < len; i++)
359 keyseq.Add (new Key (list[i].Intval));
360 else if (list[i].IsStr)
361 keyseq.Add (new Key (list[i].Strval));
362 else if (list[i].IsSymbol)
363 keyseq.Add (new Key ((string) list[i].Symval));
365 throw new Exception ("Invalid key: " + list[i]);
369 public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
371 Xex.Term term = new Xex.Term (domain, node.FirstChild).Eval (domain);
372 return (term.IsStr ? new KeySeq ((MText) term.Strval)
373 : new KeySeq (term.Listval));
376 public override string ToString ()
380 foreach (Key key in keyseq)
384 foreach (Key k in keyseq)
385 str += " " + k.ToString ();
389 foreach (Key key in keyseq)
390 str += key.ToString ();
395 public class Variable
398 public MText description;
401 public object[] candidates;
403 public Variable (MPlist p)
407 description = parse_description (p);
408 if (description == null)
409 description = new MText ("No description");
412 type = (p.IsMText ? typeof (MText)
413 : p.IsInteger ? typeof (int)
414 : p.IsSymbol ? typeof (MSymbol)
418 candidates = new object[p.Count];
419 for (int i = 0; ! p.IsEmpty; i++, p = p.next)
420 candidates[i] = p.val;
423 private static Type parse_value (XmlNode node, out object value)
425 string typename = node.Attributes["type"].Value;
428 if (typename == "integer")
431 if (! Int32.TryParse (node.InnerText, out i))
436 else if (typename == "string")
438 MText mt = node.InnerText;
440 type = typeof (MText);
442 else if (typename == "symbol")
444 MSymbol sym = node.InnerText;
446 type = typeof (MSymbol);
451 type = typeof (object);
456 public Variable (XmlNode node)
458 name = node.Attributes["id"].Value;
459 for (node = node.FirstChild; node != null; node = node.NextSibling)
460 if (node.NodeType == XmlNodeType.Element)
462 if (node.Name == "description")
463 description = parse_description (node);
464 else if (node.Name == "value")
465 type = parse_value (node, out value);
466 else if (node.Name == "valiable-value-candidate")
468 XmlNodeList n_list = node.ChildNodes;
469 candidates = new object[n_list.Count];
470 for (int i = 0; i < n_list.Count; i++)
473 parse_value (n_list[i], out val);
480 public override string ToString ()
482 return ("(" + name + " \"" + (string) description
483 + "\" " + type + " " + value + " " + candidates + ")");
490 public MText description;
491 public List<KeySeq> keys;
493 public Command (MPlist p)
497 description = parse_description (p);
498 if (description == null)
499 description = "No description";
500 keys = new List<KeySeq> ();
501 Console.WriteLine ("cmd:" + p);
502 for (p = p.next; ! p.IsEmpty; p = p.next)
505 keys.Add (new KeySeq (p.Text));
507 keys.Add (new KeySeq (p.Plist));
511 public Command (XmlNode node)
513 name = node.Attributes[0].Value;
514 keys = new List<KeySeq> ();
515 for (node = node.FirstChild; node != null; node = node.NextSibling)
517 if (node.Name == "description")
518 description = parse_description (node);
519 else if (node.Name == "keyseq")
520 keys.Add ((KeySeq) KeySeq.parser (null, node));
524 public override string ToString ()
526 string str = "(" + name + " \"" + (string) description;
527 foreach (KeySeq keyseq in keys)
533 internal class Plugin
536 private Assembly assembly;
537 private Type plugin_type;
539 public Plugin (string name)
544 public MethodInfo GetMethod (Xex.Symbol name)
546 if (assembly == null)
548 assembly = Assembly.LoadFrom (name + ".dll");
549 plugin_type = assembly.GetType ("M17n.MInputMethod.Plugin");
552 MethodInfo info = plugin_type.GetMethod ((string) name);
554 throw new Exception ("Invalid plugin method: " + name);
558 public override string ToString ()
560 return String.Format ("(module {0}", name);
564 internal class PluginMethod : Xex.Function
566 private Plugin plugin;
567 private MethodInfo method_info;
568 object[] parameters = new object[2];
570 public PluginMethod (Plugin plugin, string name)
571 : base ((Xex.Symbol) name, 0, -1)
573 this.plugin = plugin;
576 public override Xex.Term Call (Xex.Domain domain, Xex.Variable vari,
579 args = (Xex.Term[]) args.Clone ();
580 for (int i = 0; i < args.Length; i++)
582 args[i] = args[i].Eval (domain);
586 if (method_info == null)
587 method_info = plugin.GetMethod (name);
588 parameters[0] = domain.context;
589 parameters[1] = args;
590 return (Xex.Term) method_info.Invoke (null, parameters);
594 internal abstract class Marker : Xex.TermValue
596 private MSymbol name;
598 public Marker (MSymbol name)
603 public abstract int Position (MInputContext ic);
604 public abstract void Mark (MInputContext ic);
606 public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
608 MSymbol name = node.InnerText;
610 return Get ((MInputContext) domain.context, name);
613 public class Named : Marker
617 public Named (MSymbol name) : this (name, 0) { }
619 private Named (MSymbol name, int p) : base (name) { pos = p; }
621 public override int Position (MInputContext ic) { return pos; }
623 public override void Mark (MInputContext ic) { pos = ic.cursor_pos; }
625 public override Xex.TermValue Clone ()
627 return new Named (name, pos);
631 public class Predefined : Marker
633 public Predefined (MSymbol name) : base (name) { }
635 public override int Position (MInputContext ic)
637 switch (name.Name[1]) {
639 case '>': return ic.preedit.Length;
640 case '-': return ic.cursor_pos - 1;
641 case '+': return ic.cursor_pos + 1;
643 if (ic.cursor_pos > 0)
645 int pos = ic.cursor_pos;
647 ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to);
652 if (ic.cursor_pos < ic.preedit.Length - 1)
654 int pos = ic.cursor_pos;
656 ic.preedit.FindProp (Mcandidates, pos, out from, out pos);
659 return ic.preedit.Length;
661 return name.Name[1] - '0';
665 public override void Mark (MInputContext ic)
667 throw new Exception ("Can't set predefined marker: " + name);
670 public override Xex.TermValue Clone ()
672 return new Predefined (name);
676 static internal Dictionary<MSymbol,Predefined> predefined_markers;
680 predefined_markers = new Dictionary<MSymbol,Predefined> ();
681 MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]",
682 "@0", "@1", "@2", "@3", "@4",
683 "@5", "@6", "@7", "@8", "@9" };
684 foreach (MSymbol s in symlist)
685 predefined_markers[s] = new Predefined (s);
688 public static Marker Get (MInputContext ic, MSymbol name)
693 if (predefined_markers.TryGetValue (name, out pred))
695 if (name.Name[0] == '@')
696 throw new Exception ("Invalid marker name: " + name);
697 m = (Marker) ic.markers.Get (name);
700 m = new Named (name);
701 ic.markers.Put (name, m);
707 internal class Candidates
714 public Block (int index, Xex.Term term)
718 Data = (MText) term.Strval;
721 MPlist plist = new MPlist ();
723 foreach (Xex.Term t in term.Listval)
724 p = p.Add (MSymbol.mtext, (MText) t.Strval);
729 public Block (int index, MPlist plist)
734 else if (plist.IsPlist)
737 throw new Exception ("Invalid candidate: " + plist);
742 get { return (Data is MText
743 ? ((MText) Data).Length
744 : ((MPlist) Data).Count); }
747 public object this[int i]
750 if (Data is MText) return ((MText) Data)[i];
751 return ((MPlist) Data)[i];
756 private Block[] blocks;
758 private int index = 0;
759 public object[] group;
761 private bool IsFixed { get { return group != null; } }
764 Block last = blocks[blocks.Length - 1];
765 return last.Index + last.Count; }
769 get { return (IsFixed ? index % group.Length
770 : index - blocks[row].Index); }
773 public object Group {
774 get { return (IsFixed ? group : blocks[row].Data); }
777 public int GroupLength
782 int nitems = group.Length;
783 int start = index - (index % nitems);
785 return (start + nitems <= total ? nitems : total - start);
787 return blocks[row].Count;
791 public object Current {
793 return (IsFixed ? group[index % group.Length]
794 : blocks[row][index - blocks[row].Index]);
798 public Candidates (MPlist list, int column)
800 int nblocks = list.Count;
802 blocks = new Block[nblocks];
803 for (int i = 0, start = 0; i < nblocks; i++, list = list.next)
804 start += (blocks[i] = new Block (index, list)).Count;
806 group = new object[column];
809 public Candidates (List<Xex.Term> list, int column)
811 int nblocks = list.Count;
813 blocks = new Block[nblocks];
814 for (int i = 0, start = 0; i < nblocks; i++)
815 start += (blocks[i] = new Block (index, list[i])).Count;
817 group = new object[column];
820 public static void Detach (MInputContext ic)
822 ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates);
823 ic.candidates = null;
824 ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
828 // Fill the array "group" by candidates stating from INDEX.
829 // INDEX must be a multiple of "column". Set NTIMES to the
830 // number of valid candidates in "group". Update "block" if
831 // necessary. Return "group".
833 private int fill_group (int start)
835 int nitems = group.Length;
840 while (start < b.Index)
843 while (start >= b.Index + b.Count)
849 for (int i = 0; i < nitems; i++, start++)
854 if (r == blocks.Length)
865 // Update "row" to what contains the first candidate of
866 // the previous candidate-group, update "current_index", and
867 // update "group" if necessary. Return the previous
868 // candidate-group. Set NITEMS to the number of valid
869 // candidates contained in that group.
871 public int PrevGroup ()
878 nitems = group.Length;
879 if ((index -= col + nitems) < 0)
880 index = (Total / nitems) * nitems;
881 nitems = fill_group (index);
885 row = row > 0 ? row-- : blocks.Length - 1;
886 nitems = blocks[row].Count;
887 index = blocks[row].Index;
889 index += col < nitems ? col : nitems - 1;
893 public int NextGroup ()
900 nitems = group.Length;
901 if ((index += nitems - col) >= Total)
903 nitems = fill_group (index);
907 row = row < blocks.Length - 1 ? row + 1 : 0;
908 nitems = blocks[row].Count;
909 index = blocks[row].Count;
911 index += col < nitems ? col : nitems - 1;
921 int nitems = PrevGroup ();
922 index += col < nitems - 1 ? col : nitems - 1;
931 int nitems = GroupLength;
933 if (col == nitems - 1)
935 nitems = NextGroup ();
949 index += GroupLength - (Column + 1);
952 public void Select (int col)
954 int maxcol = GroupLength - 1;
957 index = index - Column + col;
961 internal abstract class Selector : Xex.TermValue
963 private Selector () { }
965 public abstract void Select (Candidates candidates);
967 public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
969 MSymbol name = node.InnerText;
972 if (predefined_selectors.TryGetValue (name, out pred))
974 if (name.Name[0] == '@')
975 throw new Exception ("Invalid selector name: " + name);
977 if (! Int32.TryParse (node.InnerText, out index))
978 throw new Exception ("Invalid selector name: " + name);
979 return new Numbered (index);
982 public class Numbered : Selector
986 public Numbered (int index) { this.index = index; }
988 public override void Select (Candidates can)
995 public class Predefined : Selector
999 private Predefined (MSymbol sym) { this.tag = sym.Name[1]; }
1001 public override void Select (Candidates can)
1005 if (sym == Mat_less_than)
1006 candidates.First ();
1007 else if (sym == Mat_greater_than)
1009 else if (sym == Mat_minus)
1011 else if (sym == Mat_plus)
1013 else if (sym == Mat_open_square_bracket)
1014 candidates.PrevGroup ();
1015 else if (sym == Mat_close_square_bracket)
1016 candidates.NextGroup ();
1021 static Predefined predefined_selectors;
1025 predefined_selectors = new Dictionary<MSymbol, Predefined> ();
1026 MSymbol[] symlist = new MSymbol[] { "@<", "@=", "@>", "@-", "@+",
1028 foreach (MSymbol s in symlist)
1029 predefined_markers[s] = new Predefined (s);
1035 public MSymbol name;
1036 public Dictionary<Key, Map> submaps;
1037 public Xex.Term actions;
1039 public void Add (KeySeq keys, int index, Xex.Term actions)
1043 if (submaps == null)
1044 submaps = new Dictionary<Key, Map> ();
1046 submaps.TryGetValue (keys.keyseq[index], out sub);
1049 Key key = keys.keyseq[index];
1050 submaps[key] = sub = new Map ();
1052 if (index + 1 < keys.keyseq.Count)
1053 sub.Add (keys, index + 1, actions);
1055 this.actions = actions;
1058 public Xex.Term Lookup (KeySeq keys, int index)
1062 if (index + 1 == keys.keyseq.Count)
1064 if (submaps.TryGetValue (keys.keyseq[index], out sub))
1065 return sub.Lookup (keys, index + 1);
1069 private void describe (MText mt, KeySeq keyseq)
1071 if (keyseq.keyseq.Count > 0)
1073 mt.Cat (" (").Cat (keyseq.ToString ());
1074 mt.Cat (' ').Cat (actions.ToString ());
1077 if (submaps != null)
1078 foreach (KeyValuePair<Key, Map> kv in submaps)
1080 keyseq.keyseq.Add (kv.Key);
1081 kv.Value.describe (mt, keyseq);
1082 keyseq.keyseq.RemoveAt (keyseq.keyseq.Count - 1);
1086 public override string ToString ()
1088 MText mt = "(" + name.Name;
1089 KeySeq keyseq = new KeySeq ();
1091 describe (mt, keyseq);
1097 internal class State
1099 public MSymbol name;
1101 public MPlist branches = new MPlist ();
1103 public State (MSymbol name)
1108 public override string ToString ()
1110 MText mt = "(" + name.Name;
1113 mt.Cat (" \"" + title + "\"");
1114 for (MPlist p = branches; ! p.IsEmpty; p = p.next)
1115 mt.Cat (" (" + p.Key + " " + (Xex) p.Val + ")");
1116 return (string) mt + ")";
1121 internal Xex.Domain domain = new Xex.Domain (im_domain, null);
1123 private LoadStatus load_status = LoadStatus.None;
1124 private MDatabase.Tag tag;
1125 private MDatabase mdb;
1127 private MText description;
1128 internal MText title;
1129 internal Command[] commands;
1130 internal Xex.Symbol[] var_names;
1131 internal Dictionary<MSymbol, Plugin> plugins;
1132 internal Dictionary<MSymbol, Map> maps;
1133 internal MPlist states;
1135 static MInputMethod ()
1137 im_domain.DefTerm ("keyseq", KeySeq.parser);
1138 im_domain.DefTerm ("marker", Marker.parser);
1139 im_domain.DefTerm ("selector", Selector.parser);
1141 im_domain.DefSubr (Finsert, "insert", true, 1, 1);
1142 im_domain.DefSubr (Finsert_candidates, "candidates", true, 1, -1);
1143 im_domain.DefSubr (Fdelete, "delete", true, 1, 1);
1144 im_domain.DefSubr (Fselect, "select", true, 1, 1);
1145 im_domain.DefSubr (Fshow, "show", true, 0, 0);
1146 im_domain.DefSubr (Fhide, "hide", true, 0, 0);
1147 im_domain.DefSubr (Fmove, "move", true, 1, 1);
1148 im_domain.DefSubr (Fmark, "mark", true, 1, 1);
1149 im_domain.DefSubr (Fpushback, "pushback", true, 1, 1);
1150 im_domain.DefSubr (Fpop, "pop", true, 0, 0);
1151 im_domain.DefSubr (Fundo, "undo", true, 0, 1);
1152 im_domain.DefSubr (Fcommit, "commit", true, 0, 0);
1153 im_domain.DefSubr (Funhandle, "unhandle", true, 0, 0);
1154 im_domain.DefSubr (Fshift, "shift", true, 1, 1);
1155 im_domain.DefSubr (Fmarker, "marker", true, 1, 1);
1156 im_domain.DefSubr (Fchar_at, "char-at", true, 1, 1);
1158 MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
1159 List<MDatabase> list = MDatabase.List (tag);
1160 M17n.DebugPrint ("Found {0} input methods\n", list.Count);
1161 foreach (MDatabase mdb in list)
1162 im_table[mdb.tag] = new MInputMethod (mdb.tag);
1166 private MInputMethod (MDatabase.Tag tag)
1171 // Instance Properties
1172 public MSymbol Language { get { return tag[1]; } }
1173 public MSymbol Name { get { return tag[2]; } }
1174 public MSymbol SubName { get { return tag[3]; } }
1176 public bool Info (out MText description,
1178 out Xex.Variable[] variables,
1179 out Command[] commands)
1181 if ((load_status & LoadStatus.Header) != LoadStatus.Header
1182 && ! load_header ())
1190 description = this.description;
1192 if (var_names == null)
1196 variables = new Xex.Variable[var_names.Length];
1198 foreach (Xex.Symbol name in var_names)
1199 variables[i++] = domain.GetVar (name, false);
1201 commands = this.commands;
1205 public static MInputMethod Find (MSymbol language, MSymbol name)
1207 return Find (language, name, MSymbol.nil);
1210 public static MInputMethod Find (MSymbol language, MSymbol name,
1213 MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
1217 return (im_table.TryGetValue (tag, out im) ? im : null);
1222 return ((load_status == LoadStatus.Full) || load_body ());
1225 public static MInputMethod[] List ()
1227 MInputMethod[] array = new MInputMethod[im_table.Count];
1230 foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
1231 array[i++] = kv.Value;
1235 private bool load_header ()
1237 mdb = MDatabase.Find (tag);
1240 mdb.name_table = Xex.Symbol.Table;
1242 MSymbol format = mdb.Format;
1244 if (format == MSymbol.plist)
1245 load ((MPlist) mdb.Load (Mmap), false);
1248 XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list);
1249 load (doc.DocumentElement, false);
1251 } catch (Exception e) {
1252 Console.WriteLine ("{0}\n", e);
1253 load_status = LoadStatus.Error;
1256 load_status |= LoadStatus.Header;
1260 private bool load_body ()
1262 mdb = MDatabase.Find (tag);
1265 mdb.name_table = Xex.Symbol.Table;
1267 object obj = mdb.Load ();
1269 load ((MPlist) obj, true);
1271 load ((XmlDocument) obj, true);
1272 } catch (Exception e) {
1273 Console.WriteLine (e);
1274 load_status = LoadStatus.Error;
1277 load_status = LoadStatus.Full;
1281 private void load (MPlist plist, bool full)
1283 maps = new Dictionary<MSymbol, Map> ();
1284 states = new MPlist ();
1286 for (; ! plist.IsEmpty; plist = plist.next)
1289 MPlist pl = plist.Plist;
1292 MSymbol sym = pl.Symbol;
1295 if (sym == Mdescription)
1296 description = parse_description (pl);
1297 else if (sym == Mtitle)
1302 else if (sym == Mvariable)
1303 parse_variables (pl);
1304 else if (sym == Mcommand)
1305 parse_commands (pl);
1310 else if (sym == Minclude)
1312 else if (sym == Mmacro)
1314 else if (sym == Mmap)
1316 else if (sym == Mstate)
1321 if (description == null)
1322 description = (MText) "No description";
1324 title = new MText (tag[2].Name);
1325 if (commands == null)
1326 commands = new Command[0];
1331 State state = new State ((MSymbol) "init");
1332 plist = new MPlist ();
1333 foreach (KeyValuePair<MSymbol, Map>kv in maps)
1334 state.branches.Add (kv.Key, null);
1335 states.Add (state.name, state);
1339 private void load (XmlNode node, bool full)
1341 bool skip_header = load_status == LoadStatus.Header;
1343 maps = new Dictionary<MSymbol, Map> ();
1344 states = new MPlist ();
1346 if (node.NodeType == XmlNodeType.Document)
1347 node = node.FirstChild;
1348 while (node.NodeType != XmlNodeType.Element)
1349 node = node.NextSibling;
1350 for (node = node.FirstChild; node != null; node = node.NextSibling)
1352 if (node.NodeType != XmlNodeType.Element)
1356 if (node.Name == "description")
1357 description = parse_description (node);
1358 else if (node.Name == "title")
1359 title = parse_title (node);
1360 else if (node.Name == "variable-list")
1361 parse_variables (node);
1362 else if (node.Name == "command-list")
1363 parse_commands (node);
1367 if (node.Name == "module-list")
1368 parse_plugins (node);
1369 else if (node.Name == "macro-list")
1370 parse_macros (node);
1371 else if (node.Name == "map-list")
1373 else if (node.Name == "state-list")
1374 parse_states (node);
1377 if (description == null)
1378 description = (MText) "No description";
1380 title = new MText (tag[2].Name);
1381 if (commands == null)
1382 commands = new Command[0];
1387 State state = new State ((MSymbol) "init");
1388 foreach (KeyValuePair<MSymbol, Map>kv in maps)
1389 state.branches.Add (kv.Key, null);
1390 states.Add (state.name, state);
1394 private static void transform (MPlist plist)
1396 for (; ! plist.IsEmpty; plist = plist.next)
1400 MPlist p = new MPlist ();
1401 p.Add (MSymbol.symbol, Minsert);
1402 p.Add (MSymbol.mtext, plist.Text);
1403 plist.Set (MSymbol.plist, p);
1405 else if (plist.IsInteger)
1407 MPlist p = new MPlist ();
1408 p.Add (MSymbol.symbol, Minsert);
1409 p.Add (MSymbol.integer, plist.Integer);
1410 plist.Set (MSymbol.plist, p);
1412 else if (plist.IsPlist)
1414 MPlist pl = plist.Plist;
1418 if (pl.Symbol == Madd)
1419 pl.Set (MSymbol.symbol, (MSymbol) "+=");
1420 else if (pl.Symbol == Msub)
1421 pl.Set (MSymbol.symbol, (MSymbol) "-=");
1422 else if (pl.Symbol == Mmul)
1423 pl.Set (MSymbol.symbol, (MSymbol) "*=");
1424 else if (pl.Symbol == Mdiv)
1425 pl.Set (MSymbol.symbol, (MSymbol) "/=");
1426 else if (pl.Symbol == Minsert)
1428 // (insert (CANDIDATES ...))
1429 // => (candidates CANDIDATES ...)
1430 if (pl.next.IsPlist)
1432 pl.Set (MSymbol.symbol, Mcandidates);
1434 MPlist p = pl.Plist;
1435 pl.Set (p.key, p.val);
1436 for (p = p.next; ! p.IsEmpty; p = p.next);
1437 pl.Add (p.key, p.val);
1440 else if (pl.Symbol == Mif)
1444 transform (pl.next);
1446 else if (pl.Symbol == Mcond)
1448 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1451 MPlist p = pl.Plist;
1459 else if (pl.Symbol == Mdelete
1460 || pl.Symbol == Mmove
1461 || pl.Symbol == Mmark)
1466 MSymbol sym = pl.Symbol;
1467 MPlist p = new MPlist ();
1468 p.Add (MSymbol.symbol, Mmarker);
1469 p.Add (MSymbol.symbol, sym);
1470 pl.Set (MSymbol.plist, p);
1473 else if (pl.Symbol == Mpushback)
1477 pl.Plist.Push (MSymbol.symbol, Mkeyseq);
1480 else if (pl.IsMText)
1482 // (CANDIDATES ...) => (candidates CANDIDATES ...)
1483 pl.Push (MSymbol.symbol, Mcandidates);
1486 else if (plist.IsSymbol)
1488 MSymbol sym = plist.Symbol;
1490 if (sym.Name.Length >= 3
1491 && sym.Name[0] == '@'
1492 && (sym.Name[1] == '-' || sym.Name[1] == '+'))
1494 int pos = int.Parse (sym.Name.Substring (1));
1495 MPlist p = new MPlist ();
1499 p.Add (MSymbol.symbol, Msurrounding_text_p);
1503 if (sym.Name[1] == '+')
1505 p.Add (MSymbol.symbol, Mchar_at);
1506 p.Add (MSymbol.integer, pos);
1508 plist.Set (MSymbol.plist, p);
1514 private static MText parse_description (MPlist plist)
1520 plist = plist.Plist;
1521 if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
1522 && plist.next.IsMText)
1523 return plist.next.Text;
1528 private static MText parse_description (XmlNode node)
1530 if (node.HasChildNodes)
1531 node = node.FirstChild;
1532 return node.InnerText;
1535 private static MText parse_title (XmlNode node)
1537 return node.InnerText;
1540 private void new_variable (Xex.Symbol name, string desc, int val,
1541 MPlist pl, Xex.Variable vari)
1549 range = new int[pl.Count * 2];
1550 for (int i = 0; i < range.Length; i++)
1554 MPlist p = pl.Plist;
1556 if (! p.IsInteger || ! p.next.IsInteger)
1557 throw new Exception ("Invalid range: " + p);
1558 range[i * 2] = p.Integer;
1559 range[i * 2 + 1] = p.next.Integer;
1561 else if (pl.IsInteger)
1562 range[i * 2] = range[i * 2 + 1] = pl.Integer;
1564 throw new Exception ("Invalid range: " + pl);
1568 domain.Defvar (new Xex.Variable.Int (name, desc, val, range));
1571 Xex.Term term = new Xex.Term (val);
1573 vari.DefaultValue = term;
1578 private void new_variable (Xex.Symbol name, string desc, MText val,
1579 MPlist pl, Xex.Variable vari)
1587 range = new string[pl.Count * 2];
1588 for (int i = 0; i < range.Length; i++)
1591 range[i] = (string) pl.Text;
1593 throw new Exception ("Invalid range: " + pl);
1597 domain.Defvar (new Xex.Variable.Str (name, desc, (string) val, range));
1600 Xex.Term term = new Xex.Term ((string) val);
1602 vari.DefaultValue = term;
1607 private void new_variable (Xex.Symbol name, string desc, MSymbol val,
1608 MPlist pl, Xex.Variable vari)
1611 Xex.Symbol sym = val.Name;
1617 range = new Xex.Symbol[pl.Count * 2];
1618 for (int i = 0; i < range.Length; i++)
1621 range[i] = pl.Symbol.Name;
1623 throw new Exception ("Invalid range: " + pl);
1627 domain.Defvar (new Xex.Variable.Sym (name, desc, sym, range));
1630 Xex.Term term = new Xex.Term (sym);
1632 vari.DefaultValue = term;
1637 private Xex.Variable get_global_var (Xex.Symbol name)
1639 if (im_global == null || this != im_global)
1641 tag = new MDatabase.Tag (Minput_method, MSymbol.t, MSymbol.nil,
1643 im_global = im_table[tag];
1644 if (! im_global.Open ())
1645 throw new Exception ("Failed to load global");
1647 return im_global.domain.GetVar (name, false);
1650 private void parse_variables (MPlist plist)
1652 var_names = new Xex.Symbol[plist.Count];
1654 for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1656 if (! plist.IsPlist || ! plist.Plist.IsSymbol)
1657 throw new Exception ("Invalid variable: " + plist);
1659 MPlist p = plist.Plist;
1660 Xex.Symbol name = (Xex.Symbol) p.Symbol.Name;
1661 var_names[i] = name;
1663 string desc = (string) parse_description (p);
1664 Xex.Variable vari = get_global_var (name);
1666 domain.Defvar (vari);
1672 new_variable (name, desc, p.Integer, p.next, vari);
1674 new_variable (name, desc, p.Text, p.next, vari);
1675 else if (p.IsSymbol)
1676 new_variable (name, desc, p.Symbol, p.next, vari);
1678 throw new Exception ("Invalid variable type: " + p.val);
1683 private void parse_variables (XmlNode node)
1685 XmlNodeList node_list = node.ChildNodes;
1687 var_names = new Xex.Symbol[node_list.Count];
1688 for (int i = 0; i < node_list.Count; i++)
1690 Xex.Symbol name = node_list[i].Attributes[0].Value;
1691 Xex.Variable vari = get_global_var (name);
1693 domain.Defvar (vari);
1694 domain.Defvar (node_list[i]);
1695 var_names[i] = name;
1699 private void parse_commands (MPlist plist)
1701 commands = new Command[plist.Count];
1703 for (int i = 0; ! plist.IsEmpty; plist = plist.next)
1704 if (plist.IsPlist && plist.Plist.IsSymbol)
1705 commands[i++] = new Command (plist.Plist);
1708 private void parse_commands (XmlNode node)
1710 XmlNodeList node_list = node.ChildNodes;
1712 commands = new Command[node_list.Count];
1713 for (int i = 0; i < node_list.Count; i++)
1715 if (node_list[i].NodeType == XmlNodeType.Element)
1716 commands[i] = new Command (node_list[i]);
1720 private void parse_plugins (MPlist plist)
1722 plugins = new Dictionary<MSymbol, Plugin> ();
1724 for (; ! plist.IsEmpty; plist = plist.Next)
1726 MPlist p = plist.Plist;
1727 MSymbol sym = p.Symbol;
1728 Plugin plugin = new Plugin (sym.Name);
1730 for (p = p.next; ! p.IsEmpty; p = p.next)
1732 Xex.Function func = new PluginMethod (plugin, p.Symbol.Name);
1733 domain.Defun (func);
1738 private void parse_plugins (XmlNode node)
1740 plugins = new Dictionary<MSymbol, Plugin> ();
1742 foreach (XmlNode n in node.ChildNodes)
1744 Plugin plugin = new Plugin (n.Attributes[0].Value);
1745 foreach (XmlNode nn in n.ChildNodes)
1747 Xex.Function func = new PluginMethod (plugin,
1748 nn.Attributes[0].Value);
1749 domain.Defun (func);
1754 private void parse_macros (XmlNode node)
1756 for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1757 if (nn.NodeType == XmlNodeType.Element)
1758 domain.Defun (nn, true);
1759 for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
1760 if (nn.NodeType == XmlNodeType.Element)
1761 domain.Defun (nn, false);
1764 private void parse_maps (XmlNode node)
1768 private void parse_states (XmlNode node)
1772 private void parse_include (MPlist plist)
1774 if (! plist.IsPlist)
1776 MPlist p = plist.Plist;
1777 MSymbol language, name, subname;
1778 language = p.Symbol;
1781 name = subname = MSymbol.nil;
1787 subname = MSymbol.nil;
1792 MInputMethod im = MInputMethod.Find (language, name, subname);
1798 if (! plist.IsSymbol)
1800 MSymbol target_type = plist.Symbol;
1802 MSymbol target_name = MSymbol.nil;
1804 target_name = plist.Symbol;
1805 if (target_type == Mmacro)
1807 if (target_name == MSymbol.nil)
1808 im.domain.CopyFunc (domain);
1810 im.domain.CopyFunc (domain, (Xex.Symbol) target_name.Name);
1812 else if (target_type == Mmap)
1814 if (target_name == MSymbol.nil)
1816 foreach (KeyValuePair<MSymbol, Map> kv in im.maps)
1817 maps[kv.Key] = kv.Value;
1822 if (im.maps.TryGetValue (target_name, out map))
1823 maps[target_name] = map;
1826 else if (target_type == Mstate)
1828 if (target_name == MSymbol.nil)
1830 for (p = im.states; ! p.IsEmpty; p = p.next)
1831 states.Add (p.key, p.val);
1835 object state = im.states.Get (target_name);
1837 states.Add (target_name, state);
1842 private Xex.Term parse_cond (MPlist plist)
1844 Xex.Term[] args = new Xex.Term[plist.Count];
1846 for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1848 if (! plist.IsPlist)
1849 throw new Exception ("Invalid cond args: " + plist);
1850 MPlist p = plist.Plist;
1851 List<Xex.Term> arg = new List<Xex.Term> (parse_action (p));
1852 args[i] = new Xex.Term (arg);
1854 return new Xex.Term (domain, (Xex.Symbol) Mcond.Name, args);
1857 private Xex.Term[] parse_action (MPlist plist)
1859 Xex.Term[] terms = new Xex.Term[plist.Count];
1861 for (int i = 0; ! plist.IsEmpty; i++, plist = plist.next)
1864 terms[i] = new Xex.Term ((Xex.Symbol) plist.Symbol.Name);
1865 else if (plist.IsMText)
1866 terms[i] = new Xex.Term ((string) plist.Text);
1867 else if (plist.IsInteger)
1868 terms[i] = new Xex.Term (plist.Integer);
1869 else if (plist.IsPlist)
1871 MPlist p = plist.Plist;
1873 throw new Exception ("Invalid action: " + p);
1874 MSymbol name = p.Symbol;
1877 terms[i] = parse_cond (p);
1878 else if (name == Mset || name == Madd || name == Msub
1879 || name == Mmul || name == Mdiv)
1882 throw new Exception ("Invalid action: " + p);
1883 Xex.Symbol varname = p.Symbol.Name;
1884 terms[i] = new Xex.Term (domain, (Xex.Symbol) name.Name,
1885 varname, parse_action (p.next));
1888 terms[i] = new Xex.Term (domain, (Xex.Symbol) name.Name,
1892 throw new Exception ("Invalid action: " + plist);
1898 private void parse_macros (MPlist plist)
1900 for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1903 MPlist p = pl.Plist;
1907 domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null, null, true);
1909 for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
1912 MPlist p = pl.Plist;
1917 domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null,
1918 parse_action (p.next), false);
1922 private void parse_maps (MPlist plist)
1924 for (; ! plist.IsEmpty; plist = plist.next)
1927 MPlist pl = plist.Plist;
1931 Map map = new Map ();
1932 map.name = pl.Symbol;
1933 maps[map.name] = map;
1934 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1938 MPlist p = pl.Plist;
1941 keys = new KeySeq (p.Text);
1943 keys = new KeySeq (p.Plist);
1950 new Xex.Term (domain, Nprogn, parse_action (p)));
1955 private void parse_states (MPlist plist)
1957 for (; ! plist.IsEmpty; plist = plist.next)
1960 MPlist pl = plist.Plist;
1971 State state = new State (pl.Symbol);
1972 state.title = title;
1974 states = new MPlist ();
1975 states.Add (state.name, state);
1976 for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
1980 MPlist p = pl.Plist;
1983 MSymbol map_name = p.Symbol;
1985 Xex.Term term = new Xex.Term (domain, Nprogn, parse_action (p));
1986 state.branches.Add (map_name, term);
1991 private static Xex.Term Finsert (Xex.Domain domain, Xex.Variable vari,
1994 ((MInputContext) domain.context).insert (args[0]);
1998 private static Xex.Term Finsert_candidates (Xex.Domain domain,
2002 ((MInputContext) domain.context).insert_candidates (args[0]);
2006 private static Xex.Term Fmarker (Xex.Domain domain, Xex.Variable vari,
2009 MSymbol name = (string) args[0].Symval;
2010 return new Xex.Term (Marker.Get ((MInputContext) domain.context, name));
2013 private static Xex.Term Fchar_at (Xex.Domain domain, Xex.Variable vari,
2016 int c = ((MInputContext) domain.context).char_at (args[0].Intval);
2017 return new Xex.Term (c);
2020 private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
2023 ((MInputContext) domain.context).delete ((int) args[0].Intval);
2027 private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
2030 Selector sel = (Selector) args[0].Objval;
2032 sel.Select (((MInputContext) domain.context).candidates);
2036 private static Xex.Term Fshow (Xex.Domain domain, Xex.Variable vari,
2039 ((MInputContext) domain.context).show ();
2043 private static Xex.Term Fhide (Xex.Domain domain, Xex.Variable vari,
2046 ((MInputContext) domain.context).hide ();
2050 private static Xex.Term Fmove (Xex.Domain domain, Xex.Variable vari,
2054 ((MInputContext) domain.context).move (args[0].Intval);
2057 Marker m = (Marker) args[0].Objval;
2058 MInputContext ic = (MInputContext) domain.context;
2059 ((MInputContext) domain.context).move (m.Position (ic));
2064 private static Xex.Term Fmark (Xex.Domain domain, Xex.Variable vari,
2067 Marker m = (Marker) args[0].Objval;
2068 m.Mark ((MInputContext) domain.context);
2072 private static Xex.Term Fpushback (Xex.Domain domain, Xex.Variable vari,
2075 MInputContext ic = (MInputContext) domain.context;
2078 ic.pushback (args[0].Intval);
2079 else if (args[0].IsStr)
2080 ic.pushback (new KeySeq (args[0].Strval));
2082 ic.pushback ((KeySeq) args[0].Objval);
2086 private static Xex.Term Fpop (Xex.Domain domain, Xex.Variable vari,
2089 ((MInputContext) domain.context).pop ();
2093 private static Xex.Term Fundo (Xex.Domain domain, Xex.Variable vari,
2096 int n = args.Length == 0 ? -2 : args[0].Intval;
2097 ((MInputContext) domain.context).undo (n);
2101 private static Xex.Term Fcommit (Xex.Domain domain, Xex.Variable vari,
2104 ((MInputContext) domain.context).commit ();
2108 private static Xex.Term Funhandle (Xex.Domain domain, Xex.Variable vari,
2111 ((MInputContext) domain.context).commit ();
2112 args = new Xex.Term[2];
2113 args[0] = args[1] = Tcatch_tag;
2114 return Xex.Fthrow (domain, vari, args);
2117 private static Xex.Term Fshift (Xex.Domain domain, Xex.Variable vari,
2120 ((MInputContext) domain.context).shift (args[0].Symval);
2124 public override string ToString ()
2126 string str = (String.Format ("({0} (title \"{1}\")", tag, title));
2127 if (commands != null)
2129 str += " (commands";
2130 foreach (Command cmd in commands)
2134 if (var_names != null)
2136 str += " (variables";
2137 foreach (Xex.Symbol var in var_names)
2141 if (plugins != null)
2144 foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
2145 str += " " + kv.Value;
2149 foreach (KeyValuePair<MSymbol, Map> kv in maps)
2150 str += " " + kv.Value;
2152 foreach (MPlist p in states)
2158 public class MInputContext
2160 internal static Xex.Symbol Ncandidates_group_size = "candidates-group-size";
2161 private static MSymbol Mat_less_than = "@<";
2162 private static MSymbol Mat_greater_than = "@>";
2163 private static MSymbol Mat_minus = "@-";
2164 private static MSymbol Mat_plus = "@+";
2165 private static MSymbol Mat_open_square_bracket = "@[";
2166 private static MSymbol Mat_close_square_bracket = "@]";
2168 public MInputMethod im;
2169 private MText produced;
2170 private bool active;
2171 private MText status;
2172 internal MText preedit;
2173 internal int cursor_pos;
2174 internal Mim.Candidates candidates;
2175 private MPlist candidate_group;
2176 private int candidate_index;
2177 private int candidate_from, candidate_to;
2178 private bool candidate_show;
2180 private Stack<Mim.State> states;
2181 internal Mim.KeySeq keys;
2182 private int key_head;
2183 private int state_key_head;
2184 private object state_var_values;
2185 private int commit_key_head;
2186 private MText state_preedit;
2187 private int state_pos;
2188 internal MPlist markers = new MPlist ();
2189 internal MText preceding_text = new MText ();
2190 internal MText following_text = new MText ();
2191 private bool key_unhandled;
2193 internal Xex.Domain domain;
2196 public enum ChangedStatus
2202 CandidateList = 0x08,
2203 CandidateIndex = 0x10,
2204 CandidateShow = 0x20,
2207 private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList
2208 | ChangedStatus.CandidateIndex
2209 | ChangedStatus.CandidateShow);
2210 private ChangedStatus changed;
2212 public ChangedStatus Changed { get { return changed; } }
2214 public MInputContext (MInputMethod im)
2217 domain = new Xex.Domain (im.domain, this);
2218 states = new Stack<Mim.State> ();
2219 states.Push ((Mim.State) im.states.val);
2220 keys = new Mim.KeySeq ();
2223 private void adjust_markers (int from, int to, object inserted)
2225 int ins = (inserted == null ? 0
2226 : inserted is int ? 1
2227 : ((MText) inserted).Length);
2228 int diff = ins - (to - from);
2230 for (MPlist plist = markers; ! plist.IsEmpty; plist = plist.next)
2232 int pos = plist.Integer;
2236 plist.val = pos + diff;
2241 if (cursor_pos >= to)
2243 else if (cursor_pos > from)
2247 private void preedit_replace (int from, int to, int c)
2249 preedit.Del (from, to);
2250 preedit.Ins (from, c);
2251 adjust_markers (from, to, c);
2254 private void preedit_replace (int from, int to, MText mt)
2256 preedit[from, to] = mt;
2257 adjust_markers (from, to, mt);
2260 internal void insert (Xex.Term arg)
2263 preedit_replace (cursor_pos, cursor_pos, arg.Intval);
2265 preedit_replace (cursor_pos, cursor_pos, new MText (arg.Strval));
2266 changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
2269 private void update_candidate ()
2271 object candidate = candidates.Current;
2273 if (candidate is MText)
2275 preedit_replace (candidate_from, candidate_to, (MText) candidate);
2276 candidate_to = candidate_from + ((MText) candidate).Length;
2280 preedit_replace (candidate_from, candidate_to, (int) candidate);
2281 candidate_to = candidate_from + 1;
2283 preedit.PushProp (candidate_from, candidate_to,
2284 Mim.Mcandidates, this);
2285 cursor_pos = candidate_from;
2286 changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos
2290 internal void insert_candidates (Xex.Term arg)
2293 Xex.Variable v = domain.GetVar (Ncandidates_group_size, false);
2296 column = v.Value.Intval;
2297 candidates = new Mim.Candidates (arg.Listval, column);
2298 candidate_from = candidate_to = cursor_pos;
2299 update_candidate ();
2302 internal void select (int n)
2304 if (candidates != null)
2306 candidates.Select (n);
2307 update_candidate ();
2311 internal int marker (MSymbol sym)
2313 int pos = cursor_pos;
2315 if (sym.Name.Length == 2 && sym.Name[0] == '@')
2317 switch (sym.Name[0])
2319 case '<': pos = 0; break;
2320 case '>': pos = preedit.Length; break;
2321 case '-': pos = cursor_pos - 1; break;
2322 case '+': pos = cursor_pos + 1; break;
2327 preedit.FindProp (Mim.Mcandidates, pos - 1,
2334 if (cursor_pos < preedit.Length - 1)
2337 preedit.FindProp (Mim.Mcandidates, pos,
2341 pos = preedit.Length;
2344 if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
2349 else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
2351 pos = int.Parse (sym.Name.Substring (2));
2355 object val = markers.Get (sym);
2363 internal int char_at (int pos)
2370 if (preceding_text.Length < -pos)
2372 MPlist plist = new MPlist ();
2373 plist.Push (MSymbol.integer, pos);
2374 if (Mim.GetSurroundingText != null
2375 && Mim.GetSurroundingText (this, plist)
2377 && preceding_text.Length < plist.Text.Length)
2378 preceding_text = plist.Text;
2380 c = (-pos < preceding_text.Length
2381 ? preceding_text[preceding_text.Length + pos] : -1);
2383 else if (pos >= 0 && pos < preedit.Length)
2387 pos -= preedit.Length;
2388 if (pos >= following_text.Length)
2390 MPlist plist = new MPlist ();
2391 plist.Push (MSymbol.integer, pos + 1);
2392 if (Mim.GetSurroundingText != null
2393 && Mim.GetSurroundingText (this, plist)
2395 && following_text.Length < plist.Text.Length)
2396 following_text = plist.Text;
2398 c = (pos < following_text.Length ? following_text[pos] : -1);
2403 internal void delete (int pos)
2405 if (pos < cursor_pos)
2406 preedit_replace (pos, cursor_pos, null);
2408 preedit_replace (cursor_pos, pos, null);
2409 changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
2412 internal void show ()
2414 candidate_show = true;
2415 changed |= ChangedStatus.CandidateShow;
2418 internal void hide ()
2420 candidate_show = false;
2421 changed |= ChangedStatus.CandidateShow;
2424 internal void move (int pos)
2428 else if (pos > preedit.Length)
2429 pos = preedit.Length;
2430 if (pos != cursor_pos)
2433 changed |= ChangedStatus.Preedit;
2437 internal void mark (MSymbol sym)
2439 MPlist slot = markers.Find (sym);
2442 markers.Push (sym, cursor_pos);
2444 slot.val = cursor_pos;
2447 internal void pushback (int n)
2460 if (key_head > keys.keyseq.Count)
2461 key_head = keys.keyseq.Count;
2465 internal void pushback (Mim.KeySeq keyseq)
2469 if (key_head < keys.keyseq.Count)
2470 keys.keyseq.RemoveRange (key_head, keys.keyseq.Count - key_head);
2471 for (int i = 0; i < keyseq.keyseq.Count; i++)
2472 keys.keyseq.Add (keyseq.keyseq[i]);
2475 internal void pop ()
2477 if (key_head < keys.keyseq.Count)
2478 keys.keyseq.RemoveRange (key_head, 1);
2481 internal void undo (int n)
2484 keys.keyseq.RemoveRange (keys.keyseq.Count + n, - n);
2486 keys.keyseq.RemoveRange (n, keys.keyseq.Count - n);
2490 internal void commit ()
2492 produced.Cat (preedit);
2494 changed |= ChangedStatus.Preedit;
2497 internal void shift (MSymbol sym)
2501 if (sym == MSymbol.t)
2503 if (states.Count > 1)
2504 state = states.Pop ();
2506 state = states.Peek ();
2510 state = (Mim.State) im.states.Get (sym);
2512 throw new Exception ("Unknown state: " + state.name);
2515 state = states.Pop ();
2516 if (state == (Mim.State) im.states.val)
2523 state_key_head = key_head;
2524 state_pos = cursor_pos;
2525 state_preedit = preedit.Dup ();
2526 if (state != states.Peek ())
2528 states.Push (state);
2529 state_var_values = domain.SaveValues ();
2530 status = state.title;
2533 changed |= ChangedStatus.StateTitle;
2535 = (Xex) state.branches.Get (MSymbol.t);
2536 if (on_entry != null)
2537 on_entry.Eval (domain);
2542 internal void reset ()
2545 state_preedit.Del ();
2549 key_head = commit_key_head = 0;
2551 states.Push ((Mim.State) im.states.Val);
2556 internal object GetCandidates (out int column)
2559 if (cursor_pos == 0)
2561 Mim.Candidates candidates
2562 = (Mim.Candidates) preedit.GetProp (cursor_pos - 1, Mim.Mcandidates);
2563 if (candidates == null)
2565 column = candidates.Column;
2566 return candidates.Current;
2569 internal void HandleKey ()
2573 public bool Toggle ()