X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=MInputMethod.cs;h=da10788cbf3f3163ed56eee4b402c4b863bb8d2f;hb=bee56ed9bc13176a3dfe4547d75e334b55a1f6c1;hp=258c9291c396c3b7850e73a72aaf15cc399341c9;hpb=4ab20c0f4785424513d93f02b82085e1394b3872;p=m17n%2Fm17n-lib-cs.git diff --git a/MInputMethod.cs b/MInputMethod.cs index 258c929..da10788 100644 --- a/MInputMethod.cs +++ b/MInputMethod.cs @@ -9,7 +9,7 @@ using M17N; using M17N.Core; using M17N.Input; -using Xex = System.Xml.Expression.Xexpression; +using Xex = System.Xml.Xexpression; namespace M17N.Input { @@ -18,13 +18,6 @@ namespace M17N.Input // Delegaes public delegate bool Callback (Context ic, MPlist args); - // Class members - public static event Callback PreeditChanged; - public static event Callback StatusChanged; - public static event Callback CandidateChanged; - public static Callback GetSurroundingText; - public static Callback DeleteSurroundingText; - internal static Xex.Domain im_domain = new Xex.Domain ("input-method", null); private static MSymbol Minput_method = "input-method"; @@ -40,7 +33,9 @@ namespace M17N.Input private static MSymbol Mstate = "state"; internal static MSymbol Mcandidates = "candidates"; private static MSymbol Mat_minus_zero = "@-0"; + private static MSymbol Matat = "@@"; + private static Xex.Symbol Qxi_include = "xi:include"; private static Xex.Symbol Qmap = "map"; private static Xex.Symbol Qrule = "rule"; private static Xex.Symbol Qkeyseq = "keyseq"; @@ -69,6 +64,12 @@ namespace M17N.Input private static Xex.Symbol Qtitle = "title"; private static Xex.Symbol Qeq = "="; private static Xex.Symbol Qeqeq = "=="; + private static Xex.Symbol Qhide = "hide"; + private static Xex.Symbol Qhide_candidates = "hide-candidates"; + private static Xex.Symbol Qshow = "show"; + private static Xex.Symbol Qshow_candidates = "show-candidates"; + private static Xex.Symbol Qkey_count = "key-count"; + private static Xex.Symbol Qsurrounding_text_flag = "surrounding-text-flag"; private static Xex.Symbol Qcandidates_group_size = "candidates-group-size"; private static Xex.Term Tnil = new Xex.Term ((Xex.Symbol) "nil"); @@ -77,883 +78,914 @@ namespace M17N.Input private static Dictionary im_table = new Dictionary (); - internal static MInputMethod im_global = null; - - [FlagsAttribute] - protected enum LoadStatus - { - None = 0x00, - Header = 0x01, - Body = 0x02, - Full = 0x03, - Error = 0x04, - }; - - [FlagsAttribute] - public enum ChangedStatus - { - None = 0x00, - StateTitle = 0x01, - PreeditText = 0x02, - CursorPos = 0x04, - CandidateList = 0x08, - CandidateIndex = 0x10, - CandidateShow = 0x20, - Preedit = PreeditText | CursorPos, - Candidate = CandidateList | CandidateIndex | CandidateShow, - } - - private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList - | ChangedStatus.CandidateIndex - | ChangedStatus.CandidateShow); - [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 keysyms - = new Dictionary (); - private static Dictionary keymodifiers - = new Dictionary (); - private static uint keysym_base = 0x200000; - private static uint char_mask = ~((uint) KeyModifier.All); - public static Key Reload; - - 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; - Reload = new Key (keysym_base); - keysyms["-reload"] = keysym_base++; - } - - 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 (int c) { key = (uint) 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); - } - - public bool HasModifier - { - get { return ((key & (uint) KeyModifier.All) != 0); } - } - - public static bool operator== (Key k1, Key k2) - { - return k1.key == k2.key; - } - - public static bool operator!= (Key k1, Key k2) - { - return k1.key != k2.key; - } - - public override bool Equals (object o) { return key == ((Key) o).key; } - - public override int GetHashCode () { return (int) key; } - - 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 int ToChar () - { - return (int) (key & 0x1FFFFF); - } - - public override string ToString () - { - int c = ToChar (); - MText mt = null; - if (c < 0x20) - foreach (KeyValuePair kv in keysyms) - if ((uint) c == kv.Value) - { - mt = kv.Key; - break; - } - if (mt == null) - mt = new MText (c); - - KeyModifier m = ((KeyModifier) key) & KeyModifier.All; - - if (m != KeyModifier.None) - { - if ((m & KeyModifier.Shift) != KeyModifier.None) - mt.Ins (0, "S-"); - if ((m & KeyModifier.Control) != KeyModifier.None) - mt.Ins (0, "C-"); - if ((m & KeyModifier.Alt) != KeyModifier.None) - mt.Ins (0, "A-"); - if ((m & KeyModifier.AltGr) != KeyModifier.None) - mt.Ins (0, "G-"); - if ((m & KeyModifier.Super) != KeyModifier.None) - mt.Ins (0, "s-"); - if ((m & KeyModifier.Hyper) != KeyModifier.None) - mt.Ins (0, "H-"); - } - return (string) mt; - } - } - - internal class KeySeq : Xex.TermValue - { - public List keyseq = new List (); - - public override Xex.TermValue Clone () - { - KeySeq ks = new KeySeq (); - ks.keyseq.InsertRange (0, keyseq); - return ks; - } - - public KeySeq () { } - - public KeySeq (MPlist plist) - { - foreach (MPlist p in plist) - { - if (p.IsSymbol) - keyseq.Add (new Key (p.Symbol)); - else if (p.IsInteger) - keyseq.Add (new Key ((char) p.Integer)); - else if (p.IsPlist) - keyseq.Add (new Key (p.Plist)); - else - throw new Exception ("Invalid Key Sequence: " + plist); - } - } - - public KeySeq (MText mt) : base () - { - for (int i = 0; i < mt.Length; i++) - keyseq.Add (new Key ((uint) mt[i])); - } - - public KeySeq (List list) - { - int len = list.Count; - - for (int i = 0; i < len; i++) - { - if (list[i].IsInt) - keyseq.Add (new Key (list[i].Intval)); - else if (list[i].IsStr) - keyseq.Add (new Key (list[i].Strval)); - else if (list[i].IsSymbol) - keyseq.Add (new Key ((string) list[i].Symval)); - else - throw new Exception ("Invalid key: " + list[i]); - } - } - - public static Xex.TermValue parser (Xex.Domain domain, XmlNode node) - { - Xex.Term term = new Xex.Term (domain, node.FirstChild).Eval (domain); - return (term.IsStr ? new KeySeq ((MText) term.Strval) - : new KeySeq (term.Listval)); - } - - public override string ToString () - { - MText mt; - foreach (Key key in keyseq) - if (key.HasModifier || key.ToChar () < 0x20) - { - mt = "("; - foreach (Key k in keyseq) - { - if (mt.Length > 1) - mt.Cat (' '); - mt.Cat (k.ToString ()); - } - return (string) mt.Cat (")"); - } - mt = "\""; - foreach (Key k in keyseq) - { - int c = k.ToChar (); - - if (c == '\\' || c == '"') - mt.Cat ('\\'); - mt.Cat (c); - } - return (string) mt.Cat ("\""); - } - } - - public class Command - { - public MSymbol name; - public MText description; - internal List keys; - - public Command (MPlist p) - { - name = p.Symbol; - p = p.Next; - description = parse_description (p); - if (description == null) - description = "No description"; - keys = new List (); - 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[0].Value; - keys = new List (); - for (node = node.FirstChild; node != null; node = node.NextSibling) - { - if (node.Name == "description") - description = parse_description (node); - else if (node.Name == "keyseq") - keys.Add ((KeySeq) KeySeq.parser (null, node)); - } - } - - public override string ToString () - { - string str = "(" + name + " \"" + (string) description; - foreach (KeySeq keyseq in keys) - str += " " + keyseq; - return str + ")"; - } - } - - internal class Plugin - { - private string name; - private Assembly assembly; - private Type plugin_type; - - public Plugin (string name) - { - this.name = name; - } - - public MethodInfo GetMethod (Xex.Symbol name) - { - if (assembly == null) - { - assembly = Assembly.LoadFrom (name + ".dll"); - plugin_type = assembly.GetType ("M17n.MInputMethod.Plugin"); - } - - MethodInfo info = plugin_type.GetMethod ((string) name); - if (info == null) - throw new Exception ("Invalid plugin method: " + name); - return info; - } - - public override string ToString () - { - return String.Format ("(module {0}", name); - } - } - - internal class PluginMethod : Xex.Function - { - private Plugin plugin; - private MethodInfo method_info; - object[] parameters = new object[2]; - - public PluginMethod (Plugin plugin, string name) - : base ((Xex.Symbol) name, 0, -1) - { - this.plugin = plugin; - } - - public override Xex.Term Call (Xex.Domain domain, Xex.Variable vari, - Xex.Term[] args) - { - args = (Xex.Term[]) args.Clone (); - for (int i = 0; i < args.Length; i++) - { - args[i] = args[i].Eval (domain); - if (domain.Thrown) - return args[i]; - } - if (method_info == null) - method_info = plugin.GetMethod (name); - parameters[0] = domain.context; - parameters[1] = args; - return (Xex.Term) method_info.Invoke (null, parameters); - } - } - - internal abstract class Marker : Xex.TermValue - { - private MSymbol name; - - private Marker (MSymbol name) - { - this.name = name; - } - - public abstract int Position (Context ic); - - public virtual void Mark (Context ic) - { - throw new Exception ("Can't set predefined marker: " + name); - } - public virtual int CharAt (Context ic) - { - return ic.preedit[Position (ic)]; - } - - public override string ToString () - { - return "" + name.Name + ""; - } - - public static Xex.TermValue parser (Xex.Domain domain, XmlNode node) - { - return Get ((MSymbol) node.InnerText); - } - - public class Named : Marker - { - public Named (MSymbol name) : base (name) { } - - public override int Position (Context ic) - { - MPlist p = ic.marker_positions.Find (name); - return (p == null ? 0 : p.Integer); - } - - public override void Mark (Context ic) - { - ic.marker_positions.Put (name, ic.cursor_pos); - } - } - - public class Predefined : Marker - { - char tag; - - public Predefined (MSymbol name) : base (name) - { - tag = ((string) name)[1]; - } - - public override int Position (Context ic) - { - switch (tag) { - case '<': return 0; - case '>': return ic.preedit.Length; - case '-': return ic.cursor_pos - 1; - case '+': return ic.cursor_pos + 1; - case '[': - if (ic.cursor_pos > 0) - { - int pos = ic.cursor_pos; - int to; - ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to); - return pos; - } - return 0; - case ']': - if (ic.cursor_pos < ic.preedit.Length - 1) - { - int pos = ic.cursor_pos; - int from; - ic.preedit.FindProp (Mcandidates, pos, out from, out pos); - return pos; - } - return ic.preedit.Length; - default: - return tag - '0'; - } - } - } - - public class PredefinedAbsolute : Marker - { - private int pos; - - public PredefinedAbsolute (MSymbol name) : base (name) - { - if (! int.TryParse (((string) name).Substring (1), out pos)) - throw new Exception ("Invalid marker name: " + name); - } - - public override int Position (Context ic) - { - return (pos < ic.preedit.Length ? pos : ic.preedit.Length); - } - } - - public class PredefinedSurround : Marker - { - private int distance; - - public PredefinedSurround (MSymbol name) : base (name) - { - if (! int.TryParse (((string) name).Substring (2), out distance)) - throw new Exception ("Invalid marker name: " + name); - if (distance > 0) - distance--; - } - - public override int Position (Context ic) - { - return ic.cursor_pos + distance; - } - - public override int CharAt (Context ic) - { - int pos = ic.cursor_pos + distance; - if (pos < 0) - return ic.GetSurroundingChar (pos); - else if (pos >= ic.preedit.Length) - return ic.GetSurroundingChar (pos - ic.preedit.Length); - return ic.preedit[pos]; - } - } - - static internal Dictionary predefined_markers; - - static Marker () - { - predefined_markers = new Dictionary (); - MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]" }; - foreach (MSymbol s in symlist) - predefined_markers[s] = new Predefined (s); - } - - public static Marker Get (MSymbol name) - { - string str = name.Name; - if (str[0] == '@') - { - Predefined pred; - if (predefined_markers.TryGetValue (name, out pred)) - return pred; - if (str.Length == 1) - throw new Exception ("Invalid marker name: " + name); - if (Char.IsDigit (str[1])) - return new PredefinedAbsolute (name); - if (str.Length == 2 || name == Mat_minus_zero - || ! (str[1] == '-' || str[1] == '+')) - throw new Exception ("Invalid marker name: " + name); - return new PredefinedSurround (name); - } - return new Named (name); - } - } - - internal class Candidates - { - private class Block - { - public int Index; - public object Data; - - public Block (int index, Xex.Term term) - { - Index = index; - if (term.IsStr) - Data = (MText) term.Strval; - else - { - MPlist plist = new MPlist (); - MPlist p = plist; - foreach (Xex.Term t in term.Listval) - p = p.Add (MSymbol.mtext, (MText) t.Strval); - Data = plist; - } - } - - public Block (int index, MPlist plist) - { - Index = index; - if (plist.IsMText) - Data = plist.Text; - else if (plist.IsPlist) - Data = plist.Plist; - else - throw new Exception ("Invalid candidate: " + plist); - } - - public int Count - { - get { return (Data is MText - ? ((MText) Data).Length - : ((MPlist) Data).Count); } - } - - public object this[int i] - { - get { - if (Data is MText) return ((MText) Data)[i]; - return ((MPlist) Data)[i]; - } - } - } - - private Block[] blocks; - private int row = 0; - private int index = 0; - public object[] group; - - private bool IsFixed { get { return group != null; } } - private int Total { - get { - Block last = blocks[blocks.Length - 1]; - return last.Index + last.Count; } - } - - public int Column { - get { return (IsFixed ? index % group.Length - : index - blocks[row].Index); } - } - - public object Group { - get { return (IsFixed ? group : blocks[row].Data); } - } - - public int GroupLength - { - get { - if (IsFixed) - { - int nitems = group.Length; - int start = index - (index % nitems); - int total = Total; - return (start + nitems <= total ? nitems : total - start); - } - return blocks[row].Count; - } - } - - public object Current { - get { - return (IsFixed ? group[index % group.Length] - : blocks[row][index - blocks[row].Index]); - } - } - - public Candidates (MPlist list, int column) - { - int nblocks = list.Count; - - blocks = new Block[nblocks]; - for (int i = 0, start = 0; i < nblocks; i++, list = list.next) - start += (blocks[i] = new Block (index, list)).Count; - if (column > 0) - group = new object[column]; - } - - public Candidates (Xex.Term[] candidates, int column) - { - int nblocks = candidates.Length; - - blocks = new Block[nblocks]; - for (int i = 0, start = 0; i < nblocks; i++) - start += (blocks[i] = new Block (index, candidates[i])).Count; - if (column > 0) - group = new object[column]; - } - - public static void Detach (Context ic) - { - ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates); - ic.candidates = null; - ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos - | CandidateAll); - } - - // Fill the array "group" by candidates stating from INDEX. - // INDEX must be a multiple of "column". Set NTIMES to the - // number of valid candidates in "group". Update "block" if - // necessary. Return "group". - - private int fill_group (int start) - { - int nitems = group.Length; - int r = row; - Block b = blocks[r]; - - if (start < b.Index) - while (start < b.Index) - b = blocks[--r]; - else - while (start >= b.Index + b.Count) - b = blocks[++r]; - row = r; - - int count = b.Count; - start -= b.Index; - for (int i = 0; i < nitems; i++, start++) - { - if (start >= count) - { - r++; - if (r == blocks.Length) - return i; - b = blocks[r]; - count = b.Count; - start = 0; - } - group[i] = b[start]; - } - return nitems; - } - - // Update "row" to what contains the first candidate of - // the previous candidate-group, update "current_index", and - // update "group" if necessary. Return the previous - // candidate-group. Set NITEMS to the number of valid - // candidates contained in that group. - - public int PrevGroup () - { - int nitems; - int col = Column; - - if (IsFixed) - { - nitems = group.Length; - if ((index -= col + nitems) < 0) - index = (Total / nitems) * nitems; - nitems = fill_group (index); - } - else - { - row = row > 0 ? row-- : blocks.Length - 1; - nitems = blocks[row].Count; - index = blocks[row].Index; - } - index += col < nitems ? col : nitems - 1; - return nitems; - } - - public int NextGroup () - { - int nitems; - int col = Column; - - if (IsFixed) - { - nitems = group.Length; - if ((index += nitems - col) >= Total) - index = 0; - nitems = fill_group (index); - } - else - { - row = row < blocks.Length - 1 ? row + 1 : 0; - nitems = blocks[row].Count; - index = blocks[row].Count; - } - index += col < nitems ? col : nitems - 1; - return nitems; - } - - public void Prev () - { - int col = Column; - - if (col == 0) - { - int nitems = PrevGroup (); - index += col < nitems - 1 ? col : nitems - 1; - } - else - index--; - } - - public void Next () - { - int col = Column; - int nitems = GroupLength; + internal static MInputMethod im_global = null; - if (col == nitems - 1) - { - nitems = NextGroup (); - index -= Column; - } - else - index++; - } + [FlagsAttribute] + protected enum LoadStatus + { + None = 0x00, + Header = 0x01, + Body = 0x02, + Full = 0x03, + Error = 0x04, + }; - public void First () - { - index -= Column; - } + [FlagsAttribute] + public enum ChangedStatus + { + None = 0x00, + StateTitle = 0x01, + PreeditText = 0x02, + CursorPos = 0x04, + CandidateList = 0x08, + CandidateIndex = 0x10, + CandidateShow = 0x20, + Preedit = PreeditText | CursorPos, + Candidate = CandidateList | CandidateIndex | CandidateShow, + } - public void Last () - { - index += GroupLength - (Column + 1); - } + private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList + | ChangedStatus.CandidateIndex + | ChangedStatus.CandidateShow); - public void Select (int col) - { - int maxcol = GroupLength - 1; - if (col > maxcol) - col = maxcol; - index = index - Column + col; - } - } + [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 keysyms + = new Dictionary (); + private static Dictionary keymodifiers + = new Dictionary (); + private static uint keysym_base = 0x200000; + private static uint char_mask = ~((uint) KeyModifier.All); + public static Key Reload; + + 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; + Reload = new Key (keysym_base); + keysyms["-reload"] = keysym_base++; + } + + 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 (int c) { key = (uint) 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); + } + + public bool HasModifier + { + get { return ((key & (uint) KeyModifier.All) != 0); } + } + + public static bool operator== (Key k1, Key k2) + { + return k1.key == k2.key; + } + + public static bool operator!= (Key k1, Key k2) + { + return k1.key != k2.key; + } + + public override bool Equals (object o) { return key == ((Key) o).key; } + + public override int GetHashCode () { return (int) key; } + + 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 int ToChar () + { + return (int) (key & 0x1FFFFF); + } + + public override string ToString () + { + int c = ToChar (); + MText mt = null; + if (c < 0x20) + foreach (KeyValuePair kv in keysyms) + if ((uint) c == kv.Value) + { + mt = kv.Key; + break; + } + if (mt == null) + mt = new MText (c); + + KeyModifier m = ((KeyModifier) key) & KeyModifier.All; + + if (m != KeyModifier.None) + { + if ((m & KeyModifier.Shift) != KeyModifier.None) + mt.Ins (0, "S-"); + if ((m & KeyModifier.Control) != KeyModifier.None) + mt.Ins (0, "C-"); + if ((m & KeyModifier.Alt) != KeyModifier.None) + mt.Ins (0, "A-"); + if ((m & KeyModifier.AltGr) != KeyModifier.None) + mt.Ins (0, "G-"); + if ((m & KeyModifier.Super) != KeyModifier.None) + mt.Ins (0, "s-"); + if ((m & KeyModifier.Hyper) != KeyModifier.None) + mt.Ins (0, "H-"); + } + return (string) mt; + } + } + + internal class KeySeq : Xex.TermValue + { + public List keyseq = new List (); + + public override Xex.TermValue Clone () + { + KeySeq ks = new KeySeq (); + ks.keyseq.InsertRange (0, keyseq); + return ks; + } + + public KeySeq () { } + + public KeySeq (MPlist plist) + { + foreach (MPlist p in plist) + { + if (p.IsSymbol) + keyseq.Add (new Key (p.Symbol)); + else if (p.IsInteger) + keyseq.Add (new Key ((char) p.Integer)); + else if (p.IsPlist) + keyseq.Add (new Key (p.Plist)); + else + throw new Exception ("Invalid Key Sequence: " + plist); + } + } + + public KeySeq (MText mt) : base () + { + for (int i = 0; i < mt.Length; i++) + keyseq.Add (new Key ((uint) mt[i])); + } + + public KeySeq (List list) + { + int len = list.Count; + + for (int i = 0; i < len; i++) + { + if (list[i].IsInt) + keyseq.Add (new Key (list[i].Intval)); + else if (list[i].IsStr) + keyseq.Add (new Key (list[i].Strval)); + else if (list[i].IsSymbol) + keyseq.Add (new Key ((string) list[i].Symval)); + else + throw new Exception ("Invalid key: " + list[i]); + } + } + + public static Xex.TermValue parser (Xex.Domain domain, XmlNode node) + { + Xex.Term term = new Xex.Term (domain, node.FirstChild).Eval (domain); + return (term.IsStr ? new KeySeq ((MText) term.Strval) + : new KeySeq (term.Listval)); + } + + public override string ToString () + { + MText mt; + foreach (Key key in keyseq) + if (key.HasModifier || key.ToChar () < 0x20) + { + mt = "("; + foreach (Key k in keyseq) + { + if (mt.Length > 1) + mt.Cat (' '); + mt.Cat (k.ToString ()); + } + return (string) mt.Cat (")"); + } + mt = "\""; + foreach (Key k in keyseq) + { + int c = k.ToChar (); + + if (c == '\\' || c == '"') + mt.Cat ('\\'); + mt.Cat (c); + } + return (string) mt.Cat ("\""); + } + } + + public class Command + { + public MSymbol name; + public MText description; + internal List keys; + + public Command (MPlist p) + { + name = p.Symbol; + p = p.Next; + description = parse_description (p); + if (description == null) + description = "No description"; + keys = new List (); + 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[0].Value; + keys = new List (); + for (node = node.FirstChild; node != null; node = node.NextSibling) + { + if (node.Name == "description") + description = parse_description (node); + else if (node.Name == "keyseq") + keys.Add ((KeySeq) KeySeq.parser (null, node)); + } + } + + public override string ToString () + { + string str = "(" + name + " \"" + (string) description; + foreach (KeySeq keyseq in keys) + str += " " + keyseq; + return str + ")"; + } + } + + internal class Plugin + { + private string name; + private Assembly assembly; + private Type plugin_type; + + public Plugin (string name) + { + this.name = name; + } + + public MethodInfo GetMethod (Xex.Symbol name) + { + if (assembly == null) + { + assembly = Assembly.LoadFrom (name + ".dll"); + plugin_type = assembly.GetType ("M17n.MInputMethod.Plugin"); + } + + MethodInfo info = plugin_type.GetMethod ((string) name); + if (info == null) + throw new Exception ("Invalid plugin method: " + name); + return info; + } + + public override string ToString () + { + return String.Format ("(module {0}", name); + } + } + + internal class PluginMethod : Xex.Function + { + private Plugin plugin; + private MethodInfo method_info; + object[] parameters = new object[2]; + + public PluginMethod (Plugin plugin, string name) + : base ((Xex.Symbol) name, 0, -1) + { + this.plugin = plugin; + } + + public override Xex.Term Call (Xex.Domain domain, Xex.Variable vari, + Xex.Term[] args) + { + args = (Xex.Term[]) args.Clone (); + for (int i = 0; i < args.Length; i++) + { + args[i] = args[i].Eval (domain); + if (domain.Thrown) + return args[i]; + } + if (method_info == null) + method_info = plugin.GetMethod (name); + parameters[0] = domain.context; + parameters[1] = args; + return (Xex.Term) method_info.Invoke (null, parameters); + } + } + + internal abstract class Marker : Xex.TermValue + { + private MSymbol name; + + private Marker (MSymbol name) + { + this.name = name; + } + + public abstract int Position (Context ic); + + public virtual void Mark (Context ic) + { + throw new Exception ("Can't set predefined marker: " + name); + } + public virtual int CharAt (Context ic) + { + return ic.preedit[Position (ic)]; + } + + public override string ToString () + { + return "" + name.Name + ""; + } + + public static Xex.TermValue parser (Xex.Domain domain, XmlNode node) + { + return Get ((MSymbol) node.InnerText); + } + + public class Named : Marker + { + public Named (MSymbol name) : base (name) { } + + public override int Position (Context ic) + { + MPlist p = ic.marker_positions.Find (name); + return (p == null ? 0 : p.Integer); + } + + public override void Mark (Context ic) + { + ic.marker_positions.Put (name, ic.cursor_pos); + } + } + + public class Predefined : Marker + { + char tag; + + public Predefined (char tag) : base ("@" + tag) { this.tag = tag; } + + public override int Position (Context ic) + { + switch (tag) { + case '<': return 0; + case '>': return ic.preedit.Length; + case '-': return ic.cursor_pos - 1; + case '+': return ic.cursor_pos + 1; + case '[': + if (ic.cursor_pos > 0) + { + int pos = ic.cursor_pos; + int to; + ic.preedit.FindProp (Mcandidates, pos - 1, out pos, out to); + return pos; + } + return 0; + case ']': + if (ic.cursor_pos < ic.preedit.Length - 1) + { + int pos = ic.cursor_pos; + int from; + ic.preedit.FindProp (Mcandidates, pos, out from, out pos); + return pos; + } + return ic.preedit.Length; + default: + return tag - '0'; + } + } + } + + public class PredefinedAbsolute : Marker + { + private int pos; + + public PredefinedAbsolute (MSymbol name) : base (name) + { + if (! int.TryParse (((string) name).Substring (1), out pos)) + throw new Exception ("Invalid marker name: " + name); + } + + public override int Position (Context ic) + { + return (pos < ic.preedit.Length ? pos : ic.preedit.Length); + } + } + + public class PredefinedSurround : Marker + { + private int distance; + + public PredefinedSurround (MSymbol name) : base (name) + { + if (! int.TryParse (((string) name).Substring (2), out distance)) + throw new Exception ("Invalid marker name: " + name); + if (distance > 0) + distance--; + } + + public override int Position (Context ic) + { + return ic.cursor_pos + distance; + } + + public override int CharAt (Context ic) + { + int pos = ic.cursor_pos + distance; + if (pos < 0) + return ic.GetSurroundingChar (pos); + else if (pos >= ic.preedit.Length) + return ic.GetSurroundingChar (pos - ic.preedit.Length); + return ic.preedit[pos]; + } + } + + static internal Dictionary predefineds; + + static Marker () + { + predefineds = new Dictionary (); + predefineds ["@<"] = predefineds["@first"] = new Predefined ('<'); + predefineds ["@>"] = predefineds["@last"] = new Predefined ('>'); + predefineds ["@-"] = predefineds["@previous"] = new Predefined ('-'); + predefineds ["@+"] = predefineds["@next"] = new Predefined ('+'); + predefineds ["@["] = predefineds["@previous-candidate-change"] + = new Predefined ('['); + predefineds ["@]"] = predefineds["@next-candidate-change"] + = new Predefined (']'); + } + + public static Marker Get (MSymbol name) + { + string str = name.Name; + if (str[0] == '@') + { + Predefined pred; + if (predefineds.TryGetValue (name, out pred)) + return pred; + if (str.Length == 1) + throw new Exception ("Invalid marker name: " + name); + if (Char.IsDigit (str[1])) + return new PredefinedAbsolute (name); + if (str.Length == 2 || name == Mat_minus_zero + || ! (str[1] == '-' || str[1] == '+')) + throw new Exception ("Invalid marker name: " + name); + return new PredefinedSurround (name); + } + return new Named (name); + } + } + + internal class Candidates + { + private class Block + { + public int Index; + public object Data; + + public Block (int index, Xex.Term term) + { + Index = index; + if (term.IsStr) + Data = (MText) term.Strval; + else + { + MPlist plist = new MPlist (); + MPlist p = plist; + foreach (Xex.Term t in term.Listval) + p = p.Add (MSymbol.mtext, (MText) t.Strval); + Data = plist; + } + } + + public Block (int index, MPlist plist) + { + Index = index; + if (plist.IsMText) + Data = plist.Text; + else if (plist.IsPlist) + Data = plist.Plist; + else + throw new Exception ("Invalid candidate: " + plist); + } + + public int Count + { + get { return (Data is MText + ? ((MText) Data).Length + : ((MPlist) Data).Count); } + } + + public object this[int i] + { + get { + if (Data is MText) return ((MText) Data)[i]; + return ((MPlist) Data)[i]; + } + } + } + + private Block[] blocks; + private int row = 0; + private int index = 0; + public object[] group; + + private bool IsFixed { get { return group != null; } } + private int Total { + get { + Block last = blocks[blocks.Length - 1]; + return last.Index + last.Count; } + } + + public int Column { + get { return (IsFixed ? index % group.Length + : index - blocks[row].Index); } + } + + public object Group { + get { return (IsFixed ? group : blocks[row].Data); } + } + + public int GroupLength + { + get { + if (IsFixed) + { + int nitems = group.Length; + int start = index - (index % nitems); + int total = Total; + return (start + nitems <= total ? nitems : total - start); + } + return blocks[row].Count; + } + } + + public object Current { + get { + return (IsFixed ? group[index % group.Length] + : blocks[row][index - blocks[row].Index]); + } + } + + public Candidates (MPlist list, int column) + { + int nblocks = list.Count; + + blocks = new Block[nblocks]; + for (int i = 0, start = 0; i < nblocks; i++, list = list.next) + start += (blocks[i] = new Block (index, list)).Count; + if (column > 0) + { + group = new object[column]; + fill_group (0); + } + } + + public Candidates (Xex.Term[] candidates, int column) + { + int nblocks = candidates.Length; + + blocks = new Block[nblocks]; + for (int i = 0, start = 0; i < nblocks; i++) + start += (blocks[i] = new Block (index, candidates[i])).Count; + if (column > 0) + { + group = new object[column]; + fill_group (0); + } + } + + public static void Detach (Context ic) + { + ic.preedit.PopProp (0, ic.preedit.Length, Mcandidates); + ic.candidates = null; + ic.changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos + | CandidateAll); + } + + // Fill the array "group" by candidates stating from START. + // START must be a multiple of "column". Return the number of + // valid candidates in "group". + + private int fill_group (int start) + { + int nitems = group.Length; + int r = row; + Block b = blocks[r]; + + if (start < b.Index) + while (start < b.Index) + b = blocks[--r]; + else + while (start >= b.Index + b.Count) + b = blocks[++r]; + row = r; + + int count = b.Count; + start -= b.Index; + for (int i = 0; i < nitems; i++, start++) + { + if (start >= count) + { + r++; + if (r == blocks.Length) + return i; + b = blocks[r]; + count = b.Count; + start = 0; + } + group[i] = b[start]; + } + return nitems; + } + + // Update "row" to what contains the first candidate of + // the previous candidate-group, update "current_index", and + // update "group" if necessary. Return the previous + // candidate-group. Set NITEMS to the number of valid + // candidates contained in that group. + + public int PrevGroup () + { + int nitems; + int col = Column; + + if (IsFixed) + { + nitems = group.Length; + if ((index -= col + nitems) < 0) + index = (Total / nitems) * nitems; + nitems = fill_group (index); + } + else + { + row = row > 0 ? row-- : blocks.Length - 1; + nitems = blocks[row].Count; + index = blocks[row].Index; + } + index += col < nitems ? col : nitems - 1; + return nitems; + } + + public int NextGroup () + { + int nitems; + int col = Column; + + if (IsFixed) + { + nitems = group.Length; + if ((index += nitems - col) >= Total) + index = 0; + nitems = fill_group (index); + } + else + { + row = row < blocks.Length - 1 ? row + 1 : 0; + nitems = blocks[row].Count; + index = blocks[row].Count; + } + index += col < nitems ? col : nitems - 1; + return nitems; + } + + public void Prev () + { + int col = Column; + + if (col == 0) + { + int nitems = PrevGroup (); + index += col < nitems - 1 ? col : nitems - 1; + } + else + index--; + } + + public void Next () + { + int col = Column; + int nitems = GroupLength; + + if (col == nitems - 1) + { + nitems = NextGroup (); + index -= Column; + } + else + index++; + } + + public void First () + { + index -= Column; + } + + public void Last () + { + index += GroupLength - (Column + 1); + } + + public object Select (int col) + { + int maxcol = GroupLength - 1; + if (col > maxcol) + col = maxcol; + index = index - Column + col; + return Current; + } + + public object Select (Selector selector) + { + switch (selector.Tag) + { + case '<': First (); break; + case '>': Last (); break; + case '-': Prev (); break; + case '+': Next (); break; + case '[': PrevGroup (); break; + case ']': NextGroup (); break; + default: break; + } + return Current; + } + + public override string ToString () + { + return (String.Format ("", row, index) + + Group + + ""); + } + } internal class Selector : Xex.TermValue { @@ -962,22 +994,20 @@ namespace M17N.Input static Selector () { selectors = new Dictionary (); - MSymbol[] symlist = new MSymbol[] { "@<", "@=", "@>", "@-", "@+", - "@[", "@]" }; - foreach (MSymbol s in symlist) - selectors[s] = new Selector (s); - selectors["@first"] = new Selector ('<'); - selectors["@current"] = new Selector ('='); - selectors["@last"] = new Selector ('>'); - selectors["@previous"] = new Selector ('-'); - selectors["@next"] = new Selector ('+'); - selectors["@previous-candidate-change"] = new Selector ('['); - selectors["@next-candidate-change"] = new Selector (']'); + selectors ["@<"] = selectors["@first"] = new Selector ('<'); + selectors ["@="] = selectors["@current"] = new Selector ('='); + selectors ["@>"] = selectors["@last"] = new Selector ('>'); + selectors ["@-"] = selectors["@previous"] = new Selector ('-'); + selectors ["@+"] = selectors["@next"] = new Selector ('+'); + selectors ["@["] = selectors["@previous-candidate-change"] + = new Selector ('['); + selectors ["@]"] = selectors["@next-candidate-change"] + = new Selector (']'); } - private char tag; + private readonly char tag; - private Selector (MSymbol sym) { tag = sym.Name[1]; } + public char Tag { get { return tag; } } private Selector (char tag) { this.tag = tag; } @@ -993,20 +1023,6 @@ namespace M17N.Input throw new Exception ("Invalid selector name: " + name); return selector; } - - public void Select (Candidates candidates) - { - switch (tag) - { - case '<': candidates.First (); break; - case '>': candidates.Last (); break; - case '-': candidates.Prev (); break; - case '+': candidates.Next (); break; - case '[': candidates.PrevGroup (); break; - case ']': candidates.NextGroup (); break; - default: break; - } - } } internal class Map @@ -1123,12 +1139,12 @@ namespace M17N.Input internal class State { - public Xex.Symbol name; + public MSymbol name; public MText title; public Xex.Term[] enter_actions, fallback_actions; public Keymap keymap = new Keymap (); - public State (Xex.Symbol name, MText title) + public State (MSymbol name, MText title) { this.name = name; this.title = title; @@ -1166,7 +1182,7 @@ namespace M17N.Input { if (! plist.IsSymbol) throw new Exception ("Invalid state: " + plist); - this.name = plist.Symbol.Name; + this.name = plist.Symbol; plist = plist.next; if (plist.IsMText) { @@ -1223,8 +1239,7 @@ namespace M17N.Input internal Xex.Symbol[] var_names; internal Dictionary plugins; internal Dictionary maps; - internal Dictionary states; - internal State initial_state; + internal MPlist states; static MInputMethod () { @@ -1236,8 +1251,8 @@ namespace M17N.Input im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, -1); im_domain.DefSubr (Fdelete, "delete", false, 1, 1); im_domain.DefSubr (Fselect, "select", false, 1, 1); - im_domain.DefSubr (Fshow, "show", false, 0, 0); - im_domain.DefSubr (Fhide, "hide", false, 0, 0); + im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0); + im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0); im_domain.DefSubr (Fmove, "move", false, 1, 1); im_domain.DefSubr (Fmark, "mark", false, 1, 1); im_domain.DefSubr (Fpushback, "pushback", false, 1, 1); @@ -1248,7 +1263,7 @@ namespace M17N.Input im_domain.DefSubr (Fshift, "shift", false, 1, 1); im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0); im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1); - im_domain.DefSubr (Fkey_count, "key-count", false, 1, 1); + im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0); im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0); @@ -1335,15 +1350,14 @@ namespace M17N.Input mdb = MDatabase.Find (tag); if (mdb == null) return false; - mdb.name_table = Xex.Symbol.Table; try { - MSymbol format = mdb.Format; - - if (format == MSymbol.plist) - load ((MPlist) mdb.Load (Mmap), false); + if (mdb.Format == MSymbol.plist) + load (mdb.Load (Mmap), false); else { - XmlDocument doc = (XmlDocument) mdb.Load (Mmap_list); + XmlDocument doc = new XmlDocument (Xex.Symbol.NameTable); + if (! mdb.Load (doc, Mmap_list)) + throw new Exception ("Load error" + mdb.tag); load (doc.DocumentElement, false); } } catch (Exception e) { @@ -1360,13 +1374,16 @@ namespace M17N.Input mdb = MDatabase.Find (tag); if (mdb == null) return false; - mdb.name_table = Xex.Symbol.Table; try { - object obj = mdb.Load (); - if (obj is MPlist) - load ((MPlist) obj, true); + if (mdb.Format == MSymbol.plist) + load (mdb.Load (), true); else - load ((XmlDocument) obj, true); + { + XmlDocument doc = new XmlDocument (Xex.Symbol.NameTable); + if (! mdb.Load (doc)) + throw new Exception ("Load error" + mdb.tag); + load (doc.DocumentElement, true); + } } catch (Exception e) { Console.WriteLine (e); load_status = LoadStatus.Error; @@ -1378,17 +1395,17 @@ namespace M17N.Input private void add_default_state () { - Xex.Symbol Qinit = "init"; + MSymbol Qinit = "init"; State state = new State (Qinit, title); foreach (KeyValuePairkv in maps) state.keymap.AddMap (kv.Value, null); - states[Qinit] = initial_state = state; + states.Add (Qinit, state); } private void load (MPlist plist, bool full) { maps = new Dictionary (); - states = new Dictionary (); + states = new MPlist (); for (; ! plist.IsEmpty; plist = plist.next) if (plist.IsPlist) @@ -1433,7 +1450,7 @@ namespace M17N.Input commands = new Command[0]; if (! full) return; - if (states.Count == 0) + if (states.IsEmpty) add_default_state (); } @@ -1442,7 +1459,7 @@ namespace M17N.Input bool skip_header = load_status == LoadStatus.Header; maps = new Dictionary (); - states = new Dictionary (); + states = new MPlist (); if (node.NodeType == XmlNodeType.Document) node = node.FirstChild; @@ -1463,7 +1480,7 @@ namespace M17N.Input else if (node.Name == "command-list") parse_commands (node); } - else if (full) + if (full) { if (node.Name == "module-list") parse_plugins (node); @@ -1483,7 +1500,7 @@ namespace M17N.Input commands = new Command[0]; if (! full) return; - if (states.Count == 0) + if (states.IsEmpty) add_default_state (); } @@ -1513,110 +1530,12 @@ namespace M17N.Input return node.InnerText; } - private void new_variable (Xex.Symbol name, string desc, int val, - MPlist pl, Xex.Variable vari) - { - int[] range; - - if (pl.IsEmpty) - range = null; - else - { - int nrange = pl.Count; - range = new int[nrange * 2]; - for (int i = 0; i < nrange; i++) - { - if (pl.IsPlist) - { - MPlist p = pl.Plist; - - if (! p.IsInteger || ! p.next.IsInteger) - throw new Exception ("Invalid range: " + p); - range[i * 2] = p.Integer; - range[i * 2 + 1] = p.next.Integer; - } - else if (pl.IsInteger) - range[i * 2] = range[i * 2 + 1] = pl.Integer; - else - throw new Exception ("Invalid range: " + pl); - } - } - if (vari == null) - domain.Defvar (new Xex.Variable.Int (name, desc, val, range)); - else - { - Xex.Term term = new Xex.Term (val); - vari.Value = term; - vari.DefaultValue = term; - vari.Range = range; - } - } - - private void new_variable (Xex.Symbol name, string desc, MText val, - MPlist pl, Xex.Variable vari) - { - string[] range; - - if (pl.IsEmpty) - range = null; - else - { - range = new string[pl.Count * 2]; - for (int i = 0; i < range.Length; i++) - { - if (pl.IsMText) - range[i] = (string) pl.Text; - else - throw new Exception ("Invalid range: " + pl); - } - } - if (vari == null) - domain.Defvar (new Xex.Variable.Str (name, desc, (string) val, range)); - else - { - Xex.Term term = new Xex.Term ((string) val); - vari.Value = term; - vari.DefaultValue = term; - vari.Range = range; - } - } - - private void new_variable (Xex.Symbol name, string desc, MSymbol val, - MPlist pl, Xex.Variable vari) - { - Xex.Symbol[] range; - Xex.Symbol sym = val.Name; - - if (pl.IsEmpty) - range = null; - else - { - range = new Xex.Symbol[pl.Count * 2]; - for (int i = 0; i < range.Length; i++) - { - if (pl.IsSymbol) - range[i] = pl.Symbol.Name; - else - throw new Exception ("Invalid range: " + pl); - } - } - if (vari == null) - domain.Defvar (new Xex.Variable.Sym (name, desc, sym, range)); - else - { - Xex.Term term = new Xex.Term (sym); - vari.Value = term; - vari.DefaultValue = term; - vari.Range = range; - } - } - private Xex.Variable get_global_var (Xex.Symbol name) { if (im_global == null || this != im_global) { - tag = new MDatabase.Tag (Minput_method, MSymbol.t, MSymbol.nil, - "global"); + MDatabase.Tag tag = + new MDatabase.Tag (Minput_method, MSymbol.t, MSymbol.nil, "global"); im_global = im_table[tag]; if (! im_global.Open ()) throw new Exception ("Failed to load global"); @@ -1637,23 +1556,84 @@ namespace M17N.Input Xex.Symbol name = (Xex.Symbol) p.Symbol.Name; var_names[i] = name; p = p.next; - string desc = (string) parse_description (p); + MText mt = parse_description (p); + string desc = mt == null ? null : (string) mt; + if (! p.IsEmpty) + p = p.next; Xex.Variable vari = get_global_var (name); if (vari != null) domain.Defvar (vari); - if (desc != null) - p = p.next; - if (! p.IsEmpty) + if (p.IsInteger) + { + int n = p.Integer; + int[] range = null; + + p = p.Next; + if (! p.IsEmpty) + { + int nrange = p.Count; + range = new int[nrange * 2]; + for (int j = 0; j < nrange; j++) + { + if (p.IsPlist) + { + MPlist p0 = p.Plist; + + if (! p0.IsInteger || ! p0.next.IsInteger) + throw new Exception ("Invalid range: " + p0); + range[j * 2] = p0.Integer; + range[j * 2 + 1] = p0.next.Integer; + } + else if (p.IsInteger) + range[j * 2] = range[j * 2 + 1] = p.Integer; + else + throw new Exception ("Invalid range: " + p); + } + } + domain.DefvarInt (name, n, desc, range); + } + else if (p.IsMText) + { + string str = (string) p.Text; + string[] range = null; + + p = p.next; + if (! p.IsEmpty) + { + range = new string[p.Count]; + for (int j = 0; j < range.Length; j++) + { + if (p.IsMText) + range[j] = (string) p.Text; + else + throw new Exception ("Invalid range: " + p); + } + } + domain.DefvarStr (name, str, desc, range); + } + else if (p.IsSymbol) { - if (p.IsInteger) - new_variable (name, desc, p.Integer, p.next, vari); - else if (p.IsMText) - new_variable (name, desc, p.Text, p.next, vari); - else if (p.IsSymbol) - new_variable (name, desc, p.Symbol, p.next, vari); + Xex.Symbol sym = p.Symbol.Name; + Xex.Symbol[] range; + + p = p.next; + if (p.IsEmpty) + range = null; else - throw new Exception ("Invalid variable type: " + p.val); + { + range = new Xex.Symbol[p.Count]; + for (int j = 0; j < range.Length; j++) + { + if (p.IsSymbol) + range[j] = p.Symbol.Name; + else + throw new Exception ("Invalid range: " + p); + } + } + domain.DefvarSym (name, sym, desc, range); } + else if (! p.IsEmpty) + throw new Exception ("Invalid variable type: " + p.val); } } @@ -1728,35 +1708,71 @@ namespace M17N.Input } } + private void parse_include (XmlNode node) + { + XmlNode n; + MSymbol language, name, subname; + MSymbol part, section; + node = node.FirstChild; + n = node.FirstChild; + language = n.InnerText; + n = n.NextSibling; + name = n.InnerText; + n = n.NextSibling; + if (n != null) + subname = n.InnerText; + else + subname = MSymbol.nil; + node = node.NextSibling; + part = node.InnerText; + node = node.NextSibling; + if (node != null) + section = node.InnerText; + else + section = MSymbol.nil; + include_part (language, name, subname, part, section); + } + private void parse_macros (XmlNode node) { for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling) if (nn.NodeType == XmlNodeType.Element) - domain.Defun (nn, true); + { + if (nn.Name == Xex.Qdefun) + domain.Defun (nn, true); + else if (nn.Name == Qxi_include) + parse_include (nn); + } for (XmlNode nn = node.FirstChild; nn != null; nn = nn.NextSibling) - if (nn.NodeType == XmlNodeType.Element) + if (nn.NodeType == XmlNodeType.Element + && nn.Name == Xex.Qdefun) domain.Defun (nn, false); } private void parse_maps (XmlNode node) { for (node = node.FirstChild; node != null; node = node.NextSibling) - if (node.Name == Qmap) - { - MSymbol name = node.Attributes[0].Value; - Map map = new Map (name); - maps[name] = map; - for (XmlNode nd = node.FirstChild; nd != null; nd = nd.NextSibling) - if (nd.Name == Qrule) - { - XmlNode n = nd.FirstChild; - if (n.Name != Qkeyseq) - continue; - KeySeq keyseq = (KeySeq) KeySeq.parser (domain, n); - Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling); - map.entries.Add (new Map.Entry (domain, keyseq, actions)); - } - } + { + if (node.Name == Qmap) + { + MSymbol name = node.Attributes[0].Value; + Map map = new Map (name); + maps[name] = map; + for (XmlNode nd = node.FirstChild; nd != null; + nd = nd.NextSibling) + if (nd.Name == Qrule) + { + XmlNode n = nd.FirstChild; + if (n.Name != Qkeyseq) + continue; + KeySeq keyseq = (KeySeq) KeySeq.parser (domain, n); + Xex.Term[] actions = Xex.ParseTerms (domain, n.NextSibling); + map.entries.Add (new Map.Entry (domain, keyseq, actions)); + } + } + else if (node.Name == Qxi_include) + parse_include (node); + } } private void parse_states (MPlist plist) @@ -1765,67 +1781,42 @@ namespace M17N.Input if (plist.IsPlist) { State state = new State (this, plist.Plist); - states[state.name] = state; - if (initial_state == null) - initial_state = state; + states.Add (state.name, state); } } private void parse_states (XmlNode node) { for (node = node.FirstChild; node != null; node = node.NextSibling) - if (node.Name == Qstate) - { - State state = new State (this, node); - states[state.name] = state; - if (initial_state == null) - initial_state = state; - } - } - - private void parse_include (MPlist plist) - { - if (! plist.IsPlist) - return; - MPlist p = plist.Plist; - MSymbol language, name, subname; - language = p.Symbol; - p = p.next; - if (! p.IsSymbol) - name = subname = MSymbol.nil; - else { - name = p.Symbol; - p = p.next; - if (! p.IsSymbol) - subname = MSymbol.nil; - else - subname = p.Symbol; + if (node.Name == Qstate) + { + State state = new State (this, node); + states.Add (state.name, state); + } + else if (node.Name == Qxi_include) + parse_include (node); } + } + private void include_part (MSymbol language, MSymbol name, MSymbol subname, + MSymbol part, MSymbol section) + { MInputMethod im = MInputMethod.Find (language, name, subname); if (im == null) return; if (! im.Open ()) return; - plist = plist.next; - if (! plist.IsSymbol) - return; - MSymbol target_type = plist.Symbol; - plist = plist.next; - MSymbol target_name = MSymbol.nil; - if (plist.IsSymbol) - target_name = plist.Symbol; - if (target_type == Mmacro) + if (part == Mmacro) { - if (target_name == MSymbol.nil) + if (section == MSymbol.nil) im.domain.CopyFunc (domain); else - im.domain.CopyFunc (domain, (Xex.Symbol) target_name.Name); + im.domain.CopyFunc (domain, (Xex.Symbol) section.Name); } - else if (target_type == Mmap) + else if (part == Mmap) { - if (target_name == MSymbol.nil) + if (section == MSymbol.nil) { foreach (KeyValuePair kv in im.maps) maps[kv.Key] = kv.Value; @@ -1833,27 +1824,57 @@ namespace M17N.Input else { Map map; - if (im.maps.TryGetValue (target_name, out map)) - maps[target_name] = map; + if (im.maps.TryGetValue (section, out map)) + maps[section] = map; } } - else if (target_type == Mstate) + else if (part == Mstate) { - if (target_name == MSymbol.nil) + if (section == MSymbol.nil) { - foreach (KeyValuePair kv in im.states) - states[kv.Key] = kv.Value; + for (MPlist p = im.states; ! p.IsEmpty; p = p.next) + states.Add (p.Key, p.Val); } else { - Xex.Symbol state_name = target_name.Name; - State state; - if (im.states.TryGetValue (state_name, out state)) - states[state_name] = state; + MSymbol state_name = (string) section.Name; + State state = (State) im.states.Get (state_name); + if (state != null) + states.Add (state.name, state); } } } + private void parse_include (MPlist plist) + { + if (! plist.IsPlist) + return; + MPlist p = plist.Plist; + MSymbol language, name, subname; + language = p.Symbol; + p = p.next; + if (! p.IsSymbol) + name = subname = MSymbol.nil; + else + { + name = p.Symbol; + p = p.next; + if (! p.IsSymbol) + subname = MSymbol.nil; + else + subname = p.Symbol; + } + plist = plist.next; + if (! plist.IsSymbol) + return; + MSymbol part = plist.Symbol; + plist = plist.next; + MSymbol section = MSymbol.nil; + if (plist.IsSymbol) + section = plist.Symbol; + include_part (language, name, subname, part, section); + } + private Xex.Term parse_cond (MPlist plist) { Xex.Term[] args = new Xex.Term[plist.Count]; @@ -1980,8 +2001,6 @@ namespace M17N.Input return parse_funcall_with_marker (p, name); if (name == Qshift) return parse_shift (p); - if (((string) name)[0] == '@') - return parse_char_at (sym); if (name == Qset || name == Qadd || name == Qsub || name == Qmul || name == Qdiv) { @@ -1996,6 +2015,10 @@ namespace M17N.Input { if (name == Qeq) name = Qeqeq; + else if (name == Qhide) + name = Qhide_candidates; + else if (name == Qshow) + name = Qshow_candidates; if (p.IsEmpty) return new Xex.Term (domain, name, null); else @@ -2004,6 +2027,10 @@ namespace M17N.Input } else if (plist.IsSymbol) { + if (plist.Symbol == Matat) + return new Xex.Term (domain, Qkey_count, null); + if (plist.Symbol == Mat_minus_zero) + return new Xex.Term (domain, Qsurrounding_text_flag, null); if (plist.Symbol.Name[0] == '@') return parse_char_at (plist.Symbol); return new Xex.Term (domain, (Xex.Symbol) plist.Symbol.Name); @@ -2033,10 +2060,9 @@ namespace M17N.Input if (pl.IsPlist) { MPlist p = pl.Plist; - if (! p.IsSymbol) continue; - domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null, null, true); + domain.Defun ((Xex.Symbol) p.Symbol.Name, null, null, true); } for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next) if (pl.IsPlist) @@ -2045,7 +2071,7 @@ namespace M17N.Input if (! p.IsSymbol) continue; - domain.Defun ((Xex.Symbol) p.Symbol.Name, false, null, + domain.Defun ((Xex.Symbol) p.Symbol.Name, null, parse_actions (p.next, false), false); } } @@ -2085,9 +2111,9 @@ namespace M17N.Input Xex.Term[] args) { if (args[0].IsInt) - ((Context) domain.context).insert (args[0].Intval); + ((Context) domain.context).insert (args[0].Intval, null); else - ((Context) domain.context).insert (args[0].Strval); + ((Context) domain.context).insert ((MText) args[0].Strval, null); return args[0]; } @@ -2098,8 +2124,13 @@ namespace M17N.Input Context ic = (Context) domain.context; Xex.Variable v = ic.domain.GetVar (Qcandidates_group_size, false); int column = (v == null ? 0 : v.Value.Intval); + Candidates candidates = new Candidates (args, column); + object candidate = candidates.Current; - ic.insert_candidates (new Candidates (args, column)); + if (candidate is MText) + ic.insert ((MText) candidate, candidates); + else + ic.insert ((int) candidate, candidates); return args[0]; } @@ -2131,14 +2162,25 @@ namespace M17N.Input private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari, Xex.Term[] args) { - Candidates can = ((Context) domain.context).candidates; + Context ic = (Context) domain.context; + Candidates can = ic.candidates; if (can != null) { + object candidate = can.Current; + + if (candidate is MText) + ic.delete (ic.cursor_pos - ((MText) candidate).Length); + else + ic.delete (ic.cursor_pos - 1); if (args[0].IsInt) - can.Select (args[0].Intval); + candidate = can.Select (args[0].Intval); else - ((Selector) args[0].Objval).Select (can); + candidate = can.Select ((Selector) args[0].Objval); + if (candidate is MText) + ic.insert ((MText) candidate, can); + else + ic.insert ((int) candidate, can); } return args[0]; } @@ -2224,11 +2266,11 @@ namespace M17N.Input Xex.Term[] args) { Context ic = (Context) domain.context; - State state; - if (ic.im.states.TryGetValue (args[0].Symval, out state)) - ((Context) domain.context).shift (state); - else - throw new Exception ("Unknown state: " + args[0].Symval); + MSymbol state_name = (string) args[0].Symval; + State state = (State) ic.im.states.Get (state_name); + if (state == null) + throw new Exception ("Unknown state: " + state_name); + ((Context) domain.context).shift (state); return args[0]; } @@ -2249,7 +2291,8 @@ namespace M17N.Input Xex.Variable vari, Xex.Term[] args) { - return new Xex.Term (GetSurroundingText == null ? 0 : 1); + return new Xex.Term (((Context) domain.context).GetSurroundingText == null + ? 0 : 1); } public override string ToString () @@ -2281,10 +2324,8 @@ namespace M17N.Input foreach (KeyValuePair kv in maps) str += " " + kv.Value; str += ") (states"; - foreach (KeyValuePair kv in states) - { - str += " (" + kv.Key + " " + kv.Value.keymap + ")"; - } + for (MPlist p = states; ! p.IsEmpty; p = p.next) + str += " (" + p.Key + " " + ((State) p.Val).keymap + ")"; return str + "))"; } @@ -2294,6 +2335,12 @@ namespace M17N.Input internal Xex.Domain domain; private bool active; + public Callback PreeditChanged; + public Callback StatusChanged; + public Callback CandidateChanged; + public Callback GetSurroundingText; + public Callback DelSurroundingText; + private MText status; private MText produced = new MText (); internal MText preedit = new MText (); @@ -2301,11 +2348,10 @@ namespace M17N.Input internal MPlist marker_positions = new MPlist (); internal Candidates candidates; - private int candidate_from, candidate_to; private bool candidate_show; public bool CandidateShow { get { return candidate_show; } } - private State state, prev_state; + private State initial_state, state, prev_state; private MText state_preedit = new MText (); private int state_key_head; private object state_var_values, state_initial_var_values; @@ -2333,11 +2379,16 @@ namespace M17N.Input private void set_cursor (string prefix, int pos) { cursor_pos = pos; + if (cursor_pos > 0) + candidates = (Candidates) preedit.GetProp (cursor_pos - 1, + Mcandidates); + else + candidates = null; } internal void reset () { - status = im.initial_state.title; + status = initial_state.title; produced.Del (); preedit.Del (); @@ -2350,7 +2401,7 @@ namespace M17N.Input state_preedit.Del (); state_var_values = state_initial_var_values; state_pos = 0; - shift (im.initial_state); + shift (initial_state); preceding_text.Del (); following_text.Del (); @@ -2400,12 +2451,9 @@ namespace M17N.Input return following_text[pos]; } - private void adjust_markers (int from, int to, object inserted) + private void adjust_markers (int from, int to, int inserted) { - int ins = (inserted == null ? 0 - : inserted is int ? 1 - : ((MText) inserted).Length); - int diff = ins - (to - from); + int diff = inserted - (to - from); for (MPlist p = marker_positions; ! p.IsEmpty; p = p.next) { @@ -2419,66 +2467,43 @@ namespace M17N.Input set_cursor ("adjust", from); } - private void preedit_replace (int from, int to, int c) + private void preedit_replace (int from, int to, int c, + Candidates candidates) { preedit.Del (from, to); preedit.Ins (from, c); - adjust_markers (from, to, c); + if (candidates != null) + { + preedit.PushProp (from, from + 1, Mcandidates, candidates); + changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos + | CandidateAll); + } + adjust_markers (from, to, 1); } - private void preedit_replace (int from, int to, MText mt) + private void preedit_replace (int from, int to, MText mt, + Candidates candidates) { preedit[from, to] = mt; - adjust_markers (from, to, mt); - } - - internal void insert (int c) - { - preedit_replace (cursor_pos, cursor_pos, c); - changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos; - } - - internal void insert (string str) - { - preedit_replace (cursor_pos, cursor_pos, (MText) str); - changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos; - } - - private void update_candidate () - { - object candidate = candidates.Current; - - if (candidate is MText) - { - preedit_replace (candidate_from, candidate_to, (MText) candidate); - candidate_to = candidate_from + ((MText) candidate).Length; - } - else + if (candidates != null) { - preedit_replace (candidate_from, candidate_to, (int) candidate); - candidate_to = candidate_from + 1; + preedit.PushProp (from, from + mt.Length, Mcandidates, candidates); + changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos + | CandidateAll); } - preedit.PushProp (candidate_from, candidate_to, - Mcandidates, this); - set_cursor ("update-candidate", candidate_to); - changed |= (ChangedStatus.Preedit | ChangedStatus.CursorPos - | CandidateAll); + adjust_markers (from, to, mt == null ? 0 : mt.Length); } - internal void insert_candidates (Candidates candidates) + internal void insert (int c, Candidates candidates) { - this.candidates = candidates; - candidate_from = candidate_to = cursor_pos; - update_candidate (); + preedit_replace (cursor_pos, cursor_pos, c, candidates); + changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos; } - internal void select (int n) + internal void insert (MText mt, Candidates candidates) { - if (candidates != null) - { - candidates.Select (n); - update_candidate (); - } + preedit_replace (cursor_pos, cursor_pos, mt, candidates); + changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos; } internal int delete (int pos) @@ -2489,10 +2514,10 @@ namespace M17N.Input { if (pos < 0) { - if (DeleteSurroundingText != null) + if (DelSurroundingText != null) { callback_arg.Set (MSymbol.integer, pos); - if (DeleteSurroundingText (this, callback_arg)) + if (DelSurroundingText (this, callback_arg)) { if (callback_arg.IsInteger) deleted = callback_arg.Integer - cursor_pos; @@ -2504,16 +2529,16 @@ namespace M17N.Input pos = 0; } if (pos < cursor_pos) - preedit_replace (pos, cursor_pos, null); + preedit_replace (pos, cursor_pos, null, null); } else { if (pos > preedit.Length) { - if (DeleteSurroundingText != null) + if (DelSurroundingText != null) { callback_arg.Set (MSymbol.integer, pos - preedit.Length); - if (DeleteSurroundingText (this, callback_arg)) + if (DelSurroundingText (this, callback_arg)) { if (callback_arg.IsInteger) deleted = callback_arg.Integer - cursor_pos; @@ -2525,7 +2550,7 @@ namespace M17N.Input pos = preedit.Length; } if (pos > cursor_pos) - preedit_replace (cursor_pos, pos, null); + preedit_replace (cursor_pos, pos, null, null); } if (deleted != 0) changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos; @@ -2602,9 +2627,9 @@ namespace M17N.Input internal void commit () { + Candidates.Detach (this); produced.Cat (preedit); - preedit_replace (0, preedit.Length, null); - changed |= ChangedStatus.Preedit; + preedit_replace (0, preedit.Length, null, null); } internal void shift (State state) @@ -2616,7 +2641,7 @@ namespace M17N.Input state = prev_state; } - if (state == im.initial_state) + if (state == initial_state) { commit (); keys.keyseq.RemoveRange (0, key_head); @@ -2649,6 +2674,7 @@ namespace M17N.Input throw new Exception ("Openging " + im.tag + " failed"); this.im = im; domain = new Xex.Domain ("context", im.domain, this); + initial_state = (State) im.states.Val; state_initial_var_values = domain.SaveValues (); reset (); active = true; @@ -2698,9 +2724,6 @@ namespace M17N.Input private bool handle_key () { - Console.Write ("\nHandle ({0}[{1}]) in {2}", - keys, key_head, state.name); - Keymap sub = keymap.Lookup (keys, ref key_head); if (sub != keymap) @@ -2716,7 +2739,7 @@ namespace M17N.Input { for (int i = state_key_head; i < key_head; i++) preedit_replace (cursor_pos, cursor_pos, - keys.keyseq[i].ToChar ()); + keys.keyseq[i].ToChar (), null); } if (keymap.submaps == null) { @@ -2740,13 +2763,13 @@ namespace M17N.Input } if (state == current_state) { - if (state == im.initial_state + if (state == initial_state && key_head < keys.keyseq.Count) return false; if (keymap != state.keymap) shift (state); else if (keymap.branch_actions == null) - shift (im.initial_state); + shift (initial_state); } } return true; @@ -2822,12 +2845,68 @@ namespace M17N.Input { CandidateChanged (this, callback_arg); } + return (! key_unhandled && produced.Length == 0); + } + } + + public class Session + { + Context ic; + MText mt; + int pos; - Console.Write ("\nPreedit(\"{0}\"/{1}), Produced({2})", - preedit, cursor_pos, produced); + public Session (MInputMethod im, MText mt, int pos) + { + ic = new Context (im); + this.mt = mt; + this.pos = pos; + ic.GetSurroundingText = get_surrounding_text; + ic.DelSurroundingText = del_surrounding_text; + } - return (! key_unhandled && produced.Length == 0); + private bool get_surrounding_text (Context ic, MPlist args) + { + int len = args.Integer; + if (len < 0) + args.Set (MSymbol.mtext, mt[0, pos]); + else + args.Set (MSymbol.mtext, mt[pos, mt.Length]); + return true; } + + private bool del_surrounding_text (Context ic, MPlist args) + { + int pos = this.pos + args.Integer; + if (pos < this.pos) + { + mt.Del (pos, this.pos); + this.pos = pos; + } + else + mt.Del (this.pos, pos); + return true; + } + + public bool HandleKey (Key key) + { + bool result = ic.Filter (key); + + if (! result) + { + MText produced = ic.Produced; + mt.Ins (pos, produced); + pos += produced.Length; + if (ic.UnhandledKey (out key)) + { + mt.Ins (pos, key.ToChar ()); + pos++; + } + } + return result; + } + + public int CurrentPos { get { return pos; } } + public MText Preedit { get { return ic.Preedit; } } } } }