private static MSymbol Mpushback = "pushback";
private static MSymbol Mkeyseq = "keyseq";
+ private static MSymbol Mget_surrounding_text = "get-surrounding-text";
+ private static MSymbol Mdel_surrounding_text = "del-surrounding-text";
+
+ private static MSymbol Mat_minus_zero = "@-0";
+
+ private static Xex.Symbol Nmap = "map";
+ private static Xex.Symbol Nrule = "rule";
+ private static Xex.Symbol Nkeyseq = "keyseq";
private static Xex.Symbol Nprogn = "progn";
private static Xex.Symbol Ninsert = "insert";
private static Xex.Symbol Ninsert_candidates = "insert-candidates";
= new Dictionary<string, KeyModifier> ();
private static uint keysym_base = 0x200000;
private static uint char_mask = ~((uint) KeyModifier.All);
+ public static Key Reload;
static Key ()
{
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)
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)
}
}
- public class KeySeq : Xex.TermValue
+ internal class KeySeq : Xex.TermValue
{
public List<Key> keyseq = new List<Key> ();
{
public MSymbol name;
public MText description;
- public List<KeySeq> keys;
+ internal List<KeySeq> keys;
public Command (MPlist p)
{
{
private MSymbol name;
- public Marker (MSymbol name)
+ private Marker (MSymbol name)
{
this.name = name;
}
public abstract int Position (Context ic);
- public abstract void Mark (Context ic);
- public abstract int CharAt (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 Xex.TermValue Clone () { return this; }
public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
{
- MSymbol name = node.InnerText;
-
- return Get ((Context) domain.context, name);
+ return Get ((MSymbol) node.InnerText);
}
public class Named : Marker
public override int Position (Context ic)
{
- int pos;
- if (ic.markers.TryGetValue (name, out pos))
- return pos;
- return 0;
+ MPlist p = ic.markers.Find (name);
+ return (p != null ? p.Integer : 0);
+
}
public override void Mark (Context ic)
{
- ic.markers[name] = ic.cursor_pos;
- }
-
- public override Xex.TermValue Clone ()
- {
- return new Named (name, pos);
+ ic.markers.Put (name, ic.cursor_pos);
}
}
return name.Name[1] - '0';
}
}
-
- public override void Mark (Context ic)
- {
- throw new Exception ("Can't set predefined marker: " + name);
- }
+ }
+
+ public class PredefinedAbsolute : Marker
+ {
+ private int pos;
- public override Xex.TermValue Clone ()
+ public PredefinedAbsolute (MSymbol name) : base (name)
+ {
+ if (! int.TryParse (name.Name.Substring (1), out pos))
+ throw new Exception ("Invalid marker name: " + name);
+ }
+
+ public override int Position (Context ic)
{
- return new Predefined (name);
+ return (pos < ic.preedit.Length ? pos : ic.preedit.Length);
}
}
- public class PredefinedPlusMinus : Marker
+ public class PredefinedSurround : Marker
{
private int distance;
- public PredefinedPlusMinus (MSymbol name): base (name)
+ public PredefinedSurround (MSymbol name) : base (name)
{
if (! int.TryParse (name.Name.Substring (2), out distance))
throw new Exception ("Invalid marker name: " + name);
{
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<MSymbol,Predefined> predefined_markers;
static Marker ()
{
predefined_markers = new Dictionary<MSymbol,Predefined> ();
- MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]",
- "@0", "@1", "@2", "@3", "@4",
- "@5", "@6", "@7", "@8", "@9" };
+ MSymbol[] symlist = new MSymbol[] {"@<", "@>", "@-", "@+", "@[", "@]" };
foreach (MSymbol s in symlist)
predefined_markers[s] = new Predefined (s);
}
public static Marker Get (MSymbol name)
{
- Predefined pred;
-
- if (predefined_markers.TryGetValue (name, out pred))
- return pred;
if (name.Name[0] == '@')
{
- int pos;
- if (name.Name.Length >= 3
- && (name.Name[1] == '-' || name.Name[1] == '+')
- && int.TryParse (name.Name.Substring (2), out pos)
- && (pos > 0))
- return (predefined_markers[name] = new Predefined (name));
- else
+ Predefined pred;
+ if (predefined_markers.TryGetValue (name, out pred))
+ return pred;
+ if (name.Name.Length == 1)
throw new Exception ("Invalid marker name: " + name);
+ if (Char.IsDigit (name.Name[1]))
+ return new PredefinedAbsolute (name);
+ if (name.Name.Length == 2 || name == Mat_minus_zero
+ || ! (name.Name[1] == '-' || name.Name[1] == '+'))
+ throw new Exception ("Invalid marker name: " + name);
+ return new PredefinedSurround (name);
}
return new Named (name);
}
internal class Selector : Xex.TermValue
{
+ static new Dictionary<MSymbol, Selector> selectors;
+
+ static Selector ()
+ {
+ selectors = new Dictionary<MSymbol, Selector> ();
+ 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-list"] = new Selector ('[');
+ selectors["@next-candidate-list"] = new Selector (']');
+ }
+
+ private char tag;
+
+ private Selector (MSymbol sym) { tag = sym.Name[1]; }
+
+ private Selector (char tag) { this.tag = tag; }
+
public static Xex.TermValue parser (Xex.Domain domain, XmlNode node)
{
return Get ((MSymbol) node.InnerText);
public static Xex.TermValue Get (MSymbol name)
{
- Predefined pred;
-
- if (! predefined_selectors.TryGetValue (name, out pred))
+ Selector selector;
+ if (! selectors.TryGetValue (name, out selector))
throw new Exception ("Invalid selector name: " + name);
- return pred;
+ return selector;
}
public override Xex.TermValue Clone () { return this; }
default: break;
}
}
+ }
- static new Dictionary<MSymbol, Selector> selectors;
+ internal class Map
+ {
+ public MSymbol name;
+ public List<Entry> entries;
- static Selector ()
+ public Map (MSymbol name) { this.name = name; }
+
+ public class Entry
+ {
+ public KeySeq keyseq;
+ public Xex.Term[] actions;
+
+ public Entry (Xex.Domain domain, KeySeq keyseq, Xex.Term[] actions)
{
- selectors = new Dictionary<MSymbol, Selector> ();
- MSymbol[] symlist = new MSymbol[] { "@<", "@=", "@>", "@-", "@+",
- "@[", "@]" };
- foreach (MSymbol s in symlist)
- selectors[s] = new Selector (s);
+ this.keyseq = keyseq;
+ this.actions = actions;
}
+ }
}
- internal class Map
+ internal class Branch
{
public MSymbol name;
- public Dictionary<Key, Map> submaps;
- public Xex.Term actions;
+ public Keymap keymap;
+ public Xex.Term[] enter_actions, fallback_actions;
+ }
- public void Add (KeySeq keys, int index, Xex.Term actions)
- {
- Map sub = null;
+ public class Keymap
+ {
+ public Dictionary<Key, Keymap> keymaps;
+ public Xex.Term[] map_actions, branch_actions;
- if (submaps == null)
- submaps = new Dictionary<Key, Map> ();
- else
- submaps.TryGetValue (keys.keyseq[index], out sub);
- if (sub == null)
+ public void Add (KeySeq keys, int index,
+ Xex.Term[] map_actions, Xex.Term[] branch_actions)
+ {
+ Map sub = null;
+
+ if (submaps == null)
+ submaps = new Dictionary<Key, Map> ();
+ else
+ submaps.TryGetValue (keys.keyseq[index], out sub);
+ if (sub == null)
+ {
+ Key key = keys.keyseq[index];
+ submaps[key] = sub = new Map ();
+ }
+ if (index + 1 < keys.keyseq.Count)
+ sub.Add (keys, index + 1, actions);
+ else
+ this.actions = actions;
+ }
+ }
+
+ public void AddMap (Map map, Xex.Term[] actions)
+ {
+ foreach (Map.Entry entry in map.entries)
{
- Key key = keys.keyseq[index];
- submaps[key] = sub = new Map ();
+ Add (entry.keyseq, 0, entry.actions, actions)
}
- if (index + 1 < keys.keyseq.Count)
- sub.Add (keys, index + 1, actions);
- else
- this.actions = actions;
}
+ public void Add (KeySeq keys, int index,
+ Xex.Term[] map_actions, Xex.Term[] branch_actions)
public Xex.Term Lookup (KeySeq keys, ref int index)
{
if (index < keys.keyseq.Count)
internal class State
{
- public MSymbol name;
+ public Xex.Symbol name;
public MText title;
public MPlist branches = new MPlist ();
- public State (MSymbol name)
+ public State (Xex.Symbol name)
{
this.name = name;
}
public override string ToString ()
{
- MText mt = "(" + name.Name;
+ MText mt = "(" + name;
if (title != null)
mt.Cat (" \"" + title + "\"");
internal Xex.Symbol[] var_names;
internal Dictionary<MSymbol, Plugin> plugins;
internal Dictionary<MSymbol, Map> maps;
- internal MPlist states;
+ internal Dictionary<Xex.Symbol, State> states;
+ internal State initial_state;
static MInputMethod ()
{
return true;
}
+ private void add_default_state ()
+ {
+ Xex.Symbol Ninit = "init";
+ State state = new State (Ninit);
+ foreach (KeyValuePair<MSymbol, Map>kv in maps)
+ state.branches.Add (kv.Key, null);
+ states[Ninit] = initial_state = state;
+ }
+
private void load (MPlist plist, bool full)
{
maps = new Dictionary<MSymbol, Map> ();
- states = new MPlist ();
+ states = new Dictionary<Xex.Symbol, State> ();
for (; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist)
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, null);
- states.Add (state.name, state);
- }
+ if (states.Count == 0)
+ add_default_state ();
}
private void load (XmlNode node, bool full)
bool skip_header = load_status == LoadStatus.Header;
maps = new Dictionary<MSymbol, Map> ();
- states = new MPlist ();
+ states = new Dictionary<Xex.Symbol, State> ();
if (node.NodeType == XmlNodeType.Document)
node = node.FirstChild;
commands = new Command[0];
if (! full)
return;
- if (states.IsEmpty)
- {
- State state = new State ((MSymbol) "init");
- foreach (KeyValuePair<MSymbol, Map>kv in maps)
- state.branches.Add (kv.Key, null);
- states.Add (state.name, state);
- }
+ if (states.Count == 0)
+ add_default_state ();
}
private static void transform (MPlist plist)
private void parse_maps (XmlNode node)
{
+ for (node = node.FirstChild; node != null; node = node.NextSibling)
+ if (node.Name == Nmap)
+ {
+ 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 == Nrule)
+ {
+ XmlNode n = nd.FirstChild;
+ if (n.Name != Nkeyseq)
+ 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));
+ }
+ }
}
private void parse_states (XmlNode node)
{
if (target_name == MSymbol.nil)
{
- for (p = im.states; ! p.IsEmpty; p = p.next)
- states.Add (p.key, p.val);
+ foreach (KeyValuePair<Xex.Symbol, State> kv in im.states)
+ states[kv.Key] = kv.Value;
}
else
{
- object state = im.states.Get (target_name);
- if (state != null)
- states.Add (target_name, state);
+ Xex.Symbol state_name = target_name.Name;
+ State state;
+ if (im.states.TryGetValue (state_name, out state))
+ states[state_name] = state;
}
}
}
return terms;
}
-
private void parse_macros (MPlist plist)
{
for (MPlist pl = plist; ! pl.IsEmpty; pl = pl.next)
if (! pl.IsSymbol)
continue;
- Map map = new Map ();
- map.name = pl.Symbol;
- maps[map.name] = map;
+ Map map = new Map (pl.Symbol);
+ maps[pl.Symbol] = map;
for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
{
if (! pl.IsPlist)
p = p.next;
if (p.IsEmpty)
continue;
- map.Add (keys, 0,
- new Xex.Term (domain, Nprogn, parse_actions (p)));
+ Xex.Term[] actions = parse_actions (p);
+ map.entries.Add (new Map.Entry (domain, keys, actions));
}
}
}
if (! pl.IsSymbol)
continue;
- State state = new State (pl.Symbol);
+ Xex.Symbol name = (Xex.Symbol) pl.Symbol.Name;
+ State state = new State (name);
state.title = title;
- if (states == null)
- states = new MPlist ();
- states.Add (state.name, state);
+ if (states.Count == 0)
+ initial_state = state;
+ states[name] = state;
for (pl = pl.next; ! pl.IsEmpty; pl = pl.next)
{
if (! pl.IsPlist)
}
private static Xex.Term Fshiftback (Xex.Domain domain, Xex.Variable vari,
- Xex.Term[] args)
+ Xex.Term[] args)
{
- ((Context) domain.context).shift_back ();
+ ((Context) domain.context).shiftback ();
return Tnil;
}
Xex.Variable vari,
Xex.Term[] args)
{
- return new Xex.Term (((Context) domain.context).surrounding_flag);
+ return new Xex.Term (((Context) domain.context).SurroundingFlag);
}
public override string ToString ()
foreach (KeyValuePair<MSymbol, Map> kv in maps)
str += " " + kv.Value;
str += ") (states";
- foreach (MPlist p in states)
- str += " " + p.val;
+ foreach (Xex.Symbol name in states.Keys)
+ str += " " + name;
return str + "))";
}
{
internal static Xex.Symbol Ncandidates_group_size
= "candidates-group-size";
- public MInputMethod im;
+ private MInputMethod im;
+ private Dictionary<MSymbol, Callback> callbacks
+ = new Dictionary<MSymbol, Callback> ();
+
private MText produced;
private bool active;
private MText status;
internal MText preedit;
internal int cursor_pos;
- internal Dictionary<Xex.Symbol, int> markers;
+ internal MPlist markers;
internal Candidates candidates;
private int candidate_from, candidate_to;
private bool candidate_show;
internal ChangedStatus changed;
- public ChangedStatus Changed { get { return changed; } }
+ static MPlist callback_arg = new MPlist ();
- public Context (MInputMethod im)
+ private bool call_callback (MSymbol name, MPlist arg)
{
- this.im = im;
- domain = new Xex.Domain (im.domain, this);
- state_list = new List<State> ();
- state_list.Add ((State) im.states.val);
- keys = new KeySeq ();
+ Callback callback;
+ if (! callbacks.TryGetValue (name, out callback))
+ return false;
+ return callback (this, arg);
}
+ private bool get_surrounding_text (int len)
+ {
+ if (len < 0 ? -len <= preceding_text.Length
+ : len <= following_text.Length)
+ return true;
+ callback_arg.Set (MSymbol.integer, len);
+ if (! call_callback (Mget_surrounding_text, callback_arg)
+ || ! callback_arg.IsMText)
+ return false;
+ if (len < 0)
+ {
+ preceding_text = callback_arg.Text;
+ return (-len <= preceding_text.Length);
+ }
+ following_text = callback_arg.Text;
+ return (len <= following_text.Length);
+ }
+
+ internal int SurroundingFlag
+ {
+ get { return (callbacks.ContainsKey (Mget_surrounding_text) ? 1 : 0); }
+ }
+
+ internal int GetSurroundingChar (int pos)
+ {
+ if (! get_surrounding_text (pos < 0 ? pos : pos + 1))
+ return 0;
+ if (pos < 0)
+ return preceding_text[preceding_text.Length + pos];
+ return following_text[pos];
+ }
+
private void adjust_markers (int from, int to, object inserted)
{
int ins = (inserted == null ? 0
}
}
- internal void mark (MSymbol sym)
- {
- MPlist slot = markers.Find (sym);
-
- if (slot == null)
- markers.Push (sym, cursor_pos);
- else
- slot.val = cursor_pos;
- }
-
internal void pushback (int n)
{
if (n > 0)
changed |= ChangedStatus.Preedit;
}
- internal void shift (MSymbol sym)
+ private void new_state (bool changed)
{
- State state;
-
- if (sym == MSymbol.t)
- {
- state = state_list.Last ();
- if (state_list.Count > 1)
- state_list.RemoveAt (state_list.Count - 1);
- }
- else
- {
- state = (State) im.states.Get (sym);
- if (state == null)
- throw new Exception ("Unknown state: " + state.name);
- }
- if (state == null)
- {
- state = state_list.Last;
- state_list.RemoveAt (state_list.Count -1);
- }
- if (state == (State) im.states.val)
+ if (state_list.Count == 1)
{
commit ();
reset ();
state_key_head = key_head;
state_pos = cursor_pos;
state_preedit = preedit.Dup ();
- if (state != state_list.Last ())
+ state_var_values = domain.SaveValues ();
+ if (changed)
{
- state_list.Add (state);
- state_var_values = domain.SaveValues ();
+ State state = state_list[state_list.Count - 1];
status = state.title;
if (status == null)
status = im.title;
- changed |= ChangedStatus.StateTitle;
+ this.changed |= ChangedStatus.StateTitle;
Xex on_entry
= (Xex) state.branches.Get (MSymbol.t);
if (on_entry != null)
}
}
+ internal void shift (Xex.Symbol sym)
+ {
+ State state;
+ bool changed;
+
+ if (! im.states.TryGetValue (sym, out state))
+ throw new Exception ("Unknown state: " + sym);
+ changed = state != state_list[state_list.Count - 1];
+ if (changed)
+ state_list.Add (state);
+ new_state (changed);
+ }
+
+ internal void shiftback ()
+ {
+ if (state_list.Count > 1)
+ state_list.RemoveAt (state_list.Count - 1);
+ new_state (true);
+ }
+
internal void reset ()
{
preedit.Del ();
cursor_pos = 0;
key_head = commit_key_head = 0;
state_list.Clear ();
- state_list.Add ((State) im.states.Val);
+ state_list.Add (im.initial_state);
state_key_head = 0;
state_pos = 0;
}
+ public Context (MInputMethod im)
+ {
+ this.im = im;
+ domain = new Xex.Domain (im.domain, this);
+ state_list.Clear ();
+ state_list.Add (im.initial_state);
+ keys = new KeySeq ();
+ }
+
+ public ChangedStatus Changed { get { return changed; } }
+
+ public void AddCallback (MSymbol name, Callback callback)
+ {
+ callbacks[name] = callback;
+ }
+
internal object GetCandidates (out int column)
{
column = 0;
return candidates.Current;
}
- internal void HandleKey ()
+ private bool handle_key ()
{
+ State state = state_list[state_list.Count - 1];
+ for (MPlist *p = state.branches; ! p.IsEmpty; p = p.next)
+ {
+ int n = state_key_head;
+ Xex.Term term = ((Map) p.Val).Lookup (keys, ref n);
+
+
+
+ }
+
}
public bool Toggle ()
return (produced.Length > 0);
}
-
// Return value:
// true: All keys are handled and there's no text to commit.
// false: Some key is unhandled or there's a text to commit.
public bool Filter (Key key)
{
- if (check_reload (key))
+ if (key == Key.Reload)
return true;
changed = ChangedStatus.None;
produced.Del ();
following_text.Del ();
key_unhandled = false;
- keys.Add (key);
+ keys.keyseq.Add (key);
int count = 0;
- while (key_head < keys.Length)
+ while (key_head < keys.keyseq.Count)
{
if (! handle_key ())
{
- unhandled_key = keys[key_head++];
+ unhandled_key = keys.keyseq[key_head++];
key_unhandled = true;
break;
}
if (++count == 100)
break;
}
- keys.RemoveRange (0, key_head);
+ keys.keyseq.RemoveRange (0, key_head);
return (! key_unhandled && produced.Length == 0);
}
}