From a2c9412461f68a5293cec24609076951e28a3b27 Mon Sep 17 00:00:00 2001 From: Anoop <46913894+anoopmsivadas@users.noreply.github.com> Date: Tue, 9 Jul 2024 20:34:51 +0530 Subject: [PATCH] Enhancements and minor bug fixes (#8) * Enhancements and minor bug fixes * Closes #4. * Closes #7. * Handled word break characters properly. * Added basic meson workflow. * Use Ubuntu:22.04. --- .github/workflows/meson_cpp.yml | 55 ++++ .gitignore | 7 +- README.md | 14 +- ...t.Fcitx5.Addon.varnamfcitx.metainfo.xml.in | 19 ++ meson.build | 27 +- meson.options | 3 +- src/meson.build | 8 +- src/varnam_candidate.cpp | 14 +- src/varnam_config.h | 20 +- src/varnam_engine.cpp | 14 +- src/varnam_state.cpp | 294 ++++++++++-------- src/varnam_state.h | 13 +- src/varnamfcitx-addon.conf | 9 - src/varnamfcitx-addon.conf.in | 4 +- 14 files changed, 317 insertions(+), 184 deletions(-) create mode 100644 .github/workflows/meson_cpp.yml create mode 100644 com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml.in delete mode 100644 src/varnamfcitx-addon.conf diff --git a/.github/workflows/meson_cpp.yml b/.github/workflows/meson_cpp.yml new file mode 100644 index 0000000..82d28a4 --- /dev/null +++ b/.github/workflows/meson_cpp.yml @@ -0,0 +1,55 @@ +name: Meson Build and Test +on: + push: + branches: [main] + paths: + - "**.cpp" + - "**.h" + - "**.build" + pull_request: + branches: [main] + paths: + - "**.cpp" + - "**.h" + - "**.build" + +jobs: + build: + name: Build and Test on ${{ matrix.os }} with Meson v${{ matrix.meson_version }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04] + meson_version: ["1.4.1"] + steps: + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.16 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install Fcitx5 dev packages + run: sudo apt install -y fcitx5-modules-dev + - name: Build and install Varnam + run: | + cd ../ + git clone https://github.com/varnamproject/govarnam.git govarnam + cd govarnam + make + sudo make install + - name: Install Meson + run: python -m pip install meson==${{ matrix.meson_version }} ninja + - name: Checkout code + uses: actions/checkout@v4 + - name: Configure Project + run: meson setup builddir/ + env: + CC: g++ + - name: Run Build + run: | + cd builddir + meson compile + - name: Run Tests + run: meson test -C builddir/ -v \ No newline at end of file diff --git a/.gitignore b/.gitignore index 08c50f7..9e867ff 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,12 @@ builddir/ *.o *.a +**/varnamfcitx-addon.conf **/CMakeLists.txt **/CMakeCache.txt CMakeFiles/ -meson_options.txt \ No newline at end of file +meson_options.txt + +compile_commands.json +.cache/ +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index b42a7b6..3e2d968 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,12 @@ A wrapper to add Varnam Input Method Engine support in Fcitx5 Input Method. Install `fcitx5-modules-dev` if you're building it on a debian based distribution. -## Build & Install +## Installation + +### Build & Install + +> [!IMPORTANT] +> Please Uninstall the older version first, to avoid conflicts. ```bash git clone https://github.com/varnamproject/varnam-fcitx5.git @@ -43,12 +48,17 @@ If meson version is less than `1.1` run the following command before `meson setu mv meson.options meson_options.txt ``` -## Uninstall + +### Uninstall ``` cd buildir sudo ninja uninstall ``` +--- + +[![Packaging status](https://repology.org/badge/vertical-allrepos/varnam-fcitx5.svg)](https://repology.org/project/varnam-fcitx5/versions) +* Thank you [@mohammedbilalns](https://github.com/mohammedbilalns) for the Arch Linux Package([AUR](https://aur.archlinux.org/packages/varnam-fcitx5-git)) ## Configuration Varnam Fcitx can be configured using `fcitx5-configtool`. Please refer the [official documentation](https://fcitx-im.org/wiki/Configtool_(Fcitx_5)). diff --git a/com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml.in b/com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml.in new file mode 100644 index 0000000..be3d048 --- /dev/null +++ b/com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml.in @@ -0,0 +1,19 @@ + + + com.varnamproject.Fcitx5.Addon.varnamfcitx + org.fcitx.Fcitx5 + CC0-1.0 + GPL-3.0+ + Varnam Fcitx5 + Varnam Engine for Fcitx5 + + The Varnam Project + + https://varnamproject.com/ + https://github.com/varnamproject/varnam-fcitx5/issues + https://github.com/varnamproject/varnam-fcitx5 + Fcitx + + + + \ No newline at end of file diff --git a/meson.build b/meson.build index 0f81489..1a2ef28 100644 --- a/meson.build +++ b/meson.build @@ -28,19 +28,30 @@ else lib_dir = get_option('libdir') endif -if (fs.exists('/usr/local/share/fcitx5/inputmethod')) - data_dir = '/usr/local/share' -elif (fs.exists('/usr/share/fcitx5/inputmethod')) - data_dir = '/usr/share/' -else - data_dir = get_option('datadir') -endif +data_dir = get_option('datadir') if get_option('varnam_debug') add_global_arguments('-DDEBUG_MODE', language: 'cpp') endif +config_data = configuration_data() +if (get_option('version') != '') + config_data.set('version', get_option('version')) +elif (run_command('git', 'describe', check: false).stdout().strip() == '') + config_data.set('version', meson.project_version()) +else + git_tag = run_command('git', 'describe', '--always', '--dirty', check: false).stdout().strip() + config_data.set('version', git_tag.strip('v')) +endif + # source subdir('src') # icons -subdir('icons') \ No newline at end of file +subdir('icons') + +# install AppStream Metadata file +install_data( + 'com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml.in', + rename: 'com.varnamproject.Fcitx5.Addon.varnamfcitx.metainfo.xml', + install_dir: data_dir + '/metainfo', +) \ No newline at end of file diff --git a/meson.options b/meson.options index 7f46fa4..507eafe 100644 --- a/meson.options +++ b/meson.options @@ -1 +1,2 @@ -option('varnam_debug', type: 'boolean', value: false) \ No newline at end of file +option('varnam_debug', type: 'boolean', value: false) +option('version', type: 'string', value: '') \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index bc1e683..db60f47 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,7 +12,6 @@ shared_library( dependencies: [fcitx5_core_dep, fcitx5_module_dep, varnam_dep], install: true, install_dir: lib_dir + '/fcitx5', - name_prefix: '', ) # Input Method registration file @@ -22,8 +21,9 @@ install_data( ) # Addon config file -install_data( - 'varnamfcitx-addon.conf.in', - rename: 'varnamfcitx.conf', +configure_file( + configuration: config_data, + input: 'varnamfcitx-addon.conf.in', + output: 'varnamfcitx.conf', install_dir: data_dir + '/fcitx5/addon', ) \ No newline at end of file diff --git a/src/varnam_candidate.cpp b/src/varnam_candidate.cpp index a20e555..a8f7ddb 100644 --- a/src/varnam_candidate.cpp +++ b/src/varnam_candidate.cpp @@ -1,5 +1,4 @@ #include "varnam_candidate.h" -#include "varnam_utils.h" #include "varnam_config.h" #include "varnam_state.h" @@ -20,12 +19,15 @@ VarnamCandidateList::VarnamCandidateList(VarnamEngine *engine, InputContext *ic) : engine_(engine), ic_(ic) { const VarnamEngineConfig *config = static_cast(engine_->getConfig()); + CandidateLayoutHint layout; if (!config) { VARNAM_WARN() << "Invalid configuration"; - throw std::runtime_error("invalid config"); + layout = CandidateLayoutHint::Vertical; + } else { + layout = config->candidateLayout.value(); } setPageable(this); - setLayoutHint(config->candidateLayout.value()); + setLayoutHint(layout); } void VarnamCandidateList::prev() { @@ -55,8 +57,9 @@ void VarnamCandidateList::prevCandidate() { if (index >= pageSize() && (currentPage() > 0)) { setPage(currentPage()); } - state->selectCandidate(cursorIndex()); setGlobalCursorIndex(index); + state->selectCandidate(cursorIndex()); + ic_->updateUserInterface(UserInterfaceComponent::InputPanel); } void VarnamCandidateList::nextCandidate() { @@ -66,8 +69,9 @@ void VarnamCandidateList::nextCandidate() { if (index >= pageSize() && (currentPage() < totalPages())) { setPage(currentPage()); } - state->selectCandidate(cursorIndex()); setGlobalCursorIndex(index); + state->selectCandidate(cursorIndex()); + ic_->updateUserInterface(UserInterfaceComponent::InputPanel); } } // namespace fcitx \ No newline at end of file diff --git a/src/varnam_config.h b/src/varnam_config.h index eb59d53..b8a903d 100644 --- a/src/varnam_config.h +++ b/src/varnam_config.h @@ -29,14 +29,13 @@ FCITX_CONFIGURATION( IntConstrain(3, 10)}; // Enable Learning Words on commit - Option shouldLearnWords{this, "Learn Words", - _("Enable Learning New Words"), true}; - + Option shouldLearnWords{this, "Learn Words", _("Learn New Words"), + true}; // Strictly Follow Schema Option strictlyFollowScheme{ this, "Strictly Follow Scheme", _("Strictly Follow Scheme For Dictionary Results"), false}; - + // Dictionary Suggestions Limit Option dictionarySuggestionsLimit{ this, "Dictionary Suggestions Limit", _("Dictionary Suggestions Limit"), @@ -57,7 +56,7 @@ FCITX_CONFIGURATION( this, "PrevCandidate", _("Previous Candidate"), - {Key("Alt+Up")}, + {Key("Up")}, KeyListConstrain(KeyConstrainFlag::AllowModifierLess)}; // Next Candidate Shortcut @@ -65,7 +64,7 @@ FCITX_CONFIGURATION( this, "NextCandidate", _("Next Candidate"), - {Key("Alt+Down")}, + {Key("Down")}, KeyListConstrain(KeyConstrainFlag::AllowModifierLess)}; // Previous Page @@ -73,17 +72,16 @@ FCITX_CONFIGURATION( this, "PrevPage", _("Previous Page"), - {Key("Alt+Left")}, - KeyListConstrain(KeyConstrainFlag::AllowModifierLess)}; + {Key("Alt+Up")}, + KeyListConstrain(KeyConstrainFlag::AllowModifierOnly)}; // Next Page KeyListOption nextPage{ this, "NextPage", _("Next Page"), - {Key("Alt+Right")}, - KeyListConstrain(KeyConstrainFlag::AllowModifierLess)}; -); + {Key("Alt+Down")}, + KeyListConstrain(KeyConstrainFlag::AllowModifierOnly)};); } // namespace fcitx #endif \ No newline at end of file diff --git a/src/varnam_engine.cpp b/src/varnam_engine.cpp index 16b387b..f0110cb 100644 --- a/src/varnam_engine.cpp +++ b/src/varnam_engine.cpp @@ -4,6 +4,7 @@ #include #include +#include extern "C" { #include @@ -14,7 +15,6 @@ namespace fcitx { VarnamEngine::VarnamEngine(Instance *instance) : instance_(instance), factory_([this](InputContext &ic) { return new VarnamState(this, ic); }) { - reloadConfig(); instance->inputContextManager().registerProperty("varnamState", &factory_); } @@ -30,6 +30,8 @@ VarnamEngine::~VarnamEngine() { void VarnamEngine::activate(const InputMethodEntry &entry, InputContextEvent &contextEvent) { + FCITX_UNUSED(contextEvent); + reloadConfig(); #ifdef DEBUG_MODE VARNAM_INFO() << "activate scheme:" << entry.uniqueName(); #endif @@ -39,7 +41,7 @@ void VarnamEngine::activate(const InputMethodEntry &entry, VARNAM_WARN() << "Failed to initialize Varnam"; throw std::runtime_error("failed to initialize varnam"); } - + varnam_config(varnam_handle, VARNAM_CONFIG_SET_DICTIONARY_MATCH_EXACT, config_.strictlyFollowScheme.value()); varnam_config(varnam_handle, VARNAM_CONFIG_SET_DICTIONARY_SUGGESTIONS_LIMIT, @@ -59,7 +61,7 @@ void VarnamEngine::deactivate(const InputMethodEntry &entry, if (event.type() == EventType::InputContextSwitchInputMethod) { auto ic = event.inputContext(); auto state = ic->propertyFor(&factory_); - state->commitPreedit(); + state->commitText(); state->updateUI(); } reset(entry, event); @@ -117,11 +119,9 @@ void VarnamEngine::reset(const InputMethodEntry &entry, InputContextEvent &event) { FCITX_UNUSED(entry); auto ic = event.inputContext(); - auto state = event.inputContext()->propertyFor(&factory_); + auto state = ic->propertyFor(&factory_); state->reset(); - ic->inputPanel().reset(); - ic->updatePreedit(); - ic->updateUserInterface(UserInterfaceComponent::InputPanel); + state->updateUI(); } void VarnamEngine::setConfig(const RawConfig &config) { diff --git a/src/varnam_state.cpp b/src/varnam_state.cpp index c8c15be..1034e7b 100644 --- a/src/varnam_state.cpp +++ b/src/varnam_state.cpp @@ -3,13 +3,15 @@ #include "varnam_engine.h" #include "varnam_utils.h" -#include +#include #include +#include #include #include #include #include +#include #include #include #include @@ -17,11 +19,11 @@ namespace fcitx { VarnamState::VarnamState(VarnamEngine *engine, InputContext &ic) - : engine_(engine), ic_(&ic) { + : ic_(&ic), engine_(engine) { result_ = nullptr; - cursor = 0; - bufferPos = 0; - utfCharPos = 0; + cursor = std::numeric_limits::max(); + candidateSelected = 0; + lastTypedCharIsDigit = false; } VarnamState::~VarnamState() { @@ -41,8 +43,8 @@ std::string VarnamState::bufferToString() { } void VarnamState::updatePreeditCursor() { - if (preedit_.textLength() < cursor) { - return; + if (cursor > preedit_.textLength()) { + cursor = preedit_.textLength(); } preedit_.setCursor(cursor); if (ic_->capabilityFlags().test(CapabilityFlag::Preedit)) { @@ -83,16 +85,13 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { } // handle candidate selection through index key - if (!buffer_.empty() && key.isDigit()) { - if (auto candidateList = ic_->inputPanel().candidateList(); - candidateList && candidateList->size()) { - auto idx = key.keyListIndex(selectionKeys); - if (idx >= 0 && idx < candidateList->size()) { - selectCandidate(idx); - } - keyEvent.filterAndAccept(); - return; - } + if (!buffer_.empty() && key.isDigit() && !lastTypedCharIsDigit) { + auto idx = key.keyListIndex(selectionKeys); + selectCandidate(idx); + commitText(key.sym()); + updateUI(); + keyEvent.filterAndAccept(); + return; } if (key.states().test(KeyState::Ctrl)) { @@ -101,18 +100,23 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { return; } if (key.sym() == FcitxKey_Delete) { - if (preedit_.empty()) { + auto candidates = ic_->inputPanel().candidateList(); + std::string wordToUnlearn( + candidates->candidate(candidateSelected) + .text() + .toStringForCommit()); // TODO try unique_ptr + if (wordToUnlearn.empty()) { keyEvent.filter(); return; } #ifdef DEBUG_MODE - VARNAM_INFO() << "unlearn word:" << preedit_.toString(); + VARNAM_INFO() << "unlearn word:" << wordToUnlearn; #endif - std::string wordToUnlearn( - preedit_.toStringForCommit()); // [TODO] try unique_ptr std::thread unlearnThread(varnam_unlearn_word, engine_->getVarnamHandle(), std::move(wordToUnlearn)); unlearnThread.detach(); + reset(); + updateUI(); keyEvent.filterAndAccept(); return; } @@ -120,27 +124,47 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { return; } if (key.checkKeyList(engine_->getConfig()->nextCandidate.value())) { + if (buffer_.empty()) { + keyEvent.filter(); + return; + } updateLookupTable(NEXT_CANDIDATE); keyEvent.filterAndAccept(); return; } if (key.checkKeyList(engine_->getConfig()->prevCandidate.value())) { + if (buffer_.empty()) { + keyEvent.filter(); + return; + } updateLookupTable(PREV_CANDIDATE); keyEvent.filterAndAccept(); return; } if (key.checkKeyList(engine_->getConfig()->nextPage.value())) { + if (buffer_.empty()) { + keyEvent.filter(); + return; + } updateLookupTable(NEXT_PAGE); keyEvent.filterAndAccept(); return; } if (key.checkKeyList(engine_->getConfig()->prevPage.value())) { + if (buffer_.empty()) { + keyEvent.filter(); + return; + } updateLookupTable(PREV_PAGE); keyEvent.filterAndAccept(); return; } + auto iterator = buffer_.begin(); + iterator += cursor; + switch (key.sym()) { + case FcitxKey_Escape: case FcitxKey_space: case FcitxKey_Tab: case FcitxKey_Return: @@ -148,59 +172,28 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { keyEvent.filter(); return; } - commitPreedit(key.sym()); - updateUI(); - keyEvent.filterAndAccept(); - return; - case FcitxKey_Escape: - commitPreedit(); + commitText(key.sym()); updateUI(); keyEvent.filterAndAccept(); return; - case FcitxKey_Left: // [TODO] move cursor left + case FcitxKey_Left: if (preedit_.empty()) { keyEvent.filter(); return; } if (cursor > 0) { - unsigned int offset = getNumOfUTFCharUnits(u32_preedit[utfCharPos]); - if (cursor >= offset) { - cursor -= offset; - } - if (bufferPos > 0) { - --bufferPos; - } - if (utfCharPos > 0) { - --utfCharPos; - } -#ifdef DEBUG_MODE - VARNAM_INFO() << "[left] cursor at:" << cursor - << " buffer pos:" << bufferPos - << " preedit cursor: " << utfCharPos; -#endif + --cursor; } updatePreeditCursor(); keyEvent.filterAndAccept(); return; - case FcitxKey_Right: //[TODO] move cursor right + case FcitxKey_Right: if (preedit_.empty()) { keyEvent.filter(); return; } - if (bufferPos < (buffer_.size() - 1)) { - ++bufferPos; - } - if (utfCharPos < (u32_preedit.size() - 1)) { - ++utfCharPos; - } - if (cursor < preedit_.textLength()) { - - cursor += getNumOfUTFCharUnits(u32_preedit[utfCharPos]); -#ifdef DEBUG_MODE - VARNAM_INFO() << "[right] cursor at:" << cursor - << " buffer pos:" << bufferPos - << " preedit cursor: " << utfCharPos; -#endif + if (cursor < (buffer_.size())) { + ++cursor; } updatePreeditCursor(); keyEvent.filterAndAccept(); @@ -214,28 +207,59 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { keyEvent.filter(); return; } - // [TODO] use cursor position to remove elements - buffer_.pop_back(); + if (cursor > 0) { + buffer_.erase(--iterator); + --cursor; + } getVarnamResult(); updateUI(); keyEvent.filterAndAccept(); return; case FcitxKey_Delete: - keyEvent.filter(); + if (buffer_.empty()) { + keyEvent.filter(); + return; + } + if (cursor < buffer_.size()) { + buffer_.erase(iterator); + } + getVarnamResult(); + updateUI(); + keyEvent.filterAndAccept(); return; case FcitxKey_Home: - keyEvent.filter(); + if (buffer_.empty()) { + keyEvent.filter(); + return; + } + cursor = 0; + updatePreeditCursor(); + keyEvent.filterAndAccept(); return; case FcitxKey_End: - keyEvent.filter(); + if (buffer_.empty()) { + keyEvent.filter(); + return; + } + cursor = preedit_.textLength(); + updatePreeditCursor(); + keyEvent.filterAndAccept(); return; default: break; } - if (result_) { - varray_clear(result_); + + if (key.isDigit()) { + lastTypedCharIsDigit = true; } else { - result_ = varray_init(); + lastTypedCharIsDigit = false; + } + + if (isWordBreak(keyEvent.key().sym())) { + commitText(keyEvent.key().sym()); + updateUI(); + keyEvent.filterAndAccept(); + return; } if (key.sym() > 0x80) { @@ -246,22 +270,23 @@ void VarnamState::processKeyEvent(KeyEvent &keyEvent) { unsigned char input = *(keyEvent.key().toString(KeyStringFormat::Localized).c_str()); #ifdef DEBUG_MODE - VARNAM_INFO() << "cursor at:" << cursor << " buffer pos:" << bufferPos - << " buf size:" << buffer_.size(); + VARNAM_INFO() << "cursor at:" << cursor; #endif - auto iterator = buffer_.begin(); - iterator += bufferPos; - if (bufferPos >= buffer_.size()) { + if (cursor >= buffer_.size()) { buffer_.push_back(input); - ++bufferPos; + cursor = buffer_.size(); } else { buffer_.insert(iterator, input); - ++bufferPos; + ++cursor; } - getVarnamResult(); - if (isWordBreak(keyEvent.key().sym())) { - commitPreedit(keyEvent.key().sym()); + + if (result_) { + varray_clear(result_); + } else { + result_ = varray_init(); } + + getVarnamResult(); updateUI(); keyEvent.filterAndAccept(); } @@ -270,21 +295,33 @@ void VarnamState::setLookupTable() { if (!result_) { return; } - auto candidates_p = std::make_unique(engine_, ic_); - candidates_p->setSelectionKey(selectionKeys); - candidates_p->setCursorPositionAfterPaging( + auto candidates = std::make_unique(engine_, ic_); + candidates->setSelectionKey(selectionKeys); + candidates->setCursorPositionAfterPaging( CursorPositionAfterPaging::ResetToFirst); - candidates_p->setPageSize(engine_->getConfig()->pageSize.value()); + candidates->setPageSize(engine_->getConfig()->pageSize.value()); + int count = varray_length(result_); + char preeditAppended = 0; for (int i = 0; i < count; i++) { + if ((candidates->pageSize() == 10) && + ((i + (preeditAppended ? (1 + preeditAppended) : 1)) % 10 == 0)) { + // TODO ;} + candidates->append(engine_, + preedit_.toString().c_str(), i); + ++preeditAppended; + } vword *word = static_cast(varray_get(result_, i)); - candidates_p->append(engine_, word->text, i); + candidates->append(engine_, word->text, + preeditAppended ? i + 1 : i); + } + if (!preeditAppended) { + candidates->append( + engine_, preedit_.toString().c_str(), ++count); } - std::string userInput = bufferToString(); - candidates_p->append(engine_, userInput.c_str(), count); if (count) { - candidates_p->setGlobalCursorIndex(0); - ic_->inputPanel().setCandidateList(std::move(candidates_p)); + candidates->setGlobalCursorIndex(0); + ic_->inputPanel().setCandidateList(std::move(candidates)); } } @@ -320,35 +357,35 @@ void VarnamState::selectCandidate(int index) { if (!candidateList_ || candidateList_->size() <= index) { return; } - const Text *candidate_ = &candidateList_->candidate(index).text(); - if (candidate_ == nullptr || candidate_->empty()) { - return; - } - preedit_.clear(); - preedit_.append(candidate_->toString(), TextFormatFlag::HighLight); - preedit_.setCursor(preedit_.textLength()); - if (ic_->capabilityFlags().test(CapabilityFlag::Preedit)) { - ic_->inputPanel().setClientPreedit(preedit_); + if (index == 9) { + candidateSelected = 0; } else { - ic_->inputPanel().setPreedit(preedit_); + if (candidateList_->size() <= index) { + return; + } + candidateSelected = index; } - ic_->updatePreedit(); - ic_->updateUserInterface(UserInterfaceComponent::InputPanel); } -void VarnamState::commitPreedit(const FcitxKeySym &key) { +void VarnamState::commitText(const FcitxKeySym &key) { + auto candidates = ic_->inputPanel().candidateList(); std::string stringToCommit; - stringToCommit.assign(preedit_.toStringForCommit()); - if (!stringToCommit.empty() && - engine_->getConfig()->shouldLearnWords.value()) { -#ifdef DEBUG_MODE - VARNAM_INFO() << "learn word:" << preedit_.toString(); -#endif - std::string wordToLearn( - preedit_.toStringForCommit()); // [TODO] try unique_ptr - std::thread learnThread(varnam_learn_word, engine_->getVarnamHandle(), - std::move(wordToLearn), 0); - learnThread.detach(); + + if (key == FcitxKey_Escape || key == FcitxKey_0 || candidates == nullptr || + candidates->size() <= 1 || result_ == nullptr || + varray_is_empty(result_) || lastTypedCharIsDigit) { + + stringToCommit.assign(preedit_.toStringForCommit()); + candidateSelected = 0; + } else if ((candidates->cursorIndex() <= 0) && !candidateSelected) { + vword *first_result = static_cast(varray_get(result_, 0)); + if (first_result != nullptr) { + stringToCommit.assign(first_result->text); + candidateSelected = 1; + } + } else { + stringToCommit.assign( + candidates->candidate(candidateSelected).text().toStringForCommit()); } if (isWordBreak(key)) { @@ -359,11 +396,24 @@ void VarnamState::commitPreedit(const FcitxKeySym &key) { << getWordBreakChar(key); #endif ic_->commitString(stringToCommit); + + if (stringToCommit.empty() || lastTypedCharIsDigit || + ic_->capabilityFlags().test(CapabilityFlag::PasswordOrSensitive) || + !engine_->getConfig()->shouldLearnWords.value() || !candidateSelected) { + reset(); + return; + } +#ifdef DEBUG_MODE + VARNAM_INFO() << "learn word:" << stringToCommit; +#endif + std::string wordToLearn(stringToCommit); // [TODO] try unique_ptr + std::thread learnThread(varnam_learn_word, engine_->getVarnamHandle(), + std::move(wordToLearn), 0); + learnThread.detach(); reset(); } void VarnamState::updateUI() { - vword *first_res = nullptr; ic_->inputPanel().reset(); if (buffer_.empty()) { ic_->updatePreedit(); @@ -376,20 +426,12 @@ void VarnamState::updateUI() { if (varray_length(result_) == 0x00) { return; } - first_res = static_cast(varray_get(result_, 0)); - if (first_res == nullptr) { - return; - } - std::string preedit_res(first_res->text); - if (preedit_res.empty()) { - return; - } - u32_preedit.clear(); - u32_preedit.assign(utf8_converter.from_bytes(preedit_res.c_str())); - cursor = preedit_res.length(); - utfCharPos = u32_preedit.length() - 1; + preedit_.clear(); - preedit_.append(preedit_res, TextFormatFlag::HighLight); + preedit_.append(bufferToString(), TextFormatFlag::HighLight); + if (cursor > preedit_.textLength()) { + cursor = preedit_.textLength(); + } preedit_.setCursor(cursor); if (ic_->capabilityFlags().test(CapabilityFlag::Preedit)) { @@ -403,9 +445,9 @@ void VarnamState::updateUI() { } void VarnamState::reset() { - cursor = 0; - bufferPos = 0; - utfCharPos = 0; + cursor = std::numeric_limits::max(); + candidateSelected = 0; + lastTypedCharIsDigit = false; buffer_.clear(); preedit_.clear(); if (result_) { diff --git a/src/varnam_state.h b/src/varnam_state.h index ac13048..0304270 100644 --- a/src/varnam_state.h +++ b/src/varnam_state.h @@ -3,7 +3,6 @@ #include "varnam_candidate.h" -#include #include #include @@ -20,14 +19,12 @@ class VarnamState : public InputContextProperty { private: // Private Variables unsigned int cursor; - unsigned int bufferPos; - unsigned int utfCharPos; + char candidateSelected; + bool lastTypedCharIsDigit; InputContext *ic_; VarnamEngine *engine_; Text preedit_; - std::u32string u32_preedit; - std::wstring_convert, char32_t> utf8_converter; std::vector buffer_; varray *result_; @@ -51,8 +48,8 @@ class VarnamState : public InputContextProperty { // Handle KeyEvents void processKeyEvent(KeyEvent &); - // Commit Preedit to text - void commitPreedit(const FcitxKeySym &key = FcitxKey_None); + // Commit Selected Candidate to text + void commitText(const FcitxKeySym &key = FcitxKey_None); // Generate Candidate List/Lookup tables void setLookupTable(); @@ -71,4 +68,4 @@ class VarnamState : public InputContextProperty { }; } // namespace fcitx -#endif \ No newline at end of file +#endif // end of _FCITX5_VARNAM_STATE_H \ No newline at end of file diff --git a/src/varnamfcitx-addon.conf b/src/varnamfcitx-addon.conf deleted file mode 100644 index ffe7281..0000000 --- a/src/varnamfcitx-addon.conf +++ /dev/null @@ -1,9 +0,0 @@ -[Addon] -Name=Varnam -Comment=Varnam Engine for Fcitx5 -Category=InputMethod -Version=0.0.1 -Library=varnamfcitx -Type=SharedLibrary -Configurable=True -Enabled=True diff --git a/src/varnamfcitx-addon.conf.in b/src/varnamfcitx-addon.conf.in index 65a9b35..e6ae9c0 100644 --- a/src/varnamfcitx-addon.conf.in +++ b/src/varnamfcitx-addon.conf.in @@ -2,8 +2,8 @@ Name=Varnam Comment=Varnam Engine for Fcitx5 Category=InputMethod -Version=0.0.1 -Library=varnamfcitx +Version=@version@ +Library=libvarnamfcitx Type=SharedLibrary Configurable=True Enabled=True \ No newline at end of file