外观里行内预编辑与候选窗预编辑各加一个「双拼显示转换后的全拼」开关,默认关闭。 开启后在双拼方案下:行内原始按键显示不带分词符号的全拼,拼音分词显示带分词符号的 全拼;候选窗显示带分词符号的全拼。 - 引擎新增 get_shuangpin_preedit_forms,同时给出原串切分与全拼切分,不受 shuangpin_preedit_mode 影响。 - 原始按键样式下 TSF 不等 Server 回包,开关开启且为双拼时 Server 下发的实际样式 改为 pinyin,回包里再按用户样式去掉分词符号;换方案时重新下发。 - 转换后字母数与按键不再对应,Server 在预编辑末尾附光标映射表 (engine/contracts/preedit_caret_map.h),DLL 用它定位光标和处理方向键, 无表或长度不符时回落到原有字母映射。
80 lines
3.3 KiB
C++
80 lines
3.3 KiB
C++
#include "tests/includes/test_framework.h"
|
|
#include "engine/contracts/preedit_caret_map.h"
|
|
#include "utils/shuangpin_preedit_display.h"
|
|
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
TEST_CASE(ShuangpinQuanpinPreeditKeepsSeparatorsForPinyinStyle)
|
|
{
|
|
const auto preedit = BuildShuangpinQuanpinPreedit("nihc", "ni'hc", "ni'hao", /*keep_separators=*/true);
|
|
REQUIRE_EQ(preedit.text, std::string("ni'hao"));
|
|
// n|i|h|c: 两键中间停在全拼音节的同一偏移,音节末尾停在全拼音节末尾。
|
|
REQUIRE(preedit.caret_map == std::vector<std::size_t>({0, 1, 2, 4, 6}));
|
|
}
|
|
|
|
TEST_CASE(ShuangpinQuanpinPreeditDropsSeparatorsForRawStyle)
|
|
{
|
|
const auto preedit = BuildShuangpinQuanpinPreedit("nihc", "ni'hc", "ni'hao", /*keep_separators=*/false);
|
|
REQUIRE_EQ(preedit.text, std::string("nihao"));
|
|
REQUIRE(preedit.caret_map == std::vector<std::size_t>({0, 1, 2, 3, 5}));
|
|
}
|
|
|
|
TEST_CASE(ShuangpinQuanpinPreeditFollowsManualSeparator)
|
|
{
|
|
// 用户手动敲的分词符号也算在原串里,光标停在它后面时落到下一个全拼音节开头。
|
|
const auto preedit = BuildShuangpinQuanpinPreedit("ni'hc", "ni'hc", "ni'hao", /*keep_separators=*/true);
|
|
REQUIRE_EQ(preedit.text, std::string("ni'hao"));
|
|
REQUIRE(preedit.caret_map == std::vector<std::size_t>({0, 1, 2, 3, 4, 6}));
|
|
|
|
const auto raw = BuildShuangpinQuanpinPreedit("ni'hc", "ni'hc", "ni'hao", /*keep_separators=*/false);
|
|
REQUIRE_EQ(raw.text, std::string("nihao"));
|
|
REQUIRE(raw.caret_map == std::vector<std::size_t>({0, 1, 2, 2, 3, 5}));
|
|
}
|
|
|
|
TEST_CASE(ShuangpinQuanpinPreeditKeepsTrailingInitial)
|
|
{
|
|
const auto preedit = BuildShuangpinQuanpinPreedit("vgh", "vg'h", "zheng'h", /*keep_separators=*/true);
|
|
REQUIRE_EQ(preedit.text, std::string("zheng'h"));
|
|
REQUIRE(preedit.caret_map == std::vector<std::size_t>({0, 1, 5, 7}));
|
|
}
|
|
|
|
TEST_CASE(ShuangpinQuanpinPreeditFallsBackWhenSegmentsDiffer)
|
|
{
|
|
const auto preedit = BuildShuangpinQuanpinPreedit("abcd", "ab'cd", "abc", /*keep_separators=*/true);
|
|
REQUIRE_EQ(preedit.text, std::string("abc"));
|
|
REQUIRE_EQ(preedit.caret_map.size(), std::size_t(5));
|
|
REQUIRE_EQ(preedit.caret_map.front(), std::size_t(0));
|
|
REQUIRE_EQ(preedit.caret_map.back(), std::size_t(3));
|
|
}
|
|
|
|
TEST_CASE(PreeditCaretMapRoundTrips)
|
|
{
|
|
std::wstring payload = FanyImePreeditCaretMap::Encode(L"你好nihao", {2, 3, 4, 5, 7});
|
|
REQUIRE(payload.find(L'\t') == std::wstring::npos);
|
|
std::vector<std::size_t> caret_map;
|
|
FanyImePreeditCaretMap::Decode(payload, caret_map);
|
|
REQUIRE(payload == L"你好nihao");
|
|
REQUIRE(caret_map == std::vector<std::size_t>({2, 3, 4, 5, 7}));
|
|
}
|
|
|
|
TEST_CASE(PreeditCaretMapIgnoresPlainAndMalformedPayloads)
|
|
{
|
|
std::vector<std::size_t> caret_map{1};
|
|
std::wstring plain = L"ni'hao";
|
|
FanyImePreeditCaretMap::Decode(plain, caret_map);
|
|
REQUIRE(plain == L"ni'hao");
|
|
REQUIRE(caret_map.empty());
|
|
|
|
std::wstring malformed = std::wstring(L"nihao") + FanyImePreeditCaretMap::kMarker + L"0,x";
|
|
FanyImePreeditCaretMap::Decode(malformed, caret_map);
|
|
REQUIRE(malformed == L"nihao");
|
|
REQUIRE(caret_map.empty());
|
|
|
|
std::wstring out_of_range = std::wstring(L"ni") + FanyImePreeditCaretMap::kMarker + L"0,9";
|
|
FanyImePreeditCaretMap::Decode(out_of_range, caret_map);
|
|
REQUIRE(out_of_range == L"ni");
|
|
REQUIRE(caret_map.empty());
|
|
}
|