*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index 3b54b3c..1527050 100644 (file)
--- 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;
        }
@@ -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)
@@ -404,9 +411,7 @@ Xex.Domain.prototype = {
        var vari = this.variables[name];
        vari.val = values[name];
       }
-  },
-
-  Trace: function () {}
+  }
 };
 
 Xex.Term = function (type) { this.type = type; }
@@ -616,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;
   }
 
@@ -624,6 +630,11 @@ Xex.Varref = function (vname)
     return new Xex.Varref (node.attributes['vname'].nodeValue);
   }
 
+  proto.ToString = function ()
+  {
+    return '<varref vname="' + this.val + '"/>';
+  }
+
   Xex.Varref.prototype = proto;
 }) ();
 
@@ -666,13 +677,14 @@ Xex.Funcall = function (func, vari, args)
 
   proto.Eval = function (domain)
   {
-    domain.Trace (this);
+    if (! (this.func instanceof Xex.Subrountine))
+      Xex.Log (this, domain.depth);
     domain.depth++;
+    var result;
     try {
-      var result = this.func.Call (domain, this.vari, this.args);
+      result = this.func.Call (domain, this.vari, this.args);
     } finally {
-      domain.depth--;
-      domain.Trace (' => ' + result + "\n");
+      Xex.Log (this + ' => ' + result, --domain.depth);
     }
     return result;
   }
@@ -694,11 +706,14 @@ 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 + '/>';
+      return str + '/>';
     for (var i = 0; i < len; i++)
-      arglist += this.args[i].toString ();
-    return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
+      arglist += '.'; //this.args[i].toString ();
+    return str + '>' + arglist + '</' + this.func.name + '>';
   }
 
   Xex.Funcall.prototype = proto;
@@ -840,19 +855,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');
@@ -1057,9 +1059,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++)
              {
@@ -1146,8 +1148,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");
@@ -1428,10 +1428,8 @@ 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);
   }
 
@@ -1440,6 +1438,8 @@ var MIM = {
   MIM.NamedMarker.prototype.Position = function (ic)
   {
     var p = ic.marker_positions[this.val];
+    if (p == undefined)
+      Xex.Log ('no position of ' + this.val);
     return (p == undefined ? 0 : p);
   }
   MIM.NamedMarker.prototype.Mark = function (ic)
@@ -1496,7 +1496,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);
   }
@@ -1505,6 +1505,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)
   {
@@ -1634,13 +1645,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;
@@ -1661,16 +1671,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)
   {
@@ -1712,10 +1723,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')
@@ -1959,13 +1968,6 @@ MIM.im_domain.DefType (MIM.Rule.prototype);
 MIM.im_domain.DefType (MIM.Map.prototype);
 MIM.im_domain.DefType (MIM.State.prototype);
 
-MIM.im_domain.Trace = function (arg)
-{
-  var node = document.getElementById ('log');
-  if (node)
-    node.value = "" + arg + node.value;
-};
-
 (function () {
   var im_domain = MIM.im_domain;
 
@@ -1976,7 +1978,8 @@ MIM.im_domain.Trace = function (arg)
       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)
@@ -1984,7 +1987,7 @@ MIM.im_domain.Trace = function (arg)
     var ic = domain.context;
     var gsize = domain.variables['candidates_group_size'];
     var candidates = new MIM.Candidates (args, gsize ? gsize.Intval : 0);
-    ic.insert (candidates.Current (), candidates);
+    ic.ins (candidates.Current (), candidates);
     return args[0];
   }
 
@@ -1992,8 +1995,7 @@ MIM.im_domain.Trace = function (arg)
   {
     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)
@@ -2003,18 +2005,18 @@ MIM.im_domain.Trace = function (arg)
 
     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');
     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)
@@ -2022,7 +2024,7 @@ MIM.im_domain.Trace = function (arg)
     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)
@@ -2033,10 +2035,10 @@ MIM.im_domain.Trace = function (arg)
 
   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];
   }
 
@@ -2279,8 +2281,14 @@ MIM.im_domain.Trace = function (arg)
     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 = {};
+    this.candidate_table = new MIM.CandidateTable ();
     this.reset ();
-    this.spot = 0;
   }
 
   MIM.CandidateTable = function ()
@@ -2372,40 +2380,38 @@ MIM.im_domain.Trace = function (arg)
   {
     var out = this.keymap.Lookup (this.keys, this.key_head);
     var sub = out.map;
-    var branch_actions = this.state.keymap.actions;
 
-    this.domain.Trace ('handling ' + this.keys.val[this.key_head]
-                      + ' in ' + this.state.name + ':'
-                      + this.keymap.name + "\n");
+    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)
       {
 
        restore_state.call (this);
        this.keymap = sub;
-       this.domain.Trace ('submap found\n');
-       if (this.keymap.actions)
+       Xex.Log ('submap found');
+       if (this.keymap.map_actions)
          {
-           this.domain.Trace ('taking map actions:\n');
-           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)
@@ -2414,24 +2420,24 @@ MIM.im_domain.Trace = function (arg)
       }
     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)
@@ -2446,23 +2452,15 @@ MIM.im_domain.Trace = function (arg)
   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.key_unhandled = false;
       this.unhandled_key = null;
@@ -2472,10 +2470,11 @@ MIM.im_domain.Trace = function (arg)
       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);
     },
 
@@ -2493,19 +2492,69 @@ MIM.im_domain.Trace = function (arg)
 
     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);
+       {
+         var pos = this.marker_positions[m];
+         if (pos > to)
+           {
+             this.marker_positions[m] = pos + diff;
+             Xex.Log ('Marker ' + m + ' = ' + this.marker_positions[m]);
+           }
+         else if (pos > from)
+           {
+             this.marker_positions[m] = from;
+             Xex.Log ('Marker ' + m + ' = ' + this.marker_positions[m]);
+           }
+       }
       if (this.cursor_pos >= to)
        set_cursor.call (this, 'adjust', this.cursor_pos + diff);
       else if (this.cursor_pos > from)
@@ -2522,31 +2571,46 @@ MIM.im_domain.Trace = function (arg)
        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;
     },
 
@@ -2624,13 +2688,10 @@ MIM.im_domain.Trace = function (arg)
     {
       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)
         {
@@ -2805,12 +2866,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)
@@ -2841,14 +2896,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
     {
@@ -2857,9 +2920,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)
@@ -2867,45 +2936,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);
 };
 
@@ -2913,41 +2964,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 {
@@ -2961,9 +3023,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 {
@@ -2991,7 +3053,7 @@ 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);
     }
 };
 
@@ -3069,5 +3131,6 @@ MIM.init = function ()
 MIM.init_debug = function ()
 {
   MIM.debug = true;
+  Xex.LogNode = document.getElementById ('log');
   MIM.init ();
 };