using M17N.Core;
using M17N.Input;
-using Xex = System.Xml.Expression.Xexpression;
+using Xex = System.Xml.Xexpression;
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";
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 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");
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];
+ {
+ group = new object[column];
+ fill_group (0);
+ }
}
public Candidates (Xex.Term[] candidates, int column)
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];
+ {
+ group = new object[column];
+ fill_group (0);
+ }
}
public static void Detach (Context ic)
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".
+ // 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];
+ 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;
+ 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;
- }
+ 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.
+ // 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;
+ 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;
- }
+ 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;
+ 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;
- }
+ 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;
+ public void Prev ()
+ {
+ int col = Column;
- if (col == 0)
- {
- int nitems = PrevGroup ();
- index += col < nitems - 1 ? col : nitems - 1;
- }
- else
- index--;
- }
+ if (col == 0)
+ {
+ int nitems = PrevGroup ();
+ index += col < nitems - 1 ? col : nitems - 1;
+ }
+ else
+ index--;
+ }
- public void Next ()
- {
- int col = Column;
- int nitems = GroupLength;
+ public void Next ()
+ {
+ int col = Column;
+ int nitems = GroupLength;
- if (col == nitems - 1)
- {
- nitems = NextGroup ();
- index -= Column;
- }
- else
- index++;
- }
+ if (col == nitems - 1)
+ {
+ nitems = NextGroup ();
+ index -= Column;
+ }
+ else
+ index++;
+ }
- public void First ()
- {
- index -= Column;
- }
+ public void First ()
+ {
+ index -= Column;
+ }
- public void Last ()
- {
- index += GroupLength - (Column + 1);
- }
+ 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 (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 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 ("<candidates row={0} col={1}>", row, index)
- + Group
- + "</candidates>");
- }
- }
+ public override string ToString ()
+ {
+ return (String.Format ("<candidates row={0} col={1}>", row, index)
+ + Group
+ + "</candidates>");
+ }
+ }
internal class Selector : Xex.TermValue
{
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;
{
if (! plist.IsSymbol)
throw new Exception ("Invalid state: " + plist);
- this.name = plist.Symbol.Name;
+ this.name = plist.Symbol;
plist = plist.next;
if (plist.IsMText)
{
internal Xex.Symbol[] var_names;
internal Dictionary<MSymbol, Plugin> plugins;
internal Dictionary<MSymbol, Map> maps;
- internal Dictionary<Xex.Symbol, State> states;
- internal State initial_state;
+ internal MPlist states;
static MInputMethod ()
{
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);
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);
private void add_default_state ()
{
- Xex.Symbol Qinit = "init";
+ MSymbol Qinit = "init";
State state = new State (Qinit, title);
foreach (KeyValuePair<MSymbol, Map>kv 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<MSymbol, Map> ();
- states = new Dictionary<Xex.Symbol, State> ();
+ states = new MPlist ();
for (; ! plist.IsEmpty; plist = plist.next)
if (plist.IsPlist)
commands = new Command[0];
if (! full)
return;
- if (states.Count == 0)
+ if (states.IsEmpty)
add_default_state ();
}
bool skip_header = load_status == LoadStatus.Header;
maps = new Dictionary<MSymbol, Map> ();
- states = new Dictionary<Xex.Symbol, State> ();
+ states = new MPlist ();
if (node.NodeType == XmlNodeType.Document)
node = node.FirstChild;
node = node.NextSibling;
for (node = node.FirstChild; node != null; node = node.NextSibling)
{
- Console.WriteLine (this.tag + node.Name);
if (node.NodeType != XmlNodeType.Element)
continue;
if (! skip_header)
commands = new Command[0];
if (! full)
return;
- if (states.Count == 0)
+ if (states.IsEmpty)
add_default_state ();
}
Xex.Symbol name = (Xex.Symbol) p.Symbol.Name;
var_names[i] = name;
p = p.next;
- string desc = (string) parse_description (p);
- if (desc != null)
+ 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)
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);
}
}
if (node.Name == Qstate)
{
State state = new State (this, node);
- states[state.name] = state;
- if (initial_state == null)
- initial_state = state;
+ 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)
{
- Console.WriteLine ("including {0}:{1}:{2}:{3}:{4}",
- language, name, subname, part, section);
-
MInputMethod im = MInputMethod.Find (language, name, subname);
if (im == null)
return;
{
if (section == MSymbol.nil)
{
- foreach (KeyValuePair<Xex.Symbol, State> 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 = section.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);
}
}
}
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)
{
{
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
}
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);
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];
}
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 ()
foreach (KeyValuePair<MSymbol, Map> kv in maps)
str += " " + kv.Value;
str += ") (states";
- foreach (KeyValuePair<Xex.Symbol, State> 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 + "))";
}
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 ();
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;
internal void reset ()
{
- status = im.initial_state.title;
+ status = initial_state.title;
produced.Del ();
preedit.Del ();
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 ();
{
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;
{
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;
internal void commit ()
{
+ Candidates.Detach (this);
produced.Cat (preedit);
preedit_replace (0, preedit.Length, null, null);
- changed |= ChangedStatus.Preedit;
}
internal void shift (State state)
state = prev_state;
}
- if (state == im.initial_state)
+ if (state == initial_state)
{
commit ();
keys.keyseq.RemoveRange (0, key_head);
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;
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)
}
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;
{
CandidateChanged (this, callback_arg);
}
+ return (! key_unhandled && produced.Length == 0);
+ }
+ }
- Console.Write ("\nPreedit(\"{0}\"/{1}), Produced({2})",
- preedit, cursor_pos, produced);
+ public class Session
+ {
+ Context ic;
+ MText mt;
+ int pos;
- return (! key_unhandled && produced.Length == 0);
+ 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;
+ }
+
+ 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; } }
}
}
}