+ domain.context.Error = result.toString ();
+ return false;
+ }
+ return (result != Xex.CatchTag._mimtag);
+}
+
+MIM.Keymap = function ()
+{
+ this.name = 'TOP';
+ this.submaps = null;
+};
+
+(function () {
+ var proto = {};
+
+ function add_rule (keymap, rule, branch_actions)
+ {
+ var keyseq = rule.keyseq;
+ var len = keyseq.val.length;
+ var name = '';
+
+ for (var i = 0; i < len; i++)
+ {
+ var key = keyseq.val[i];
+ var sub = false;
+
+ name += key.key;
+ if (! keymap.submaps)
+ keymap.submaps = {};
+ else
+ sub = keymap.submaps[key.key];
+ if (! sub)
+ keymap.submaps[key.key] = sub = new MIM.Keymap ();
+ keymap = sub;
+ keymap.name = name;
+ }
+ if (rule.actions)
+ keymap.map_actions = rule.actions;
+ if (branch_actions)
+ keymap.branch_actions = branch_actions;
+ }
+
+ proto.Add = function (map, branch_actions)
+ {
+ var rules = map.rules;
+ var len = rules.length;
+
+ for (var i = 0; i < len; i++)
+ add_rule (this, rules[i], branch_actions);
+ }
+ proto.Lookup = function (keys, index)
+ {
+ var sub;
+
+ if (index < keys.val.length && this.submaps
+ && ! keys.val[index])
+ {
+ Xex.Log ('invalid key at ' + index);
+ throw 'invalid key';
+ }
+
+ if (index < keys.val.length && this.submaps
+ && (sub = this.submaps[keys.val[index].key]))
+ {
+ index++;
+ return sub.Lookup (keys, index);
+ }
+ return { map: this, index: index };
+ }
+
+ MIM.Keymap.prototype = proto;
+}) ();
+
+MIM.State = function (name)
+{
+ this.name = name;
+ this.keymap = new MIM.Keymap ();
+};
+
+(function () {
+ var proto = new Xex.Term ('state');
+
+ proto.Parser = function (domain, node)
+ {
+ var map_list = domain.map_list;
+ var name = node.attributes['sname'].nodeValue;
+ if (! name)
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
+ var state = new MIM.State (name);
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ if (node.nodeName == 'title')
+ state.title = node.firstChild.nodeValue;
+ else
+ {
+ var n = node.firstElement ();
+ var branch_actions = n ? Xex.Term.Parse (domain, n, null) : null;
+ if (node.nodeName == 'branch')
+ state.keymap.Add (map_list[node.attributes['mname'].nodeValue],
+ branch_actions);
+ else if (node.nodeName == 'state-hook')
+ state.keymap.map_actions = branch_actions;
+ else if (node.nodeName == 'catch-all-branch')
+ state.keymap.branch_actions = branch_actions;
+ }
+ }
+ return state;
+ }
+
+ proto.toString = function ()
+ {
+ return '<state sname="' + this.name + '">' + this.keymap + '</state>';
+ }
+
+ MIM.State.prototype = proto;
+}) ();
+
+(function () {
+ function Block (index, term)
+ {
+ this.Index = index;
+ if (term.IsStr)
+ this.Data = term.val;
+ else if (term.IsList)
+ {
+ this.Data = new Array ();
+ for (var i = 0; i < term.val.length; i++)
+ this.Data.push (term.val[i].val);
+ }
+ }
+
+ Block.prototype.Count = function () { return this.Data.length; }
+ Block.prototype.get = function (i)
+ {
+ return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
+ }
+
+ MIM.Candidates = function (ic, candidates, column)
+ {
+ this.ic = ic;
+ this.column = column;
+ this.row = 0;
+ this.index = 0;
+ this.total = 0;
+ this.blocks = new Array ();
+
+ for (var i = 0; i < candidates.length; i++)
+ {
+ var block = new Block (this.total, candidates[i]);
+ this.blocks.push (block);
+ this.total += block.Count ();
+ }
+ }
+
+ function get_col ()
+ {
+ return (this.column > 0 ? this.index % this.column
+ : this.index - this.blocks[this.row].Index);
+ }
+
+ function prev_group ()
+ {
+ var col = get_col.call (this);
+ var nitems;
+ if (this.column > 0)
+ {
+ this.index -= this.column;
+ if (this.index >= 0)
+ nitems = this.column;
+ else
+ {
+ var lastcol = (this.total - 1) % this.column;
+ this.index = (col < lastcol ? this.total - lastcol + col
+ : this.total - 1);
+ this.row = this.blocks.length - 1;
+ nitems = lastcol + 1;
+ }
+ while (this.blocks[this.row].Index > this.index)
+ this.row--;
+ }
+ else
+ {
+ this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
+ nitems = this.blocks[this.row].Count ();
+ this.index = (this.blocks[this.row].Index
+ + (col < nitems ? col : nitems - 1));
+ }
+ return nitems;
+ }
+
+ function next_group ()
+ {
+ var col = get_col.call (this);
+ var nitems;
+ if (this.column > 0)
+ {
+ this.index += this.column - col;
+ if (this.index < this.total)
+ {
+ if (this.index + col >= this.total)
+ {
+ nitems = this.total - this.index;
+ this.index = this.total - 1;
+ }
+ else
+ {
+ nitems = this.column;
+ this.index += col;
+ }
+ }
+ else
+ {
+ this.index = col;
+ this.row = 0;
+ }
+ while (this.blocks[this.row].Index + this.blocks[this.row].Count ()
+ <= this.index)
+ this.row++;
+ }
+ else
+ {
+ this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
+ nitems = this.blocks[this.row].Count ();
+ this.index = (this.blocks[this.row].Index
+ + (col < nitems ? col : nitems - 1));
+ }
+ return nitems;
+ }
+
+ function prev ()
+ {
+ if (this.index == 0)
+ {
+ this.index = this.total - 1;
+ this.row = this.blocks.length - 1;
+ }
+ else
+ {
+ this.index--;
+ if (this.blocks[this.row].Index > this.index)
+ this.row--;
+ }
+ }
+
+ function next ()
+ {
+ this.index++;
+ if (this.index == this.total)
+ {
+ this.index = 0;
+ this.row = 0;
+ }
+ else
+ {
+ var b = this.blocks[this.row];
+ if (this.index == b.Index + b.Count ())
+ this.row++;
+ }
+ }
+
+ function first ()
+ {
+ this.index -= get_col.call (this);
+ while (this.blocks[this.row].Index > this.index)
+ this.row--;
+ }
+
+ function last ()
+ {
+ var b = this.blocks[this.row];
+ if (this.column > 0)
+ {
+ if (this.index + 1 < this.total)
+ {
+ this.index += this.column - get_col.call (this) + 1;
+ while (b.Index + b.Count () <= this.index)
+ b = this.blocks[++this.row];
+ }
+ }
+ else
+ this.index = b.Index + b.Count () - 1;
+ }
+
+ MIM.Candidates.prototype.Current = function ()
+ {
+ var b = this.blocks[this.row];
+ return b.get (this.index - b.Index);
+ }
+
+ MIM.Candidates.prototype.Select = function (selector)
+ {
+ var idx = this.index;
+ var gidx = this.column > 0 ? idx / this.column : this.row;
+ if (selector.type == 'selector')
+ {
+ switch (selector.val)
+ {
+ case '@<': first.call (this); break;
+ case '@>': last.call (this); break;
+ case '@-': prev.call (this); break;
+ case '@+': next.call (this); break;
+ case '@[': prev_group.call (this); break;
+ case '@]': next_group.call (this); break;
+ default: break;
+ }
+ }
+ else
+ {
+ var col, start, end
+ if (this.column > 0)
+ {
+ col = this.index % this.column;
+ start = this.index - col;
+ end = start + this.column;
+ }
+ else
+ {
+ start = this.blocks[this.row].Index;
+ col = this.index - start;
+ end = start + this.blocks[this.row].Count;
+ }
+ if (end > this.total)
+ end = this.total;
+ this.index += selector.val - col;
+ if (this.index >= end)
+ this.index = end - 1;
+ if (this.column > 0)
+ {
+ if (selector.val > col)
+ while (this.blocks[this.row].Index + this.blocks[this.row].Count
+ < this.index)
+ this.row++;
+ else
+ while (this.blocks[this.row].Index > this.index)
+ this.row--;
+ }
+ }
+ var newgidx = this.column > 0 ? this.index / this.column : this.row;
+ if (this.index != idx)
+ this.ic.changed |= (gidx == newgidx
+ ? MIM.ChangedStatus.CandidateIndex
+ : MIM.ChangedStatus.CandidateList);
+ return this.Current ();
+ }
+
+ MIM.Candidates.prototype.CurrentCol = function ()
+ {
+ return get_col.call (this);
+ }
+
+ MIM.Candidates.prototype.CurrentGroup = function ()
+ {
+ var col, start, end, gnum, gidx;
+ if (this.column > 0)
+ {
+ gnum = Math.floor ((this.total - 1) / this.column) + 1;
+ col = this.index % this.column;
+ start = this.index - col;
+ gidx = start / this.column + 1;
+ end = start + this.column;
+ if (end > this.total)
+ end = this.total;
+ }
+ else
+ {
+ gnum = this.blocks.length;
+ gidx = this.row + 1;
+ start = this.blocks[this.row].Index;
+ col = this.index - start;
+ end = start + this.blocks[this.row].Count ();
+ }
+ var group = new Array ();
+ var indices = new Array (gnum, gidx, col);
+ group.push (indices);
+ var row = this.row;
+ var block = this.blocks[row++];
+ while (start < end)
+ {
+ var c = block.get (start - block.Index);
+ group.push (c);
+ start++;
+ if (start == block.Index + block.Count ())
+ block = this.blocks[row++];
+ }
+ return group;
+ }
+}) ();
+
+MIM.im_domain = new Xex.Domain ('input-method', null, null);
+MIM.im_domain.DefType (MIM.KeySeq.prototype);
+MIM.im_domain.DefType (MIM.Marker.prototype);
+MIM.im_domain.DefType (MIM.Selector.prototype);
+MIM.im_domain.DefType (MIM.Rule.prototype);
+MIM.im_domain.DefType (MIM.Map.prototype);
+MIM.im_domain.DefType (MIM.State.prototype);
+
+(function () {
+ var im_domain = MIM.im_domain;
+
+ function Finsert (domain, vari, args)
+ {
+ var text;
+ if (args[0].type == 'integer')
+ text = String.fromCharCode (args[0].val);
+ else
+ text = args[0].val;
+ domain.context.ins (text, null);
+ return args[0];
+ }
+
+ function Finsert_candidates (domain, vari, args)
+ {
+ var ic = domain.context;
+ var gsize = domain.variables['candidates-group-size'];
+ var candidates = new MIM.Candidates (ic, args,
+ gsize ? gsize.val.Intval () : 0);
+ ic.ins (candidates.Current (), candidates);
+ return args[0];
+ }
+
+ function Fdelete (domain, vari, args)
+ {
+ var ic = domain.context;
+ var pos = args[0].IsInt ? args[0].Intval () : args[0].Position (ic);
+ return new Xex.IntTerm (ic.del (pos));
+ }
+
+ function Fselect (domain, vari, args)
+ {
+ var ic = domain.context;
+ var can = ic.candidates;
+
+ if (can)
+ {
+ var old_text = can.Current ();
+ var new_text = can.Select (args[0]);
+ ic.rep (old_text, new_text, can);
+ }
+ else
+ Xex.Log ('no candidates at ' + ic.cursor_pos + ' of ' + ic.candidate_table.table.length);
+ return args[0];
+ }
+
+ function Fshow (domain, vari, args)
+ {
+ domain.context.candidate_show = true;
+ domain.context.changed |= MIM.ChangedStatus.CandidateShow;
+ return Xex.nil;
+ }
+
+ function Fhide (domain, vari, args)
+ {
+ domain.context.candidate_show = false;
+ domain.context.changed |= MIM.ChangedStatus.CandidateShow;
+ return Xex.nil;
+ }
+
+ function Fchar_at (domain, vari, args)
+ {
+ return new Xex.IntTerm (args[0].CharAt (domain.context));
+ }
+
+ function Fmove (domain, vari, args)
+ {
+ var ic = domain.context;
+ var pos = args[0].IsInt ? args[0].val : args[0].Position (ic);
+ ic.move (pos);
+ return new Xex.IntTerm (pos);
+ }
+
+ function Fmark (domain, vari, args)
+ {
+ args[0].Mark (domain.context);
+ return args[0];
+ }
+
+ function Fpushback (domain, vari, args)
+ {
+ var a = (args[0].IsInt ? args[0].Intval ()
+ : args[0].IsStr ? new KeySeq (args[0])
+ : args[0]);
+ domain.context.pushback (a);
+ return args[0];
+ }
+
+ function Fpop (domain, vari, args)
+ {
+ var ic = domain.context;
+ if (ic.key_head < ic.keys.val.length)
+ ic.keys.val.splice (ic.keys_head, 1);
+ return Xex.nil;
+ }
+
+ function Fundo (domain, vari, args)
+ {
+ var ic = domain.context;
+ var n = args.length == 0 ? -2 : args[0].val;
+ Xex.Log ('undo with arg ' + args[0]);
+ if (n < 0)
+ ic.keys.val.splice (ic.keys.val.length + n, -n);
+ else
+ ic.keys.val.splice (n, ic.keys.val.length);
+ ic.reset (false);
+ return Xex.nil;
+ }
+
+ function Fcommit (domain, vari, args)
+ {
+ domain.context.commit ();
+ return Xex.nil;
+ }
+
+ function Funhandle (domain, vari, args)
+ {
+ domain.context.commit ();
+ return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
+ }
+
+ function Fshift (domain, vari, args)
+ {
+ var ic = domain.context;
+ var state_name = args[0].val;
+ var state = ic.im.state_list[state_name];
+ if (! state)
+ throw ("Unknown state: " + state_name);
+ ic.shift (state);
+ return args[0];
+ }
+
+ function Fshiftback (domain, vari, args)
+ {
+ domain.context.shift (null);
+ return Xex.nil;
+ }
+
+ function Fkey_count (domain, vari, args)
+ {
+ return new Xex.IntTerm (domain.context.key_head);
+ }
+
+ function Fsurrounding_flag (domain, vari, args)
+ {
+ return new Xex.IntTerm (-1);
+ }
+
+ im_domain.DefSubr (Finsert, "insert", false, 1, 1);
+ 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-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 (Fpop, "pop", false, 0, 0);
+ im_domain.DefSubr (Fundo, "undo", false, 0, 1);
+ im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
+ im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
+ 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, 0, 0);
+ im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0);
+}) ();
+
+
+(function () {
+ function get_global_var (vname)
+ {
+ if (MIM.im_global.load_status == MIM.LoadStatus.NotLoaded)
+ MIM.im_global.Load ()
+ return MIM.im_global.domain.variables[vname];
+ }
+
+ function include (node)
+ {
+ node = node.firstElement ();
+ if (node.nodeName != 'tags')
+ return null;
+
+ var lang = null, name = null, extra = null, im;
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ if (node.nodeName == 'language')
+ lang = node.firstChild.nodeValue;
+ else if (node.nodeName == 'name')
+ name = node.firstChild.nodeValue;
+ else if (node.nodeName == 'extra-id')
+ extra = node.firstChild.nodeValue;
+ }
+ if (! lang || ! MIM.imlist[lang])
+ return null;
+ if (! extra)
+ {
+ if (! name || ! (im = MIM.imlist[lang][name]))
+ return null;
+ }
+ else
+ {
+ if (! (im = MIM.imextra[lang][extra]))
+ return null;
+ }
+ if (im.load_status != MIM.LoadStatus.Loaded)
+ {
+ if (im.load_status == MIM.LoadStatus.NotLoaded)
+ im.Load ();
+ if (im.load_status != MIM.LoadStatus.Loading)
+ return null;
+ }
+ return im;
+ }
+
+ var parsers = { };
+
+ parsers['description'] = function (node)
+ {
+ this.description = node.firstChild.nodeValue;
+ return true;
+ }
+ parsers['variable-list'] = function (node)
+ {
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ var vname = node.attributes['vname'].nodeValue;
+ if (this != MIM.im_global)
+ {
+ var vari = get_global_var (vname);
+ if (vari != null)
+ this.domain.Defvar (vname, vari.desc, vari.val, vari.range);
+ }
+ vname = Xex.Term.Parse (this.domain, node)
+ }
+ return true;
+ }
+ parsers['command-list'] = function (node)
+ {
+ return true;
+ }
+ parsers['macro-list'] = function (node)
+ {
+ for (var n = node.firstElement (); n; n = n.nextElement ())
+ if (n.nodeName == 'xi:include')
+ {
+ var im = include (n);
+ if (! im)
+ {
+ alert ('inclusion fail');
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
+ }
+ if (im.load_status == MIM.LoadStatus.Loading)
+ return false; // force reloading
+ for (var macro in im.domain.functions)
+ {
+ var func = im.domain.functions[macro];
+ if (func instanceof Xex.Macro)
+ im.domain.CopyFunc (this.domain, macro);
+ }
+ n = n.previousSibling;
+ node.removeChild (n.nextSibling);
+ }
+ Xex.Term.Parse (this.domain, node.firstElement (), null);
+ return true;
+ }
+ parsers['title'] = function (node)
+ {
+ this.title = node.firstChild.nodeValue;
+ return true;
+ }
+ parsers['map-list'] = function (node)
+ {
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ if (node.nodeName == 'xi:include')
+ {
+ var im = include (node);
+ if (! im)
+ {
+ alert ('inclusion fail');
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
+ }
+ else if (im.load_status == MIM.LoadStatus.Loading)
+ return false;
+ for (var mname in im.map_list)
+ this.map_list[mname] = im.map_list[mname];
+ }
+ else
+ {
+ var map = Xex.Term.Parse (this.domain, node);
+ this.map_list[map.name] = map;
+ }
+ }
+ return true;
+ }
+ parsers['state-list'] = function (node)
+ {
+ this.domain.map_list = this.map_list;
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ if (node.nodeName == 'xi:include')
+ {
+ var im = include (node);
+ if (! im)
+ {
+ alert ('inclusion fail');
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
+ }
+ else if (im.load_status == MIM.LoadStatus.Loading)
+ return false;
+ for (var sname in im.state_list)
+ {
+ state = im.state_list[sname];
+ if (! this.initial_state)
+ this.initial_state = state;
+ this.state_list[sname] = state;
+ }
+ }
+ else if (node.nodeName == 'state')
+ {
+ var state = Xex.Term.Parse (this.domain, node);
+ if (! state.title)
+ state.title = this.title;
+ if (! this.initial_state)
+ this.initial_state = state;
+ this.state_list[state.name] = state;
+ }
+ }
+ delete this.domain.map_list;
+ return true;
+ }
+
+ MIM.IM = function (lang, name, extra_id, file)
+ {
+ this.lang = lang;
+ this.name = name;
+ this.extra_id = extra_id;
+ this.file = file;
+ this.load_status = MIM.LoadStatus.NotLoaded;
+ this.domain = new Xex.Domain (this.lang + '-'
+ + (this.name != 'nil'
+ ? this.name : this.extra_id),
+ MIM.im_domain, null);
+ };
+
+ function load_im (node, im)
+ {
+ //alert ('Loading IM (' + im + ':' + im.lang + '-' + im.name + ')');
+ im.map_list = {};
+ im.initial_state = null;
+ im.state_list = {};
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ var name = node.nodeName;
+ var parser = parsers[name];
+ if (parser && ! parser.call (im, node))
+ {
+ im.Load ();
+ return;
+ }
+ }
+ //alert ('initial state = ' + im.initial_state);
+ im.load_status = MIM.LoadStatus.Loaded;
+ }
+
+ MIM.IM.prototype = {
+ Load: function ()
+ {
+ this.load_status = MIM.LoadStatus.Loading;
+ Xex.Load (MIM.server, this.file, load_im, this);
+ }
+ };
+
+ MIM.IC = function (im, target)
+ {
+ if (im.load_status == MIM.LoadStatus.NotLoaded)
+ im.Load ();
+ if (im.load_status != MIM.LoadStatus.Loaded)
+ alert ('im:' + im.name + ' error:' + im.load_status);
+ this.im = im;
+ this.target = target;
+ this.domain = new Xex.Domain ('context', im.domain, this);
+ this.active = true;
+ this.range = new Array ();
+ this.range[0] = this.range[1] = 0;
+ this.state = null;
+ this.initial_state = this.im.initial_state;
+ this.keys = new MIM.KeySeq ();
+ this.marker_positions = new Array ();
+ this.candidate_table = new MIM.CandidateTable ();
+ this.reset (false);
+ }
+
+ MIM.CandidateTable = function ()
+ {
+ this.table = new Array ();
+ }
+
+ MIM.CandidateTable.prototype.get = function (pos)
+ {
+ for (var i = 0; i < this.table.length; i++)
+ {
+ var elt = this.table[i];
+ if (elt.from < pos && pos <= elt.to)
+ return elt.val;
+ }
+ }
+
+ MIM.CandidateTable.prototype.put = function (from, to, candidates)
+ {
+ for (var i = 0; i < this.table.length; i++)
+ {
+ var elt = this.table[i];
+ if (elt.from < to && elt.to > from)
+ {
+ elt.from = from;
+ elt.to = to;
+ elt.val = candidates;
+ return;
+ }
+ }
+ this.table.push ({ from: from, to: to, val: candidates });
+ }
+
+ MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
+ {
+ var diff = inserted - (to - from);
+ if (diff == 0)
+ return;
+ for (var i = 0; i < this.table.length; i++)
+ {
+ var elt = this.table[i];
+ if (elt.from >= to)
+ {
+ elt.from += diff;
+ elt.to += diff;
+ }
+ }
+ }
+
+ MIM.CandidateTable.prototype.clear = function ()
+ {
+ this.table.length = 0;
+ }
+
+ function set_cursor (prefix, pos)
+ {
+ this.cursor_pos = pos;
+ var candidates = this.candidate_table.get (pos);
+ if (this.candidates != candidates)
+ {
+ this.candidates = candidates;
+ this.changed |= MIM.ChangedStatus.CandidateList;
+ }
+ }
+
+ function save_state ()
+ {
+ this.state_var_values = this.domain.SaveValues ();
+ this.state_preedit = this.preedit;
+ this.state_key_head = this.key_head;
+ this.state_pos = this.cursor_pos;
+ }
+
+ function restore_state ()
+ {
+ this.domain.RestoreValues (this.state_var_values);
+ this.preedit = this.state_preedit;
+ set_cursor.call (this, "restore", this.state_pos);
+ }
+
+ function handle_key ()
+ {
+ Xex.Log ('Key(' + this.key_head + ') "' + this.keys.val[this.key_head]
+ + '" in ' + this.state.name + ':' + this.keymap.name
+ + " key/state/commit-head/len:"
+ + this.key_head + '/' + this.state_key_head + '/' + this.commit_key_head + '/' + this.keys.val.length);
+ var out = this.state.keymap.Lookup (this.keys, this.state_key_head);
+ var sub = out.map;
+
+ if (out.index > this.key_head)
+ {
+ this.key_head = out.index;
+ Xex.Log (' with submap', -1);
+ restore_state.call (this);
+ this.keymap = sub;
+ if (sub.map_actions)
+ {
+ Xex.Log ('taking map actions:');
+ if (! this.take_actions (sub.map_actions))
+ return false;
+ }
+ else if (sub.submaps)
+ {
+ Xex.Log ('no map actions');
+ for (var i = this.state_key_head; i < this.key_head; i++)
+ {
+ Xex.Log ('inserting key:' + this.keys.val[i].key);
+ this.ins (this.keys.val[i].key, null);
+ }
+ }
+ if (! sub.submaps)
+ {
+ Xex.Log ('terminal:');
+ if (this.keymap.branch_actions)
+ {
+ Xex.Log ('branch actions:');
+ if (! this.take_actions (this.keymap.branch_actions))
+ return false;
+ }
+ if (sub != this.state.keymap)
+ this.shift (this.state);
+ }
+ }
+ else
+ {
+ Xex.Log (' without submap', -1);
+ this.keymap = sub;
+ var current_state = this.state;
+ var map = this.keymap;
+
+ if (map.branch_actions)
+ {
+ Xex.Log ('branch actions:');
+ if (! this.take_actions (map.branch_actions))
+ return false;
+ }
+
+ if (map == this.keymap)
+ {
+ Xex.Log ('no state change');
+ if (map == this.initial_state.keymap
+ && this.key_head < this.keys.val.length)
+ {
+ Xex.Log ('unhandled');
+ return false;
+ }
+ if (map != current_state.keymap)
+ this.shift (current_state);
+ else if (this.keymap.actions == null)
+ this.shift (this.initial_state);
+ }
+ }
+ return true;
+ }
+
+ MIM.IC.prototype = {
+ reset: function (clear_keys)
+ {
+ this.cursor_pos = 0;
+ this.prev_state = null;
+ this.title = this.initial_state.title;
+ this.state_preedit = '';
+ this.state_key_head = 0;
+ this.state_var_values = {};
+ this.state_pos = 0;
+ this.key_head = 0;
+ if (clear_keys)
+ this.keys.val.length = 0;
+ this.commit_key_head = 0;
+ this.key_unhandled = false;
+ this.unhandled_key = null;
+ this.changed = MIM.ChangedStatus.None;
+ this.error_message = '';
+ this.title = this.initial_state.title;
+ this.produced = '';
+ this.preedit = '';
+ this.preedit_saved = '';
+ if (this.candidate_show)
+ MIM.hide (this);
+ this.candidate_table.clear ();
+ this.candidates = null;
+ this.candidate_show = false;
+ for (var elt in this.marker_positions)
+ this.marker_positions[elt] = 0;
+ this.shift (this.initial_state);
+ },
+
+ catch_args: new Array (Xex.CatchTag._mimtag, null),
+
+ take_actions: function (actions)
+ {
+ if (actions.length == 0)
+ return true;;
+ var func_progn = this.domain.GetFunc ('progn');
+ var func_catch = this.domain.GetFunc ('catch');
+ this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
+ var term = new Xex.Funcall (func_catch, null, this.catch_args);
+ term = term.Eval (this.domain);
+ return (! term.IsSymbol || term.val != '@mimtag');
+ },
+
+ GetSurroundingChar: function (pos)
+ {
+ if (pos < 0)
+ {
+ pos += this.range[0];
+ if (pos < 0)
+ return -1;
+ }
+ else
+ {
+ pos += this.range[1];
+ if (pos >= this.target.value.length)
+ return -1;
+ }
+ return this.target.value.charCodeAt (pos);
+ },
+
+ DelSurroundText: function (pos)
+ {
+ var text;
+ if (pos < 0)
+ {
+ pos += this.range[0];
+ if (pos <= 0)
+ {
+ pos = 0; text = '';
+ }
+ else
+ text = this.target.value.substring (0, pos);
+ if (this.range[0] < this.target.value.length)
+ text += this.target.value.substring (this.range[0]);
+ this.target.value = text;
+ this.range[1] -= this.range[0] - pos;
+ this.range[0] = pos;
+ }
+ else
+ {
+ pos += this.range[1];
+ text = this.target.value.substring (0, this.range[1]);
+ if (pos >= this.target.value.length)
+ pos = this.target.value.length;
+ else
+ text += this.target.value.substring (pos);
+ this.target.value = text;
+ }
+ },
+
+ adjust_markers: function (from, to, inserted)
+ {
+ var diff = inserted - (to - from);
+
+ for (var name in this.marker_positions)
+ {
+ var pos = this.marker_positions[name];
+ if (pos > from)
+ {
+ if (pos >= to)
+ this.marker_positions[name] += diff;
+ else if (pos > from)
+ this.marker_positions[name] = from;
+ }
+ }
+ },
+
+ preedit_replace: function (from, to, text, candidates)
+ {
+ var newlen = text.length;
+ this.preedit = (this.preedit.substring (0, from)
+ + text + this.preedit.substring (to));
+ this.changed |= MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
+ this.adjust_markers (from, to, newlen);
+ this.candidate_table.adjust (from, to, newlen);
+ if (candidates)
+ this.candidate_table.put (from, from + newlen, candidates)
+ if (this.cursor_pos >= to)
+ set_cursor.call (this, 'adjust', this.cursor_pos + text.length - (to - from));
+ else if (this.cursor_pos > from)
+ set_cursor.call (this, 'adjust', from)
+ },
+
+ ins: function (text, candidates)
+ {
+ this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
+ },
+
+ rep: function (old_text, new_text, candidates)
+ {
+ this.preedit_replace (this.cursor_pos - old_text.length,
+ this.cursor_pos, new_text, candidates);
+ },
+
+ del: function (pos)
+ {
+ var deleted = pos - this.cursor_pos;
+ if (pos < this.cursor_pos)
+ {
+ if (pos < 0)
+ {
+ this.DelSurroundText (pos);
+ deleted = - this.cursor_pos;
+ pos = 0;
+ }
+ if (pos < this.cursor_pos)
+ this.preedit_replace (pos, this.cursor_pos, '', null);
+ }
+ else
+ {
+ if (pos > this.preedit.length)
+ {
+ this.DelSurroundText (pos - this.preedit.length);
+ deleted = this.preedit.length - this.cursor_pos;
+ pos = this.preedit.length;
+ }
+ if (pos > this.cursor_pos)
+ this.preedit_replace (this.cursor_pos, pos, '', null);
+ }
+ return deleted;
+ },
+
+ show: function ()
+ {
+ this.candidate_show = true;
+ this.changed |= MIM.ChangedStatus.CandidateShow;
+ },
+
+ hide: function ()
+ {
+ this.candidate_show = false;
+ this.changed |= MIM.ChangedStatus.CandidateShow;
+ },
+
+ move: function (pos)
+ {
+ if (pos < 0)
+ pos = 0;
+ else if (pos > this.preedit.length)
+ pos = this.preedit.length;
+ if (pos != this.cursor_pos)
+ {
+ set_cursor.call (this, 'move', pos);
+ this.changed |= MIM.ChangedStatus.Preedit;
+ }
+ },
+
+ pushback: function (n)
+ {
+ if (n instanceof MIM.KeySeq)
+ {
+ if (this.key_head > 0)
+ this.key_head--;
+ if (this.key_head < this.keys.val.length)
+ this.keys.val.splice (this.key_head,
+ this.keys.val.length - this.key_head);
+ for (var i = 0; i < n.val.length; i++)
+ this.keys.val.push (n.val[i]);
+ return;
+ }
+ if (n > 0)
+ {
+ this.key_head -= n;
+ if (this.key_head < 0)
+ this.key_head = 0;
+ }
+ else if (n == 0)
+ this.key_head = 0;
+ else
+ {
+ this.key_head = - n;
+ if (this.key_head > this.keys.val.length)
+ this.key_head = this.keys.val.length;
+ }
+ },
+
+ pop: function ()
+ {
+ if (this.key_head < this.keys.val.length)
+ this.keys.val.splice (this.key_head, 1);
+ },
+
+ commit: function ()
+ {
+ if (this.preedit.length > 0)
+ {
+ this.candidate_table.clear ();
+ this.produced += this.preedit;
+ this.preedit_replace.call (this, 0, this.preedit.length, '', null);
+ this.preedit_saved = '';
+ this.state_pos = 0;
+ this.commit_key_head = this.key_head;
+ }
+ },
+
+ shift: function (state)
+ {
+ if (state == null)
+ {
+ if (this.prev_state == null)
+ return;
+ state = this.prev_state;
+ }
+
+ if (state == this.initial_state)