(get_preceding_char): Fix previous change.
[m17n/m17n-lib.git] / src / input.c
index 729b2ba..091e7f5 100644 (file)
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
@@ -469,21 +469,22 @@ fully_initialize ()
 
 \f
 static int
-marker_code (MSymbol sym)
+marker_code (MSymbol sym, int surrounding)
 {
   char *name;
 
   if (sym == Mnil)
     return -1;
   name = MSYMBOL_NAME (sym);
-  return ((name[0] == '@'
-          && ((name[1] >= '0' && name[1] <= '9')
-              || name[1] == '<' || name[1] == '>'
-              || name[1] == '=' || name[1] == '+' || name[1] == '-'
-              || name[1] == '[' || name[1] == ']'
-              || name[1] == '@')
-          && name[2] == '\0')
-         ? name[1] : -1);
+  return (name[0] != '@' ? -1
+         : (((name[1] >= '0' && name[1] <= '9')
+             || name[1] == '<' || name[1] == '>' || name[1] == '='
+             || name[1] == '[' || name[1] == ']'
+             || name[1] == '@')
+            && name[2] == '\0') ? name[1]
+         : (name[1] != '+' && name[1] != '-') ? -1
+         : (name[2] == '\0' || surrounding) ? name[1]
+         : -1);
 }
 
 
@@ -512,7 +513,7 @@ get_surrounding_text (MInputContext *ic, int len)
   MText *mt = NULL;
 
   mplist_push (ic->plist, Minteger, (void *) len);
-  if (minput__callback (ic, Minput_get_surrounding_text) >= 0
+  if (minput_callback (ic, Minput_get_surrounding_text) >= 0
       && MPLIST_MTEXT_P (ic->plist))
     mt = MPLIST_MTEXT (ic->plist);
   mplist_pop (ic->plist);
@@ -525,12 +526,18 @@ delete_surrounding_text (MInputContext *ic, int pos)
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
 
   mplist_push (ic->plist, Minteger, (void *) pos);
-  minput__callback (ic, Minput_delete_surrounding_text);
+  minput_callback (ic, Minput_delete_surrounding_text);
   mplist_pop (ic->plist);
   if (pos < 0)
-    M17N_OBJECT_UNREF (ic_info->preceding_text);
+    {
+      M17N_OBJECT_UNREF (ic_info->preceding_text);
+      ic_info->preceding_text = NULL;
+    }
   else if (pos > 0)
-    M17N_OBJECT_UNREF (ic_info->following_text);
+    {
+      M17N_OBJECT_UNREF (ic_info->following_text);
+      ic_info->following_text = NULL;
+    }
 }
 
 static int
@@ -540,11 +547,13 @@ get_preceding_char (MInputContext *ic, int pos)
   MText *mt;
   int len;
 
-  if (ic_info->preceding_text)
+  if (pos && ic_info->preceding_text)
     {
       len = mtext_nchars (ic_info->preceding_text);
       if (pos <= len)
        return mtext_ref_char (ic_info->preceding_text, len - pos);
+      if (ic->produced && mtext_len (ic->produced) >= pos - len)
+       return mtext_ref_char (ic->produced, len + mtext_len (ic->produced) - pos);
     }
   mt = get_surrounding_text (ic, - pos);
   if (! mt)
@@ -605,7 +614,8 @@ surrounding_pos (MSymbol sym)
   if (sym == Mnil)
     return 0;
   name = MSYMBOL_NAME (sym);
-  if ((name[1] == '-' || name[1] == '+')
+  if (name[0] == '@'
+      && (name[1] == '-' || name[1] == '+')
       && name[2] >= '1' && name[2] <= '9')
     return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
   return 0;
@@ -615,7 +625,7 @@ static int
 integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  int code;
+  int code, pos;
   MText *preedit = ic->preedit;
   int len = mtext_nchars (preedit);
 
@@ -623,12 +633,8 @@ integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
     *value = NULL;
   if (MPLIST_INTEGER_P (arg))
     return MPLIST_INTEGER (arg);
-  if (surrounding
-      && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
-    return (surrounding < 0
-           ? get_preceding_char (ic, - surrounding)
-           : get_following_char (ic, surrounding));
-  code = marker_code (MPLIST_SYMBOL (arg));
+
+  code = marker_code (MPLIST_SYMBOL (arg), surrounding);
   if (code < 0)
     {
       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
@@ -639,19 +645,37 @@ integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
     }
   if (code == '@')
     return ic_info->key_head;
-  if (code >= '0' && code <= '9')
-    code -= '0';
+  if ((code == '-' || code == '+'))
+    {
+      char *name = MSYMBOL_NAME (MPLIST_SYMBOL (arg));
+
+      if (name[2])
+       {
+         pos = atoi (name + 1);
+         if (pos == 0)
+           return get_preceding_char (ic, 0);
+         pos = ic->cursor_pos + pos;
+         if (pos < 0)
+           return get_preceding_char (ic, - pos);
+         if (pos >= len)
+           return get_following_char (ic, pos - len + 1);
+       }
+      else
+       pos = ic->cursor_pos + (code == '+' ? 1 : -1);
+    }
+  else if (code >= '0' && code <= '9')
+    pos = code - '0';
   else if (code == '=')
-    code = ic->cursor_pos;
-  else if (code == '-' || code == '[')
-    code = ic->cursor_pos - 1;
-  else if (code == '+' || code == ']')
-    code = ic->cursor_pos + 1;
+    pos = ic->cursor_pos;
+  else if (code == '[')
+    pos = ic->cursor_pos - 1;
+  else if (code == ']')
+    pos = ic->cursor_pos + 1;
   else if (code == '<')
-    code = 0;
+    pos = 0;
   else if (code == '>')
-    code = len;
-  return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
+    pos = len - 1;
+  return (pos >= 0 && pos < len ? mtext_ref_char (preedit, pos) : -1);
 }
 
 static int
@@ -833,8 +857,7 @@ parse_action_list (MPlist *plist, MPlist *macros)
              if (! MPLIST_TAIL_P (pl))
                {
                  if (! MPLIST_SYMBOL_P (pl)
-                     && (! MPLIST_INTEGER_P (pl)
-                         || MPLIST_INTEGER (pl) == 0))
+                     && ! MPLIST_INTEGER_P (pl))
                    MERROR (MERROR_IM, -1);                 
                }
            }
@@ -1929,7 +1952,7 @@ load_variables (MInputMethodInfo *im_info, MPlist *plist)
              /* P ::= ((NAME DESC ...) ...) */
              p = MPLIST_PLIST (p); /* P ::= (NAME DESC ...) */
              global = MPLIST_NEXT (p); /* P ::= (DESC VALUE ...) */
-             global = MPLIST_NEXT (p); /* P ::= (VALUE ...) */
+             global = MPLIST_NEXT (global); /* P ::= (VALUE ...) */
            }
 
          p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */
@@ -2308,7 +2331,12 @@ shift_state (MInputContext *ic, MSymbol state_name)
   if (state != orig_state)
     {
       if (state == (MIMState *) MPLIST_VAL (im_info->states))
-       ic_info->prev_state = NULL;
+       {
+         /* Shifted to the initial state.  */
+         ic_info->prev_state = NULL;
+         M17N_OBJECT_UNREF (ic_info->vars_saved);
+         ic_info->vars_saved = mplist_copy (ic_info->vars);
+       }
       else
        ic_info->prev_state = orig_state;
 
@@ -2361,22 +2389,53 @@ find_candidates_group (MPlist *plist, int index,
   return NULL;
 }
 
+/* Adjust markers for the change of preedit text.
+   If FROM == TO, the change is insertion of INS chars.
+   If FROM < TO and INS == 0, the change is deletion of the range.
+   If FROM < TO and INS > 0, the change is replacement.  */
+
 static void
-preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+adjust_markers (MInputContext *ic, int from, int to, int ins)
 {
   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
   MPlist *markers;
+
+  if (from == to)
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       if (MPLIST_INTEGER (markers) > from)
+         MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + ins);
+      if (ic->cursor_pos >= from)
+       ic->cursor_pos += ins;
+    }
+  else
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       {
+         if (MPLIST_INTEGER (markers) >= to)
+           MPLIST_VAL (markers)
+             = (void *) (MPLIST_INTEGER (markers) + ins - (to - from));
+         else if (MPLIST_INTEGER (markers) > from)
+           MPLIST_VAL (markers) = (void *) from;
+       }
+      if (ic->cursor_pos >= to)
+       ic->cursor_pos += ins - (to - from);
+      else if (ic->cursor_pos > from)
+       ic->cursor_pos = from;
+    }
+}
+
+
+static void
+preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+{
   int nchars = mt ? mtext_nchars (mt) : 1;
 
   if (mt)
     mtext_ins (ic->preedit, pos, mt);
   else
     mtext_ins_char (ic->preedit, pos, c, 1);
-  MPLIST_DO (markers, ic_info->markers)
-    if (MPLIST_INTEGER (markers) > pos)
-      MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
-  if (ic->cursor_pos >= pos)
-    ic->cursor_pos += nchars;
+  adjust_markers (ic, pos, pos, nchars);
   ic->preedit_changed = 1;
 }
 
@@ -2384,25 +2443,32 @@ preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
 static void
 preedit_delete (MInputContext *ic, int from, int to)
 {
-  MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
-  MPlist *markers;
+  mtext_del (ic->preedit, from, to);
+  adjust_markers (ic, from, to, 0);
+  ic->preedit_changed = 1;
+}
+
+static void
+preedit_replace (MInputContext *ic, int from, int to, MText *mt, int c)
+{
+  int ins;
 
   mtext_del (ic->preedit, from, to);
-  MPLIST_DO (markers, ic_info->markers)
-    {
-      if (MPLIST_INTEGER (markers) > to)
-       MPLIST_VAL (markers)
-         = (void *) (MPLIST_INTEGER (markers) - (to - from));
-      else if (MPLIST_INTEGER (markers) > from);
-       MPLIST_VAL (markers) = (void *) from;
-    }
-  if (ic->cursor_pos >= to)
-    ic->cursor_pos -= to - from;
-  else if (ic->cursor_pos > from)
-    ic->cursor_pos = from;
+  if (mt)
+    {
+      mtext_ins (ic->preedit, from, mt);
+      ins = mtext_nchars (mt);
+    }
+  else
+    {
+      mtext_ins_char (ic->preedit, from, c, 1);
+      ins = 1;
+    }
+  adjust_markers (ic, from, to, ins);
   ic->preedit_changed = 1;
 }
 
+
 static void
 preedit_commit (MInputContext *ic)
 {
@@ -2418,27 +2484,20 @@ preedit_commit (MInputContext *ic)
       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
                             Mcandidate_index, NULL, 0);
       mtext_cat (ic->produced, ic->preedit);
-      if ((mdebug__flag & mdebug_mask)
-         && mtext_nchars (ic->preedit) > 0)
-       {
-         int i;
-
-         MDEBUG_PRINT (" (produced");
-         for (i = 0; i < mtext_nchars (ic->preedit); i++)
-           MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
-         MDEBUG_PRINT (")");
-       }
       mtext_reset (ic->preedit);
       mtext_reset (ic_info->preedit_saved);
       MPLIST_DO (p, ic_info->markers)
        MPLIST_VAL (p) = 0;
       ic->cursor_pos = ic_info->state_pos = 0;
       ic->preedit_changed = 1;
+      ic_info->commit_key_head = ic_info->key_head;
     }
   if (ic->candidate_list)
     {
       M17N_OBJECT_UNREF (ic->candidate_list);
       ic->candidate_list = NULL;
+      ic->candidate_index = 0;
+      ic->candidate_from = ic->candidate_to = 0;
       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
       if (ic->candidate_show)
        {
@@ -2446,16 +2505,12 @@ preedit_commit (MInputContext *ic)
          ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
        }
     }
-  memmove (ic_info->keys, ic_info->keys + ic_info->key_head,
-          sizeof (int) * (ic_info->used - ic_info->key_head));
-  ic_info->used -= ic_info->key_head;
-  ic_info->state_key_head = ic_info->key_head = 0;
 }
 
 static int
 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
 {
-  int code = marker_code (sym);
+  int code = marker_code (sym, 0);
 
   if (mt && (code == '[' || code == ']'))
     {
@@ -2499,11 +2554,10 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
   int ingroup_index = idx - start;
   MText *mt;
 
-  preedit_delete (ic, from, to);
   if (MPLIST_MTEXT_P (group))
     {
       mt = MPLIST_MTEXT (group);
-      preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
+      preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
       to = from + 1;
     }
   else
@@ -2514,7 +2568,7 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
           i++, plist = MPLIST_NEXT (plist));
       mt = MPLIST_MTEXT (plist);
-      preedit_insert (ic, from, mt, 0);
+      preedit_replace (ic, from, to, mt, 0);
       to = from + mtext_nchars (mt);
     }
   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
@@ -2651,14 +2705,9 @@ get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
 
   plist = MPLIST_PLIST (args);
   if (charset)
-    {
-      if (! (plist = adjust_candidates (plist, charset)))
-       return NULL;
-    }
-  else
-    M17N_OBJECT_REF (plist);
+    plist = adjust_candidates (plist, charset);
 
-  if (column > 0)
+  if (plist && column > 0)
     {
       if (MPLIST_MTEXT_P (plist))
        {
@@ -2795,7 +2844,7 @@ regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
 }
 
 /* Perform list of actions in ACTION_LIST for the current input
-   context IC.  If all actions are performed without error, return 0.
+   context IC.  If unhandle action was not performed, return 0.
    Otherwise, return -1.  */
 
 static int
@@ -2858,7 +2907,6 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          mtext_put_prop (ic->preedit,
                          ic->cursor_pos - len, ic->cursor_pos,
                          Mcandidate_index, (void *) 0);
-         M17N_OBJECT_UNREF (plist);
        }
       else if (name == Mselect)
        {
@@ -2866,31 +2914,41 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          int code, idx, gindex;
          int pos = ic->cursor_pos;
          MPlist *group;
+         int idx_decided = 0;
 
          if (pos == 0
              || ! (prop = mtext_get_property (ic->preedit, pos - 1,
                                               Mcandidate_list)))
            continue;
+         idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
+         group = find_candidates_group (mtext_property_value (prop), idx,
+                                        &start, &end, &gindex);
          if (MPLIST_SYMBOL_P (args))
            {
-             code = marker_code (MPLIST_SYMBOL (args));
+             code = marker_code (MPLIST_SYMBOL (args), 0);
              if (code < 0)
-               continue;
+               {
+                 args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+                 if (! MPLIST_INTEGER_P (args))
+                   continue;
+                 idx = start + MPLIST_INTEGER (args);
+                 if (idx < start || idx >= end)
+                   continue;
+                 idx_decided = 1;
+               }                 
            }
          else
            code = -1;
-         idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
-         group = find_candidates_group (mtext_property_value (prop), idx,
-                                        &start, &end, &gindex);
 
          if (code != '[' && code != ']')
            {
-             idx = (start
-                    + (code >= 0
-                       ? new_index (NULL, ic->candidate_index - start,
-                                    end - start - 1, MPLIST_SYMBOL (args),
-                                    NULL)
-                       : MPLIST_INTEGER (args)));
+             if (! idx_decided)
+               idx = (start
+                      + (code >= 0
+                         ? new_index (NULL, ic->candidate_index - start,
+                                      end - start - 1, MPLIST_SYMBOL (args),
+                                      NULL)
+                         : MPLIST_INTEGER (args)));
              if (idx < 0)
                {
                  find_candidates_group (mtext_property_value (prop), -1,
@@ -2932,6 +2990,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              idx += ingroup_index;
            }
          update_candidate (ic, prop, idx);
+         MDEBUG_PRINT1 ("(%d)", idx);
        }
       else if (name == Mshow)
        ic->candidate_show = 1;
@@ -2946,7 +3005,17 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          if (MPLIST_SYMBOL_P (args)
              && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
            {
-             delete_surrounding_text (ic, pos);
+             to = ic->cursor_pos + pos;
+             if (to < 0)
+               {
+                 delete_surrounding_text (ic, to);
+                 to = 0;
+               }
+             else if (to > len)
+               {
+                 delete_surrounding_text (ic, to - len);
+                 to = len;
+               }
            }
          else
            {
@@ -2958,12 +3027,12 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                to = 0;
              else if (to > len)
                to = len;
-             MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
-             if (to < ic->cursor_pos)
-               preedit_delete (ic, to, ic->cursor_pos);
-             else if (to > ic->cursor_pos)
-               preedit_delete (ic, ic->cursor_pos, to);
            }
+         MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
+         if (to < ic->cursor_pos)
+           preedit_delete (ic, to, ic->cursor_pos);
+         else if (to > ic->cursor_pos)
+           preedit_delete (ic, ic->cursor_pos, to);
        }
       else if (name == Mmove)
        {
@@ -2983,25 +3052,42 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              ic->cursor_pos = pos;
              ic->preedit_changed = 1;
            }
+         MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
        }
       else if (name == Mmark)
        {
-         int code = marker_code (MPLIST_SYMBOL (args));
+         int code = marker_code (MPLIST_SYMBOL (args), 0);
 
          if (code < 0)
-           mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
-                       (void *) ic->cursor_pos);
+           {
+             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
+                         (void *) ic->cursor_pos);
+             MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
+           }
        }
       else if (name == Mpushback)
        {
-         if (MPLIST_INTEGER_P (args))
+         if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
            {
-             int num = MPLIST_INTEGER (args);
+             int num;
+
+             if (MPLIST_SYMBOL_P (args))
+               {
+                 args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+                 if (MPLIST_INTEGER_P (args))
+                   num = MPLIST_INTEGER (args);
+                 else
+                   num = 0;
+               }
+             else
+               num = MPLIST_INTEGER (args);
 
              if (num > 0)
                ic_info->key_head -= num;
+             else if (num == 0)
+               ic_info->key_head = 0;
              else
-               ic_info->key_head = num;
+               ic_info->key_head = - num;
              if (ic_info->key_head > ic_info->used)
                ic_info->key_head = ic_info->used;
            }
@@ -3071,7 +3157,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
 
              if (MPLIST_KEY (args) == Msymbol
                  && MPLIST_KEY (args) != Mnil
-                 && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
+                 && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
                {
                  code = new_index (ic, ic->cursor_pos, 
                                    mtext_nchars (ic->preedit),
@@ -3101,14 +3187,25 @@ take_action_list (MInputContext *ic, MPlist *action_list)
 
          mtext_reset (ic->preedit);
          mtext_reset (ic_info->preedit_saved);
+         mtext_reset (ic->produced);
+         M17N_OBJECT_UNREF (ic_info->vars);
+         ic_info->vars = mplist_copy (ic_info->vars_saved);
          ic->cursor_pos = ic_info->state_pos = 0;
-         ic_info->state_key_head = ic_info->key_head = 0;
+         ic_info->state_key_head = ic_info->key_head
+           = ic_info->commit_key_head = 0;
 
+         shift_state (ic, Mnil);
          if (intarg < 0)
-           ic_info->used += intarg;
+           {
+             if (MPLIST_TAIL_P (args))
+               {
+                 ic_info->used = 0;
+                 return -1;
+               }
+             ic_info->used += intarg;
+           }
          else
            ic_info->used = intarg;
-         shift_state (ic, Mnil);
          break;
        }
       else if (name == Mset || name == Madd || name == Msub
@@ -3217,7 +3314,11 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        }
     }
 
-  M17N_OBJECT_UNREF (ic->candidate_list);
+  if (ic->candidate_list)
+    {
+      M17N_OBJECT_UNREF (ic->candidate_list);
+      ic->candidate_list = NULL;
+    }
   if (ic->cursor_pos > 0
       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
                                     Mcandidate_list)))
@@ -3324,47 +3425,40 @@ handle_key (MInputContext *ic)
     {
       /* MAP can not handle KEY.  */
 
-      /* If MAP is the root map of the initial state, it means that
-        the current input method can not handle KEY.  */
-      if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+      /* Perform branch actions if any.  */
+      if (map->branch_actions)
        {
-         MDEBUG_PRINT (" unhandled\n");
-         return -1;
+         MDEBUG_PRINT (" branch-actions:");
+         if (take_action_list (ic, map->branch_actions) < 0)
+           {
+             MDEBUG_PRINT ("\n");
+             return -1;
+           }
        }
 
-      if (map != ic_info->state->map)
+      if (map == ic_info->map)
        {
-         /* If MAP is not the root map... */
-         /* If MAP has branch actions, perform them.  */
-         if (map->branch_actions)
+         /* The above branch actions didn't change the state.  */
+
+         /* If MAP is the root map of the initial state, it means
+            that the current input method can not handle KEY.  */
+         if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
            {
-             MDEBUG_PRINT (" branch-actions:");
-             if (take_action_list (ic, map->branch_actions) < 0)
-               {
-                 MDEBUG_PRINT ("\n");
-                 return -1;
-               }
+             MDEBUG_PRINT (" unhandled\n");
+             return -1;
            }
-         /* If MAP is still not the root map, shift to the current
-            state. */
-         if (ic_info->map != ic_info->state->map)
-           shift_state (ic, ic_info->state->name);
-       }
-      else
-       {
-         /* MAP is the root map, perform branch actions (if any) or
-            shift to the initial state.  */
-         if (map->branch_actions)
+
+         if (map != ic_info->state->map)
            {
-             MDEBUG_PRINT (" branch-actions:");
-             if (take_action_list (ic, map->branch_actions) < 0)
-               {
-                 MDEBUG_PRINT ("\n");
-                 return -1;
-               }
+             /* MAP is not the root map.  Shift to the root map of the
+                current state. */
+             shift_state (ic, ic_info->state->name);
            }
          else
-           shift_state (ic, Mnil);
+           {
+             /* MAP is the root map.  Shift to the initial state.  */
+             shift_state (ic, Mnil);
+           }
        }
     }
   MDEBUG_PRINT ("\n");
@@ -3402,6 +3496,7 @@ init_ic_info (MInputContext *ic)
            mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
          }
       }
+  ic_info->vars_saved = mplist_copy (ic_info->vars);
 
   if (im_info->externals)
     {
@@ -3453,6 +3548,7 @@ fini_ic_info (MInputContext *ic)
   M17N_OBJECT_UNREF (ic_info->preedit_saved);
   M17N_OBJECT_UNREF (ic_info->markers);
   M17N_OBJECT_UNREF (ic_info->vars);
+  M17N_OBJECT_UNREF (ic_info->vars_saved);
   M17N_OBJECT_UNREF (ic_info->preceding_text);
   M17N_OBJECT_UNREF (ic_info->following_text);
 
@@ -3474,6 +3570,7 @@ re_init_ic (MInputContext *ic, int reload)
     {
       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
       M17N_OBJECT_UNREF (ic->candidate_list);
+      ic->candidate_list = NULL;
     }
   if (ic->candidate_show)
     {
@@ -3621,6 +3718,7 @@ filter (MInputContext *ic, MSymbol key, void *arg)
   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
   M17N_OBJECT_UNREF (ic_info->preceding_text);
   M17N_OBJECT_UNREF (ic_info->following_text);
+  ic_info->preceding_text = ic_info->following_text = NULL;
   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
   ic_info->key_unhandled = 0;
 
@@ -3633,6 +3731,10 @@ filter (MInputContext *ic, MSymbol key, void *arg)
            memmove (ic_info->keys, ic_info->keys + 1,
                     sizeof (int) * (ic_info->used - 1));
            ic_info->used--;
+           if (ic_info->state_key_head > 0)
+             ic_info->state_key_head--;
+           if (ic_info->commit_key_head > 0)
+             ic_info->commit_key_head--;             
          }
        /* This forces returning 1.  */
        ic_info->key_unhandled = 1;
@@ -3650,18 +3752,40 @@ filter (MInputContext *ic, MSymbol key, void *arg)
 
   /* If the current map is the root of the initial state, we should
      produce any preedit text in ic->produced.  */
-  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
-      && mtext_nchars (ic->preedit) > 0)
-    shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
+  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+    preedit_commit (ic);
 
   if (mtext_nchars (ic->produced) > 0)
     {
       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
 
+      if (mdebug__flag & mdebug_mask)
+       {
+         MDEBUG_PRINT (" (produced");
+         for (i = 0; i < mtext_nchars (ic->produced); i++)
+           MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
+         MDEBUG_PRINT (")");
+       }
+
       if (lang != Mnil)
        mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
                        Mlanguage, ic->im->language);
     }
+  if (ic_info->commit_key_head > 0)
+    {
+      memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
+              sizeof (int) * (ic_info->used - ic_info->commit_key_head));
+      ic_info->used -= ic_info->commit_key_head;
+      ic_info->key_head -= ic_info->commit_key_head;
+      ic_info->state_key_head -= ic_info->commit_key_head;
+      ic_info->commit_key_head = 0;
+    }
+  if (ic_info->key_unhandled)
+    {
+      ic_info->used = 0;
+      ic_info->key_head = ic_info->state_key_head
+       = ic_info->commit_key_head = 0;
+    }
 
   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
 }
@@ -3812,21 +3936,6 @@ minput__fini ()
 
 }
 
-int
-minput__callback (MInputContext *ic, MSymbol command)
-{
-  MInputCallbackFunc func;
-
-  if (! ic->im->driver.callback_list)
-    return -1;
-  func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
-                                         command);
-  if (! func)
-    return -1;
-  (func) (ic, command);
-  return 0;
-}
-
 MSymbol
 minput__char_to_key (int c)
 {
@@ -3863,6 +3972,8 @@ minput__char_to_key (int c)
     it specifies the number of characters following the current cursor
     position.  If the value is negative, the absolute value specifies
     the number of characters preceding the current cursor position.
+    If the value is zero, it means that the caller just wants to know
+    if the surrounding text is currently supported or not.
 
     If the surrounding text is currently supported, the callback
     function must set the key of this element to #Mtext and the value
@@ -3896,7 +4007,8 @@ minput__char_to_key (int c)
     ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
     ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
     ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
-    ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£
+    ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
+    ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
 
     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
     ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
@@ -3905,8 +4017,7 @@ minput__char_to_key (int c)
     ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
 
     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
-    ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѲ½¤µ¤»¤ë¤³¤È¤Ê¤¯ÊÖ¤µ¤Ê¤¯¤Æ
-    ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
     Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
     ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
@@ -4041,6 +4152,16 @@ MSymbol Minput_driver;
 /*=*/
 
 /***en
+    @name Functions
+*/
+/***ja
+    @name ´Ø¿ô
+*/
+/*** @{ */
+
+/*=*/
+
+/***en
     @brief Open an input method.
 
     The minput_open_im () function opens an input method whose
@@ -4198,9 +4319,9 @@ minput_create_ic (MInputMethod *im, void *arg)
 
   if (im->driver.callback_list)
     {
-      minput__callback (ic, Minput_preedit_start);
-      minput__callback (ic, Minput_status_start);
-      minput__callback (ic, Minput_status_draw);
+      minput_callback (ic, Minput_preedit_start);
+      minput_callback (ic, Minput_status_start);
+      minput_callback (ic, Minput_status_draw);
     }
 
   MDEBUG_PRINT (" ok\n");
@@ -4234,9 +4355,9 @@ minput_destroy_ic (MInputContext *ic)
                 msymbol_name (ic->im->name), msymbol_name (ic->im->language));
   if (ic->im->driver.callback_list)
     {
-      minput__callback (ic, Minput_preedit_done);
-      minput__callback (ic, Minput_status_done);
-      minput__callback (ic, Minput_candidates_done);
+      minput_callback (ic, Minput_preedit_done);
+      minput_callback (ic, Minput_status_done);
+      minput_callback (ic, Minput_candidates_done);
     }
   (*ic->im->driver.destroy_ic) (ic);
   M17N_OBJECT_UNREF (ic->preedit);
@@ -4302,16 +4423,20 @@ minput_filter (MInputContext *ic, MSymbol key, void *arg)
   if (! ic
       || ! ic->active)
     return 0;
+  if (ic->im->driver.callback_list
+      && mtext_nchars (ic->preedit) > 0)
+    minput_callback (ic, Minput_preedit_draw);
+
   ret = (*ic->im->driver.filter) (ic, key, arg);
 
   if (ic->im->driver.callback_list)
     {
       if (ic->preedit_changed)
-       minput__callback (ic, Minput_preedit_draw);
+       minput_callback (ic, Minput_preedit_draw);
       if (ic->status_changed)
-       minput__callback (ic, Minput_status_draw);
+       minput_callback (ic, Minput_status_draw);
       if (ic->candidates_changed)
-       minput__callback (ic, Minput_candidates_draw);
+       minput_callback (ic, Minput_candidates_draw);
     }
 
   return ret;
@@ -4414,7 +4539,7 @@ minput_set_spot (MInputContext *ic, int x, int y,
   ic->spot.mt = mt;
   ic->spot.pos = pos;
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_set_spot);
+    minput_callback (ic, Minput_set_spot);
 }
 /*=*/
 
@@ -4434,7 +4559,7 @@ void
 minput_toggle (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_toggle);
+    minput_callback (ic, Minput_toggle);
   ic->active = ! ic->active;
 }
 
@@ -4464,7 +4589,7 @@ void
 minput_reset_ic (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_reset);
+    minput_callback (ic, Minput_reset);
 }
 
 /*=*/
@@ -4494,7 +4619,7 @@ minput_reset_ic (MInputContext *ic)
 
     plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
     ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
-    ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¤ÎÀäÂÐ¥Õ¥¡¥¤¥ë¥Í¡¼¥à¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
+    ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
 
     @return
     »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
@@ -4572,10 +4697,16 @@ MText *
 minput_get_description (MSymbol language, MSymbol name)
 {
   MInputMethodInfo *im_info;
+  MSymbol extra;
 
   MINPUT__INIT ();
 
-  im_info = get_im_info (language, name, Mnil, Mdescription);
+  if (name != Mnil)
+    extra = Mnil;
+  else
+    extra = language, language = Mt;
+
+  im_info = get_im_info (language, name, extra, Mdescription);
   if (! im_info || ! im_info->description)
     return NULL;
   M17N_OBJECT_REF (im_info->description);
@@ -4697,8 +4828,8 @@ minput_get_description (MSymbol language, MSymbol name)
 MText *
 get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
 {
-  /* Return a description of the command COMMAND of the input method */
-  /* specified by LANGUAGE and NAME.  */
+  /* Return a description of the command COMMAND of the input method
+     specified by LANGUAGE and NAME.  */
   MPlist *cmd = minput_get_command (langauge, name, command);
   MPlist *plist;
 
@@ -4819,11 +4950,11 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
   cmd = mplist_get_command (Mt, unicode, start_command);
   if (! cmd)
     {
-      /* The input method does not have the command "start".  Here */
-      /* should come some error handling code.  */
+      /* The input method does not have the command "start".  Here
+        should come some error handling code.  */
     }
-  /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract */
-  /* the part (KEY-SEQUENCE ...).  */
+  /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract
+     the part (KEY-SEQUENCE ...).  */
   plist = mplist_next (mplist_next (mplist_value (cmd)));
   /* Copy it because we should not modify it directly.  */
   key_seq_list = mplist_copy (plist);
@@ -4831,7 +4962,7 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
   
   key_seq = mplist ();
   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
-  mplist_add (key_seq, Msymbo, msymbol ("u"));
+  mplist_add (key_seq, Msymbol, msymbol ("u"));
   mplist_add (key_seq_list, Mplist, key_seq);
   m17n_object_unref (key_seq);
 
@@ -5477,7 +5608,8 @@ minput_save_config (void)
 }
 
 /*=*/
-
+/*** @} */
+/*=*/
 /***en
     @name Obsolete functions
 */
@@ -5863,6 +5995,35 @@ minput_assign_command_keys (MSymbol language, MSymbol name,
   return ret;
 }
 
+/*=*/
+
+/***en
+    @brief Call a callback function
+
+    The minput_callback () functions calls a callback function
+    $COMMAND assigned for the input context $IC.  The caller must set
+    specific elements in $IC->plist if the callback function requires.
+
+    @return
+    If there exists a specified callback function, 0 is returned.
+    Otherwise -1 is returned.  By side effects, $IC->plist may be
+    modified.  */
+
+int
+minput_callback (MInputContext *ic, MSymbol command)
+{
+  MInputCallbackFunc func;
+
+  if (! ic->im->driver.callback_list)
+    return -1;
+  func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
+                                         command);
+  if (! func)
+    return -1;
+  (func) (ic, command);
+  return 0;
+}
+
 /*** @} */ 
 /*** @} */
 /*=*/