Skip to content

Commit

Permalink
Use new selectCustom to handle partial selection
Browse files Browse the repository at this point in the history
Fix #164
  • Loading branch information
wengxt committed Apr 13, 2024
1 parent 4208c4f commit 6f99154
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 27 deletions.
33 changes: 23 additions & 10 deletions im/pinyin/pinyin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2221,24 +2221,37 @@ void PinyinEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &event) {
} else if (int idx =
event.key().keyListIndex(*config_.selectCharFromPhrase);
idx >= 0) {
if (candidateList && candidateList->size() &&
if (candidateList && !candidateList->empty() &&
candidateList->cursorIndex() >= 0) {
auto str =
candidateList->candidate(candidateList->cursorIndex())
.text()
.toStringForCommit();
const auto &candidate =
candidateList->candidate(candidateList->cursorIndex());
auto str = candidate.text().toStringForCommit();
// Validate string and length.
if (auto len = utf8::lengthValidated(str);
len != utf8::INVALID_LENGTH &&
len > static_cast<size_t>(idx)) {
// Get idx-th char.
auto charRange =
const std::string_view chr =
std::next(utf8::MakeUTF8CharRange(str).begin(), idx)
.charRange();
std::string chr(charRange.first, charRange.second);
inputContext->commitString(chr);
.view();
auto segmentLength = state->context_.size() -
state->context_.selectedLength();
const auto *pyCandidate =
dynamic_cast<const PinyinCandidateWord *>(&candidate);
if (pyCandidate) {
const auto &contextCandidates =
state->context_.candidatesToCursor();
if (pyCandidate->idx_ < contextCandidates.size()) {
const auto &sentence =
contextCandidates[pyCandidate->idx_].sentence();
const auto candidateSegmentLength =
sentence.back()->to()->index();
segmentLength =
std::min(segmentLength, candidateSegmentLength);
}
}
state->context_.selectCustom(segmentLength, chr);
event.filterAndAccept();
state->context_.clear();
}
}
}
Expand Down
78 changes: 61 additions & 17 deletions test/testpinyin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,30 @@
#include <fcitx/instance.h>
#include <iostream>
#include <memory>
#include <string_view>

using namespace fcitx;

std::unique_ptr<EventSourceTime> endTestEvent;
void testPunctuationPart2(EventDispatcher *dispatcher, Instance *instance);

int findCandidateOrDie(InputContext *ic, std::string_view word) {
auto candList = ic->inputPanel().candidateList();
for (int i = 0; i < candList->toBulk()->totalSize(); i++) {
const auto &candidate = candList->toBulk()->candidateFromAll(i);
if (candidate.text().toString() == word) {
return i;
}
}
FCITX_ASSERT(false) << "Failed to find candidate: " << word;
return -1;
}

void findAndSelectCandidate(InputContext *ic, std::string_view word) {
auto candList = ic->inputPanel().candidateList();
candList->candidate(findCandidateOrDie(ic, word)).select(ic);
}

void testBasic(EventDispatcher *dispatcher, Instance *instance) {
dispatcher->schedule([instance]() {
auto *pinyin = instance->addonManager().addon("pinyin", true);
Expand Down Expand Up @@ -67,17 +85,10 @@ void testBasic(EventDispatcher *dispatcher, Instance *instance) {
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("h"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("a"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("o"), false);
auto ic = instance->inputContextManager().findByUUID(uuid);
auto *ic = instance->inputContextManager().findByUUID(uuid);
FCITX_ASSERT(ic);
// Make a partial selection, we do search because the data might change.
auto candList = ic->inputPanel().candidateList();
for (int i = 0; i < candList->size(); i++) {
auto &candidate = candList->candidate(i);
if (candidate.text().toString() == "") {
candidate.select(ic);
break;
}
}
findAndSelectCandidate(ic, "");
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Return"), false);

// Test switch input method.
Expand All @@ -99,14 +110,7 @@ void testBasic(EventDispatcher *dispatcher, Instance *instance) {
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("a"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("o"), false);
// Make a partial selection, we do search because the data might change.
candList = ic->inputPanel().candidateList();
for (int i = 0; i < candList->size(); i++) {
auto &candidate = candList->candidate(i);
if (candidate.text().toString() == "") {
candidate.select(ic);
break;
}
}
findAndSelectCandidate(ic, "");
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
Expand Down Expand Up @@ -143,6 +147,45 @@ void testBasic(EventDispatcher *dispatcher, Instance *instance) {
});
}

void testSelectByChar(EventDispatcher *dispatcher, Instance *instance) {
dispatcher->schedule([instance, dispatcher]() {
auto *testfrontend = instance->addonManager().addon("testfrontend");
auto uuid =
testfrontend->call<ITestFrontend::createInputContext>("testapp");

testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
false);

testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("n"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("i"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("h"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("a"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("o"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("g"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("o"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("n"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("g"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("z"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("h"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("u"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("b"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("i"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("n"), false);
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("g"), false);

testfrontend->call<ITestFrontend::pushCommitExpectation>("你好主病");
auto *ic = instance->inputContextManager().findByUUID(uuid);
FCITX_ASSERT(ic);
findAndSelectCandidate(ic, "你好");
auto candidateIdx = findCandidateOrDie(ic, "公主");
ic->inputPanel().candidateList()->toBulkCursor()->setGlobalCursorIndex(
candidateIdx);
// With default config, this should select "主".
testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("]"), false);
findAndSelectCandidate(ic, "");
});
}

void testPunctuation(EventDispatcher *dispatcher, Instance *instance) {
dispatcher->schedule([instance, dispatcher]() {
auto *testfrontend = instance->addonManager().addon("testfrontend");
Expand Down Expand Up @@ -226,6 +269,7 @@ int main() {
EventDispatcher dispatcher;
dispatcher.attach(&instance.eventLoop());
testBasic(&dispatcher, &instance);
testSelectByChar(&dispatcher, &instance);
testPunctuation(&dispatcher, &instance);
instance.exec();
endTestEvent.reset();
Expand Down

0 comments on commit 6f99154

Please sign in to comment.