diff options
author | Peng Huang <shawn.p.huang@gmail.com> | 2010-06-18 11:25:15 +0800 |
---|---|---|
committer | Peng Huang <shawn.p.huang@gmail.com> | 2010-06-18 11:25:15 +0800 |
commit | f1944e652c6e4c73b87193c7e8cc82ccb0c35ddd (patch) | |
tree | 2e2ec9058151f7ac06f76547db125f4d16dda5b9 /src | |
parent | f1f93631962b46a8a2744796ebbb9fdc74c981ff (diff) | |
parent | 40093940e25ada4c0cf3c258ab49e9ebd32bbc65 (diff) | |
download | ibus-pinyin-f1944e652c6e4c73b87193c7e8cc82ccb0c35ddd.tar.gz |
Merge remote branch 'epico/lua-plugin' into lua-plugin
Conflicts:
src/ExtEditor.cc
src/ExtEditor.h
src/LookupTable.h
src/Makefile.am
src/PinyinEngine.cc
Diffstat (limited to 'src')
-rw-r--r-- | src/ExtEditor.cc | 606 | ||||
-rw-r--r-- | src/ExtEditor.h | 59 | ||||
-rw-r--r-- | src/LookupTable.h | 3 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/PinyinEngine.cc | 2 |
5 files changed, 670 insertions, 4 deletions
diff --git a/src/ExtEditor.cc b/src/ExtEditor.cc index 73407e9..28a739a 100644 --- a/src/ExtEditor.cc +++ b/src/ExtEditor.cc @@ -20,54 +20,658 @@ */ #include "ExtEditor.h" +#define _(text) (dgettext (GETTEXT_PACKAGE, text)) + namespace PY { +/* Write digit/alpha/none Label generator here. + * foreach (results): 1, from get_retval; 2..n from get_retvals. + */ + ExtEditor::ExtEditor (PinyinProperties & props, Config & config) - : Editor (props, config) + : Editor (props), + m_mode(LABEL_NONE), + m_result_num(0), + m_candidate(NULL), + m_candidates(NULL) +{ + m_lua_plugin = ibus_engine_plugin_new(); + + loadLuaScript("../lua/base.lua"); + + m_text = ""; + m_cursor = 0; + m_lookup_table.clear(); +} + +int +ExtEditor::loadLuaScript(std::string filename) { + return ibus_engine_plugin_load_lua_script(m_lua_plugin, filename.c_str()); } +void +ExtEditor::resetLuaState() +{ + g_object_unref(m_lua_plugin); + m_lua_plugin = ibus_engine_plugin_new(); +} + + gboolean ExtEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers) { + //IBUS_SHIFT_MASK is removed. + modifiers &= (IBUS_CONTROL_MASK | + IBUS_MOD1_MASK | + IBUS_SUPER_MASK | + IBUS_HYPER_MASK | + IBUS_META_MASK | + IBUS_LOCK_MASK); + if ( modifiers ) + return FALSE; + + //handle backspace/delete here. + if (processEditKey(keyval)) + return TRUE; + + //handle page/cursor up/down here. + if (processPageKey(keyval)) + return TRUE; + + //handle label key select here. + if (processLabelKey(keyval)) + return TRUE; + + if (processSpace(keyval)) + return TRUE; + + m_cursor = std::min(m_cursor, (guint)m_text.length()); + + /* Remember the input string. */ + switch(m_cursor){ + case 0: //Empty input string. + { + g_return_val_if_fail( 'i' == keyval, FALSE); + if ( 'i' == keyval ) { + m_text.insert(m_cursor, keyval); + m_cursor++; + } + } + break; + case 1 ... 2: // Only contains 'i' in input string. + { + g_return_val_if_fail( 'i' == m_text[0], FALSE); + if ( isalnum(keyval) ) { + m_text.insert(m_cursor, keyval); + m_cursor++; + } + } + break; + default: //Here is the appended argment. + { + g_return_val_if_fail( 'i' == m_text[0], FALSE); + if (isprint(keyval)){ + m_text.insert(m_cursor, keyval); + m_cursor++; + } + } + break; + } + /* Deal other staff with updateStateFromInput(). */ + updateStateFromInput(); + update(); + return TRUE; +} + +gboolean +ExtEditor::processEditKey(guint keyval){ + switch (keyval){ + case IBUS_Delete: + case IBUS_KP_Delete: + removeCharAfter(); + updateStateFromInput(); + update(); + return TRUE; + case IBUS_BackSpace: + removeCharBefore(); + updateStateFromInput(); + update(); + return TRUE; + } + return FALSE; +} + +gboolean +ExtEditor::processPageKey(guint keyval){ + switch (keyval) { + //For 2000-10-10 16:30 input. + case IBUS_comma: + if (Config::commaPeriodPage ()) { + pageUp (); + return TRUE; + } + break; +#if 0 + case IBUS_minus: + if (Config::minusEqualPage ()) { + pageUp (); + return TRUE; + } + break; +#endif + case IBUS_period: + if (Config::commaPeriodPage ()) { + pageDown (); + return TRUE; + } + break; + case IBUS_equal: + if (Config::minusEqualPage ()) { + pageDown (); + return TRUE; + } + break; + case IBUS_Up: + case IBUS_KP_Up: + cursorUp (); + return TRUE; + + case IBUS_Down: + case IBUS_KP_Down: + cursorDown (); + return TRUE; + + case IBUS_Page_Up: + case IBUS_KP_Page_Up: + pageUp (); + return TRUE; + + case IBUS_Page_Down: + case IBUS_KP_Page_Down: + pageDown (); + return TRUE; + + case IBUS_Escape: + reset (); + return TRUE; + } return FALSE; } +gboolean +ExtEditor::processLabelKey(guint keyval){ + //According to enum ExtEditorLabelMode. + + switch(m_mode){ + case LABEL_LIST_DIGIT: + switch(keyval){ + case 1 ... 9: + selectCandidateInPage(keyval - '1'); + return TRUE; + break; + case 0: + selectCandidateInPage(9); + return TRUE; + break; + } + break; + case LABEL_LIST_ALPHA: + switch(keyval){ + case 'a' ... 'k': + selectCandidateInPage(keyval - 'a'); + return TRUE; + break; + case 'A' ... 'K': + selectCandidateInPage(keyval - 'A'); + return TRUE; + break; + } + break; + } + return FALSE; +} + +gboolean +ExtEditor::processSpace(guint keyval){ + if (!(keyval == IBUS_space || keyval == IBUS_KP_Space)) + return FALSE; + + guint cursor_pos = m_lookup_table.cursorPos(); + + switch(m_mode){ + case LABEL_LIST_NUMBERS: + //TODO: implement number mode. + break; + case LABEL_LIST_COMMANDS: + case LABEL_LIST_DIGIT: + case LABEL_LIST_ALPHA: + selectCandidateInPage(cursor_pos); + break; + case LABEL_LIST_SINGLE: + g_return_val_if_fail(cursor_pos == 0 , FALSE); + selectCandidateInPage(cursor_pos); + break; + } + return TRUE; +} + void ExtEditor::pageUp (void) { + if (G_LIKELY(m_lookup_table.pageUp())) { + update(); + } } void ExtEditor::pageDown (void) { + if (G_LIKELY(m_lookup_table.pageDown())) { + update(); + } +} + +gboolean +ExtEditor::removeCharBefore() +{ + if (G_UNLIKELY( m_cursor <= 0 )) { + m_cursor = 0; + return FALSE; + } + + if (G_UNLIKELY( m_cursor > m_text.length() )) { + m_cursor = m_text.length(); + return FALSE; + } + + m_text.erase(m_cursor - 1, 1); + m_cursor = std::max(0, (int)(m_cursor - 1)); +} + +gboolean +ExtEditor::removeCharAfter() +{ + if (G_UNLIKELY( m_cursor < 0 )) { + m_cursor = 0; + return FALSE; + } + + if (G_UNLIKELY( m_cursor >= m_text.length() )) { + m_cursor = m_text.length(); + return FALSE; + } + m_text.erase(m_cursor, 1); + m_cursor = std::min(m_cursor, (guint)m_text.length()); } void ExtEditor::cursorUp (void) { + if (G_LIKELY (m_lookup_table.cursorUp ())) { + update(); + } } void ExtEditor::cursorDown (void) { + if (G_LIKELY (m_lookup_table.cursorDown ())) { + update(); + } } void ExtEditor::update (void) { + updateLookupTable(); + updatePreeditText(); + updateAuxiliaryText(); } void ExtEditor::reset (void) { + m_text = ""; + updateStateFromInput(); + update(); } void ExtEditor::candidateClicked (guint index, guint button, guint state) { + selectCandidateInPage (index); } +gboolean +ExtEditor::selectCandidateInPage (guint index) +{ + guint page_size = m_lookup_table.pageSize(); + guint cursor_pos = m_lookup_table.cursorPos(); + + if (G_UNLIKELY(index >= page_size)) + return FALSE; + index += (cursor_pos / page_size) * page_size; + + return selectCandidate (index); +} + +gboolean +ExtEditor::selectCandidate (guint index) +{ + switch(m_mode){ + case LABEL_LIST_NUMBERS: + //TODO: implement pinyin extension i number mode. + break; + case LABEL_LIST_COMMANDS: + { + std::string prefix = m_text.substr(1, 2); + int len = prefix.length(); + const char * prefix_str = prefix.c_str(); + const GArray * commands = ibus_engine_plugin_get_available_commands(m_lua_plugin); + int match_count = -1; + for (int i = 0; i < commands->len; ++i) { + lua_command_t * command = &g_array_index(commands, lua_command_t, i); + if ( strncmp(prefix_str, command->command_name, len) == 0 ){ + match_count++; + } + if ( match_count == index ) { + m_text.clear(); + m_text = "i"; + m_text += command->command_name; + break; + } + } + updateStateFromInput(); + update(); + } + return TRUE; + break; + case LABEL_LIST_DIGIT: + case LABEL_LIST_ALPHA: + { + g_return_val_if_fail(m_result_num > 1, FALSE); + g_return_val_if_fail(index < m_result_num, FALSE); + + const lua_command_candidate_t * candidate = g_array_index(m_candidates, lua_command_candidate_t *, index); + if ( candidate->content ){ + StaticText text(candidate->content); + commitText(text); + m_text.clear(); + } else if (candidate->suggest){ + m_text += candidate->suggest; + } + + updateStateFromInput(); + update(); + return TRUE; + } + break; + case LABEL_LIST_SINGLE: + { + g_return_val_if_fail(m_result_num == 1, FALSE); + g_return_val_if_fail(index == 0, FALSE); + if ( m_candidate->content ){ + StaticText text(m_candidate->content); + commitText(text); + m_text.clear(); + } else if (m_candidate->suggest){ + m_text += m_candidate->suggest; + } + + updateStateFromInput(); + update(); + return TRUE; + } + break; + } + return FALSE; +} + +bool +ExtEditor::updateStateFromInput() +{ + /* Do parse and candidates update here. */ + /* prefix i double check here. */ + if ( !m_text.length() ) { + m_preedit_text = ""; + m_auxiliary_text = ""; + clearLookupTable(); + return false; + } + if ( ! 'i' == m_text[0] ){ + g_warning("i is expected in m_input string.\n"); + return false; + } + + m_auxiliary_text = "i"; + + m_mode = LABEL_LIST_COMMANDS; + if ( 1 == m_text.length() ){ + fillCommandCandidates(); + return true; + } + /* Check m_text len, and update auxiliary string meanwhile. + * 1. only "i", dispatch to fillCommandCandidates(void). + * 2. "i" with one charactor, + * dispatch to fillCommandCandidates(std::string). + * 3. "i" with two charactor or more, + * dispatch to fillCommand(std::string, const char * argument). + */ + + if ( isalpha(m_text[1])){ + m_mode = LABEL_LIST_COMMANDS; + if ( m_text.length() == 2){ + fillCommandCandidates(m_text.substr(1,1).c_str()); + + m_auxiliary_text += " "; + m_auxiliary_text += m_text.substr(1, 1); + return true; + } else if ( m_text.length() >= 3) { + std::string command_name = m_text.substr(1,2); + + m_auxiliary_text += " "; + m_auxiliary_text += m_text.substr(1,2); + + const lua_command_t * command = ibus_engine_plugin_lookup_command(m_lua_plugin, command_name.c_str()); + if ( NULL == command) { + m_mode = LABEL_NONE; + clearLookupTable(); + m_lookup_table.clear(); + return false; + } + + std::string label = command->leading; + + if ( "digit" == label ) + m_mode = LABEL_LIST_DIGIT; + else if ( "alpha" == label ) + m_mode = LABEL_LIST_ALPHA; + else + m_mode = LABEL_LIST_NONE; + + const char * argment = NULL; + std::string arg = ""; + if (m_text.length() > 3) { + arg = m_text.substr(3); + argment = arg.c_str(); + m_auxiliary_text += " "; + m_auxiliary_text += argment; + } + + fillCommand(command_name, argment); + } + } + else if ( isdigit(m_text[1]) ){ + m_mode = LABEL_LIST_NUMBERS; + //Generate Chinese number. + //fillChineseNumber(). (Label use digit.) + } + + return true; +} + +bool +ExtEditor::fillCommandCandidates() +{ + return fillCommandCandidates(""); +} + +bool +ExtEditor::fillCommandCandidates(std::string prefix) +{ + clearLookupTable(); + + /* fill candidates here. */ + int len = prefix.length(); + const char * prefix_str = prefix.c_str(); + const GArray * commands = ibus_engine_plugin_get_available_commands(m_lua_plugin); + for ( int i = 0; i < commands->len; ++i){ + lua_command_t * command = &g_array_index(commands, lua_command_t, i); + if ( strncmp(prefix_str, command->command_name, len) == 0){ + std::string candidate = command->command_name; + candidate += "."; + candidate += command->description; + m_lookup_table.appendLabel(Text("")); + m_lookup_table.appendCandidate(Text(candidate)); + } + } + + return true; +} + +bool +ExtEditor::fillCommand(std::string command_name, const char * argument){ + const lua_command_t * command = ibus_engine_plugin_lookup_command(m_lua_plugin, command_name.c_str()); + if ( NULL == command ) + return false; + + if ( m_result_num != 0) { + if ( m_result_num == 1) { + ibus_engine_plugin_free_candidate((lua_command_candidate_t *)m_candidate); + m_candidate = NULL; + }else{ + for ( int i = 0; i < m_result_num; ++i){ + const lua_command_candidate_t * candidate = g_array_index(m_candidates, lua_command_candidate_t *, i); + ibus_engine_plugin_free_candidate((lua_command_candidate_t *)candidate); + } + + g_array_free(m_candidates, TRUE); + m_candidates = NULL; + } + m_result_num = 0; + g_assert(m_candidates == NULL && m_candidate == NULL); + } + + m_result_num = ibus_engine_plugin_call(m_lua_plugin, command->lua_function_name, argument); + + if ( 1 == m_result_num ) + m_mode = LABEL_LIST_SINGLE; + + clearLookupTable(); + + //Generate labels according to m_mode + if ( LABEL_LIST_DIGIT == m_mode ) { + //skip codes, as this is the default behavior of lookup table. + } + + if ( LABEL_LIST_ALPHA == m_mode) { + for ( int i = 1; i <= 10; ++i ) + m_lookup_table.appendLabel( Text(i - 1 + 'a') ); + } + + if ( LABEL_LIST_NONE == m_mode || LABEL_LIST_SINGLE == m_mode) { + for ( int i = 1; i <= 10; ++i) + m_lookup_table.appendLabel(Text("")); + } + + //Generate candidates + std::string result; + if ( 1 == m_result_num ){ + m_candidate = ibus_engine_plugin_get_retval(m_lua_plugin); + result = ""; + if ( m_candidate->content ){ + result = m_candidate->content; + if (strstr(result.c_str(), "\n")) + result = _("(Character Chart)"); + } + if ( m_candidate->suggest && m_candidate-> help ){ + result += m_candidate->suggest; + result += " "; + result += "["; + result += m_candidate->help; + result += "]"; + } + + m_lookup_table.appendCandidate(Text(result)); + }else if (m_result_num > 1){ + m_candidates = ibus_engine_plugin_get_retvals(m_lua_plugin); + for ( int i = 0; i < m_result_num; ++i){ + const lua_command_candidate_t * candidate = g_array_index(m_candidates, lua_command_candidate_t *, i); + result = ""; + if ( candidate->content ){ + result = candidate->content; + if (strstr(result.c_str(), "\n")) + result = _("(Character Chart)"); + } + if ( candidate->suggest && candidate-> help ){ + result += candidate->suggest; + result += " "; + result += "["; + result += candidate->help; + result += "]"; + } + + m_lookup_table.appendCandidate(Text(result)); + } + } + + return true; +} + + +void +ExtEditor::clearLookupTable() +{ + m_lookup_table.clear (); + m_lookup_table.setPageSize (Config::pageSize ()); + m_lookup_table.setOrientation (Config::orientation ()); +} + +void +ExtEditor::updateLookupTable() +{ + if (m_lookup_table.size ()) { + Editor::updateLookupTable (m_lookup_table, TRUE); + } + else { + hideLookupTable (); + } +} + +void +ExtEditor::updatePreeditText(){ + if( G_UNLIKELY(m_preedit_text.empty()) ){ + hidePreeditText (); + return; + } + + StaticText preedit_text(m_preedit_text); + Editor::updatePreeditText(preedit_text, m_cursor, TRUE); +} + +void +ExtEditor::updateAuxiliaryText(){ + if( G_UNLIKELY(m_auxiliary_text.empty()) ){ + hideAuxiliaryText (); + return; + } + + StaticText aux_text (m_auxiliary_text); + Editor::updateAuxiliaryText (aux_text, TRUE); +} + + }; diff --git a/src/ExtEditor.h b/src/ExtEditor.h index 262c1c7..36125d8 100644 --- a/src/ExtEditor.h +++ b/src/ExtEditor.h @@ -21,10 +21,29 @@ #ifndef __PY_EXT_EDITOR_ #define __PY_EXT_EDITOR_ +#include <glib.h> +extern "C" { +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +#include "lua-plugin.h" +} +#include <string> #include "Editor.h" namespace PY { +enum ExtEditorLabelMode{ + LABEL_NONE, + LABEL_LIST_NUMBERS, + LABEL_LIST_COMMANDS, + LABEL_LIST_NONE, + LABEL_LIST_DIGIT, + LABEL_LIST_ALPHA, + LABEL_LIST_SINGLE, + LABEL_LAST, +}; + class ExtEditor : public Editor { public: ExtEditor (PinyinProperties & props, Config & config); @@ -38,7 +57,47 @@ public: virtual void reset (void); virtual void candidateClicked (guint index, guint button, guint state); + int loadLuaScript(std::string filename); + void resetLuaState(); + private: + bool updateStateFromInput(); + + /* Fill lookup table, and update preedit string. */ + bool fillCommandCandidates(); + bool fillCommandCandidates(std::string prefix); + bool fillCommand(std::string command_name, const char * argument); + + /* Auxiliary functions for lookup table */ + void clearLookupTable(); + void updateLookupTable(); + gboolean selectCandidateInPage (guint index); + gboolean selectCandidate (guint index); + + void updatePreeditText(); + void updateAuxiliaryText(); + + gboolean processEditKey(guint keyval); + gboolean processPageKey(guint keyval); + gboolean processLabelKey(guint keyval); + + gboolean processSpace(guint keyval); + + gboolean removeCharBefore(); + gboolean removeCharAfter(); + + ExtEditorLabelMode m_mode; + Pointer<IBusEnginePlugin> m_lua_plugin; + + std::string m_preedit_text; + std::string m_auxiliary_text; + + LookupTable m_lookup_table; + + //saved lua extension call results. + int m_result_num; + const lua_command_candidate_t * m_candidate; + GArray * m_candidates; }; }; diff --git a/src/LookupTable.h b/src/LookupTable.h index d43cce6..eb2a041 100644 --- a/src/LookupTable.h +++ b/src/LookupTable.h @@ -51,13 +51,14 @@ public: void clear (void) { ibus_lookup_table_clear (*this); } void setCursorVisable (gboolean visable){ ibus_lookup_table_set_cursor_visible (*this, visable); } void setLabel (guint index, IBusText *text) { ibus_lookup_table_set_label (*this, index, text); } - void appendCandidate (IBusText *text) { ibus_lookup_table_append_candidate (*this, text); } + void appendLabel (IBusText *text) { ibus_lookup_table_append_label (*this, text); } operator IBusLookupTable * (void) const { return get<IBusLookupTable> (); } + }; }; diff --git a/src/Makefile.am b/src/Makefile.am index d7373dd..5997c8d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,11 +121,15 @@ ibus_engine_pinyin_CXXFLAGS = \ -DGETTEXT_PACKAGE=\"@GETTEXT_PACKAGE@\" \ -DPKGDATADIR=\"$(pkgdatadir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ + -I../lua/ \ $(NULL) + ibus_engine_pinyin_LDADD = \ @IBUS_LIBS@ \ @SQLITE_LIBS@ \ @OPENCC_LIBS@ \ + -L../lua/ \ + -lpylua \ $(NULL) if HAVE_LIBUUID diff --git a/src/PinyinEngine.cc b/src/PinyinEngine.cc index e70b46f..46f05a6 100644 --- a/src/PinyinEngine.cc +++ b/src/PinyinEngine.cc @@ -99,11 +99,9 @@ PinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers) case IBUS_grave: m_input_mode = MODE_PUNCT; break; - #if 0 case IBUS_i: m_input_mode = MODE_EXTENSION; break; - #endif } } else { |