fix(server): adopt isolated engine sessions and helpcode annotations (#178)

This commit is contained in:
Evan authored and GitHub committed 2026-09-06 11:44:30 +09:00
1 parent acff323ac1
commit 2b8bf937d9
8 files changed
+91 -6

No files matched your search

+4
View File
@@ -28,6 +28,10 @@ Windows 端的全部一方源码在本仓。**合仓改变的是仓库数量,
- **候选与输入状态的权威在 Server 和引擎**,页面只负责展示和发出用户动作,不要在网页侧复制状态机。
- `ui-html/webview2/shared/` 是 Engine web 契约的副本,由 `ui-html/scripts/sync-contracts.py` 生成,CI 用 `--check` 验证它和 submodule 一致。手改这个目录会被 CI 拦下来,改契约要改 Engine。
Server 当前仍使用 Engine 的兼容 `InputSession`,尚未迁移公共 `Session` facade。
辅助码筛选与候选提示都按会话配置,禁止用全局默认码表驱动活动会话。
`RuntimePaths::legacy()` 在适配器创建时捕获现有安装布局;完整资源包和用户数据代际切换仍待接入。
## 构建
每个组件是独立的 CMake 工程,各自带 `vcpkg.json` 和 preset,从仓库根目录指定 `-S`:
+1 -1
View File
@@ -3,7 +3,7 @@
"repositories": {
"engine": {
"repository": "metasequoiaime/MSIME-Engine",
"commit": "cc21e42916cf93ce43051fec474e87eeeba305bf"
"commit": "c63ba774ac03c9ff8ba82776d50e97d27fd459a3"
}
},
"dictionary": {
+1 -1
View File
@@ -925,7 +925,7 @@ std::string BuildCurrentCandidatePage()
if (show_helpcodes && item.source != CandidateSource::EnglishDictionary &&
item.source != CandidateSource::QuickPhrase && item.source != CandidateSource::Emoji &&
item.source != CandidateSource::Kaomoji && item.source != CandidateSource::Generated)
view.annotation = HelpcodeUtils::compute_helpcodes(item.word, uppercase_all_helpcodes);
view.annotation = g_inputSession->get_helpcode_annotation(item.word, uppercase_all_helpcodes);
if (item.source == CandidateSource::CloudSuggestion)
view.badge = " ☁️";
else if (item.source == CandidateSource::AiSuggestion)
+25 -3
View File
@@ -2,7 +2,8 @@
#include "config/ime_config.h"
#include "MetasequoiaImeEngine/common/helpcode_utils.h"
EngineInputSession::EngineInputSession(SchemeType scheme, const ShuangpinProfile &profile) : session_(scheme, profile)
EngineInputSession::EngineInputSession(SchemeType scheme, const ShuangpinProfile &profile)
: paths_(metasequoia::RuntimePaths::legacy()), session_(scheme, profile, paths_)
{
ApplyConfiguration();
}
@@ -11,8 +12,21 @@ void EngineInputSession::ApplyConfiguration()
{
const auto scheme = session_.scheme();
if (scheme == SchemeType::Quanpin || scheme == SchemeType::Shuangpin)
HelpcodeUtils::select_helpcode_schema(scheme == SchemeType::Quanpin ? GetConfiguredQuanpinHelpcodeSchema()
: GetConfiguredShuangpinHelpcodeSchema());
{
const auto &schema = scheme == SchemeType::Quanpin ? GetConfiguredQuanpinHelpcodeSchema()
: GetConfiguredShuangpinHelpcodeSchema();
if (schema != helpcode_schema_)
{
// Keep filtering and annotations on this session's captured resource layout.
// Applying unchanged settings on each key must not reload the tables.
auto keymap = HelpcodeUtils::load_helpcode_keymap(paths_.resources, schema);
if (session_.set_helpcode_schema(schema))
{
helpcode_schema_ = schema;
helpcode_keymap_ = std::move(keymap);
}
}
}
session_.set_shuangpin_helpcode_enabled(GetConfiguredShuangpinHelpcodeEnabled());
session_.set_quanpin_helpcode_enabled(GetConfiguredQuanpinHelpcodeEnabled());
session_.set_quanpin_autocorrect_enabled(GetConfiguredQuanpinAutocorrectEnabled());
@@ -160,3 +174,11 @@ IInputSession::CreatingWordProgress EngineInputSession::update_creating_word_pro
{
return session_.update_creating_word_progress(current_pinyin, current_word, selected_word, selection_transition);
}
std::string EngineInputSession::get_helpcode_annotation(const std::string &word, bool uppercase_all) const
{
const auto scheme = session_.scheme();
if (!helpcode_keymap_ || (scheme != SchemeType::Quanpin && scheme != SchemeType::Shuangpin))
return {};
return HelpcodeUtils::compute_helpcodes(word, uppercase_all, helpcode_keymap_.get());
}
@@ -1,6 +1,7 @@
#pragma once
#include "input_session.h"
#include "MetasequoiaImeEngine/common/helpcode_utils.h"
#include "MetasequoiaImeEngine/core/input_session.h"
class EngineInputSession : public IInputSession
@@ -19,6 +20,7 @@ class EngineInputSession : public IInputSession
const std::vector<WordItem> &get_candidates() const override;
bool expand_initial_candidates() override;
std::string get_helpcode_annotation(const std::string &word, bool uppercase_all) const override;
std::optional<WordItem> find_candidate(const std::string &key, const std::string &value) override;
const std::string &get_pinyin_sequence() const override;
@@ -49,5 +51,8 @@ class EngineInputSession : public IInputSession
private:
void ApplyConfiguration();
const metasequoia::RuntimePaths paths_;
metasequoia::InputSession session_;
std::string helpcode_schema_;
HelpcodeUtils::SharedKeymap helpcode_keymap_;
};
+1
View File
@@ -28,6 +28,7 @@ class IInputSession
virtual const std::vector<WordItem> &get_candidates() const = 0;
virtual bool expand_initial_candidates() = 0;
virtual std::string get_helpcode_annotation(const std::string &word, bool uppercase_all) const = 0;
virtual std::optional<WordItem> find_candidate(const std::string &, const std::string &)
{
return std::nullopt;
@@ -1,5 +1,6 @@
#include "tests/includes/test_framework.h"
#include "src/session/engine_input_session.h"
#include "src/config/ime_config.h"
#include "MetasequoiaImeEngine/common/helpcode_utils.h"
#include "MetasequoiaImeEngine/quanpin/quanpin_query.h"
#include "MetasequoiaImeEngine/shuangpin/shuangpin_dictionary.h"
@@ -784,3 +785,55 @@ TEST_CASE(EngineShuangpinSegmentedInitialCandidatesExpandInPlace)
REQUIRE(count_initials(expanded_candidates) > 24);
REQUIRE_EQ(count_other_candidates(expanded_candidates), other_count);
}
TEST_CASE(EngineSessionsKeepHelpcodeFilteringAndAnnotationsTogether)
{
// The integration runner supplies an isolated config and the locked release dictionaries.
InitImeConfig();
struct RestoreConfiguration
{
std::string quanpin = GetConfiguredQuanpinHelpcodeSchema();
std::string shuangpin = GetConfiguredShuangpinHelpcodeSchema();
bool quanpin_enabled = GetConfiguredQuanpinHelpcodeEnabled();
bool shuangpin_enabled = GetConfiguredShuangpinHelpcodeEnabled();
~RestoreConfiguration()
{
SetConfiguredQuanpinHelpcodeSchema(quanpin);
SetConfiguredShuangpinHelpcodeSchema(shuangpin);
SetConfiguredQuanpinHelpcodeEnabled(quanpin_enabled);
SetConfiguredShuangpinHelpcodeEnabled(shuangpin_enabled);
}
} restore;
REQUIRE(SetConfiguredQuanpinHelpcodeEnabled(true));
REQUIRE(SetConfiguredShuangpinHelpcodeEnabled(true));
REQUIRE(SetConfiguredQuanpinHelpcodeSchema("lantian"));
REQUIRE(SetConfiguredShuangpinHelpcodeSchema("ziranma"));
EngineInputSession quanpin(SchemeType::Quanpin);
EngineInputSession shuangpin(SchemeType::Shuangpin);
REQUIRE_EQ(quanpin.get_helpcode_annotation("你", true), std::string("(RX)"));
REQUIRE_EQ(shuangpin.get_helpcode_annotation("你", false), std::string("(rE)"));
InputLetters(quanpin, "niRX");
REQUIRE(!quanpin.get_candidates().empty());
REQUIRE(std::any_of(quanpin.get_candidates().begin(), quanpin.get_candidates().end(),
[](const auto &item) { return item.word == "你"; }));
InputLetters(shuangpin, "ni");
shuangpin.recompute_candidates();
quanpin.recompute_candidates();
REQUIRE_EQ(quanpin.get_helpcode_annotation("你", true), std::string("(RX)"));
REQUIRE_EQ(shuangpin.get_helpcode_annotation("你", false), std::string("(rE)"));
REQUIRE(std::any_of(quanpin.get_candidates().begin(), quanpin.get_candidates().end(),
[](const auto &item) { return item.word == "你"; }));
// A settings change is adopted by the next refresh, including candidate annotations.
REQUIRE(SetConfiguredQuanpinHelpcodeSchema("ziranma"));
quanpin.reset_state();
InputLetters(quanpin, "niRE");
REQUIRE_EQ(quanpin.get_helpcode_annotation("你", true), std::string("(RE)"));
REQUIRE(std::any_of(quanpin.get_candidates().begin(), quanpin.get_candidates().end(),
[](const auto &item) { return item.word == "你"; }));
REQUIRE_EQ(shuangpin.get_helpcode_annotation("你", false), std::string("(rE)"));
quanpin.switch_scheme(SchemeType::Shuangpin);
REQUIRE_EQ(quanpin.get_helpcode_annotation("你", false), std::string("(rE)"));
}