using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Xml;
+
using M17N;
using M17N.Core;
int len = pattern.Length;
int i;
+ M17n.DebugPrint ("Listing {0} in {1} ...", pattern, dirinfo);
for (i = 0; i < len && pattern[i] != sep; i++);
try {
if (i == len)
{
FileInfo[] listing = dirinfo.GetFiles (pattern);
+ i = listing.Length;
foreach (FileInfo elt in listing)
files.Add (elt);
}
string tail = pattern.Substring (i + 1);
pattern = pattern.Substring (0, i);
DirectoryInfo[] listing = dirinfo.GetDirectories (pattern);
+
+ i = listing.Length;
foreach (DirectoryInfo elt in listing)
list (ref files, elt, tail);
}
} catch {
}
+ M17n.DebugPrint (" found {0} files\n", i);
}
}
public MDatabaseInfo (MPlist plist)
{
- Format = MSymbol.plist;
+ Format = MSymbol.nil;
if (plist.IsMText)
{
+ Format = MSymbol.plist;
Filename = plist.Text.ToString ();
plist = plist.Next;
}
MPlist p = plist.Plist;
if (p.IsMText)
- Filename = p.Text.ToString ();
- p = p.Next;
- if (! p.IsEmpty)
{
- if (p.IsSymbol)
- Format = p.Symbol;
+ Filename = p.Text.ToString ();
+ p = p.Next;
+ }
+ if (p.IsSymbol)
+ {
+ Format = p.Symbol;
p = p.Next;
- if (! p.IsEmpty)
- {
- if (p.IsSymbol)
- Schema = p.Symbol;
- p = p.Next;
- if (p.IsMText)
- SchemaFile = p.Text.ToString ();
- }
}
+ if (p.IsSymbol)
+ {
+ Schema = p.Symbol;
+ p = p.Next;
+ }
+ if (p.IsMText)
+ SchemaFile = p.Text.ToString ();
plist = plist.Next;
}
private static DateTime LastUpdateTime = new DateTime (0);
- private static readonly MSymbol Mversion = MSymbol.Of ("version");
- private static readonly MSymbol Mwildcard = MSymbol.Of ("*");
- private static readonly MSymbol Mchar_table = MSymbol.Of ("char-table");
- private static readonly MSymbol Mcharset = MSymbol.Of ("charset");
+ private static readonly MSymbol Mversion = "version";
+ private static readonly MSymbol Mwildcard = "*";
+ private static readonly MSymbol Mchar_table = "char-table";
+ private static readonly MSymbol Mcharset = "charset";
+ private static readonly MSymbol Mxml = "xml";
+
+ private static TimeSpan CheckInterval = new TimeSpan (50000000);
/// Type of database
private enum MDBType
// current system, or the validation was failed.
DISABLED,
// The database is deleted by the modificaiton of mdb.dir, or
- // is overwritten by a new explicit definition..
+ // is overwritten by a new explicit definition.
INVALID,
};
private MDBType DBType;
private MDBStatus DBStatus;
internal MDatabaseInfo Info;
- // File in which the database contents is stored.
+ // File in which the database contents is stored. This is null
+ // when DBStatus is NOT_READY.
internal FileInfo FileInfo;
- // When the database file is checked (or validated).
- internal DateTime CheckedTime;
+ // When the database file is loaded last.
+ internal DateTime LastLoaded = DateTime.Now;
+
+ public enum LoadStatus
+ {
+ None,
+ InvalidLoadMethod,
+ NotAvailable,
+ NotReadable,
+ InvalidContents,
+ };
+
+ public LoadStatus LastLoadStatus = LoadStatus.None;
static MDatabase ()
{
}
DBDirs[2] = new MDatabaseDir (null);
DBDirs[3] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
- update_all ();
+ update_all (true);
}
public static string ApplicationDir
{
get { return (DBDirs[1].Dirname); }
- set { DBDirs[2] = new MDatabaseDir (value); update_all (); }
+ set { DBDirs[2] = new MDatabaseDir (value); update_all (true); }
}
- private static bool update_all ()
+ // Update all listing and directories. Return true iff some are
+ // really updated.
+ private static bool update_all (bool force)
{
- bool updated = false;
+ if (! force && DateTime.Now - LastUpdateTime < CheckInterval)
+ return false;
+ bool updated = false;
for (int i = 1; i < 4; i++)
if (DBDirs[i].Dirname != null)
{
updated = true;
}
}
- LastUpdateTime = DateTime.Now;
+ if (updated)
+ LastUpdateTime = DateTime.Now;
return updated;
}
public static void Dump ()
{
- update_all ();
+ update_all (false);
Console.WriteLine ("[DBDirs]");
for (int i = 1; i < 4; i++)
if (DBDirs[i].Dirname != null)
mdb = mdbs[i];
if (mdb.ListIndex == list_idx && mdb.DirIndex >= dir_idx)
{
- if (mdb.DBStatus == MDBStatus.INVALID)
- M17n.DebugPrint ("registering: {0}\n", mdb);
- else
- M17n.DebugPrint ("updating: {0}\n", mdb);
mdb.DirIndex = dir_idx;
if (dict == wdict)
{
mdb.DBStatus = MDBStatus.READY;
}
mdb.Info = info;
+ if (mdb.DBStatus == MDBStatus.INVALID)
+ M17n.DebugPrint ("registering: {0}\n", mdb);
+ else
+ M17n.DebugPrint ("updating: {0}\n", mdb);
return;
}
}
if (mdb.DBStatus == MDBStatus.READY)
{
M17n.DebugPrint ("re-expanding: {0}\n", mdb);
- register_files (DBDirs[dir_idx].Dirname, mdb.ListIndex,
- dir_idx, mdb.Info);
+ register_files (DBDirs[dir_idx].Dirname, dir_idx, mdb);
+ }
+ }
+
+ private static bool parse_plist_header (FileInfo fileinfo, MDatabase mdb,
+ out Tag tag, out MDatabaseInfo info)
+ {
+ MPlist plist = null;
+
+ tag = new Tag (MSymbol.nil);
+ info = null;
+ using (FileStream stream = fileinfo.OpenRead ())
+ {
+ try { plist = new MPlist (stream, 1); } catch { }
+ }
+ if (plist == null || ! plist.IsPlist)
+ return false;
+ plist = plist.Plist;
+ tag = new Tag (ref plist);
+ if (tag.HasWildcard || ! tag.Match (mdb.tag))
+ return false;
+ info = new MDatabaseInfo (plist);
+ return true;
+ }
+
+ private static bool parse_xml_header (FileInfo fileinfo, MDatabase mdb,
+ out Tag tag, out MDatabaseInfo info)
+ {
+ tag = new Tag (MSymbol.nil);
+ info = null;
+ using (FileStream stream = fileinfo.OpenRead ())
+ {
+ try {
+ MPlist plist = new MPlist ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ do {
+ reader.Read ();
+ } while (reader.NodeType != XmlNodeType.Element);
+ plist.Add (MSymbol.symbol, (MSymbol) reader.Name);
+ reader.Read ();
+ if (reader.NodeType == XmlNodeType.Element && reader.Name == "tags")
+ {
+ reader.Read ();
+ while (reader.NodeType == XmlNodeType.Element)
+ {
+ reader.Read ();
+ plist.Add (MSymbol.symbol, (MSymbol) reader.Value);
+ reader.Read ();
+ reader.Read ();
+ }
+ tag = new Tag (ref plist);
+ if (tag.HasWildcard || ! tag.Match (mdb.tag))
+ return false;
+ info = new MDatabaseInfo (plist);
+ return true;
}
+ } catch (Exception e) {
+ Console.WriteLine ("error {0}", e);
+ }
+ }
+ return false;
}
- private static void register_files (string dir, int list_idx, int dir_idx,
- MDatabaseInfo base_info)
+ private static void register_files (string dir, int dir_idx, MDatabase mdb)
{
+ int list_idx = mdb.ListIndex;
List<FileInfo> files = new List<FileInfo> ();
- MGlob.FileList (ref files, dir, base_info.Filename);
+ MGlob.FileList (ref files, dir, mdb.Info.Filename);
foreach (FileInfo fileinfo in files)
{
- MPlist plist = null;
- using (FileStream stream = fileinfo.OpenRead ())
- {
- plist = new MPlist (stream, 1);
- }
- if (plist != null && plist.IsPlist)
- {
- plist = plist.Plist;
- Tag tag = new Tag (ref plist);
+ Tag tag;
+ MDatabaseInfo info;
- if (! tag.HasWildcard && tag.Match (tag))
- {
- MDatabaseInfo info = new MDatabaseInfo (plist);
- info.Merge (base_info);
- if (Path.IsPathRooted (base_info.Filename))
- info.Filename = fileinfo.FullName;
- else
- info.Filename = fileinfo.Name;
- register (list_idx, dir_idx, tag, info);
- }
+ if (mdb.Info.Format == MSymbol.plist
+ ? parse_plist_header (fileinfo, mdb, out tag, out info)
+ : parse_xml_header (fileinfo, mdb, out tag, out info))
+ {
+ info.Merge (mdb.Info);
+ if (Path.IsPathRooted (mdb.Info.Filename))
+ info.Filename = fileinfo.FullName;
+ else
+ info.Filename = fileinfo.Name;
+ register (list_idx, dir_idx, tag, info);
}
}
}
M17n.DebugPrint ("expanding: {0}\n", this);
if (DirIndex == 0)
- register_files (null, ListIndex, DirIndex, Info);
+ register_files (null, DirIndex, this);
else
for (int i = 1; i < 4; i++)
if (DBDirs[i].DirInfo != null)
- register_files (DBDirs[i].DirInfo.FullName, ListIndex, i, Info);
+ register_files (DBDirs[i].DirInfo.FullName, i, this);
DBStatus = MDBStatus.READY;
}
}
}
+ // Update the status. Return true iff the database file is
+ // readable but changed.
+
private bool update_status ()
{
if (DBType == MDBType.UNKNOWN)
return true;
+ update_all (false);
if (DBStatus == MDBStatus.INVALID)
return false;
- if (DBStatus == MDBStatus.READY)
+ if (DBStatus != MDBStatus.NOT_READY)
{
- if (DirIndex > 0
- || File.Exists (FileInfo.FullName))
- return true;
- DBStatus = MDBStatus.INVALID;
- return false;
- }
+ try {
+ FileInfo.Refresh ();
+ } catch {
+ DBStatus = MDBStatus.INVALID;
+ return false;
+ }
+ if (LastLoaded >= FileInfo.LastWriteTime)
+ return false;
+ DBStatus = MDBStatus.READY;
+ return true;
+ }
for (int i = 1; i < 4; i++)
if (DBDirs[i] != null && DBDirs[i].Dirname != null)
{
{
FileInfo = new FileInfo (filename);
DirIndex = i;
+ DBStatus = MDBStatus.READY;
return true;
- }
+ }
}
return false;
}
break;
}
}
- if (! update_all () && mdb != null)
+ if (! update_all (false) && mdb != null)
return mdb;
maybe_expand_wildcard (tag);
if (! ndict.TryGetValue (tag, out mdbs))
return null;
for (int i = 0; i < mdbs.Count; i++)
- if ((mdb = mdbs[i]).update_status ())
- return mdb;
+ {
+ mdb = mdbs[i];
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ return mdb;
+ }
return null;
}
{
List<MDatabase> list = new List<MDatabase> ();
- update_all ();
+ update_all (false);
maybe_expand_wildcard (tag);
if (tag.HasWildcard)
foreach (KeyValuePair<Tag, List<MDatabase>> kv in ndict)
if (kv.Key.Match (tag))
foreach (MDatabase mdb in kv.Value)
- if (mdb.update_status ())
- {
- list.Add (mdb);
- break;
- }
+ {
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
}
else
{
List<MDatabase> mdbs;
if (ndict.TryGetValue (tag, out mdbs))
foreach (MDatabase mdb in mdbs)
- if (mdb.update_status ())
- {
- list.Add (mdb);
- break;
- }
+ {
+ mdb.update_status ();
+ if (mdb.DBStatus == MDBStatus.READY)
+ {
+ list.Add (mdb);
+ break;
+ }
+ }
}
return list;
}
+ private FileStream get_stream ()
+ {
+ if (loader != null
+ || (Info.Format != MSymbol.plist && Info.Format != Mxml))
+ {
+ LastLoadStatus = LoadStatus.InvalidLoadMethod;
+ return null;
+ }
+ if (DBStatus != MDBStatus.READY)
+ {
+ LastLoadStatus = LoadStatus.NotAvailable;
+ return null;
+ }
+
+ FileStream stream = null;
+ try {
+ stream = FileInfo.OpenRead ();
+ } catch {
+ LastLoadStatus = LoadStatus.NotReadable;
+ }
+ return stream;
+ }
+
public object Load ()
{
if (loader != null)
return loader (tag, ExtraInfo);
- if (Info.Format == Mchar_table)
- throw new Exception ("Use Load (MCharTable) to load this database");
- if (Info.Format == Mcharset)
- throw new Exception ("Use Load (MCharset) to load this database");
- if (! update_status ())
- throw new Exception ("Database invalid");
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ try {
+ XmlReader reader = XmlReader.Create (FileInfo.FullName);
+ doc.Load (reader);
+ LastLoaded = DateTime.Now;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ }
+ return doc;
+ }
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
MPlist plist = null;
- using (FileStream stream = File.OpenRead (FileInfo.FullName))
+ try {
plist = new MPlist (stream);
+ LastLoaded = DateTime.Now;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
return plist;
}
public object Load (MSymbol key, MSymbol stop)
{
- if (loader != null || Info.Format != MSymbol.plist)
- throw new ArgumentException
- ("Key can't be specified for loading this database");
- if (! update_status ())
- throw new Exception ("Database invalid");
+ FileStream stream = get_stream ();
+
+ if (stream == null)
+ return null;
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ try {
+ reader.Read ();
+ while (reader.NodeType != XmlNodeType.Element)
+ reader.Read ();
+ doc.LoadXml ("<" + reader.Name + "></" + reader.Name + ">");
+ reader.Read ();
+ XmlNode node = doc.DocumentElement;
+ while (reader.NodeType == XmlNodeType.Element
+ ? reader.Name != stop.Name
+ : reader.NodeType != XmlNodeType.EndElement)
+ if (reader.NodeType == XmlNodeType.Element
+ && reader.Name == key.Name)
+ node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader),
+ node);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return doc;
+ }
+
MPlist plist = null;
- using (FileStream stream = File.OpenRead (FileInfo.FullName))
+ try {
plist = new MPlist (stream, key, stop);
+ LastLoaded = DateTime.Now;
+ } catch {
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
return plist;
}
+ public object Load (MSymbol stop)
+ {
+ FileStream stream = get_stream ();
+
+ if (stream == null)
+ return null;
+ if (Info.Format == Mxml)
+ {
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ try {
+ reader.Read ();
+ while (reader.NodeType != XmlNodeType.Element)
+ reader.Read ();
+ doc.LoadXml ("<" + reader.Name + "></" + reader.Name + ">");
+ reader.Read ();
+ XmlNode node = null;
+ while (reader.NodeType == XmlNodeType.Element
+ ? reader.Name != stop.Name
+ : reader.NodeType != XmlNodeType.EndElement)
+ if (reader.NodeType == XmlNodeType.Element)
+ node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader),
+ node);
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return doc;
+ }
+
+ MPlist plist = null;
+ try {
+ plist = new MPlist (stream, stop);
+ LastLoaded = DateTime.Now;
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ LastLoadStatus = LoadStatus.InvalidContents;
+ } finally {
+ stream.Dispose ();
+ }
+ return plist;
+ }
+
+ public XmlNode Load (string id, params string[] nodes)
+ {
+ FileStream stream = get_stream ();
+ if (stream == null)
+ return null;
+ if (Info.Format != Mxml)
+ throw new Exception ("Not an XML format");
+
+ XmlDocument doc = new XmlDocument ();
+ XmlTextReader reader = new XmlTextReader (stream);
+ int len = nodes.Length;
+
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ do {
+ reader.Read ();
+ } while (reader.NodeType != XmlNodeType.Element);
+
+ if (reader.Name != nodes[0])
+ return null;
+
+ string ns = reader.GetAttribute ("xmlns");
+ XmlNode top = doc.CreateNode (XmlNodeType.Element, nodes[0], ns);
+ XmlNode node = top;
+
+ try {
+ int i;
+
+ for (i = 1; i + 1 < len; i++)
+ {
+ if (! reader.ReadToDescendant (nodes[i]))
+ return null;
+ node = node.InsertAfter (doc.CreateNode (XmlNodeType.Element,
+ nodes[i], ns), null);
+ }
+ if (! reader.ReadToDescendant (nodes[i]))
+ return null;
+ XmlNode ref_node = null;
+ while (reader.NodeType != XmlNodeType.EndElement)
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ if (reader.Name == nodes[i]
+ && (id == null || id == reader.GetAttribute ("id")))
+ ref_node = node.InsertAfter (doc.ReadNode (reader), ref_node);
+ else
+ reader.Skip ();
+ }
+ else
+ reader.Read ();
+ }
+
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ } finally {
+ reader.Close ();
+ stream.Dispose ();
+ }
+ return top;
+ }
+
/// <summary>Return a list of currently available database
/// directory names</summary>.
public static string[] DirectoryList ()
return dirs.ToArray ();
}
+ public MSymbol Format { get { return Info.Format; } }
+
+ public static bool Changed (DateTime time)
+ {
+ update_all (false);
+ return (time < LastUpdateTime);
+ }
+
+ public bool NeedReload ()
+ {
+ return update_status ();
+ }
+
// For IComparable<MDatabase>
public int CompareTo (MDatabase other)
{
using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Xml;
+
using M17N;
using M17N.Core;
{
public class MExpression
{
- private static MSymbol Mvarref = MSymbol.Of ("symbol-value");
- private static MSymbol Mdefun = MSymbol.Of ("defun");
- private static MSymbol Mcond = MSymbol.Of ("cond");
- private static MSymbol Mprogn = MSymbol.Of ("progn");
- private static MSymbol Mwhen = MSymbol.Of ("when");
+ private static MSymbol Mvarref = "symbol-value";
+ private static MSymbol Mdefun = "defun";
+ private static MSymbol Mcond = "cond";
+ private static MSymbol Mprogn = "progn";
+ private static MSymbol Mwhen = "when";
public class Domain
{
- internal MPlist functions;
- internal MPlist bindings;
+ private Domain parent;
+ internal MPlist functions = new MPlist ();
+ internal MPlist bindings = new MPlist ();
+ private Stack<MPlist> boundaries = new Stack<MPlist> ();
internal Translator translator;
public object context;
internal Domain ()
{
- functions = new MPlist ();
- bindings = new MPlist ();
+ boundaries.Push (bindings);
}
- public Domain (object context)
- {
- functions = basic.functions;
- bindings = basic.bindings;
- translator = basic.translator;
- this.context = context;
- }
+ public Domain (object context) : this (basic, context) { }
public Domain (Domain parent, object context)
{
- functions = parent.functions;
- bindings = parent.bindings;
- translator = parent.translator;
+ this.parent = parent;
this.context = context;
+ boundaries.Push (bindings);
}
public void AddTranslator (Translator translator)
bindings = bindings.Cons (sym, value);
}
- public void Defun (string name, Evaluator evaluator,
- int min_arg, int max_arg)
+ public MPlist SetBoundary ()
+ {
+ boundaries.Push (bindings);
+ return bindings;
+ }
+
+ public void UnboundTo (MPlist boundary)
+ {
+ while (boundary != boundaries.Pop ());
+ while (bindings != boundary)
+ bindings = bindings.next;
+ }
+
+ public void Defun (string name, Builtin builtin, int min_arg, int max_arg)
{
- Defun (name, evaluator, min_arg, max_arg, false);
+ Defun (name, builtin, min_arg, max_arg, false);
}
- public void Defun (string name, Evaluator evaluator,
- int min_arg, int max_arg, bool special)
+ public void Defun (string name, Builtin builtin, int min_arg, int max_arg,
+ bool specialp)
{
- MSymbol sym = MSymbol.Of (name);
- Function func = new Function (sym, evaluator,
- min_arg, max_arg, special);
+ MSymbol sym = name;
+ Function func = (Function) functions.Get (sym);
- functions = functions.Cons (sym, func);
+ if (func != null)
+ {
+ if (func.min_arg < min_arg || func.max_arg > max_arg)
+ throw new Exception ("Incompatible argument numbers to override: "
+ + name);
+ func.builtin = builtin;
+ func.lambda = null;
+ func.min_arg = min_arg;
+ func.max_arg = max_arg;
+ func.specialp = specialp;
+ }
+ else
+ {
+ func = new Function (sym, builtin, min_arg, max_arg, specialp);
+ functions = functions.Cons (sym, func);
+ }
}
public void Defun (MSymbol sym, MPlist args, MPlist body)
{
- Function func = new Function (sym, args, body, this);
+ Function func = (Function) functions.Get (sym);
+
+ if (func != null)
+ {
+ int nargs = args == null ? 0 : args.Count;
+
+ if (func.min_arg < nargs || func.max_arg > nargs)
+ throw new Exception ("Incompatible argument numbers to override: "
+ + sym);
+ func.lambda.SetArgs (args);
+ func.lambda.SetBody (body, this);
+ func.builtin = null;
+ }
+ else
+ {
+ func = new Function (sym, args, body, this);
+ functions = functions.Cons (sym, func);
+ }
+ }
+
+ public void Defun (XmlNode node)
+ {
+ MSymbol sym = node.Attributes["id"].Value;
+ Function func = (Function) functions.Get (sym);
- functions = functions.Cons (sym, func);
+ if (func != null)
+ {
+ XmlNode args = node.FirstChild;
+ int nargs = args.Name == "args" ? args.ChildNodes.Count : 0;
+
+ if (func.min_arg < nargs || func.max_arg > nargs)
+ throw new Exception ("Incompatible argument numbers to override: "
+ + sym);
+ func.lambda.Set (node, this);
+ func.builtin = null;
+ }
+ else
+ {
+ func = new Function (sym, node, this);
+ functions = functions.Cons (sym, func);
+ }
}
internal Function GetFunc (MSymbol name)
Function func = (Function) functions.Get (name);
if (func == null)
- throw new Exception ("Unknown function: " + name);
+ {
+ if (parent != null)
+ return parent.GetFunc (name);
+ throw new Exception ("Unknown function: " + name);
+ }
return func;
}
- public bool CopyFunc (MSymbol name, Domain domain)
+ public bool CopyFunc (Domain domain, MSymbol name)
{
Function func = (Function) functions.Get (name);
if (func == null)
MPlist slot = bindings.Find (name);
if (slot == null)
- throw new Exception ("Unbound variable: " + name);
+ {
+ if (parent != null)
+ return parent.GetValue (name);
+ throw new Exception ("Unbound variable: " + name);
+ }
return slot.val;
}
public object SetValue (MSymbol name, object val)
{
- MPlist slot = bindings.Find (name);
+ MPlist boundary = boundaries.Peek ();
- if (slot == null)
- bindings = bindings.Cons (name, val);
- else
- slot.val = val;
+ for (MPlist plist = bindings; plist != boundary; plist = plist.next)
+ if (plist.key == name)
+ {
+ plist.val = val;
+ return val;
+ }
+ bindings = bindings.Cons (name, val);
return val;
}
public void Translate (MPlist plist)
{
+ if (parent != null)
+ parent.Translate (plist);
if (translator != null)
for (MPlist p = plist; ! p.IsEmpty; p = p.next)
translator (p, this);
}
}
- public delegate object Evaluator (MExpression[] args, Domain domain);
+ public delegate object Builtin (MExpression[] args, Domain domain);
public delegate void Translator (MPlist plist, Domain domain);
internal class Function
{
- private class Lambda
+ internal class Lambda
{
- internal readonly MSymbol[] args;
- internal readonly MExpression[] body;
+ internal MSymbol[] args;
+ internal MExpression[] body;
public Lambda (MPlist args, MPlist body, Domain domain)
{
- int len;
+ SetArgs (args);
+ SetBody (body, domain);
+ }
- len = args.Count;
- this.args = new MSymbol[len];
- for (int i = 0; ! args.IsEmpty; i++, args = args.next)
+ public Lambda (XmlNode node, Domain domain)
+ {
+ Set (node, domain);
+ }
+
+ public void SetArgs (MPlist args)
+ {
+ int len = args == null ? 0 : args.Count;
+
+ if (this.args == null)
+ this.args = new MSymbol[len];
+ for (int i = 0; i < len; i++, args = args.next)
this.args[i] = args.Symbol;
- len = body.Count;
- this.body = new MExpression[len];
- for (int i = 0; ! body.IsEmpty; i++, body = body.next)
+ }
+
+ public void SetBody (MPlist body, Domain domain)
+ {
+ int len = body == null ? 0 : body.Count;
+ if (this.body == null)
+ this.body = new MExpression[len];
+ for (int i = 0; i < len; i++, body = body.next)
{
domain.Translate (body);
this.body[i] = new MExpression (body.key, body.val, domain);
}
}
+
+ public void Set (XmlNode node, Domain domain)
+ {
+ XmlNodeList body = node.ChildNodes;
+ int idx = 0;
+
+ if (body[0].Name == "args")
+ {
+ XmlNodeList args = body[0].ChildNodes;
+ if (this.args == null)
+ this.args = new MSymbol[args.Count];
+ for (int i = 0; i < args.Count; i++)
+ this.args[i] = args[i].InnerText;
+ idx++;
+ }
+ else if (this.args == null)
+ this.args = new MSymbol[0];
+ if (this.body == null)
+ this.body = new MExpression[body.Count - idx];
+ for (int i = 0; idx < body.Count; i++, idx++)
+ this.body[i] = new MExpression (body[idx], domain);
+ }
}
public readonly MSymbol Name;
- private readonly Evaluator eval;
- public readonly int min_arg, max_arg;
- private readonly Lambda lambda;
- private readonly bool specialp = false;
+ public Builtin builtin;
+ public int min_arg, max_arg;
+ internal Lambda lambda;
+ public bool specialp = false;
internal static Function ignore, varref, block;
- public Function (MSymbol name, Evaluator eval,
+ public Function (MSymbol name, Builtin builtin,
int min_arg, int max_arg, bool specialp)
{
Name = name;
- this.eval = eval;
+ this.builtin = builtin;
this.min_arg = min_arg;
this.max_arg = max_arg;
this.specialp = specialp;
}
- internal Function (MSymbol name, MPlist args, MPlist body, Domain domain)
+ internal Function (MSymbol name, MPlist args, MPlist body,
+ Domain domain)
{
Name = name;
lambda = new Lambda (args, body, domain);
this.min_arg = this.max_arg = lambda.args.Length;
}
+ internal Function (MSymbol name, XmlNode node, Domain domain)
+ {
+ Name = name;
+ lambda = new Lambda (node, domain);
+ this.min_arg = this.max_arg = lambda.args.Length;
+ }
+
private Function ()
{
Name = MSymbol.nil;
public object Call (MExpression[] args, Domain domain)
{
- if (eval != null)
+ if (builtin != null)
{
if (! specialp)
foreach (MExpression e in args)
e.Eval (domain);
- return eval (args, domain);
+ return builtin (args, domain);
}
if (lambda == null)
return null;
basic.Defun ("set", set_value, 2, 2, true);
basic.Defun ("=", set_value, 2, 2, true);
+ basic.Defun ("!", not, 1, 1, false);
basic.Defun ("+", plus, 2, -1, false);
basic.Defun ("*", multi, 2, -1, false);
basic.Defun ("-", minus, 1, -1, false);
basic.Defun (">=", moreeq, 2, -1, false);
basic.Defun ("progn", progn, 0, -1, true);
basic.Defun ("if", ifclause, 2, -1, true);
- basic.Defun ("when", whenclause, 2, -1, true);
+ basic.Defun ("when", whenclause, 1, -1, true);
basic.Defun ("while", whileclause, 1, -1, true);
basic.AddTranslator (new Translator (translate_cond));
args[1].Eval (domain));
}
+ private static object not (MExpression[] args, Domain domain)
+ {
+ if (args[0].val is int)
+ return (int) args[0].val == 0;
+ if (args[0].val is bool)
+ return ! ((bool) args[0].val);
+ return true;
+ }
+
private static object plus (MExpression[] args, Domain domain)
{
if (args[0].val is int)
}
// (cond (COND1 ...) (COND2 ...) ...)
- // => (progn (when COND1 ...) (when COND2 ...) ...)
+ // => (cond (when COND1 ...) (when COND2 ...) ...)
private static void translate_cond (MPlist plist, Domain domain)
{
if (plist.IsPlist)
}
}
+ public MExpression (XmlNode node, Domain domain)
+ {
+ MSymbol sym = node.Name;
+
+ function = domain.GetFunc (sym);
+
+ XmlAttributeCollection attrs = node.Attributes;
+
+ int nargs = attrs.Count + node.ChildNodes.Count;
+ if (nargs < function.min_arg
+ || (function.max_arg >= 0 && nargs > function.max_arg))
+ throw new Exception ("Invalid number of arguments: " + node.InnerXml);
+ args = new MExpression[nargs];
+ int i;
+ for (i = 0; i < attrs.Count; i++)
+ {
+ string str = sttrs[i].Value;
+
+ }
+ }
+
public object Eval (Domain domain)
{
if (function == null)
str += ")";
}
else if (val != null)
- str = val.ToString ();
+ {
+ if (val is MText)
+ str = "\"" + (string) ((MText) val) + "\"";
+ else
+ str = val.ToString ();
+ }
else
str = "()";
return str;
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
{
+ // 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);
- internal MExpression.Domain local_domain;
+ 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 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");
- private static MSymbol Mdelete = MSymbol.Of ("delete");
- private static MSymbol Mmove = MSymbol.Of ("move");
- private static MSymbol Mmark = MSymbol.Of ("mark");
- private static MSymbol Mmarker = MSymbol.Of ("marker");
- private static MSymbol Madd = MSymbol.Of ("add");
- private static MSymbol Msub = MSymbol.Of ("sub");
- private static MSymbol Mmul = MSymbol.Of ("mul");
- private static MSymbol Mdiv = MSymbol.Of ("div");
- private static MSymbol Mif = MSymbol.Of ("if");
- private static MSymbol Mcond = MSymbol.Of ("cond");
- private static MSymbol Mchar_at = MSymbol.Of ("char-at");
-
- internal class Variable
- {
- public MSymbol name;
- public MText description;
- public Type type;
- public object value;
- public MPlist candidates;
- }
+ 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
{
- public MSymbol[] keys;
+ 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
+ {
+ internal uint key;
+
+ 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)
+ {
+ key = c;
+ }
+
+ 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);
+ }
- private static MSymbol char_to_symbol (int c)
+ public bool HasModifier
{
- return MSymbol.Of (String.Format ("#{0:X}", c));
+ 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)
+ 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]));
+ }
+
+ 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;
+
+ 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 MSymbol this[int i] { get { return keys[i]; } }
+ 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 int Length { get { return keys.Length; } }
+ 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 ();
+
+ public State (MSymbol name)
+ {
+ this.name = name;
+ }
+
+ public override string ToString ()
+ {
+ MText mt = "(" + name.Name;
+
+ 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 + ")";
+ }
}
- private static Dictionary<MDatabase.Tag, MInputMethod> im_table
- = new Dictionary<MDatabase.Tag, MInputMethod> ();
+ // Instance members
+ internal MExpression.Domain local_domain;
- public readonly MSymbol language;
- public readonly MSymbol name;
- public readonly MSymbol subname;
+ private LoadStatus load_status = LoadStatus.None;
+ private MDatabase.Tag tag;
+ private MDatabase mdb;
- 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 ()
{
domain.Defun ("insert", insert, 1, 1);
- domain.Defun ("candidates", insert_candidates, 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);
+ 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);
- domain.Defun ("call", call, 2, -1);
+ 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];
+ 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 ();
- MPlist plist = (MPlist) mdb.Load ();
- if (plist == null)
- return;
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)
if (pl.IsSymbol)
{
if (pl.Symbol == Madd)
- pl.Set (MSymbol.symbol, MSymbol.Of ("+="));
+ pl.Set (MSymbol.symbol, (MSymbol) "+=");
else if (pl.Symbol == Msub)
- pl.Set (MSymbol.symbol, MSymbol.Of ("-="));
+ pl.Set (MSymbol.symbol, (MSymbol) "-=");
else if (pl.Symbol == Mmul)
- pl.Set (MSymbol.symbol, MSymbol.Of ("*="));
+ pl.Set (MSymbol.symbol, (MSymbol) "*=");
else if (pl.Symbol == Mdiv)
- pl.Set (MSymbol.symbol, MSymbol.Of ("/="));
+ pl.Set (MSymbol.symbol, (MSymbol) "/=");
else if (pl.Symbol == Minsert)
{
// (insert (CANDIDATES ...))
pl.Set (MSymbol.plist, p);
}
}
- else if (pl.Symbol == Mstate)
+ else if (pl.Symbol == Mpushback)
{
pl = pl.next;
- if (pl.IsSymbol)
- {
- MSymbol sym = pl.Symbol;
- MPlist p = new MPlist ();
- p.Add (MSymbol.symbol, Mstate);
- p.Add (MSymbol.symbol, sym);
- pl.Set (MSymbol.plist, p);
- }
+ if (pl.IsPlist)
+ pl.Plist.Push (MSymbol.symbol, Mkeyseq);
}
}
else if (pl.IsMText)
{
MSymbol sym = plist.Symbol;
- if (sym.Name[0] == '@')
+ 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 ();
- p.Add (MSymbol.symbol, Mchar_at);
- p.Add (MSymbol.symbol, sym);
+
+ 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_name == MSymbol.nil)
im.local_domain.CopyFunc (local_domain);
else
- im.local_domain.CopyFunc (target_name, local_domain);
+ 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;
+ object state = im.states.Get (target_name);
+ if (state != null)
+ states.Add (target_name, state);
}
}
}
- private void parse_macros (MPlist plist)
+ 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)
+ if (plist.IsPlist)
+ {
+ MPlist pl = plist.Plist;
+
+ if (! pl.IsSymbol)
+ continue;
+ Map map = new Map ();
+ map.name = pl.Symbol;
+ maps[map.name] = map;
+ for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
+ {
+ if (! pl.IsPlist)
+ continue;
+ MPlist p = pl.Plist;
+ KeySeq keys;
+ if (p.IsMText)
+ keys = new KeySeq (p.Text);
+ else if (p.IsPlist)
+ keys = new KeySeq (p.Plist);
+ else
+ continue;
+ p = p.next;
+ if (p.IsEmpty)
+ continue;
+ transform (p);
+ MExpression expr = new MExpression (p, local_domain);
+ map.Add (keys, 0, expr);
+ }
+ }
+ }
+
+ private void parse_states (MPlist plist)
+ {
+ for (; ! plist.IsEmpty; plist = plist.next)
+ if (plist.IsPlist)
+ {
+ MPlist pl = plist.Plist;
+ MText title = null;
+
+ if (pl.IsMText)
+ {
+ title = pl.Text;
+ pl = pl.next;
+ }
+ if (! pl.IsSymbol)
+ continue;
+
+ State state = new State (pl.Symbol);
+ state.title = title;
+ if (states == null)
+ states = new MPlist ();
+ states.Add (state.name, state);
+ for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
+ {
+ if (! pl.IsPlist)
+ continue;
+ MPlist p = pl.Plist;
+ if (! p.IsSymbol)
+ continue;
+ MSymbol map_name = p.Symbol;
+ p = p.next;
+ transform (p);
+ state.branches.Add (map_name,
+ new MExpression (p, local_domain));
+ }
+ }
+ }
+
+ private static object insert (MExpression[] args, MExpression.Domain domain)
+ {
+ ((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)
{
- for (; ! plist.IsEmpty; plist = plist.next)
- if (plist.IsPlist)
- {
- MPlist pl = plist.Plist;
+ MSymbol module = (MSymbol) args[0].Args[0].Val;
+ MSymbol method = (MSymbol) args[1].Args[0].Val;
+ MPlist arglist = new MPlist ();
- if (! pl.IsSymbol)
- continue;
- transform (pl.next);
- local_domain.Defun (pl.Symbol, new MPlist (), pl.next);
- }
+ 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);
}
- private void parse_maps (MPlist plist)
+ public override string ToString ()
{
- for (; ! plist.IsEmpty; plist = plist.next)
- if (plist.IsPlist)
- {
- MPlist pl = plist.Plist;
-
- if (! pl.IsSymbol)
- continue;
- Map map = new Map ();
- map.name = pl.Symbol;
- maps[map.name] = map;
- for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
- {
- if (! pl.IsPlist)
- continue;
- MPlist p = pl.Plist;
- KeySeq keys;
- if (p.IsMText)
- keys = new KeySeq (p.Text);
- else if (p.IsPlist)
- keys = new KeySeq (p.Plist);
- else
- continue;
- if (keys.keys.Length == 0
- && keys.keys[0] == null)
- continue;
- p = p.next;
- if (p.IsEmpty)
- continue;
- transform (p);
- MExpression expr = new MExpression (p, local_domain);
- map.Add (keys, 0, expr);
- }
- }
+ 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 + "))";
}
+ }
- private void parse_states (MPlist plist)
- {
- for (; ! plist.IsEmpty; plist = plist.next)
- if (plist.IsPlist)
- {
- MPlist pl = plist.Plist;
- MText title = null;
-
- if (pl.IsMText)
- {
- title = pl.Text;
- pl = pl.next;
- }
- if (! pl.IsSymbol)
- continue;
+ 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 = "@]";
- State state = new State ();
- state.name = pl.Symbol;
- state.title = title;
- states[state.name] = state;
- if (init_state == null)
- init_state = state;
- for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
- {
- if (! pl.IsPlist)
- continue;
- MPlist p = pl.Plist;
- if (! p.IsSymbol)
- continue;
- MSymbol map_name = p.Symbol;
- p = p.next;
- transform (p);
- state.branches[map_name] = new MExpression (p, local_domain);
- }
- }
- }
+ 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 static MInputMethod Get (MSymbol language, MSymbol name,
- MSymbol extra)
+ public MInputContext (MInputMethod im)
{
- 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;
+ 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 (MExpression[] args,
- MExpression.Domain domain)
+ internal void insert (object arg)
{
- MInputContext ic = (MInputContext) domain.context;
- object arg = args[0].Val;
-
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 (MExpression[] args,
- MExpression.Domain domain)
+ internal void insert_candidates (MPlist list)
{
- MInputContext ic = (MInputContext) domain.context;
- MPlist list = (MPlist) args[0].Val;
int column = 0;
if (domain.IsBound (Mcandidates_group_size))
if (val is int)
column = (int) val;
}
- Candidates candidates = new Candidates (list, column);
- candidates.Update (ic);
- return 1;
+ candidates = new Candidates (list, column);
+ candidate_from = candidate_to = cursor_pos;
+ update_candidate ();
}
- private static object state (MExpression[] args,
- MExpression.Domain domain)
+ internal void select (int n)
{
- MInputContext ic = (MInputContext) domain.context;
- MSymbol sym = (MSymbol) args[0].Args[0].Val;
+ if (candidates != null)
+ {
+ candidates.Select (n);
+ update_candidate ();
+ }
+ }
- if (sym == MSymbol.t)
- return MSymbol.t;
- return ic.im.states[sym];
+ internal void select (MSymbol sym)
+ {
+ if (candidates != null)
+ {
+ if (sym == Mat_less_than)
+ candidates.First ();
+ else if (sym == Mat_greater_than)
+ candidates.Last ();
+ else if (sym == Mat_minus)
+ candidates.Prev ();
+ else if (sym == Mat_plus)
+ candidates.Next ();
+ else if (sym == Mat_open_square_bracket)
+ candidates.PrevGroup ();
+ else if (sym == Mat_close_square_bracket)
+ candidates.NextGroup ();
+ }
}
- private static object marker (MExpression[] args,
- MExpression.Domain domain)
+ internal int marker (MSymbol sym)
{
- MInputContext ic = (MInputContext) domain.context;
- MSymbol sym = (MSymbol) args[0].Args[0].Val;
- int pos = ic.cursor_pos;
+ int pos = cursor_pos;
if (sym.Name.Length == 2 && sym.Name[0] == '@')
{
switch (sym.Name[0])
{
case '<': pos = 0; break;
- case '>': pos = ic.preedit.Length; break;
- case '-': pos = ic.cursor_pos - 1; break;
- case '+': pos = ic.cursor_pos + 1; break;
+ case '>': pos = preedit.Length; break;
+ case '-': pos = cursor_pos - 1; break;
+ case '+': pos = cursor_pos + 1; break;
case '[':
if (pos > 0)
{
int to;
- ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to);
+ preedit.FindProp (MInputMethod.Mcandidates, pos - 1,
+ out pos, out to);
}
else
pos = 0;
break;
case ']':
- if (ic.cursor_pos < ic.preedit.Length - 1)
+ if (cursor_pos < preedit.Length - 1)
{
int from;
- ic.preedit.FindProp (Mcandidates, pos, out from, out pos);
+ preedit.FindProp (MInputMethod.Mcandidates, pos,
+ out from, out pos);
}
else
- pos = ic.preedit.Length;
+ pos = preedit.Length;
break;
default:
if (sym.Name[0] >= '0' && sym.Name[0] <= '9')
}
else if (sym.Name.Length >= 3 && sym.Name[0] == '@')
{
-
-
+ pos = int.Parse (sym.Name.Substring (2));
}
else
{
- object val = ic.markers.Get (sym);
+ object val = markers.Get (sym);
if (val is int)
pos = (int) val;
return pos;
}
- private static object char_at (MExpression[] args,
- MExpression.Domain domain)
+ internal int char_at (int pos)
{
- MInputContext ic = (MInputContext) domain.context;
- MSymbol sym = (MSymbol) args[0].Args[0].Val;
+ 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;
+ }
- if (
+ 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;
+ }
- return 0;
+ internal void hide ()
+ {
+ candidate_show = false;
+ candidate_changed = true;
}
- private static object delete (MExpression[] args,
- MExpression.Domain domain)
+ internal void move (int pos)
{
- MInputContext ic = (MInputContext) domain.context;
- int pos = (int) args[0].Val;
+ if (pos < 0)
+ pos = 0;
+ else if (pos > preedit.Length)
+ pos = preedit.Length;
+ if (pos != cursor_pos)
+ {
+ cursor_pos = pos;
+ preedit_changed = true;
+ }
+ }
- if (pos < ic.cursor_pos)
- preedit_replace (ic, pos, ic.cursor_pos, null);
+ internal void mark (MSymbol sym)
+ {
+ MPlist slot = markers.Find (sym);
+
+ if (slot == null)
+ markers.Push (sym, cursor_pos);
else
- preedit_replace (ic, ic.cursor_pos, pos, null);
- ic.preedit_changed = true;
- ic.cursor_pos_changed = true;
- return true;
+ slot.val = cursor_pos;
}
- private static object select (MExpression[] args,
- MExpression.Domain domain)
+ internal void pushback (int n)
{
- MInputContext ic = (MInputContext) domain.context;
- object arg = args[0].Val;
-
- if (ic.candidates == null)
- return 0;
- if (arg is MSymbol)
+ if (n > 0)
+ {
+ key_head -= n;
+ if (key_head < 0)
+ key_head = 0;
+ }
+ else if (n == 0)
+ key_head = 0;
+ else
{
- MSymbol sym = (MSymbol) arg;
+ key_head = - n;
+ if (key_head > keys.Count)
+ key_head = keys.Count;
+ }
+ }
- if (sym == Mat_less_than)
- ic.candidates.First ();
- else if (sym == Mat_greater_than)
- ic.candidates.Last ();
- else if (sym == Mat_minus)
- ic.candidates.Prev ();
- else if (sym == Mat_plus)
- ic.candidates.Next ();
- else if (sym == Mat_open_square_bracket)
- ic.candidates.PrevGroup ();
- else if (sym == Mat_close_square_bracket)
- ic.candidates.NextGroup ();
+ 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;
+ 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);
+ }
}
- else if (arg is int)
- ic.candidates.Select ((int) arg);
- ic.candidates.Update (ic);
- return 0;
}
- private static object show (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object hide (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object move (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object mark (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object pushback (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object pop (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object undo (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object commit (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object unhandle (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object shift (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- private static object call (MExpression[] args, MExpression.Domain domain)
- { return 1; }
- }
+ internal bool call (MSymbol module, MSymbol method, MPlist arglist)
+ {
+ MInputMethod.Plugin plugin;
- 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;
+ if (! im.plugins.TryGetValue (module, out plugin))
+ return false;
+ if (plugin.assembly == null)
+ {
+ Assembly assembly;
- internal MExpression.Domain domain;
+ 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));
+ }
- public MInputContext (MInputMethod im)
+ 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 ()
{
- this.im = im;
- domain = new MExpression.Domain (im.local_domain, this);
+ 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 ();
+
+
+ }
}
}