diff --git a/src/libime/pinyin/pinyincontext.cpp b/src/libime/pinyin/pinyincontext.cpp index bca92cc..fe00cb9 100644 --- a/src/libime/pinyin/pinyincontext.cpp +++ b/src/libime/pinyin/pinyincontext.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include namespace libime { @@ -155,6 +157,28 @@ class PinyinContextPrivate : public fcitx::QPtrHolder { q->update(); } + + void selectCustom(size_t inputLength, std::string_view segment) { + FCITX_Q(); + auto offset = q->selectedLength(); + + selected_.emplace_back(); + + auto &selection = selected_.back(); + selection.emplace_back(offset + inputLength, + WordNode{segment, ime_->model()->index(segment)}, + ""); + // add some special code for handling separator at the end + auto remain = std::string_view(q->userInput()).substr(offset); + if (!remain.empty()) { + if (std::all_of(remain.begin(), remain.end(), + [](char c) { return c == '\''; })) { + selection.emplace_back(q->size(), WordNode("", 0), ""); + } + } + + q->update(); + } }; void matchPinyinCase(std::string_view ref, std::string &actualPinyin) { @@ -364,6 +388,14 @@ void PinyinContext::selectCandidatesToCursor(size_t idx) { d->select(candidates[idx]); } +void PinyinContext::selectCustom(size_t inputLength, std::string_view segment) { + FCITX_D(); + if (inputLength == 0 && selectedLength() + inputLength > size()) { + throw std::out_of_range("Invalid input length"); + } + d->selectCustom(inputLength, segment); +} + bool PinyinContext::cancelTill(size_t pos) { bool cancelled = false; while (selectedLength() > pos) { diff --git a/src/libime/pinyin/pinyincontext.h b/src/libime/pinyin/pinyincontext.h index 7955afd..a534d25 100644 --- a/src/libime/pinyin/pinyincontext.h +++ b/src/libime/pinyin/pinyincontext.h @@ -59,6 +59,17 @@ class LIBIMEPINYIN_EXPORT PinyinContext : public InputBuffer { void cancel(); bool cancelTill(size_t pos); + /** + * Create a custom selection + * + * This allows Engine to do make a custom selection that is not pinyin. + * + * @param inputLength the length of characters to match in the input + * @param segment segment + * @since 1.1.7 + */ + void selectCustom(size_t inputLength, std::string_view segment); + /// Whether the input is fully selected. bool selected() const; diff --git a/test/testpinyincontext.cpp b/test/testpinyincontext.cpp index f8a3975..3485474 100644 --- a/test/testpinyincontext.cpp +++ b/test/testpinyincontext.cpp @@ -188,5 +188,26 @@ int main() { } } + { + c.clear(); + c.type("hellonihao"); + c.selectCustom(5, "Hello"); + size_t i = 0; + for (const auto &candidate : c.candidatesToCursor()) { + if (candidate.toString() == "你") { + break; + } + i++; + } + FCITX_ASSERT(i < c.candidatesToCursor().size()); + c.selectCandidatesToCursor(i); + + FCITX_ASSERT(!c.selected()); + c.selectCustom(3, "What"); + + FCITX_ASSERT(c.selected()); + FCITX_ASSERT(c.selectedSentence() == "Hello你What"); + } + return 0; }