(Mdetail_text, minput_get_description, minput_get_commands)
[m17n/m17n-lib.git] / src / input.c
index 270924e..928da5b 100644 (file)
 
 #include <stdio.h>
 #include <string.h>
-#include <dlfcn.h>
 
 #include "config.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
 #include "m17n-gui.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "symbol.h"
 #include "plist.h"
 
+static int mdebug_mask = MDEBUG_INPUT;
+
 static MSymbol Minput_method;
 
 /** Symbols to load an input method data.  */
@@ -233,7 +239,7 @@ integer_value (MInputContext *ic, MPlist *arg)
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
   int code;
   MText *preedit = ic->preedit;
-  int len = mtext_nbytes (preedit);
+  int len = mtext_nchars (preedit);
 
   if (MPLIST_INTEGER_P (arg))
     return MPLIST_INTEGER (arg);
@@ -250,7 +256,7 @@ integer_value (MInputContext *ic, MPlist *arg)
     code = ic->cursor_pos + 1;
   else if (code == '<')
     code = 0;
-  else if (code == '<')
+  else if (code == '>')
     code = len;
   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
 }
@@ -686,8 +692,6 @@ load_input_method (MSymbol language, MSymbol name, MPlist *plist,
   MPlist *macros = NULL;
   MPlist *elt;
 
-  if (! MPLIST_PLIST_P (plist))
-    MERROR (MERROR_IM, -1);
   for (; MPLIST_PLIST_P (plist); plist = MPLIST_NEXT (plist))
     {
       elt = MPLIST_PLIST (plist);
@@ -747,9 +751,12 @@ load_input_method (MSymbol language, MSymbol name, MPlist *plist,
        }
     }
 
-  MPLIST_DO (elt, maps)
-    M17N_OBJECT_UNREF (MPLIST_VAL (elt));
-  M17N_OBJECT_UNREF (maps);
+  if (maps)
+    {
+      MPLIST_DO (elt, maps)
+       M17N_OBJECT_UNREF (MPLIST_VAL (elt));
+      M17N_OBJECT_UNREF (maps);
+    }
   if (! title)
     title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
                             MTEXT_FORMAT_US_ASCII);
@@ -807,7 +814,7 @@ shift_state (MInputContext *ic, MSymbol state_name)
 {
   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  MIMState *state = ic_info->state;
+  MIMState *state;
 
   /* Find a state to shift to.  If not found, shift to the initial
      state.  */
@@ -815,6 +822,8 @@ shift_state (MInputContext *ic, MSymbol state_name)
   if (! state)
     state = (MIMState *) MPLIST_VAL (im_info->states);
 
+  MDEBUG_PRINT1 ("\n[IM] state-shift (%s)", MSYMBOL_NAME (state->name));
+
   /* Enter the new state.  */
   ic_info->state = state;
   ic_info->map = state->map;
@@ -829,6 +838,16 @@ shift_state (MInputContext *ic, MSymbol state_name)
       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->produced) > 0)
+       {
+         int i;
+
+         MDEBUG_PRINT (" (produced");
+           for (i = 0; i < mtext_nchars (ic->produced); i++)
+             MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
+         MDEBUG_PRINT (")");
+       }
       mtext_reset (ic->preedit);
       ic->candidate_list = NULL;
       ic->candidate_show = 0;
@@ -852,9 +871,17 @@ shift_state (MInputContext *ic, MSymbol state_name)
   if (ic_info->key_head == ic_info->used
       && ic_info->map == ic_info->state->map
       && ic_info->map->map_actions)
-    take_action_list (ic, ic_info->map->map_actions);
+    {
+      MDEBUG_PRINT (" init-actions:");
+      take_action_list (ic, ic_info->map->map_actions);
+    }
 }
 
+/* Find a candidate group that contains a candidate number INDEX from
+   PLIST.  Set START_INDEX to the first candidate number of the group,
+   END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
+   candidate group number if they are non-NULL.  If INDEX is -1, find
+   the last candidate group.  */
 
 static MPlist *
 find_candidates_group (MPlist *plist, int index,
@@ -868,7 +895,8 @@ find_candidates_group (MPlist *plist, int index,
        len = mtext_nchars (MPLIST_MTEXT (plist));
       else
        len = mplist_length (MPLIST_PLIST (plist));
-      if (i + len > index)
+      if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
+         : i + len > index)
        {
          if (start_index)
            *start_index = i;
@@ -963,7 +991,7 @@ new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
 }
 
 static void
-udpate_candidate (MInputContext *ic, MTextProperty *prop, int idx)
+update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
 {
   int from = mtext_property_start (prop);
   int to = mtext_property_end (prop);
@@ -1027,6 +1055,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          args = MPLIST_NEXT (action);
        }
 
+      MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
       if (name == Minsert)
        {
          if (MPLIST_MTEXT_P (args))
@@ -1097,9 +1126,14 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                                     end - start - 1, MPLIST_SYMBOL (args),
                                     NULL)
                        : MPLIST_INTEGER (args)));
-             if (idx < 0
-                 || (idx >= end
-                     && MPLIST_TAIL_P (MPLIST_NEXT (group))))
+             if (idx < 0)
+               {
+                 find_candidates_group (mtext_property_value (prop), -1,
+                                        NULL, &end, NULL);
+                 idx = end - 1;
+               }
+             else if (idx >= end
+                      && MPLIST_TAIL_P (MPLIST_NEXT (group)))
                idx = 0;
            }
          else
@@ -1132,7 +1166,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                ingroup_index = len - 1;
              idx += ingroup_index;
            }
-         udpate_candidate (ic, prop, idx);
+         update_candidate (ic, prop, idx);
        }
       else if (name == Mshow)
        ic->candidate_show = 1;
@@ -1285,12 +1319,13 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          else
            val1 /= val2;
          mplist_put (ic_info->vars, sym, (void *) val1);
+         MDEBUG_PRINT2 ("(%s=%d)", MSYMBOL_NAME (sym), val1);
        }
       else if (name == Mequal || name == Mless || name == Mgreater)
        {
          int val1, val2;
          MPlist *actions1, *actions2;
-         int ret;
+         int ret = 0;
 
          val1 = integer_value (ic, args);
          args = MPLIST_NEXT (args);
@@ -1360,6 +1395,9 @@ handle_key (MInputContext *ic)
   MSymbol key = ic_info->keys[ic_info->key_head];
   int i;
 
+  MDEBUG_PRINT2 ("[IM] handle `%s' in state %s", 
+                MSYMBOL_NAME (key), MSYMBOL_NAME (ic_info->state->name));
+
   if (map->submaps)
     {
       submap = mplist_get (map->submaps, key);
@@ -1369,12 +1407,14 @@ handle_key (MInputContext *ic)
 
   if (submap)
     {
+      MDEBUG_PRINT (" submap-found");
       mtext_cpy (ic->preedit, ic_info->preedit_saved);
       ic->cursor_pos = ic_info->state_pos;
       ic_info->key_head++;
       ic_info->map = map = submap;
       if (map->map_actions)
        {
+         MDEBUG_PRINT (" map-actions:");
          if (take_action_list (ic, map->map_actions) < 0)
            return -1;
        }
@@ -1397,6 +1437,7 @@ handle_key (MInputContext *ic)
        {
          if (map->branch_actions)
            {
+             MDEBUG_PRINT (" branch-actions:");
              if (take_action_list (ic, map->branch_actions) < 0)
                return -1;
            }
@@ -1405,6 +1446,7 @@ handle_key (MInputContext *ic)
          if (ic_info->map != ic_info->state->map)
            shift_state (ic, ic_info->state->name);
        }
+      MDEBUG_PRINT ("\n");
     }
   else
     {
@@ -1413,14 +1455,20 @@ handle_key (MInputContext *ic)
       /* 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)
-       return -1;
+       {
+         MDEBUG_PRINT (" unhandled\n");
+         return -1;
+       }
 
       if (map != ic_info->state->map)
        {
          /* If MAP is not the root map... */
          /* If MAP has branch actions, perform them.  */
          if (map->branch_actions)
-           take_action_list (ic, map->branch_actions);
+           {
+             MDEBUG_PRINT (" branch-actions:");
+             take_action_list (ic, map->branch_actions);
+           }
          /* If MAP is still not the root map, shift to the current
             state. */
          if (ic_info->map != ic_info->state->map)
@@ -1428,7 +1476,10 @@ handle_key (MInputContext *ic)
              shift_state (ic, ic_info->state->name);
              /* If MAP has branch_actions, perform them.  */
              if (ic_info->map->branch_actions)
-               take_action_list (ic, ic_info->map->branch_actions);
+               {
+                 MDEBUG_PRINT (" init-actions:");
+                 take_action_list (ic, ic_info->map->branch_actions);
+               }
            }
        }
       else
@@ -1436,33 +1487,42 @@ handle_key (MInputContext *ic)
          /* MAP is the root map, perform branch actions (if any) or
             shift to the initial state.  */
          if (map->branch_actions)
-           take_action_list (ic, map->branch_actions);
+           {
+             MDEBUG_PRINT (" branch-actions:");
+             take_action_list (ic, map->branch_actions);
+           }
          else
            shift_state (ic,
                         ((MIMState *) MPLIST_VAL (im_info->states))->name);
        }
+      MDEBUG_PRINT ("\n");
     }
   return 0;
 }
 
 static void
-reset_ic (MInputContext *ic)
+reset_ic (MInputContext *ic, MSymbol ignore)
 {
   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
 
+  if (im_info->states)
+    /* Shift to the initial state.  */
+    shift_state (ic, Mnil);
+  else
+    ic_info->state = NULL;
   MLIST_RESET (ic_info);
-  ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
-  ic_info->map = ic_info->state->map;
+  ic_info->map = ic_info->state ? ic_info->state->map : NULL;
   ic_info->state_key_head = ic_info->key_head = 0;
+  ic_info->key_unhandled = 0;
   ic->cursor_pos = ic_info->state_pos = 0;
-  ic->status = ic_info->state->title;
+  ic->status = ic_info->state ? ic_info->state->title : NULL;
   if (! ic->status)
     ic->status = im_info->title;
   ic->candidate_list = NULL;
   ic->candidate_show = 0;
   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
-  if (ic_info->map->map_actions)
+  if (ic_info->map && ic_info->map->map_actions)
     take_action_list (ic, ic_info->map->map_actions);
 }
 
@@ -1571,7 +1631,7 @@ create_ic (MInputContext *ic)
        }
       M17N_OBJECT_UNREF (func_args);
     }
-  reset_ic (ic);
+  reset_ic (ic, Mnil);
   return 0;
 }
 
@@ -1618,6 +1678,11 @@ filter (MInputContext *ic, MSymbol key, void *arg)
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
   int i = 0;
 
+  if (! ic_info->state)
+    {
+      ic_info->key_unhandled = 1;
+      return 0;
+    }
   mtext_reset (ic->produced);
   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
@@ -1627,7 +1692,7 @@ filter (MInputContext *ic, MSymbol key, void *arg)
       {
        /* KEY was not handled.  Reset the status and break the
           loop.  */
-       reset_ic (ic);
+       reset_ic (ic, Mnil);
        /* This forces returning 1.  */
        ic_info->key_unhandled = 1;
        break;
@@ -1635,7 +1700,7 @@ filter (MInputContext *ic, MSymbol key, void *arg)
     if (i++ == 100)
       {
        mdebug_hook ();
-       reset_ic (ic);
+       reset_ic (ic, Mnil);
        ic_info->key_unhandled = 1;
        break;
       }
@@ -1784,6 +1849,7 @@ minput__init ()
   Minput_candidates_draw = msymbol ("input-candidates-draw");
   Minput_set_spot = msymbol ("input-set-spot");
   Minput_toggle = msymbol ("input-toggle");
+  Minput_reset = msymbol ("input-reset");
 
   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
   Mcandidate_index = msymbol ("  candidate-index");
@@ -1829,7 +1895,9 @@ minput__init ()
   minput_default_driver.destroy_ic = destroy_ic;
   minput_default_driver.filter = filter;
   minput_default_driver.lookup = lookup;
-  minput_default_driver.callback_list = NULL;
+  minput_default_driver.callback_list = mplist ();
+  mplist_put (minput_default_driver.callback_list, Minput_reset,
+             (void *) reset_ic);
   minput_driver = &minput_default_driver;
   return 0;
 }
@@ -1908,6 +1976,7 @@ MSymbol Minput_candidates_done;
 MSymbol Minput_candidates_draw;
 MSymbol Minput_set_spot;
 MSymbol Minput_toggle;
+MSymbol Minput_reset;
 /*** @} */
 /*=*/
 
@@ -1963,15 +2032,16 @@ MInputDriver minput_default_driver;
     The variable #minput_driver is a pointer to the input method
     driver that is used by internal input methods.  The macro
     M17N_INIT () initializes it to a pointer to #minput_default_driver
-    (if <m17n.h> is included) or to #minput_gui_driver (if
-    <m17n-gui.h> is included).  */ 
+    (if <m17n<EM></EM>.h> is included) or to #minput_gui_driver (if
+    <m17n-gui<EM></EM>.h> is included).  */ 
 /***ja
     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
 
     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
-    ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥íM17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
-    ¥¿¤ò #minput_default_driver (<m17n.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï 
-    #minput_gui_driver ( <m17n-gui.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
+    ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
+    ¥¿¤ò #minput_default_driver (<m17n<EM></EM>.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï
+    #minput_gui_driver ( <m17n-gui<EM></EM>.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹
+    ¤ë¡£  */ 
 
 MInputDriver *minput_driver;
 
@@ -2228,7 +2298,6 @@ minput_filter (MInputContext *ic, MSymbol key, void *arg)
        minput__callback (ic, Minput_status_draw);
       if (ic->candidates_changed)
        minput__callback (ic, Minput_candidates_draw);
-      ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
     }
 
   return ret;
@@ -2355,6 +2424,32 @@ minput_toggle (MInputContext *ic)
   ic->active = ! ic->active;
 }
 
+/***en
+    @brief Reset an input context.
+
+    The minput_reset_ic () function resets the input context $IC by
+    calling a callback functions corresponding to #Minput_reset.  It
+    actually shifts the state to the initial one, and thus the current
+    preediting text (if any) is committed.  If necessary, a program
+    can extract that text by calling minput_lookup () just after the
+    call of minput_reset_ic ().  In that case, the arguments @c KEY
+    and @c ARG of minput_lookup () are ignored.  */
+/***ja
+    @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
+
+    ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
+    ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¤³¤ì¤Ï¼ÂºÝ¤Ï
+    ÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˥·¥Õ¥È¤µ¤»¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢¤â¤·¸½ºßÆþÎÏÃæ¤Î
+    ¥Æ¥­¥¹¥È¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¡£É¬Íפʤ饢¥×¥ê¥±¡¼¥·¥ç¥ó¥×
+    ¥í¥°¥é¥à¤Ï minput_lookup () ¤òÆɤó¤Ç¤½¤Î¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤»¤ë¡£¤½¤Î
+    ºÝ¡¢minput_lookup () ¤Î°ú¿ô @c KEY ¤È @c ARG ¤Ï̵»ë¤µ¤ì¤ë¡£ */
+void
+minput_reset_ic (MInputContext *ic)
+{
+  if (ic->im->driver.callback_list)
+    minput__callback (ic, Minput_reset);
+}
+
 
 /*** @} */
 /*=*/