using System;
using System.Collections;
using System.Collections.Generic;
+using System.Reflection;
using System.IO;
+using System.Xml;
+
using M17N;
using M17N.Core;
using M17N.Input;
{
public class MInputMethod
{
- private static MSymbol Minput_method = MSymbol.Of ("input-method");
- private static MSymbol Mdescription = MSymbol.Of ("description");
- private static MSymbol Mvariable = MSymbol.Of ("variable");
- private static MSymbol Mcommand = MSymbol.Of ("command");
- private static MSymbol Mtitle = MSymbol.Of ("title");
- private static MSymbol Minclude = MSymbol.Of ("include");
- private static MSymbol Mmacro = MSymbol.Of ("macro");
- private static MSymbol Mmap = MSymbol.Of ("map");
- private static MSymbol Mstate = MSymbol.Of ("state");
- internal static MSymbol Mcandidates = MSymbol.Of ("candidates");
- internal static MSymbol Mcandidates_group_size = MSymbol.Of ("candidates-group-size");
- private static MSymbol Mat_less_than = MSymbol.Of ("@<");
- private static MSymbol Mat_greater_than = MSymbol.Of ("@>");
- private static MSymbol Mat_minus = MSymbol.Of ("@-");
- private static MSymbol Mat_plus = MSymbol.Of ("@+");
- private static MSymbol Mat_open_square_bracket = MSymbol.Of ("@[");
- private static MSymbol Mat_close_square_bracket = MSymbol.Of ("@]");
- private static MSymbol Minsert = MSymbol.Of ("insert");
-
- internal class Variable
- {
- public MSymbol name;
- public MText description;
- public Type type;
- public object value;
- public MPlist candidates;
- }
+ // Delegaes
+ public delegate bool Callback (MInputContext ic, MPlist args);
+
+ // Class members
+ public static Callback PreeditStart, PreeditDone, PreeditDraw;
+ public static Callback StatusStart, StatusDone, StatusDraw;
+ public static Callback CandidateStart, CandidateDone, CandidateDraw;
+ public static Callback SetSpot;
+ public static Callback Toggle;
+ public static Callback Reset;
+ public static Callback GetSurroundingText;
+ public static Callback DeleteSurroundingText;
+
+ internal static MExpression.Domain domain = new MExpression.Domain (null);
+ private static MSymbol Minput_method = "input-method";
+ private static MSymbol Mdescription = "description";
+ private static MSymbol Mvariable = "variable";
+ private static MSymbol Mcommand = "command";
+ private static MSymbol Mmodule = "module";
+ private static MSymbol Mmodule_list = "module-list";
+ private static MSymbol Mtitle = "title";
+ private static MSymbol Minclude = "include";
+ private static MSymbol Mmacro = "macro";
+ private static MSymbol Mmacro_list = "macro-list";
+ private static MSymbol Mmap = "map";
+ private static MSymbol Mmap_list = "map-list";
+ private static MSymbol Mstate = "state";
+ private static MSymbol Mstate_list = "state-list";
+ internal static MSymbol Mcandidates = "candidates";
+ private static MSymbol Minsert = "insert";
+ private static MSymbol Mdelete = "delete";
+ private static MSymbol Mmove = "move";
+ private static MSymbol Mmark = "mark";
+ private static MSymbol Mmarker = "marker";
+ private static MSymbol Madd = "add";
+ private static MSymbol Msub = "sub";
+ private static MSymbol Mmul = "mul";
+ private static MSymbol Mdiv = "div";
+ private static MSymbol Mif = "if";
+ private static MSymbol Mcond = "cond";
+ private static MSymbol Mchar_at = "char-at";
+ private static MSymbol Msurrounding_text_p = "surrounding-text-p";
+ private static MSymbol Mpushback = "pushback";
+ private static MSymbol Mkeyseq = "keyseq";
+
+ private static Dictionary<MDatabase.Tag, MInputMethod> im_table
+ = new Dictionary<MDatabase.Tag, MInputMethod> ();
- internal class Command
+ // Sub classes
+ private class Exception : System.Exception
{
- public MSymbol name;
- public MText description;
- public MSymbol[][] keys;
+ bool error;
+
+ public Exception (string msg) : base (msg)
+ {
+ error = true;
+ }
+
+ public Exception (string fmt, params object[] args)
+ : base (String.Format (fmt, args))
+ {
+ error = true;
+ }
+
+ public Exception (string msg, bool error) : base (msg)
+ {
+ this.error = error;
+ }
}
- internal class KeySeq
+ [FlagsAttribute]
+ private enum LoadStatus
+ {
+ None = 0x00,
+ Header = 0x01,
+ Body = 0x02,
+ Full = 0x03,
+ Error = 0x04,
+ };
+
+ [FlagsAttribute]
+ public enum KeyModifier
+ {
+ None = 0x00000000,
+ Shift_L = 0x00400000,
+ Shift_R = 0x00800000,
+ Shift = 0x00C00000,
+ Control_L = 0x01000000,
+ Control_R = 0x02000000,
+ Control = 0x03000000,
+ Alt_L = 0x04000000,
+ Alt_R = 0x08000000,
+ Alt = 0x0C000000,
+ AltGr = 0x10000000,
+ Super = 0x20000000,
+ Hyper = 0x40000000,
+ High = 0x70000000,
+ All = 0x7FC00000,
+ };
+
+ public struct Key
{
- public MSymbol[] keys;
+ internal uint key;
- private static MSymbol char_to_symbol (int c)
+ private static Dictionary<string, uint> keysyms
+ = new Dictionary<string, uint> ();
+ private static Dictionary<string, KeyModifier> keymodifiers
+ = new Dictionary<string, KeyModifier> ();
+ private static uint keysym_base = 0x200000;
+ private static uint char_mask = ~((uint) KeyModifier.All);
+
+ static Key ()
+ {
+ keysyms["bs"] = keysyms["backspace"] = 0x08;
+ keysyms["tab"] = 0x09;
+ keysyms["lf"] = keysyms["linefeed"] = 0x10;
+ keysyms["cr"] = keysyms["return"] = keysyms["enter"] = 0x13;
+ keysyms["esc"] = keysyms["escape"] = 0x1B;
+ keysyms["spc"] = keysyms["space"] = 0x20;
+ keysyms["del"] = keysyms["delete"] = 0x7F;
+ keymodifiers["shift-l"] = KeyModifier.Shift_L;
+ keymodifiers["shift-r"] = KeyModifier.Shift_R;
+ keymodifiers["shift"] = KeyModifier.Shift;
+ keymodifiers["control-l"] = KeyModifier.Control_L;
+ keymodifiers["control-r"] = KeyModifier.Control_R;
+ keymodifiers["control"] = KeyModifier.Control;
+ keymodifiers["alt-l"] = KeyModifier.Alt_L;
+ keymodifiers["alt-r"] = KeyModifier.Alt_R;
+ keymodifiers["alt"] = KeyModifier.Alt;
+ keymodifiers["altgr"] = KeyModifier.AltGr;
+ keymodifiers["super"] = KeyModifier.Super;
+ keymodifiers["hyper"] = KeyModifier.Hyper;
+ }
+
+ private static uint decode_keysym (MSymbol keysym)
+ {
+ uint key;
+ string name = keysym.Name;
+
+ if (name.Length == 1)
+ return name[0];
+ name = name.ToLower ();
+ if (! keysyms.TryGetValue (name, out key))
+ keysyms[name] = key = keysym_base++;
+ return key;
+ }
+
+ private static uint combine_modifiers (uint c, KeyModifier modifiers)
+ {
+ if (c < 0x7F && c != 0x20)
+ {
+ if ((modifiers & KeyModifier.Shift) != KeyModifier.None
+ && Char.IsLower ((char) c))
+ {
+ modifiers &= ~KeyModifier.Shift;
+ c = Char.ToUpper ((char) c);
+ }
+ if ((modifiers & KeyModifier.Control) != KeyModifier.None)
+ {
+ modifiers &= ~KeyModifier.Control;
+ c &= 0x1F;
+ }
+ }
+ return c | (uint) modifiers;
+ }
+
+ public Key (uint c)
{
- return MSymbol.Of (String.Format ("#{0:X}", c));
+ key = c;
}
- public KeySeq (MPlist plist)
+ public Key (uint c, KeyModifier modifiers)
+ {
+ key = combine_modifiers (c, modifiers);
+ }
+
+ public Key (MSymbol keysym, KeyModifier modifiers)
+ {
+ key = combine_modifiers (decode_keysym (keysym), modifiers);
+ }
+
+ public Key (MSymbol keysym)
+ {
+ string str = keysym.Name;
+ int len = str.Length;
+ int i;
+ KeyModifier modifiers = KeyModifier.None;
+
+ for (i = 0; i + 2 < len && str[i + 1] == '-'; i += 2)
+ {
+ if (str[i] == 'S')
+ modifiers |= KeyModifier.Shift;
+ else if (str[i] == 'C')
+ modifiers |= KeyModifier.Control;
+ else if (str[i] == 'A')
+ modifiers |= KeyModifier.Alt;
+ else if (str[i] == 'G')
+ modifiers |= KeyModifier.AltGr;
+ else if (str[i] == 's')
+ modifiers |= KeyModifier.Super;
+ else if (str[i] == 'H')
+ modifiers |= KeyModifier.Hyper;
+ }
+ if (i + 1 == len)
+ key = combine_modifiers (str[i], modifiers);
+ else
+ key = combine_modifiers (decode_keysym (keysym), modifiers);
+ }
+
+ public Key (MPlist plist)
+ {
+ KeyModifier modifiers = KeyModifier.None;
+ MPlist p;
+
+ for (p = plist; ! p.IsEmpty; p = p.next)
+ {
+ if (p.IsInteger)
+ {
+ if (! p.next.IsEmpty)
+ throw new Exception ("Invalid Key: " + plist);
+ break;
+ }
+ else if (! p.IsSymbol)
+ throw new Exception ("Invalid Key: " + plist);
+ else
+ {
+ string name = p.Symbol.Name.ToLower ();
+ KeyModifier m;
+
+ if (! keymodifiers.TryGetValue (name, out m))
+ break;
+ modifiers |= m;
+ }
+ }
+ if (p.IsEmpty || ! p.next.IsEmpty)
+ throw new Exception ("Invalid Key: " + plist);
+ if (p.IsInteger)
+ key = combine_modifiers ((uint) p.Integer, modifiers);
+ else
+ key = combine_modifiers (decode_keysym (p.Symbol), modifiers);
+ }
+
+ public bool HasModifier
+ {
+ get { return ((key & (uint) KeyModifier.All) != 0); }
+ }
+
+ public bool Match (Key k)
+ {
+ if (k.key == key)
+ return true;
+ if ((k.key & char_mask) != (key & char_mask))
+ return false;
+ KeyModifier m1 = ((KeyModifier) key) & KeyModifier.All;
+ KeyModifier m2 = ((KeyModifier) k.key) & KeyModifier.All;
+ return (((m1 & KeyModifier.Shift) == (m2 & KeyModifier.Shift)
+ || ((m1 & KeyModifier.Shift) == KeyModifier.Shift
+ && (m2 & KeyModifier.Shift) != KeyModifier.None))
+ && ((m1 & KeyModifier.Control) == (m2 & KeyModifier.Control)
+ || ((m1 & KeyModifier.Control) == KeyModifier.Control
+ && (m2 & KeyModifier.Control) != KeyModifier.None))
+ && ((m1 & KeyModifier.Alt) == (m2 & KeyModifier.Alt)
+ || ((m1 & KeyModifier.Alt) == KeyModifier.Alt
+ && (m2 & KeyModifier.Alt) != KeyModifier.None))
+ && ((m1 & KeyModifier.High) == (m2 & KeyModifier.High)));
+ }
+
+ public override string ToString ()
+ {
+ string str = Char.ToString ((char) key);
+ KeyModifier m = ((KeyModifier) key) & KeyModifier.All;
+
+ if (m != KeyModifier.None)
+ {
+ if ((m & KeyModifier.Shift) != KeyModifier.None)
+ str = "S-" + str;
+ if ((m & KeyModifier.Control) != KeyModifier.None)
+ str = "C-" + str;
+ if ((m & KeyModifier.Alt) != KeyModifier.None)
+ str = "A-" + str;
+ if ((m & KeyModifier.AltGr) != KeyModifier.None)
+ str = "G-" + str;
+ if ((m & KeyModifier.Super) != KeyModifier.None)
+ str = "s-" + str;
+ if ((m & KeyModifier.Hyper) != KeyModifier.None)
+ str = "H-" + str;
+ }
+ return str;
+ }
+ }
+
+ public class KeySeq : List<Key>
+ {
+ public KeySeq () : base () { }
+
+ public KeySeq (MPlist plist) : base ()
{
- keys = new MSymbol[plist.Count];
- int i = 0;
foreach (MPlist p in plist)
{
if (p.IsSymbol)
- keys[i++] = p.Symbol;
+ this.Add (new Key (p.Symbol));
else if (p.IsInteger)
- keys[i++] = char_to_symbol (p.Integer);
+ this.Add (new Key ((char) p.Integer));
+ else if (p.IsPlist)
+ this.Add (new Key (p.Plist));
else
- keys[i] = null;
+ throw new Exception ("Invalid Key Sequence: " + plist);
}
}
- public KeySeq (MText mt)
+ public KeySeq (MText mt) : base ()
{
- keys = new MSymbol[mt.Length];
for (int i = 0; i < mt.Length; i++)
- keys[i] = char_to_symbol (mt[i]);
+ this.Add (new Key ((uint) mt[i]));
}
- public MSymbol this[int i] { get { return keys[i]; } }
+ private static uint parse_integer (string str)
+ {
+ if (Char.IsDigit (str[0]))
+ {
+ if (str[0] == '0' && str.Length > 2 && str[1] == 'x')
+ {
+ uint i = 0;
+ for (int idx = 2; idx < str.Length; idx++)
+ {
+ uint c = str[idx];
+ if (c >= '0' && c <= '9')
+ i = i * 16 + (c - '0');
+ else if (c >= 'A' && c <= 'F')
+ i = i * 16 + 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f')
+ i = i * 16 + 10 + (c - 'a');
+ else
+ break;
+ }
+ return i;
+ }
+ return UInt32.Parse (str);
+ }
+ else if (str[0] == '?')
+ return str[1];
+ return 0;
+ }
+
+ public KeySeq (XmlNode node) : base ()
+ {
+ XmlAttributeCollection acol = node.Attributes;
+ XmlNode n;
- public int Length { get { return keys.Length; } }
+ if (acol != null && (n = acol["keys"]) != null)
+ {
+ foreach (char c in n.Value)
+ this.Add (new Key ((uint) c));
+ }
+
+ for (node = node.FirstChild; node != null; node = node.NextSibling)
+ {
+ if (node.Name == "key-event")
+ this.Add (new Key ((MSymbol) node.InnerText));
+ else
+ this.Add (new Key (parse_integer (node.InnerText)));
+ }
+ }
+
+ public override string ToString ()
+ {
+ string str;
+
+ foreach (Key key in this)
+ if (key.HasModifier)
+ {
+ str = "(keyseq";
+ foreach (Key k in this)
+ str += " " + k.ToString ();
+ return str + ")";
+ }
+ str = "\"";
+ foreach (Key key in this)
+ str += key.ToString ();
+ return str + "\"";
+ }
+ }
+
+ public class Variable
+ {
+ public MSymbol name;
+ public MText description;
+ public Type type;
+ public object value;
+ public object[] candidates;
+
+ public Variable (MPlist p)
+ {
+ name = p.Symbol;
+ p = p.Next;
+ description = parse_description (p);
+ if (description == null)
+ description = new MText ("No description");
+ else
+ p = p.next;
+ type = (p.IsMText ? typeof (MText)
+ : p.IsInteger ? typeof (int)
+ : p.IsSymbol ? typeof (MSymbol)
+ : typeof (object));
+ value = p.val;
+ p = p.next;
+ candidates = new object[p.Count];
+ for (int i = 0; ! p.IsEmpty; i++, p = p.next)
+ candidates[i] = p.val;
+ }
+
+ private static Type parse_value (XmlNode node, out object value)
+ {
+ string typename = node.Attributes["type"].Value;
+ Type type;
+
+ if (typename == "integer")
+ {
+ int i;
+ if (! Int32.TryParse (node.InnerText, out i))
+ i = 0;
+ value = i;
+ type = typeof (int);
+ }
+ else if (typename == "string")
+ {
+ MText mt = node.InnerText;
+ value = mt;
+ type = typeof (MText);
+ }
+ else if (typename == "symbol")
+ {
+ MSymbol sym = node.InnerText;
+ value = sym;
+ type = typeof (MSymbol);
+ }
+ else
+ {
+ value = null;
+ type = typeof (object);
+ }
+ return type;
+ }
+
+ public Variable (XmlNode node)
+ {
+ name = node.Attributes["id"].Value;
+ for (node = node.FirstChild; node != null; node = node.NextSibling)
+ if (node.NodeType == XmlNodeType.Element)
+ {
+ if (node.Name == "description")
+ description = parse_description (node);
+ else if (node.Name == "value")
+ type = parse_value (node, out value);
+ else if (node.Name == "valiable-value-candidate")
+ {
+ XmlNodeList n_list = node.ChildNodes;
+ candidates = new object[n_list.Count];
+ for (int i = 0; i < n_list.Count; i++)
+ {
+ object val;
+ parse_value (n_list[i], out val);
+ candidates[i] = val;
+ }
+ }
+ }
+ }
+
+ public override string ToString ()
+ {
+ return ("(" + name + " \"" + (string) description
+ + "\" " + type + " " + value + " " + candidates + ")");
+ }
+ }
+
+ public class Command
+ {
+ public MSymbol name;
+ public MText description;
+ public List<KeySeq> keys;
+
+ public Command (MPlist p)
+ {
+ name = p.Symbol;
+ p = p.Next;
+ description = parse_description (p);
+ if (description == null)
+ description = "No description";
+ keys = new List<KeySeq> ();
+ for (p = p.next; ! p.IsEmpty; p = p.next)
+ {
+ if (p.IsMText)
+ keys.Add (new KeySeq (p.Text));
+ else if (p.IsPlist)
+ keys.Add (new KeySeq (p.Plist));
+ }
+ }
+
+ public Command (XmlNode node)
+ {
+ name = node.Attributes["id"].Value;
+ keys = new List<KeySeq> ();
+ for (node = node.FirstChild; node != null; node = node.NextSibling)
+ {
+ if (node.Name == "description")
+ description = parse_description (node);
+ else if (node.Name == "keyseq")
+ keys.Add (new KeySeq (node));
+ }
+ }
+
+ public override string ToString ()
+ {
+ string str = "(" + name + " \"" + (string) description;
+ foreach (KeySeq keyseq in keys)
+ str += " " + keyseq;
+ return str + ")";
+ }
+ }
+
+ internal class Plugin
+ {
+ public string name;
+ public Assembly assembly;
+ public MPlist methods;
+
+ public override string ToString ()
+ {
+ string str = "(" + name;
+ for (MPlist p = methods; ! p.IsEmpty; p = p.next)
+ str += " " + p.key;
+ return str + ")";
+ }
}
internal class Map
{
public MSymbol name;
- public Dictionary<MSymbol, Map> submaps;
+ public Dictionary<Key, Map> submaps;
public MExpression actions;
public void Add (KeySeq keys, int index, MExpression actions)
Map sub = null;
if (submaps == null)
- submaps = new Dictionary<MSymbol, Map> ();
+ submaps = new Dictionary<Key, Map> ();
else
submaps.TryGetValue (keys[index], out sub);
if (sub == null)
{
- MSymbol sym = keys[index];
- submaps[sym] = sub = new Map ();
+ Key key = keys[index];
+ submaps[key] = sub = new Map ();
}
- if (index + 1 < keys.Length)
+ if (index + 1 < keys.Count)
sub.Add (keys, index + 1, actions);
else
this.actions = actions;
{
Map sub;
- if (index + 1 == keys.Length)
+ if (index + 1 == keys.Count)
return actions;
if (submaps.TryGetValue (keys[index], out sub))
return sub.Lookup (keys, index + 1);
return null;
}
+
+ private void describe (MText mt, KeySeq keyseq)
+ {
+ if (keyseq.Count > 0)
+ {
+ mt.Cat (" (").Cat (keyseq.ToString ());
+ if (actions != null)
+ mt.Cat (' ').Cat (actions.ToString ());
+ mt.Cat (')');
+ }
+ if (submaps != null)
+ foreach (KeyValuePair<Key, Map> kv in submaps)
+ {
+ keyseq.Add (kv.Key);
+ kv.Value.describe (mt, keyseq);
+ keyseq.RemoveAt (keyseq.Count - 1);
+ }
+ }
+
+ public override string ToString ()
+ {
+ MText mt = "(" + name.Name;
+ KeySeq keyseq = new KeySeq ();
+
+ describe (mt, keyseq);
+ mt.Cat (')');
+ return (string) mt;
+ }
}
internal class State
{
public MSymbol name;
public MText title;
- public Dictionary<MSymbol, MExpression> branches
- = new Dictionary<MSymbol, MExpression> ();
- }
+ public MPlist branches = new MPlist ();
- private static Dictionary<MDatabase.Tag, MInputMethod> im_table
- = new Dictionary<MDatabase.Tag, MInputMethod> ();
+ public State (MSymbol name)
+ {
+ this.name = name;
+ }
- private static MExpression.FunctionTable global_table
- = new MExpression.FunctionTable ();
+ public override string ToString ()
+ {
+ MText mt = "(" + name.Name;
- public readonly MSymbol language;
- public readonly MSymbol name;
- public readonly MSymbol subname;
+ if (title != null)
+ mt.Cat (" \"" + title + "\"");
+ for (MPlist p = branches; ! p.IsEmpty; p = p.next)
+ mt.Cat (" (" + p.Key + " " + (MExpression) p.Val + ")");
+ return (string) mt + ")";
+ }
+ }
+
+ // Instance members
+ internal MExpression.Domain local_domain;
+
+ private LoadStatus load_status = LoadStatus.None;
+ private MDatabase.Tag tag;
+ private MDatabase mdb;
- internal MExpression.FunctionTable local_table
- = new MExpression.FunctionTable (global_table);
- internal MDatabase mdb;
- internal MText description;
+ private MText description;
internal MText title;
internal Command[] commands;
internal Variable[] variables;
+ internal Dictionary<MSymbol, Plugin> plugins;
internal MPlist bindings;
- internal Dictionary<MSymbol, Map> maps
- = new Dictionary<MSymbol, Map> ();
- internal State init_state;
- internal Dictionary<MSymbol, State> states
- = new Dictionary<MSymbol, State> ();
- internal MPlist externals;
+ internal Dictionary<MSymbol, Map> maps;
+ internal MPlist states;
static MInputMethod ()
{
- MExpression.Defun (global_table, "insert",
- new MExpression.Evaluator (insert),
- 1, 1, typeof (MExpression));
- MExpression.Defun (global_table, "candidates",
- new MExpression.Evaluator (insert_candidates),
- 1, 1, typeof (object));
- MExpression.Defun (global_table, "delete",
- new MExpression.Evaluator (delete),
- 1, 1, typeof (object));
- MExpression.Defun (global_table, "select",
- new MExpression.Evaluator (select),
- 1, 1, typeof (object));
- MExpression.Defun (global_table, "show",
- new MExpression.Evaluator (show),
- 0, 0);
- MExpression.Defun (global_table, "hide",
- new MExpression.Evaluator (hide),
- 0, 0);
- MExpression.Defun (global_table, "move",
- new MExpression.Evaluator (move),
- 1, 1, typeof (object));
- MExpression.Defun (global_table, "mark",
- new MExpression.Evaluator (mark),
- 1, 1, typeof (MSymbol));
- MExpression.Defun (global_table, "pushback",
- new MExpression.Evaluator (pushback),
- 1, 1, typeof (object));
- MExpression.Defun (global_table, "pop",
- new MExpression.Evaluator (pop),
- 0, 0);
- MExpression.Defun (global_table, "undo",
- new MExpression.Evaluator (undo),
- 0, 1, typeof (object));
- MExpression.Defun (global_table, "commit",
- new MExpression.Evaluator (commit),
- 0, 0);
- MExpression.Defun (global_table, "unhandle",
- new MExpression.Evaluator (unhandle),
- 0, 0);
- MExpression.Defun (global_table, "shift",
- new MExpression.Evaluator (shift),
- 1, 1, typeof (MSymbol));
- MExpression.Defun (global_table, "call",
- new MExpression.Evaluator (call),
- 2, -1, typeof (MSymbol), typeof (MSymbol),
- typeof (object));
+ domain.Defun ("insert", insert, 1, 1);
+ domain.Defun ("candidates", insert_candidates, 1, -1);
+ domain.Defun ("delete", delete, 1, 1);
+ domain.Defun ("select", select, 1, 1);
+ domain.Defun ("show", show, 0, 0);
+ domain.Defun ("hide", hide, 0, 0);
+ domain.Defun ("move", move, 1, 1);
+ domain.Defun ("mark", mark, 1, 1, true);
+ domain.Defun ("pushback", pushback, 1, 1);
+ domain.Defun ("pop", pop, 0, 0);
+ domain.Defun ("undo", undo, 0, 1);
+ domain.Defun ("commit", commit, 0, 0);
+ domain.Defun ("unhandle", unhandle, 0, 0);
+ domain.Defun ("shift", shift, 1, 1, true);
+ domain.Defun ("call", call, 2, -1, true);
+ // Pseudo functions to make arguments of special objects.
+ domain.Defun ("marker", marker, 1, 1, true);
+ domain.Defun ("char-at", char_at, 1, 1, true);
+ domain.Defun ("keyseq", keyseq, 1, -1, true);
+
+ MDatabase.Tag tag = new MDatabase.Tag (Minput_method, "*", "*", "*");
+ List<MDatabase> list = MDatabase.List (tag);
+ M17n.DebugPrint ("Found {0} input methods\n", list.Count);
+ foreach (MDatabase mdb in list)
+ im_table[mdb.tag] = new MInputMethod (mdb.tag);
}
+ // Constructor
private MInputMethod (MDatabase.Tag tag)
{
+ this.tag = tag;
+ }
+
+ // Instance Properties
+ public MSymbol Language { get { return tag[1]; } }
+ public MSymbol Name { get { return tag[2]; } }
+ public MSymbol SubName { get { return tag[3]; } }
+
+ public bool Info (out MText description, out MText title,
+ out Variable[] variables, out Command[] commands)
+ {
+ if ((load_status & LoadStatus.Header) != LoadStatus.Header
+ && ! load_header ())
+ {
+ description = null;
+ title = null;
+ variables = null;
+ commands = null;
+ return false;
+ }
+ description = this.description;
+ title = this.title;
+ variables = this.variables;
+ commands = this.commands;
+ return true;
+ }
+
+ public static MInputMethod Find (MSymbol language, MSymbol name)
+ {
+ return Find (language, name, MSymbol.nil);
+ }
+
+ public static MInputMethod Find (MSymbol language, MSymbol name,
+ MSymbol subname)
+ {
+ MDatabase.Tag tag = new MDatabase.Tag (Minput_method, language,
+ name, subname);
+ MInputMethod im;
+
+ return (im_table.TryGetValue (tag, out im) ? im : null);
+ }
+
+ public bool Open ()
+ {
+ return ((load_status == LoadStatus.Full) || load_body ());
+ }
+
+ public static MInputMethod[] List ()
+ {
+ MInputMethod[] array = new MInputMethod[im_table.Count];
+ int i = 0;
+
+ foreach (KeyValuePair<MDatabase.Tag, MInputMethod> kv in im_table)
+ array[i++] = kv.Value;
+ return array;
+ }
+
+ private bool load_header ()
+ {
mdb = MDatabase.Find (tag);
if (mdb == null)
- throw new Exception (String.Format ("Input method {0} not available",
- tag));
- language = tag[1];
- name = tag[2];
- subname = tag[3];
- MPlist plist = (MPlist) mdb.Load ();
- if (plist == null)
- return;
+ return false;
+ try {
+ MSymbol format = mdb.Format;
+
+ if (format == MSymbol.plist)
+ load ((MPlist) mdb.Load (Mmap), false);
+ else
+ {
+ XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list);
+ load (doc.DocumentElement, false);
+ }
+ } catch (Exception e) {
+ Console.WriteLine ("{0}\n", e);
+ load_status = LoadStatus.Error;
+ return false;
+ }
+ load_status |= LoadStatus.Header;
+ return true;
+ }
+
+ private bool load_body ()
+ {
+ local_domain = new MExpression.Domain (domain, null);
+ mdb = MDatabase.Find (tag);
+ if (mdb == null)
+ return false;
+ try {
+ object obj = mdb.Load ();
+ if (obj is MPlist)
+ load ((MPlist) obj, true);
+ else
+ load ((XmlDocument) obj, true);
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ load_status = LoadStatus.Error;
+ return false;
+ }
+ load_status = LoadStatus.Full;
+ return true;
+ }
+
+ private void load (MPlist plist, bool full)
+ {
+ maps = new Dictionary<MSymbol, Map> ();
+ states = new MPlist ();
+
for (; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist)
{
if (pl.IsSymbol)
{
MSymbol sym = pl.Symbol;
+
pl = pl.next;
if (sym == Mdescription)
{
parse_variables (pl);
else if (sym == Mcommand)
parse_commands (pl);
- else if (sym == Minclude)
- parse_include (pl);
- else if (sym == Mmacro)
- parse_macros (pl);
- else if (sym == Mmap)
- parse_maps (pl);
- else if (sym == Mstate)
- parse_states (pl);
+ else if (full)
+ {
+ if (sym == Mmodule)
+ parse_plugins (pl);
+ else if (sym == Minclude)
+ parse_include (pl);
+ else if (sym == Mmacro)
+ parse_macros (pl);
+ else if (sym == Mmap)
+ parse_maps (pl);
+ else if (sym == Mstate)
+ parse_states (pl);
+ }
}
}
+ if (description == null)
+ description = (MText) "No description";
+ if (title == null)
+ title = new MText (tag[2].Name);
+ if (variables == null)
+ variables = new Variable[0];
+ if (commands == null)
+ commands = new Command[0];
+ if (! full)
+ return;
+ if (states.IsEmpty)
+ {
+ State state = new State ((MSymbol) "init");
+ plist = new MPlist ();
+ foreach (KeyValuePair<MSymbol, Map>kv in maps)
+ state.branches.Add (kv.Key, new MExpression (plist, local_domain));
+ states.Add (state.name, state);
+ }
+ }
+
+ private void load (XmlNode node, bool full)
+ {
+ bool skip_header = load_status == LoadStatus.Header;
+
+ maps = new Dictionary<MSymbol, Map> ();
+ states = new MPlist ();
+
+ if (node.NodeType == XmlNodeType.Document)
+ node = node.FirstChild;
+ while (node.NodeType != XmlNodeType.Element)
+ node = node.NextSibling;
+ for (node = node.FirstChild; node != null; node = node.NextSibling)
+ {
+ if (node.NodeType != XmlNodeType.Element)
+ continue;
+ if (! skip_header)
+ {
+ if (node.Name == "description")
+ description = parse_description (node);
+ else if (node.Name == "title")
+ title = parse_title (node);
+ else if (node.Name == "variable-list")
+ parse_variables (node);
+ else if (node.Name == "command-list")
+ parse_commands (node);
+ }
+ else if (full)
+ {
+ if (node.Name == "module-list")
+ parse_plugins (node);
+ else if (node.Name == "macro-list")
+ parse_macros (node);
+ else if (node.Name == "map-list")
+ parse_maps (node);
+ else if (node.Name == "state-list")
+ parse_states (node);
+ }
+ }
+ if (description == null)
+ description = (MText) "No description";
+ if (title == null)
+ title = new MText (tag[2].Name);
+ if (variables == null)
+ variables = new Variable[0];
+ if (commands == null)
+ commands = new Command[0];
+ if (! full)
+ return;
+ if (states.IsEmpty)
+ {
+ State state = new State ((MSymbol) "init");
+ MPlist plist = new MPlist ();
+ foreach (KeyValuePair<MSymbol, Map>kv in maps)
+ state.branches.Add (kv.Key, new MExpression (plist, local_domain));
+ states.Add (state.name, state);
+ }
+ }
+
+ private static void transform (MPlist plist)
+ {
+ for (; ! plist.IsEmpty; plist = plist.next)
+ {
+ if (plist.IsMText)
+ {
+ MPlist p = new MPlist ();
+ p.Add (MSymbol.symbol, Minsert);
+ p.Add (MSymbol.mtext, plist.Text);
+ plist.Set (MSymbol.plist, p);
+ }
+ else if (plist.IsInteger)
+ {
+ MPlist p = new MPlist ();
+ p.Add (MSymbol.symbol, Minsert);
+ p.Add (MSymbol.integer, plist.Integer);
+ plist.Set (MSymbol.plist, p);
+ }
+ else if (plist.IsPlist)
+ {
+ MPlist pl = plist.Plist;
+
+ if (pl.IsSymbol)
+ {
+ if (pl.Symbol == Madd)
+ pl.Set (MSymbol.symbol, (MSymbol) "+=");
+ else if (pl.Symbol == Msub)
+ pl.Set (MSymbol.symbol, (MSymbol) "-=");
+ else if (pl.Symbol == Mmul)
+ pl.Set (MSymbol.symbol, (MSymbol) "*=");
+ else if (pl.Symbol == Mdiv)
+ pl.Set (MSymbol.symbol, (MSymbol) "/=");
+ else if (pl.Symbol == Minsert)
+ {
+ // (insert (CANDIDATES ...))
+ // => (candidates CANDIDATES ...)
+ if (pl.next.IsPlist)
+ {
+ pl.Set (MSymbol.symbol, Mcandidates);
+ pl = pl.next;
+ MPlist p = pl.Plist;
+ pl.Set (p.key, p.val);
+ for (p = p.next; ! p.IsEmpty; p = p.next);
+ pl.Add (p.key, p.val);
+ }
+ }
+ else if (pl.Symbol == Mif)
+ {
+ pl = pl.next;
+ if (! pl.IsEmpty)
+ transform (pl.next);
+ }
+ else if (pl.Symbol == Mcond)
+ {
+ for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
+ if (pl.IsPlist)
+ {
+ MPlist p = pl.Plist;
+
+ if (p.IsPlist)
+ transform (p);
+ else
+ transform (p.next);
+ }
+ }
+ else if (pl.Symbol == Mdelete
+ || pl.Symbol == Mmove
+ || pl.Symbol == Mmark)
+ {
+ pl = pl.next;
+ if (pl.IsSymbol)
+ {
+ MSymbol sym = pl.Symbol;
+ MPlist p = new MPlist ();
+ p.Add (MSymbol.symbol, Mmarker);
+ p.Add (MSymbol.symbol, sym);
+ pl.Set (MSymbol.plist, p);
+ }
+ }
+ else if (pl.Symbol == Mpushback)
+ {
+ pl = pl.next;
+ if (pl.IsPlist)
+ pl.Plist.Push (MSymbol.symbol, Mkeyseq);
+ }
+ }
+ else if (pl.IsMText)
+ {
+ // (CANDIDATES ...) => (candidates CANDIDATES ...)
+ pl.Push (MSymbol.symbol, Mcandidates);
+ }
+ }
+ else if (plist.IsSymbol)
+ {
+ MSymbol sym = plist.Symbol;
+
+ if (sym.Name.Length >= 3
+ && sym.Name[0] == '@'
+ && (sym.Name[1] == '-' || sym.Name[1] == '+'))
+ {
+ int pos = int.Parse (sym.Name.Substring (1));
+ MPlist p = new MPlist ();
+
+ if (pos == 0)
+ {
+ p.Add (MSymbol.symbol, Msurrounding_text_p);
+ }
+ else
+ {
+ if (sym.Name[1] == '+')
+ pos--;
+ p.Add (MSymbol.symbol, Mchar_at);
+ p.Add (MSymbol.integer, pos);
+ }
+ plist.Set (MSymbol.plist, p);
+ }
+ }
+ }
}
private static MText parse_description (MPlist plist)
{
- return (plist.IsMText ? plist.Text
- : plist.IsPlist && plist.Plist.IsMText ? plist.Plist.Text
- : null);
+ if (plist.IsMText)
+ return plist.Text;
+ if (plist.IsPlist)
+ {
+ plist = plist.Plist;
+ if (plist.IsSymbol && plist.Symbol == (MSymbol) "_"
+ && plist.next.IsMText)
+ return plist.next.Text;
+ }
+ return null;
+ }
+
+ private static MText parse_description (XmlNode node)
+ {
+ if (node.HasChildNodes)
+ node = node.FirstChild;
+ return node.InnerText;
+ }
+
+ private static MText parse_title (XmlNode node)
+ {
+ return node.InnerText;
}
private void parse_variables (MPlist plist)
for (int i = 0; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist && plist.Plist.IsSymbol)
- {
- Variable var = new Variable ();
- MPlist p = plist.Plist;
-
- var.name = p.Symbol;
- p = p.Next;
- var.description = parse_description (p);
- if (var.description == null)
- var.description = new MText ("No description");
- else
- p = p.next;
- var.type = (p.IsMText ? typeof (MText)
- : p.IsInteger ? typeof (int)
- : p.IsSymbol ? typeof (MSymbol)
- : typeof (object));
- var.value = p.val;
- var.candidates = p.next;
- variables[i++] = var;
- }
+ variables[i++] = new Variable (plist.Plist);
+ }
+
+ private void parse_variables (XmlNode node)
+ {
+ XmlNodeList node_list = node.ChildNodes;
+
+ variables = new Variable[node_list.Count];
+ for (int i = 0; i < node_list.Count; i++)
+ if (node_list[i].NodeType == XmlNodeType.Element)
+ variables[i] = new Variable (node_list[i]);
}
private void parse_commands (MPlist plist)
for (int i = 0; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist && plist.Plist.IsSymbol)
+ commands[i++] = new Command (plist.Plist);
+ }
+
+ private void parse_commands (XmlNode node)
+ {
+ XmlNodeList node_list = node.ChildNodes;
+
+ commands = new Command[node_list.Count];
+ for (int i = 0; i < node_list.Count; i++)
+ {
+ if (node_list[i].NodeType == XmlNodeType.Element)
+ commands[i] = new Command (node_list[i]);
+ }
+ }
+
+ private void parse_plugins (MPlist plist)
+ {
+ plugins = new Dictionary<MSymbol, Plugin> ();
+
+ for (; ! plist.IsEmpty; plist = plist.Next)
+ {
+ MPlist p = plist.Plist;
+ MSymbol sym = p.Symbol;
+ Plugin plugin = new Plugin ();
+
+ plugin.name = sym.Name;
+ plugin.methods = new MPlist ();
+ for (p = p.next; ! p.IsEmpty; p = p.next)
+ plugin.methods.Add (p.Symbol, null);
+ plugins.Add (sym, plugin);
+ }
+ }
+
+ private void parse_plugins (XmlNode node)
+ {
+ plugins = new Dictionary<MSymbol, Plugin> ();
+
+ foreach (XmlNode n in node.ChildNodes)
+ {
+ Plugin plugin = new Plugin ();
+ plugin.name = n.Attributes["id"].Value;
+ plugin.methods = new MPlist ();
+ foreach (XmlNode nn in n.ChildNodes)
+ plugin.methods.Add ((MSymbol) nn.Attributes["id"].Value,
+ null);
+ plugins.Add (plugin.name, plugin);
+ }
+ }
+
+ private void parse_macros (XmlNode node)
+ {
+ for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
+ if (nn.NodeType == XmlNodeType.Element
+ && nn.Name == "xi:include")
{
- Command cmd = new Command ();
- MPlist p = plist.Plist;
-
- cmd.name = p.Symbol;
- p = p.Next;
- cmd.description = parse_description (p);
- if (cmd.description == null)
- cmd.description = new MText ("No description");
+ XmlNode n = nn.FirstChild.FirstChild;
+ MSymbol language = n.InnerText;
+ n = n.NextSibling;
+ MSymbol name = n.InnerText;
+ n = n.NextSibling;
+ MSymbol subname = (n != null ? n.InnerText : MSymbol.nil);
+ n = n.ParentNode.NextSibling;
+ MSymbol section = n.InnerText;
+ n = n.NextSibling;
+ MSymbol id = (n != null ? n.InnerText : MSymbol.nil);
+
+ MInputMethod im = MInputMethod.Find (language, name, subname);
+ if (im == null || ! im.Open ())
+ continue;
+ if (id == MSymbol.nil)
+ im.local_domain.CopyFunc (local_domain);
else
- p = p.next;
- KeySeq[] keys = new KeySeq[p.Count];
- for (int j = 0; ! p.IsEmpty; p = p.next)
- {
- if (p.IsMText)
- keys[j++] = new KeySeq (p.Text);
- else if (p.IsPlist)
- keys[j++] = new KeySeq (p.Plist);
- }
- commands[i++] = cmd;
+ im.local_domain.CopyFunc (local_domain, id);
}
+ for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
+ if (nn.NodeType == XmlNodeType.Element
+ && nn.Name != "xi:include")
+ local_domain.Defun ((MSymbol) node.GetAttribute ("id"));
+ for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling)
+ if (nn.NodeType == XmlNodeType.Element
+ && nn.Name != "xi:include")
+ local_domain.Defun ((MSymbol) node.GetAttribute ("id"), null,
+ nn.FirstChild);
+ }
+
+ private void parse_maps (XmlNode node)
+ {
+ }
+
+ private void parse_states (XmlNode node)
+ {
}
private void parse_include (MPlist plist)
if (! plist.IsPlist)
return;
MPlist p = plist.Plist;
- MSymbol language, name, extra;
+ MSymbol language, name, subname;
language = p.Symbol;
p = p.next;
if (! p.IsSymbol)
- name = extra = MSymbol.nil;
+ name = subname = MSymbol.nil;
else
{
name = p.Symbol;
p = p.next;
if (! p.IsSymbol)
- extra = MSymbol.nil;
+ subname = MSymbol.nil;
else
- extra = p.Symbol;
+ subname = p.Symbol;
}
- MInputMethod im = MInputMethod.Get (language, name, extra);
+ MInputMethod im = MInputMethod.Find (language, name, subname);
if (im == null)
return;
+ if (! im.Open ())
+ return;
plist = plist.next;
if (! plist.IsSymbol)
return;
if (target_type == Mmacro)
{
if (target_name == MSymbol.nil)
- im.local_table.Copy (local_table);
+ im.local_domain.CopyFunc (local_domain);
else
- im.local_table.Copy (target_name, local_table);
+ im.local_domain.CopyFunc (local_domain, target_name);
}
else if (target_type == Mmap)
{
{
if (target_name == MSymbol.nil)
{
- foreach (KeyValuePair<MSymbol, State> kv in im.states)
- states[kv.Key] = kv.Value;
+ for (p = im.states; ! p.IsEmpty; p = p.next)
+ states.Add (p.key, p.val);
}
else
{
- State state;
- if (im.states.TryGetValue (target_name, out state))
- states[target_name] = state;
- }
- }
- }
-
- private void parse_macros (MPlist plist)
- {
- for (; ! plist.IsEmpty; plist = plist.next)
- if (plist.IsPlist)
- {
- MPlist pl = plist.Plist;
-
- if (! pl.IsSymbol)
- continue;
- MSymbol name = pl.Symbol;
- MExpression expr = new MExpression (pl.next, local_table);
- MExpression.Defmacro (local_table, name, expr);
- }
- }
-
- private static void regulalize_command (MPlist plist)
- {
- if (plist.IsSymbol)
- {
- MSymbol sym = plist.Symbol;
-
- if (sym == MSymbol.Of ("add"))
- plist.val = MSymbol.Of ("+=");
- regulalize_actions (plist.next);
- }
- }
-
- private static void regulalize_actions (MPlist plist)
- {
- for (; ! plist.IsEmpty; plist = plist.next)
- {
- if (plist.IsMText)
- {
- MText mt = plist.Text;
- MPlist p = new MPlist ();
- p.Add (MSymbol.symbol, Minsert);
- p.Add (MSymbol.mtext, mt);
- plist.key = MSymbol.plist;
- plist.val = p;
- }
- else if (plist.IsInteger)
- {
- int c = plist.Integer;
- MPlist p = new MPlist ();
- p.Add (MSymbol.symbol, Minsert);
- p.Add (MSymbol.integer, c);
- plist.key = MSymbol.plist;
- plist.val = p;
- }
- else if (plist.IsPlist)
- {
-
+ object state = im.states.Get (target_name);
+ if (state != null)
+ states.Add (target_name, state);
}
}
}
+ private void parse_macros (MPlist plist)
+ {
+ for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
+ if (pl.IsPlist)
+ {
+ MPlist p = pl.Plist;
+
+ if (! p.IsSymbol)
+ continue;
+ local_domain.Defun (p.Symbol, null, null);
+ }
+ for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
+ if (pl.IsPlist)
+ {
+ MPlist p = pl.Plist;
+
+ if (! p.IsSymbol)
+ continue;
+ transform (p.next);
+ local_domain.Defun (p.Symbol, null, p.next);
+ }
+ }
+
private void parse_maps (MPlist plist)
{
for (; ! plist.IsEmpty; plist = plist.next)
keys = new KeySeq (p.Plist);
else
continue;
- if (keys.keys.Length == 0
- && keys.keys[0] == null)
- continue;
p = p.next;
if (p.IsEmpty)
continue;
- regulalize_actions (p);
- MExpression expr = new MExpression (p, local_table);
+ transform (p);
+ MExpression expr = new MExpression (p, local_domain);
map.Add (keys, 0, expr);
}
}
if (! pl.IsSymbol)
continue;
- State state = new State ();
- state.name = pl.Symbol;
+ State state = new State (pl.Symbol);
state.title = title;
- states[state.name] = state;
- if (init_state == null)
- init_state = state;
+ if (states == null)
+ states = new MPlist ();
+ states.Add (state.name, state);
for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
{
if (! pl.IsPlist)
continue;
MSymbol map_name = p.Symbol;
p = p.next;
- if (! p.IsEmpty)
- regulalize_actions (p);
- state.branches[map_name]
- = new MExpression (p, local_table);
+ transform (p);
+ state.branches.Add (map_name,
+ new MExpression (p, local_domain));
}
}
}
- public static MInputMethod Get (MSymbol language, MSymbol name,
- MSymbol extra)
+ private static object insert (MExpression[] args, MExpression.Domain domain)
{
- MDatabase.Tag tag
- = new MDatabase.Tag (Minput_method, language, name, extra);
- MInputMethod im;
- if (im_table.TryGetValue (tag, out im))
- return im;
- try {
- im = new MInputMethod (tag);
- } catch (Exception e) {
- Console.WriteLine (e);
- im = null;
- }
- return im;
+ ((MInputContext) domain.context).insert (args[0].Val);
+
+ return true;
+ }
+
+ private static object insert_candidates (MExpression[] args,
+ MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).insert_candidates ((MPlist) args[0].Val);
+
+ return true;
+ }
+
+ private static object marker (MExpression[] args, MExpression.Domain domain)
+ {
+ MSymbol sym = (MSymbol) args[0].Args[0].Val;
+
+ return ((MInputContext) domain.context).marker (sym);
+ }
+
+ private static object char_at (MExpression[] args,
+ MExpression.Domain domain)
+ {
+ return ((MInputContext) domain.context).char_at ((int) args[0].Val);
+ }
+
+ private static object delete (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).delete ((int) args[0].Val);
+ return true;
+ }
+
+ private static object select (MExpression[] args, MExpression.Domain domain)
+ {
+ MInputContext ic = (MInputContext) domain.context;
+ object val = args[0].Val;
+
+ if (val is int)
+ ic.select ((int) val);
+ else
+ ic.select ((MSymbol) val);
+ return true;
+ }
+
+ private static object show (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).show ();
+
+ return true;
+ }
+
+ private static object hide (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).hide ();
+
+ return true;
+ }
+
+ private static object move (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).move ((int) args[0].Val);
+
+ return true;
+ }
+
+ private static object mark (MExpression[] args, MExpression.Domain domain)
+ {
+ MSymbol sym = (MSymbol) args[0].Val;
+
+ ((MInputContext) domain.context).mark (sym);
+ return true;
+ }
+
+ private static object keyseq (MExpression[] args, MExpression.Domain domain)
+ {
+ MPlist p = new MPlist ();
+
+ for (int i = 0; i < args.Length; i++)
+ p.Add (MSymbol.symbol, (MSymbol) args[i].Val);
+ return new KeySeq (p);
+ }
+
+ private static object pushback (MExpression[] args,
+ MExpression.Domain domain)
+ {
+ MInputContext ic = (MInputContext) domain.context;
+ object val = args[0].Val;
+
+ if (val is int)
+ ic.pushback ((int) val);
+ else if (val is MText)
+ ic.pushback (new KeySeq ((MText) val));
+ else if (val is KeySeq)
+ ic.pushback ((KeySeq) val);
+ else
+ throw new Exception ("Invalid keyseq: " + val);
+ return true;
+ }
+
+ private static object pop (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).pop ();
+ return true;
+ }
+
+ private static object undo (MExpression[] args, MExpression.Domain domain)
+ {
+ int n = args.Length == 0 ? -2 : (int) args[0].Val;
+ ((MInputContext) domain.context).undo (n);
+ return true;
+ }
+
+ private static object commit (MExpression[] args, MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).commit ();
+ return true;
+ }
+
+ private static object unhandle (MExpression[] args,
+ MExpression.Domain domain)
+ {
+ ((MInputContext) domain.context).commit ();
+ return false;
+ }
+
+ private static object shift (MExpression[] args, MExpression.Domain domain)
+ {
+ MSymbol sym = (MSymbol) args[0].Args[0].Val;
+
+ ((MInputContext) domain.context).shift (sym);
+ return true;
+ }
+
+ private static object call (MExpression[] args, MExpression.Domain domain)
+ {
+ MSymbol module = (MSymbol) args[0].Args[0].Val;
+ MSymbol method = (MSymbol) args[1].Args[0].Val;
+ MPlist arglist = new MPlist ();
+
+ for (int i = 2; i < args.Length; i++)
+ {
+ object val = args[i].Eval (domain);
+
+ if (val is int)
+ arglist.Add (MSymbol.integer, val);
+ else if (val is MSymbol)
+ arglist.Add (MSymbol.symbol, val);
+ else if (val is MText)
+ arglist.Add (MSymbol.mtext, val);
+ else if (val is MPlist)
+ arglist.Add (MSymbol.plist, val);
+ else
+ throw new Exception ("Invalid argument to {0}/{1}: {2}",
+ module, method, val);
+ }
+ return ((MInputContext) domain.context).call (module, method, arglist);
+ }
+
+ public override string ToString ()
+ {
+ string str = (String.Format ("({0} (title \"{1}\")", tag, title));
+ if (commands != null)
+ {
+ str += " (commands";
+ foreach (Command cmd in commands)
+ str += " " + cmd;
+ str += ")";
+ }
+ if (variables != null)
+ {
+ str += " (variables";
+ foreach (Variable var in variables)
+ str += " " + var;
+ str += ")";
+ }
+ if (plugins != null)
+ {
+ str += " (modules";
+ foreach (KeyValuePair<MSymbol, Plugin> kv in plugins)
+ str += " " + kv.Value;
+ str += ")";
+ }
+ str += " (maps";
+ foreach (KeyValuePair<MSymbol, Map> kv in maps)
+ str += " " + kv.Value;
+ str += ") (states";
+ foreach (MPlist p in states)
+ str += " " + p.val;
+ return str + "))";
+ }
+ }
+
+ public class MInputContext
+ {
+ internal static MSymbol Mcandidates_group_size = "candidates-group-size";
+ private static MSymbol Mat_less_than = "@<";
+ private static MSymbol Mat_greater_than = "@>";
+ private static MSymbol Mat_minus = "@-";
+ private static MSymbol Mat_plus = "@+";
+ private static MSymbol Mat_open_square_bracket = "@[";
+ private static MSymbol Mat_close_square_bracket = "@]";
+
+ public MInputMethod im;
+ private MText produced;
+ private bool active;
+ private MText status;
+ private bool status_changed;
+ private MText preedit;
+ private bool preedit_changed;
+ private int cursor_pos;
+ private bool cursor_pos_changed;
+ private Candidates candidates;
+ private MPlist candidate_group;
+ private int candidate_index;
+ private int candidate_from, candidate_to;
+ private bool candidate_show;
+ private bool candidate_changed;
+
+ private Stack<MInputMethod.State> states;
+ internal MInputMethod.KeySeq keys;
+ private int key_head;
+ private int state_key_head;
+ private MPlist state_boundary;
+ private int commit_key_head;
+ private MText state_preedit;
+ private int state_pos;
+ internal MPlist markers = new MPlist ();
+ private MPlist vars;
+ private MPlist vars_saved;
+ internal MText preceding_text = new MText ();
+ internal MText following_text = new MText ();
+ private bool key_unhandled;
+
+ internal MExpression.Domain domain;
+
+ public MInputContext (MInputMethod im)
+ {
+ this.im = im;
+ domain = new MExpression.Domain (im.local_domain, this);
+ states = new Stack<MInputMethod.State> ();
+ states.Push ((MInputMethod.State) im.states.val);
+ keys = new MInputMethod.KeySeq ();
}
- private static void adjust_markers (MInputContext ic,
- int from, int to, object inserted)
+ private void adjust_markers (int from, int to, object inserted)
{
int ins = (inserted == null ? 0
: inserted is int ? 1
: ((MText) inserted).Length);
int diff = ins - (to - from);
- for (MPlist plist = ic.markers; ! plist.IsEmpty; plist = plist.next)
+ for (MPlist plist = markers; ! plist.IsEmpty; plist = plist.next)
{
int pos = plist.Integer;
if (pos > from)
plist.val = from;
}
}
- if (ic.cursor_pos >= to)
- ic.cursor_pos += diff;
- else if (ic.cursor_pos > from)
- ic.cursor_pos = from;
+ if (cursor_pos >= to)
+ cursor_pos += diff;
+ else if (cursor_pos > from)
+ cursor_pos = from;
}
- private static void preedit_replace (MInputContext ic,
- int from, int to, int c)
+ private void preedit_replace (int from, int to, int c)
{
- ic.preedit.Del (from, to);
- ic.preedit.Ins (from, c);
- adjust_markers (ic, from, to, c);
+ preedit.Del (from, to);
+ preedit.Ins (from, c);
+ adjust_markers (from, to, c);
}
- private static void preedit_replace (MInputContext ic,
- int from, int to, MText mt)
+ private void preedit_replace (int from, int to, MText mt)
{
- ic.preedit[from, to] = mt;
- adjust_markers (ic, from, to, mt);
+ preedit[from, to] = mt;
+ adjust_markers (from, to, mt);
}
- private static object insert (object[] args, MPlist bindings,
- object context)
+ internal void insert (object arg)
{
- MInputContext ic = (MInputContext) context;
- object arg = ((MExpression) args[0]).Eval (bindings, ic);
-
if (arg is int)
- preedit_replace (ic, ic.cursor_pos, ic.cursor_pos, (int) arg);
+ preedit_replace (cursor_pos, cursor_pos, (int) arg);
else
- preedit_replace (ic, ic.cursor_pos, ic.cursor_pos, (MText) arg);
- ic.preedit_changed = true;
- ic.cursor_pos_changed = true;
- return 1;
+ preedit_replace (cursor_pos, cursor_pos, (MText) arg);
+ preedit_changed = true;
+ cursor_pos_changed = true;
}
- internal class Candidates
+ private class Candidates
{
private class Block
{
public static void Detach (MInputContext ic)
{
- ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates);
+ ic.preedit.PopProp (0, ic.preedit.Length, MInputMethod.Mcandidates);
ic.candidates = null;
ic.preedit_changed = true;
ic.cursor_pos_changed = true;
col = maxcol;
index = index - Column + col;
}
+ }
- public void Update (MInputContext ic)
- {
- int from, to;
-
- if (ic.candidates == null)
- {
- from = ic.cursor_pos;
- to = ic.cursor_pos;
- ic.candidates = this;
- }
- else
- {
- from = ic.candidate_from;
- to = ic.candidate_to;
- }
-
- object candidate = ic.candidates.Current;
+ private void update_candidate ()
+ {
+ object candidate = candidates.Current;
- if (candidate is MText)
- preedit_replace (ic, from, to, (MText) candidate);
- else
- preedit_replace (ic, from, to, (int) candidate);
- ic.preedit.PushProp (from, to, Mcandidates, this);
- ic.cursor_pos = to;
- ic.candidate_from = from;
- ic.candidate_to = to;
- ic.preedit_changed = true;
- ic.cursor_pos_changed = true;
- ic.candidate_changed = true;
- }
+ if (candidate is MText)
+ {
+ preedit_replace (candidate_from, candidate_to, (MText) candidate);
+ candidate_to = candidate_from + ((MText) candidate).Length;
+ }
+ else
+ {
+ preedit_replace (candidate_from, candidate_to, (int) candidate);
+ candidate_to = candidate_from + 1;
+ }
+ preedit.PushProp (candidate_from, candidate_to,
+ MInputMethod.Mcandidates, this);
+ cursor_pos = candidate_from;
+ preedit_changed = true;
+ cursor_pos_changed = true;
+ candidate_changed = true;
}
- private static object insert_candidates (object[] args, MPlist bindings,
- object context)
+ internal void insert_candidates (MPlist list)
{
- MInputContext ic = (MInputContext) context;
- MPlist list = (MPlist) args[0];
int column = 0;
- MPlist slot = (MPlist) bindings.Find (Mcandidates_group_size);
- if (slot != null)
- column = slot.Integer;
- Candidates candidates = new Candidates (list, column);
- candidates.Update (ic);
- return 1;
+ if (domain.IsBound (Mcandidates_group_size))
+ {
+ object val = domain.GetValue (Mcandidates_group_size);
+ if (val is int)
+ column = (int) val;
+ }
+ candidates = new Candidates (list, column);
+ candidate_from = candidate_to = cursor_pos;
+ update_candidate ();
}
- private static object select (object[] args, MPlist bindings,
- object context)
+ internal void select (int n)
{
- MInputContext ic = (MInputContext) context;
- object arg = args[0];
-
- if (ic.candidates == null)
- return 0;
- if (arg is MSymbol)
+ if (candidates != null)
{
- MSymbol sym = (MSymbol) arg;
+ candidates.Select (n);
+ update_candidate ();
+ }
+ }
+ internal void select (MSymbol sym)
+ {
+ if (candidates != null)
+ {
if (sym == Mat_less_than)
- ic.candidates.First ();
+ candidates.First ();
else if (sym == Mat_greater_than)
- ic.candidates.Last ();
+ candidates.Last ();
else if (sym == Mat_minus)
- ic.candidates.Prev ();
+ candidates.Prev ();
else if (sym == Mat_plus)
- ic.candidates.Next ();
+ candidates.Next ();
else if (sym == Mat_open_square_bracket)
- ic.candidates.PrevGroup ();
+ candidates.PrevGroup ();
else if (sym == Mat_close_square_bracket)
- ic.candidates.NextGroup ();
+ candidates.NextGroup ();
+ }
+ }
+
+ internal int marker (MSymbol sym)
+ {
+ int pos = cursor_pos;
+
+ if (sym.Name.Length == 2 && sym.Name[0] == '@')
+ {
+ switch (sym.Name[0])
+ {
+ case '<': pos = 0; break;
+ case '>': pos = preedit.Length; break;
+ case '-': pos = cursor_pos - 1; break;
+ case '+': pos = cursor_pos + 1; break;
+ case '[':
+ if (pos > 0)
+ {
+ int to;
+ preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
+ out pos, out to);
+ }
+ else
+ pos = 0;
+ break;
+ case ']':
+ if (cursor_pos < preedit.Length - 1)
+ {
+ int from;
+ preedit.FindProp (MInputMethod.Mcandidates, pos,
+ out from, out pos);
+ }
+ else
+ pos = preedit.Length;
+ break;
+ default:
+ if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
+ pos = sym.Name[0];
+ break;
+ }
+ }
+ else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
+ {
+ pos = int.Parse (sym.Name.Substring (2));
+ }
+ else
+ {
+ object val = markers.Get (sym);
+
+ if (val is int)
+ pos = (int) val;
+ }
+ return pos;
+ }
+
+ internal int char_at (int pos)
+ {
+ int c;
+
+ pos += cursor_pos;
+ if (pos < 0)
+ {
+ if (preceding_text.Length < -pos)
+ {
+ MPlist plist = new MPlist ();
+ plist.Push (MSymbol.integer, pos);
+ if (MInputMethod.GetSurroundingText != null
+ && MInputMethod.GetSurroundingText (this, plist)
+ && plist.IsMText
+ && preceding_text.Length < plist.Text.Length)
+ preceding_text = plist.Text;
+ }
+ c = (-pos < preceding_text.Length
+ ? preceding_text[preceding_text.Length + pos] : -1);
+ }
+ else if (pos >= 0 && pos < preedit.Length)
+ c = preedit[pos];
+ else
+ {
+ pos -= preedit.Length;
+ if (pos >= following_text.Length)
+ {
+ MPlist plist = new MPlist ();
+ plist.Push (MSymbol.integer, pos + 1);
+ if (MInputMethod.GetSurroundingText != null
+ && MInputMethod.GetSurroundingText (this, plist)
+ && plist.IsMText
+ && following_text.Length < plist.Text.Length)
+ following_text = plist.Text;
+ }
+ c = (pos < following_text.Length ? following_text[pos] : -1);
+ }
+ return c;
+ }
+
+ internal void delete (int pos)
+ {
+ if (pos < cursor_pos)
+ preedit_replace (pos, cursor_pos, null);
+ else
+ preedit_replace (cursor_pos, pos, null);
+ preedit_changed = true;
+ cursor_pos_changed = true;
+ }
+
+ internal void show ()
+ {
+ candidate_show = true;
+ candidate_changed = true;
+ }
+
+ internal void hide ()
+ {
+ candidate_show = false;
+ candidate_changed = true;
+ }
+
+ internal void move (int pos)
+ {
+ if (pos < 0)
+ pos = 0;
+ else if (pos > preedit.Length)
+ pos = preedit.Length;
+ if (pos != cursor_pos)
+ {
+ cursor_pos = pos;
+ preedit_changed = true;
+ }
+ }
+
+ internal void mark (MSymbol sym)
+ {
+ MPlist slot = markers.Find (sym);
+
+ if (slot == null)
+ markers.Push (sym, cursor_pos);
+ else
+ slot.val = cursor_pos;
+ }
+
+ internal void pushback (int n)
+ {
+ if (n > 0)
+ {
+ key_head -= n;
+ if (key_head < 0)
+ key_head = 0;
+ }
+ else if (n == 0)
+ key_head = 0;
+ else
+ {
+ key_head = - n;
+ if (key_head > keys.Count)
+ key_head = keys.Count;
+ }
+ }
+
+ internal void pushback (MInputMethod.KeySeq keyseq)
+ {
+ if (key_head > 0)
+ key_head--;
+ if (key_head < keys.Count)
+ keys.RemoveRange (key_head, keys.Count - key_head);
+ for (int i = 0; i < keyseq.Count; i++)
+ keys.Add (keyseq[i]);
+ }
+
+ internal void pop ()
+ {
+ if (key_head < keys.Count)
+ keys.RemoveRange (key_head, 1);
+ }
+
+ internal void undo (int n)
+ {
+ if (n < 0)
+ keys.RemoveRange (keys.Count + n, - n);
+ else
+ keys.RemoveRange (n, keys.Count - n);
+ reset ();
+ }
+
+ internal void commit ()
+ {
+ produced.Cat (preedit);
+ preedit.Del ();
+ preedit_changed = true;
+ }
+
+ internal void shift (MSymbol sym)
+ {
+ MInputMethod.State state;
+
+ if (sym == MSymbol.t)
+ {
+ if (states.Count > 1)
+ state = states.Pop ();
else
- return 0;
- }
- else if (arg is int)
- ic.candidates.Select ((int) arg);
- ic.candidates.Update (ic);
- return 0;
- }
-
- private static object delete (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object show (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object hide (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object move (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object mark (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object pushback (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object pop (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object undo (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object commit (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object unhandle (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object shift (object[] args, MPlist bindings,
- object context) { return 1; }
- private static object call (object[] args, MPlist bindings,
- object context) { return 1; }
- }
+ state = states.Peek ();
+ }
+ else
+ {
+ state = (MInputMethod.State) im.states.Get (sym);
+ if (state == null)
+ throw new Exception ("Unknown state: " + state.name);
+ }
+ if (state == null)
+ state = states.Pop ();
+ if (state == (MInputMethod.State) im.states.val)
+ {
+ commit ();
+ reset ();
+ }
+ else
+ {
+ state_key_head = key_head;
+ state_pos = cursor_pos;
+ state_preedit = preedit.Dup ();
+ if (state != states.Peek ())
+ {
+ states.Push (state);
+ state_boundary = domain.SetBoundary ();
+ status = state.title;
+ if (status == null)
+ status = im.title;
+ status_changed = true;
+ MExpression on_entry
+ = (MExpression) state.branches.Get (MSymbol.t);
+ if (on_entry != null)
+ on_entry.Eval (domain);
+ }
+ }
+ }
- public class MInputContext
- {
- public MInputMethod im;
- public MText produced;
- public bool active;
- public MText status;
- public bool status_changed;
- public MText preedit;
- public bool preedit_changed;
- public int cursor_pos;
- public bool cursor_pos_changed;
- internal MInputMethod.Candidates candidates;
- public MPlist candidate_group;
- public int candidate_index;
- public int candidate_from, candidate_to;
- public bool candidate_show;
- public bool candidate_changed;
- public MPlist callback_args;
-
- private MInputMethod.State state;
- private MInputMethod.State prev_state;
- private Stack<MSymbol> keys;
- private int state_key_head;
- private int key_head;
- private int commit_key_head;
- private MText preedit_saved;
- private int state_pos;
- internal MPlist markers = new MPlist ();
- private MPlist vars;
- private MPlist vars_saved;
- private MText preceding_text;
- private MText following_text;
- private bool key_unhandled;
+ internal bool call (MSymbol module, MSymbol method, MPlist arglist)
+ {
+ MInputMethod.Plugin plugin;
+
+ if (! im.plugins.TryGetValue (module, out plugin))
+ return false;
+ if (plugin.assembly == null)
+ {
+ Assembly assembly;
+
+ try {
+ assembly = Assembly.LoadFrom (module.Name + ".dll");
+ } catch {
+ return false;
+ }
+ Type t = assembly.GetType ("Plugin");
+ for (MPlist p = plugin.methods; ! p.IsEmpty; p = p.next)
+ p.Set (p.key, t.GetMethod (p.key.Name));
+ }
+
+ MethodInfo method_info = (MethodInfo) plugin.methods.Get (method);
+ if (method_info == null)
+ return false;
+ object[] method_arg = new object[1];
+ method_arg[0] = arglist;
+ bool result = (bool) method_info.Invoke (null, method_arg);
+ if (! result)
+ return false;
+ if (! arglist.IsEmpty)
+ (new MExpression (arglist, domain)).Eval (domain);
+ return true;
+ }
+
+ internal void reset ()
+ {
+ preedit.Del ();
+ state_preedit.Del ();
+ produced.Del ();
+ markers.Clear ();
+ cursor_pos = 0;
+ key_head = commit_key_head = 0;
+ states.Clear ();
+ states.Push ((MInputMethod.State) im.states.Val);
+ state_key_head = 0;
+ state_pos = 0;
+ }
internal object GetCandidates (out int column)
{
column = 0;
if (cursor_pos == 0)
return null;
- MInputMethod.Candidates candidates
- = (MInputMethod.Candidates) preedit.GetProp (cursor_pos - 1,
- MInputMethod.Mcandidates);
+ Candidates candidates
+ = (Candidates) preedit.GetProp (cursor_pos - 1,
+ MInputMethod.Mcandidates);
if (candidates == null)
return null;
column = candidates.Column;
return candidates.Current;
}
+
+ internal void HandleKey ()
+ {
+ MInputMethod.State state = states.Peek ();
+
+
+ }
}
}