diff --git a/CMakeLists.txt b/CMakeLists.txt index 11474fc..1a13de0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.12) -project(libime VERSION 1.1.12) +project(libime VERSION 1.1.13) set(LibIME_VERSION ${PROJECT_VERSION}) set(REQUIRED_FCITX_VERSION 5.1.13) diff --git a/src/libime/core/lattice.h b/src/libime/core/lattice.h index 8dc5971..5306995 100644 --- a/src/libime/core/lattice.h +++ b/src/libime/core/lattice.h @@ -68,9 +68,9 @@ class LIBIMECORE_EXPORT WordNode { virtual ~WordNode() = default; WordNode(WordNode &&other) noexcept( - std::is_nothrow_move_constructible::value); + std::is_nothrow_move_constructible_v); WordNode &operator=(WordNode &&other) noexcept( - std::is_nothrow_move_assignable::value); + std::is_nothrow_move_assignable_v); const std::string &word() const { return word_; } WordIndex idx() const { return idx_; } diff --git a/src/libime/pinyin/pinyincontext.cpp b/src/libime/pinyin/pinyincontext.cpp index c53923e..edc9d3c 100644 --- a/src/libime/pinyin/pinyincontext.cpp +++ b/src/libime/pinyin/pinyincontext.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ class PinyinContextPrivate : public fcitx::QPtrHolder { mutable std::vector candidatesToCursor_; mutable std::unordered_set candidatesToCursorSet_; std::vector conn_; + std::vector contextWords_; size_t alignCursorToNextSegment() const { FCITX_Q(); @@ -526,16 +528,19 @@ State PinyinContext::state() const { FCITX_D(); auto *model = d->ime_->model(); State state = model->nullState(); - if (!d->selected_.empty()) { - for (const auto &s : d->selected_) { - for (const auto &item : s) { - if (item.word_.word().empty()) { - continue; - } - State temp; - model->score(state, item.word_, temp); - state = std::move(temp); + for (const auto &word : d->contextWords_) { + State temp; + model->score(state, word, temp); + state = std::move(temp); + } + for (const auto &s : d->selected_) { + for (const auto &item : s) { + if (item.word_.word().empty()) { + continue; } + State temp; + model->score(state, item.word_, temp); + state = std::move(temp); } } return state; @@ -552,21 +557,9 @@ void PinyinContext::update() { d->clearCandidates(); } else { size_t start = 0; - auto *model = d->ime_->model(); - State state = model->nullState(); + State state = this->state(); if (!d->selected_.empty()) { start = d->selected_.back().back().offset_; - - for (auto &s : d->selected_) { - for (auto &item : s) { - if (item.word_.word().empty()) { - continue; - } - State temp; - model->score(state, item.word_, temp); - state = std::move(temp); - } - } } SegmentGraph newGraph; if (auto spProfile = d->matchState_.shuangpinProfile()) { @@ -991,6 +984,16 @@ void PinyinContext::learn() { } } +void PinyinContext::setContextWords( + const std::vector &contextWords) { + FCITX_D(); + d->contextWords_.clear(); + for (const auto &word : contextWords) { + d->contextWords_.push_back( + WordNode(word, d->ime_->model()->index(word))); + } +} + bool PinyinContext::learnWord() { return false; } PinyinIME *PinyinContext::ime() const { diff --git a/src/libime/pinyin/pinyincontext.h b/src/libime/pinyin/pinyincontext.h index 2da6612..fec543a 100644 --- a/src/libime/pinyin/pinyincontext.h +++ b/src/libime/pinyin/pinyincontext.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -136,6 +137,13 @@ class LIBIMEPINYIN_EXPORT PinyinContext : public InputBuffer { /// Opaque language model state. State state() const; + /** + * Set context words for better prediction. + * @param contextWords The context words. + * @since 1.1.13 + */ + void setContextWords(const std::vector &contextWords); + protected: bool typeImpl(const char *s, size_t length) override; diff --git a/test/testpinyincontext.cpp b/test/testpinyincontext.cpp index 2d444f0..ed63cf3 100644 --- a/test/testpinyincontext.cpp +++ b/test/testpinyincontext.cpp @@ -246,5 +246,34 @@ int main() { FCITX_ASSERT(c.selectedWordsWithPinyin().size() == 1); } + // Check that context words can change prediction. + { + { + c.clear(); + c.type("ta"); + size_t i = 0; + for (const auto &candidate : c.candidatesToCursor()) { + if (candidate.toString() == "她") { + break; + } + i++; + } + FCITX_ASSERT(i > 0) << i; + } + { + c.clear(); + c.setContextWords({"他", "爱"}); + c.type("ta"); + size_t i = 0; + for (const auto &candidate : c.candidatesToCursor()) { + if (candidate.toString() == "她") { + break; + } + i++; + } + FCITX_ASSERT(i == 0) << i; + } + } + return 0; }