X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=xex.js;h=68e38dfa9506b0b8ee0d824b106dc64930ef59da;hb=a172637653ab0db1a9a2a559bfa60d162e4e24e5;hp=a86a5b2ccbd90019e66f7e4b43f0a7108405ce4d;hpb=50a3588238d0139dd3b73acb6d1dd927ec3ee9aa;p=m17n%2Fm17n-lib-js.git diff --git a/xex.js b/xex.js index a86a5b2..68e38df 100644 --- a/xex.js +++ b/xex.js @@ -1,6 +1,18 @@ // -* coding: utf-8; -* -var Xex = {}; +var Xex = { + LogNode: null, + Log: function (arg, indent) + { + if (! Xex.LogNode) + return; + var str = ''; + if (indent != undefined) + for (var i = 0; i <= indent; i++) + str += ' '; + Xex.LogNode.value = str + arg + "\n" + Xex.LogNode.value; + } +}; Xex.Error = { UnknownError: "unknown-error", @@ -74,7 +86,7 @@ Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) Xex.Subrountine.prototype.Call = function (domain, vari, args) { - newargs = new Array (); + var newargs = new Array (); for (var i = 0; i < args.length; i++) { newargs[i] = args[i].Eval (domain); @@ -171,9 +183,9 @@ Xex.Macro.prototype.Call = function (domain, vari, args) domain.Bind (this.args[i], args[i]); try { domain.Catch (Xex.CatchTag.Return); - for (var term in body) + for (var i in this.body) { - result = term.Eval (domain); + result = this.body[i].Eval (domain); if (domain.Thrown ()) break; } @@ -352,7 +364,7 @@ Xex.Domain.prototype = { }, Defvar: function (name, desc, val, range) { - var vari = new Xex.Variable (name, desc, val, range); + var vari = new Xex.Variable (this, name, desc, val, range); this.variables[name] = vari; return vari; }, @@ -388,12 +400,7 @@ Xex.Domain.prototype = { { values = {}; for (var elt in this.variables) - { - if (! this.variables[elt].val) - alert ('unknown value of ' + elt); - else - values[elt] = this.variables[elt].val.Clone (); - } + values[elt] = this.variables[elt].val.Clone (); return values; }, RestoreValues: function (values) @@ -453,7 +460,7 @@ Node.prototype.nextElement = function () var name = node.attributes['vname'].nodeValue; if (! name) throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, ''); - var vari = domain.variables['name']; + var vari = domain.variables[name]; var desc, val, range; if (vari) { @@ -570,26 +577,19 @@ Node.prototype.nextElement = function () if (name == 'defun' || name == 'defmacro') { name = parse_defun_head (domain, node); - MIM.log ('defmacro:' + name); parse_defun_body (domain, node); return new Xex.StrTerm (name); } if (name == 'defvar') { name = parse_defvar (domain, node); - MIM.log ('defvar:' + name); return new Xex.StrTerm (name); } return new Xex.Funcall.prototype.Parser (domain, node); } for (var n = node; n && n != stop; n = n.nextElement ()) - { - if (n.nodeName == 'defun' || n.nodeName == 'defmacro') - { - var name = parse_defun_head (domain, n); - MIM.log ('defmacro:' + name); - } - } + if (n.nodeName == 'defun' || n.nodeName == 'defmacro') + parse_defun_head (domain, n); var terms = null; for (var n = node; n && n != stop; n = n.nextElement ()) { @@ -621,6 +621,7 @@ Xex.Varref = function (vname) { if (! this.vari || this.vari.domain != domain) this.vari = domain.GetVarCreate (this.val); + Xex.Log (this.ToString () + '=>' + this.vari.val, domain.depth); return this.vari.val; } @@ -629,6 +630,11 @@ Xex.Varref = function (vname) return new Xex.Varref (node.attributes['vname'].nodeValue); } + proto.ToString = function () + { + return ''; + } + Xex.Varref.prototype = proto; }) (); @@ -671,7 +677,16 @@ Xex.Funcall = function (func, vari, args) proto.Eval = function (domain) { - return this.func.Call (domain, this.vari, this.args); + if (! (this.func instanceof Xex.Subrountine)) + Xex.Log (this, domain.depth); + domain.depth++; + var result; + try { + result = this.func.Call (domain, this.vari, this.args); + } finally { + Xex.Log (this + ' => ' + result, --domain.depth); + } + return result; } proto.Clone = function () @@ -691,11 +706,18 @@ Xex.Funcall = function (func, vari, args) { var arglist = '' var len = this.args.length; + var str = '<' + this.func.name; + if (this.vari) + str += ' vname="' + this.vari.name + '"'; if (len == 0) - return '<' + this.func.name + '/>'; - for (var i = 0; i < len; i++) - arglist += this.args[i].toString (); - return '<' + this.func.name + '>' + arglist + ''; + return str + '/>'; + if (this.func instanceof Xex.Subrountine) + for (var i = 0; i < len; i++) + arglist += this.args[i].toString (); + else + for (var i = 0; i < len; i++) + arglist += '.'; + return str + '>' + arglist + ''; } Xex.Funcall.prototype = proto; @@ -837,19 +859,6 @@ Xex.LstTerm = function (list) { this.val = list; }; function Fset (domain, vari, args) { - return vari.SetValue (args[0]); - } - - function maybe_set_intvar (vari, n) - { - var term = new Xex.IntTerm (n); - if (vari != null) - vari.SetValue (term); - return term; - } - - function Fset (domain, vari, args) - { if (! vari) throw new Xex.ErrTerm (Xex.Error.NoVariableName, 'No variable name to set'); @@ -859,7 +868,7 @@ Xex.LstTerm = function (list) { this.val = list; }; function maybe_set_intvar (vari, n) { - var term = new IntTerm (n); + var term = new Xex.IntTerm (n); if (vari) vari.SetValue (term); return term; @@ -1054,9 +1063,9 @@ Xex.LstTerm = function (list) { this.val = list; }; { for (var i = 0; i < args.length; i++) { - var list = args[i].val; - var result = list.val[0].Eval (doamin); - if (result.isTrue ()) + var list = args[i]; + var result = list.val[0].Eval (domain); + if (result.IsTrue ()) { for (var j = 1; j < list.val.length; j++) { @@ -1143,8 +1152,6 @@ Xex.LstTerm = function (list) { this.val = list; }; Xex.BasicDomain = basic; basic.DefSubr (Fset, "set", true, 1, 1); - if (basic.functions['=']) - alert (basic.functions['=']); basic.DefAlias ("=", "set"); //basic.DefSubr (Fnot, "not", false, 1, 1); //basic.DefAlias ("!", "not"); @@ -1425,24 +1432,16 @@ var MIM = { MIM.Marker.prototype.CharAt = function (ic) { var p = this.Position (ic); - if (p < 0) - return ic.GetSurroundingChar (p); - else if (p >= ic.preedit.length) - return ic.GetSurroundingChar (p - ic.preedit.length); + if (p < 0 || p >= ic.preedit.length) + return 0; return ic.preedit.charCodeAt (p); } - MIM.NamedMarker = function (name) { this.val = name; } - MIM.NamedMarker.prototype = new MIM.Marker (); - MIM.NamedMarker.prototype.Position = function (ic) - { - var p = ic.marker_positions[this.val]; - return (p == undefined ? 0 : p); - } - MIM.NamedMarker.prototype.Mark = function (ic) - { - ic.marker_positions[this.val] = ic.cursor_pos; - } + MIM.FloatingMarker = function (name) { this.val = name; }; + var proto = new MIM.Marker (); + MIM.FloatingMarker.prototype = proto; + proto.Position = function (ic) { return ic.marker_positions[this.val]; }; + proto.Mark = function (ic) { ic.marker_positions[this.val] = ic.cursor_pos; }; MIM.PredefinedMarker = function (name) { this.val = name; } MIM.PredefinedMarker.prototype = new MIM.Marker (); @@ -1493,7 +1492,7 @@ var MIM = { MIM.SurroundMarker = function (name) { this.val = name; - this.distance = parseInt (name.slice (2)); + this.distance = parseInt (name.slice (1)); if (isNaN (this.distance)) throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name); } @@ -1502,6 +1501,17 @@ var MIM = { { return ic.cursor_pos + this.distance; } + MIM.SurroundMarker.prototype.CharAt = function (ic) + { + if (this.val == '@-0') + return -1; + var p = this.Position (ic); + if (p < 0) + return ic.GetSurroundingChar (p); + else if (p >= ic.preedit.length) + return ic.GetSurroundingChar (p - ic.preedit.length); + return ic.preedit.charCodeAt (p); + } MIM.Marker.prototype.Parser = function (domain, node) { @@ -1516,7 +1526,7 @@ var MIM = { throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name); } - return new MIM.NamedMarker (name); + return new MIM.FloatingMarker (name);; } }) (); @@ -1631,13 +1641,12 @@ MIM.Keymap = function () { this.name = 'TOP'; this.submaps = null; - this.actions = null; }; (function () { var proto = {}; - function add_rule (keymap, rule) + function add_rule (keymap, rule, branch_actions) { var keyseq = rule.keyseq; var len = keyseq.val.length; @@ -1658,16 +1667,17 @@ MIM.Keymap = function () keymap = sub; keymap.name = name; } - keymap.actions = rule.actions; + keymap.map_actions = rule.actions; + keymap.branch_actions = branch_actions; } - proto.Add = function (map) + 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]); + add_rule (this, rules[i], branch_actions); } proto.Lookup = function (keys, index) { @@ -1709,10 +1719,8 @@ MIM.State = function (name) { var n = node.firstElement (); if (node.nodeName == 'branch') - { - state.keymap.Add (map_list[node.attributes['mname'].nodeValue]); - state.keymap.actions = Xex.Term.Parse (domain, n, null); - } + state.keymap.Add (map_list[node.attributes['mname'].nodeValue], + Xex.Term.Parse (domain, n, null)); else if (node.nodeName == 'state-hook') state.enter_actions = Xex.Term.Parse (domain, n, null); else if (node.nodeName == 'catch-all-branch') @@ -1730,6 +1738,224 @@ MIM.State = function (name) 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 (candidates, column) + { + 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.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) + { + 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.cal (this); break; + default: break; + } + return this.Current (); + } + 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--; + } + return this.Current (); + } +}) (); + MIM.im_domain = new Xex.Domain ('input-method', null, null); MIM.im_domain.DefType (MIM.KeySeq.prototype); MIM.im_domain.DefType (MIM.Marker.prototype); @@ -1748,14 +1974,16 @@ MIM.im_domain.DefType (MIM.State.prototype); text = String.fromCharCode (args[0].val); else text = args[0].val; - domain.context.insert (text, null); + domain.context.ins (text, null); + return args[0]; } function Finsert_candidates (domain, vari, args) { var ic = domain.context; - var candidates = new Candidates (args, column); - ic.insert (candidates.Current (), candidates); + var gsize = domain.variables['candidates_group_size']; + var candidates = new MIM.Candidates (args, gsize ? gsize.Intval : 0); + ic.ins (candidates.Current (), candidates); return args[0]; } @@ -1763,8 +1991,7 @@ MIM.im_domain.DefType (MIM.State.prototype); { var ic = domain.context; var pos = args[0].IsInt ? args[0].Intval : args[0].Position (ic); - ic.del (pos); - return new Xex.Term (ic.del (pos)); + return new Xex.IntTerm (ic.del (pos)); } function Fselect (domain, vari, args) @@ -1774,18 +2001,18 @@ MIM.im_domain.DefType (MIM.State.prototype); if (can) { - var candidate = can.Current (); - - ic.del (ic.cursor_pos - candidate.length); - candidate = can.Select (args[0]); - ic.insert (candidate, 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 Fchar_at (domain, vari, args) { - return new Xex.Term (args[0].CharAt (domain.context)); + return new Xex.IntTerm (args[0].CharAt (domain.context)); } function Fmove (domain, vari, args) @@ -1793,7 +2020,7 @@ MIM.im_domain.DefType (MIM.State.prototype); var ic = domain.context; var pos = args[0].IsInt ? args[0].val : args[0].Position (ic); ic.move (pos); - return args[0]; + return new Xex.IntTerm (pos); } function Fmark (domain, vari, args) @@ -1804,10 +2031,10 @@ MIM.im_domain.DefType (MIM.State.prototype); function Fpushback (domain, vari, args) { - var arg = (args[0].IsInt ? args[0].Intval - : args[0].IsStr ? new KeySeq (args[0]) - : args[0]); - domain.context.pushback (arg) + var a = (args[0].IsInt ? args[0].Intval () + : args[0].IsStr ? new KeySeq (args[0]) + : args[0]); + domain.context.pushback (a); return args[0]; } @@ -1931,7 +2158,7 @@ MIM.im_domain.DefType (MIM.State.prototype); if (vari != null) this.domain.Defvar (vname); } - Xex.Term.Parse (this.domain, node); + vname = Xex.Term.Parse (this.domain, node) } } parsers['command-list'] = function (node) @@ -2034,7 +2261,6 @@ MIM.im_domain.DefType (MIM.State.prototype); parser.call (this, node); } this.load_status = MIM.LoadStatus.Loaded; - MIM.log ('loading done: ' + this.lang + '-' + this.name + '-' + this.extra_id); return true; } } @@ -2051,8 +2277,14 @@ MIM.im_domain.DefType (MIM.State.prototype); 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 (); - this.spot = 0; } MIM.CandidateTable = function () @@ -2060,12 +2292,12 @@ MIM.im_domain.DefType (MIM.State.prototype); this.table = new Array (); } - MIM.CandidateTable.prototype.get = function (from) + MIM.CandidateTable.prototype.get = function (pos) { for (var i = 0; i < this.table.length; i++) { var elt = this.table[i]; - if (elt.from <= from && elt.to > from) + if (elt.from < pos && pos <= elt.to) return elt.val; } } @@ -2075,8 +2307,7 @@ MIM.im_domain.DefType (MIM.State.prototype); for (var i = 0; i < this.table.length; i++) { var elt = this.table[i]; - if (elt.from >= from && elt.from < to - || elt.to >= from && elt.to < to) + if (elt.from < to && elt.to > from) { elt.from = from; elt.to = to; @@ -2090,6 +2321,8 @@ MIM.im_domain.DefType (MIM.State.prototype); 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]; @@ -2106,265 +2339,6 @@ MIM.im_domain.DefType (MIM.State.prototype); this.table.length = 0; } - 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)); - } - - function fill_group (start) - { - var nitems = this.group.length; - var r = this.row; - var b = this.blocks[r]; - - if (start < b.Index) - while (start < b.Index) - b = this.blocks[--r]; - else - while (start >= b.Index + b.Count ()) - b = this.blocks[++r]; - this.row = r; - - var count = b.Count (); - start -= b.Index; - for (var i = 0; i < nitems; i++, start++) - { - if (start >= count) - { - r++; - if (r == this.blocks.Length) - return i; - b = this.blocks[r]; - count = b.Count (); - start = 0; - } - this.group[i] = b.get (start); - } - return nitems; - } - - function Candidates (candidates, column) - { - 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 (); - } - } - - Candidates.prototype.Column = function () - { - return (this.column > 0 ? this.index % this.column - : this.index - this.blocks[this.row].Index); - } - - Candidates.prototype.GroupLength = function () - { - if (this.column > 0) - { - var start = this.index - (this.index % this.column); - return (start + this.column <= this.total ? this.column - : this.total - start); - } - return this.blocks[this.row].Count; - } - - Candidates.prototype.Current = function () - { - var b = this.blocks[this.row]; - return b.get (this.index - b.Index); - } - - Candidates.prototype.PrevGroup = function () - { - var col = this.Column (); - 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; - } - - Candidates.prototype.NextGroup = function () - { - var col = this.Column (); - 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.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; - } - - Candidates.prototype.Prev = function () - { - 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--; - } - } - - Candidates.prototype.Next = function () - { - 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++; - } - } - - Candidates.prototype.First = function () - { - this.index -= this.Column (); - while (this.blocks[this.row].Index > this.index) - this.row--; - } - - Candidates.prototype.Last = function () - { - var b = this.blocks[this.row]; - if (this.column > 0) - { - if (this.index + 1 < this.total) - { - this.index += this.column - this.Column () + 1; - while (b.Index + b.Count () <= this.index) - b = this.blocks[++this.row]; - } - } - else - this.index = b.Index + b.Count () - 1; - } - - Candidates.prototype.Select = function (selector) - { - if (selector.type == 'selector') - { - switch (selector.val) - { - case '@<': this.First (); break; - case '@>': this.Last (); break; - case '@-': this.Prev (); break; - case '@+': this.Next (); break; - case '@[': this.PrevGroup (); break; - case '@]': this.NextGroup (); break; - default: break; - } - return this.Current (); - } - 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--; - } - return this.Current (); - } - function detach_candidates (ic) { ic.candidate_table.clear (); @@ -2378,10 +2352,7 @@ MIM.im_domain.DefType (MIM.State.prototype); function set_cursor (prefix, pos) { this.cursor_pos = pos; - if (pos > 0) - this.candidates = this.candidate_table.get (pos - 1); - else - this.candidates = null; + this.candidates = this.candidate_table.get (pos); } function save_state () @@ -2403,9 +2374,8 @@ MIM.im_domain.DefType (MIM.State.prototype); { var out = this.keymap.Lookup (this.keys, this.key_head); var sub = out.map; - var branch_actions = this.state.keymap.actions; - MIM.log ('handling ' + this.keys.val[this.key_head] + Xex.Log ('handling ' + this.keys.val[this.key_head] + ' in ' + this.state.name + ':' + this.keymap.name); this.key_head = out.index; if (sub != this.keymap) @@ -2413,29 +2383,29 @@ MIM.im_domain.DefType (MIM.State.prototype); restore_state.call (this); this.keymap = sub; - MIM.log ('submap found'); - if (this.keymap.actions) + Xex.Log ('submap found'); + if (this.keymap.map_actions) { - MIM.log ('taking map actions:'); - if (! this.take_actions (this.keymap.actions)) + Xex.Log ('taking map actions:'); + if (! this.take_actions (this.keymap.map_actions)) return false; } else if (this.keymap.submaps) { - MIM.log ('no map actions'); + Xex.Log ('no map actions'); for (var i = this.state_key_head; i < this.key_head; i++) { - MIM.log ('inserting key:' + this.keys.val[i].key); - this.insert (this.keys.val[i].key, null); + Xex.Log ('inserting key:' + this.keys.val[i].key); + this.ins (this.keys.val[i].key, null); } } if (! this.keymap.submaps) { - MIM.log ('terminal:'); + Xex.Log ('terminal:'); if (this.keymap.branch_actions != null) { - MIM.log ('branch actions:'); - if (! this.take_actions (branch_actions)) + Xex.Log ('branch actions:'); + if (! this.take_actions (this.keymap.branch_actions)) return false; } if (this.keymap != this.state.keymap) @@ -2444,24 +2414,24 @@ MIM.im_domain.DefType (MIM.State.prototype); } else { - MIM.log ('no submap'); + Xex.Log ('no submap'); var current_state = this.state; var map = this.keymap; - if (branch_actions) + if (map.branch_actions) { - MIM.log ('branch actions'); - if (! this.take_actions (this.keymap.branch_actions)) + Xex.Log ('branch actions'); + if (! this.take_actions (map.branch_actions)) return false; } if (map == this.keymap) { - MIM.log ('no state change'); + Xex.Log ('no state change'); if (map == this.initial_state.keymap && this.key_head < this.keys.val.length) { - MIM.log ('unhandled'); + Xex.Log ('unhandled'); return false; } if (this.keymap != current_state.keymap) @@ -2476,24 +2446,16 @@ MIM.im_domain.DefType (MIM.State.prototype); proto = { reset: function () { - this.produced = null; - this.preedit = ''; - this.preedit_saved = ''; this.cursor_pos = 0; - this.marker_positions = {}; - this.candidates = null; this.candidate_show = false; - this.state = null; this.prev_state = null; - this.initial_state = this.im.initial_state; this.title = this.initial_state.title; this.state_preedit = ''; this.state_key_head = 0; this.state_var_values = {}; this.state_pos = 0; - this.keymap = null; - this.keys = new MIM.KeySeq (); this.key_head = 0; + this.keys.val.length = 0; this.key_unhandled = false; this.unhandled_key = null; this.changed = MIM.ChangedStatus.None; @@ -2502,10 +2464,11 @@ MIM.im_domain.DefType (MIM.State.prototype); this.produced = ''; this.preedit = ''; this.preedit_saved = ''; - this.marker_positions = {}; - this.candidate_table = new MIM.CandidateTable (); + 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); }, @@ -2523,19 +2486,66 @@ MIM.im_domain.DefType (MIM.State.prototype); GetSurroundingChar: function (pos) { - if (pos < 0 ? this.caret_pos < - pos : this.target.value.length < pos) - return 0; - return this.target.value.charCodeAt (this.caret_pos + pos); + if (pos < 0) + { + pos += this.range[0]; + if (pos < 0) + return 0; + } + else + { + pos += this.range[1]; + if (pos >= this.target.value.length) + return 0; + } + 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 m in this.marker_positions) - if (this.marker_positions[m] > from) - this.marker_positions[m] = (this.marker_positions[m] >= to - ? pos + diff : 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; + } + } if (this.cursor_pos >= to) set_cursor.call (this, 'adjust', this.cursor_pos + diff); else if (this.cursor_pos > from) @@ -2552,31 +2562,46 @@ MIM.im_domain.DefType (MIM.State.prototype); this.candidate_table.put (from, from + text.length, candidates) }, - insert: function (text, candidates) + ins: function (text, candidates) { this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates); this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; }, + rep: function (old_text, new_text, candidates) + { + this.preedit_replace (this.cursor_pos - old_text.length, + this.cursor_pos, new_text, candidates); + this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; + }, + del: function (pos) { var deleted = pos - this.cursor_pos; - if (pos < 0) + if (pos < this.cursor_pos) { - this.DelSurroundText (pos); - pos = 0; + 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) + else { - this.DelSurroundText (pos - this.preedit.length); - pos = this.preedit.length; + 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); } - if (pos < this.cursor_pos) - this.preedit = (this.predit.substring (0, pos) - + this.preedit.substring (this.cursor_pos)); - else - this.preedit = (this.preedit.substring (0, this.cursor_pos) - + this.predit.substring (pos)); + if (deleted != 0) + this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; return deleted; }, @@ -2654,13 +2679,10 @@ MIM.im_domain.DefType (MIM.State.prototype); { if (state == null) { - MIM.log ("shifting back to previous"); if (this.prev_state == null) return; state = this.prev_state; } - else - MIM.log ("shifting to " + state.name); if (state == this.initial_state) { @@ -2835,12 +2857,6 @@ MIM.add_event_listener = function (e) { listener.call (target, e || window.event); }; }); -MIM.log = function (msg) -{ - var node = document.getElementById ('log'); - node.value = msg + "\n" + node.value; -} - MIM.debug_print = function (event, ic) { if (! MIM.debug) @@ -2871,14 +2887,22 @@ MIM.debug_print = function (event, ic) MIM.debug_nodes['status' + index].innerHTML = 'no IM'; MIM.debug_nodes['keymap' + index].innerHTML = ic.state.name; MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit; + if (index == 0) + { + MIM.debug_nodes.keypress.innerHTML = ''; + MIM.debug_nodes.status1.innerHTML = ''; + MIM.debug_nodes.keymap1.innerHTML = ''; + MIM.debug_nodes.preedit1.innerHTML = '' + } }; -MIM.get_range = function (target, range) +MIM.get_range = function (target, ic) { + var from, to; if (target.selectionStart != null) // for Mozilla { - range[0] = target.selectionStart; - range[1] = target.selectionEnd; + from = target.selectionStart; + to = target.selectionEnd; } else // for IE { @@ -2887,9 +2911,15 @@ MIM.get_range = function (target, range) rr.moveToElementText (target); rr.setEndPoint ('EndToEnd', range); - range[0] = rr.text.length - r.text.length; - range[1] = rr.text.length; + from = rr.text.length - r.text.length; + to = rr.text.length; } + if (ic.range[0] == from && ic.range[1] == to + && (to == from || target.value.substring (from, to) == ic.preedit)) + return true; + ic.range[0] = from; + ic.range[1] = to; + return false; } MIM.set_caret = function (target, ic) @@ -2897,45 +2927,27 @@ MIM.set_caret = function (target, ic) if (target.setSelectionRange) // Mozilla { var scrollTop = target.scrollTop; - target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length); + target.setSelectionRange (ic.range[0], ic.range[1]); target.scrollTop = scrollTop; } else // IE { var range = target.createTextRange (); - range.moveStart ('character', ic.spot); - range.moveEnd ('character', ic.spot + ic.preedit.length); + range.moveStart ('character', ic.range[0]); + range.moveEnd ('character', ic.range[1]); range.select (); } }; -(function () { - var range = new Array (); - - MIM.check_range = function (target, ic) - { - MIM.get_range (target, range); - if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length - || target.value.substring (range[0], range[1]) != ic.preedit) - { - MIM.log ('reset:' + ic.spot + '-' + (ic.spot + ic.preedit.length) - + '/' + range[0] + '-' + range[1]); - ic.reset (); - } - target.value = (target.value.substring (0, range[0]) - + target.value.substring (range[1])); - ic.spot = range[0]; - } -}) (); - MIM.update = function (target, ic) { var text = target.value; - target.value = (text.substring (0, ic.spot) + target.value = (text.substring (0, ic.range[0]) + ic.produced + ic.preedit - + text.substring (ic.spot)); - ic.spot += ic.produced.length; + + text.substring (ic.range[1])); + ic.range[0] += ic.produced.length; + ic.range[1] = ic.range[0] + ic.preedit.length; MIM.set_caret (target, ic); }; @@ -2943,41 +2955,52 @@ MIM.reset_ic = function (event) { if (event.target.mim_ic) { - var ic = event.target.mim_ic; - var pos = ic.spot + ic.preedit.length; + var target = event.target; + var ic = target.mim_ic; + if (ic.preedit.length > 0) + event.target.setSelectionRange (ic.range[1], ic.range[1]); ic.reset (); - if (pos > ic.spot) - event.target.setSelectionRange (pos, pos); } }; MIM.keydown = function (event) { var target = event.target; + if (target.id == 'log') + return; if (! (target.type == "text" || target.type == "textarea")) return; var ic = target.mim_ic; if (! ic || ic.im != MIM.current) { - MIM.log ('creating IC'); + target.mim_ic = null; + Xex.Log ('creating IC'); ic = new MIM.IC (MIM.current, target); + if (ic.im.load_status != MIM.LoadStatus.Loaded) + return; target.mim_ic = ic; MIM.add_event_listener (target, 'blur', MIM.reset_ic); + MIM.get_range (target, ic) + } + else + { + if (! MIM.get_range (target, ic)) + ic.reset (); } - if (ic.im.load_status != MIM.LoadStatus.Loaded) - return; - MIM.check_range (target, ic); MIM.debug_print (event, ic); ic.key = MIM.decode_key_event (event); }; MIM.keypress = function (event) { - if (! (event.target.type == "text" || event.target.type == "textarea")) + var target = event.target; + if (target.id == 'log') + return; + if (! (target.type == "text" || target.type == "textarea")) return; - var ic = event.target.mim_ic; + var ic = target.mim_ic; var i; try { @@ -2991,9 +3014,9 @@ MIM.keypress = function (event) return; } - MIM.log ("filtering " + ic.key); + Xex.Log ("filtering " + ic.key); var result = ic.Filter (ic.key); - MIM.update (event.target, ic); + MIM.update (target, ic); if (! ic.key_unhandled) event.preventDefault (); } finally { @@ -3002,10 +3025,89 @@ MIM.keypress = function (event) return; }; +MIM.Lang = { + European: new Array ('de', 'fr'), + MiddleEast: new Array ('ar', 'he'), + SouthAsia: new Array ('hi'), + SouthEastAsia: new Array ('th'), + EastAsia: new Array ('ja', 'zh'), + Other: new Array () +}; + +// Other +// am +// ath +// bla +// cr +// el +// eo +// iu +// nsk +// oj + +// Middle Eastern +// ar +// dv +// fa +// he +// hi +// kk +// ps +// ug +// yi* + +// South Asian +// as +// bn +// bo +// gu +// kn +// ks +// ml +// mr +// ne +// or +// pa +// sd +// sa +// si +// ta +// te +// ur + +// European +// cs +// da +// eo +// fr +// hr +// hy +// kk +// ru +// sk +// sr +// sv +// vi* +// yi* + +// East Asian +// ii +// ja +// ko +// zh + +// SouthEast Asian +// km +// lo +// my +// tai +// th +// vi* + MIM.select_im = function (event) { var target = event.target.parentNode; - while (target.tagName != "SELECT") + while (target.tagName != "mim-select-im") target = target.parentNode; var idx = 0; var im = false; @@ -3021,48 +3123,127 @@ MIM.select_im = function (event) if (im && im != MIM.current) { MIM.current = im; - MIM.log ('select IM: ' + im.name); + Xex.Log ('select IM: ' + im.name); } }; MIM.destroy_menu = function (event) { - if (event.target.tagName == "SELECT") + if (event.target.tagName == "mim-select-im") document.getElementsByTagName ('body')[0].removeChild (event.target); }; MIM.select_menu = function (event) { var target = event.target; + var sel; if (! ((target.type == "text" || target.type == "textarea") && event.which == 1 && event.ctrlKey)) return; - - var sel = document.createElement ('select'); - sel.onclick = MIM.select_im; - sel.onmouseout = MIM.destroy_menu; - sel.style.position='absolute'; - sel.style.left = (event.clientX - 10) + "px"; - sel.style.top = (event.clientY - 10) + "px"; - sel.target = target; - var idx = 0; - for (var lang in MIM.imlist) - for (var name in MIM.imlist[lang]) - { - var option = document.createElement ('option'); - var imname = lang + "-" + name; - option.appendChild (document.createTextNode (imname)); - option.value = imname; - sel.appendChild (option); - if (MIM.imlist[lang][name] == MIM.current) - sel.selectedIndex = idx; - idx++; - } - sel.size = idx; + if (! sel) + { + sel = document.createElement ('select'); + sel.onclick = MIM.select_im; + sel.onmouseout = MIM.destroy_menu; + sel.style.position='absolute'; + sel.style.left = (event.clientX - 10) + "px"; + sel.style.top = (event.clientY - 10) + "px"; + sel.target = target; + var idx = 0; + for (var lang in MIM.imlist) + for (var name in MIM.imlist[lang]) + { + var option = document.createElement ('option'); + var imname = lang + "-" + name; + option.appendChild (document.createTextNode (imname)); + option.value = imname; + sel.appendChild (option); + if (MIM.imlist[lang][name] == MIM.current) + sel.selectedIndex = idx; + idx++; + } + sel.size = idx; + } document.getElementsByTagName ('body')[0].appendChild (sel); }; +MIM.select_menu = function (event) +{ + var target = event.target; + var menu; + + if (! ((target.type == "text" || target.type == "textarea") + && event.which == 1 && event.ctrlKey)) + return; + if (! menu) + { + menu = document.createElement ('ul'); + menu.style.margin = '0'; + menu.style.padding = '0'; + menu.id = 'mim-select-im'; + menu.onclick = MIM.select_im; + menu.onmouseout = MIM.destroy_menu; + menu.style.position='absolute'; + menu.style.left = (event.clientX - 10) + "px"; + menu.style.top = (event.clientY - 10) + "px"; + menu.style['border-bottom'] = '1px solid #ccc'; + menu.style['background-color'] = 'white'; + menu.target = target; + var idx = 0; + for (var lang in MIM.imlist) + { + var li = document.createElement ('li'); + li.style.position = 'relative'; + li.style['list-style']= 'none'; + li.style.margin = '0'; + li.style.padding = '0'; + li.onmouseover = function () + { + this.style.backgroundColor = 'yellow'; + var children = this.getElementsByTagName ('ul'); + for (var i = children.length - 1; i >= 0; i--) + { + children[i].display = 'block'; + children[i].visibility = 'visible'; + children[i].left = '100px'; + } + children = this.getElementsByTagName ('li'); + for (var i = children.length - 1; i >= 0; i--) + { + children[i].display = 'block'; + children[i].visibility = 'visible'; + children[i].left = '100px'; + } + }; + li.onmouseout = function () { this.style.backgroundColor = 'white'; }; + li.appendChild (document.createTextNode (lang)); + var sub = document.createElement ('ul'); + sub.style.position = 'absolute'; + sub.style.top = '0px'; + sub.style.visibility = 'hidden'; + li.appendChild (sub); + for (var name in MIM.imlist[lang]) + { + var sub_li = document.createElement ('li'); + var imname = ' ' + lang + "-" + name; + sub_li.style.position = 'absolute'; + sub_li.style.top = '0px'; + sub_li.style['list-style']= 'none'; + //sub_li.style.visibility = 'hidden'; + sub_li.appendChild (document.createTextNode (imname)); + sub.appendChild (sub_li); + if (MIM.imlist[lang][name] == MIM.current) + menu.selectedIndex = idx; + idx++; + } + menu.appendChild (li); + } + menu.size = idx; + } + document.getElementsByTagName ('body')[0].appendChild (menu); +}; + MIM.test = function () { var im = MIM.imlist['t']['latn-post']; @@ -3099,5 +3280,6 @@ MIM.init = function () MIM.init_debug = function () { MIM.debug = true; + Xex.LogNode = document.getElementById ('log'); MIM.init (); };