From aa1af8ed8ad7cf8b63e00515d3ac0a6899ee20f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Thu, 16 May 2024 16:27:44 +0800 Subject: [PATCH 1/2] feat(api): provide a flavor of api using stdbool API type: RimeApi_stdbool API entry function: rime_get_api_stdbool --- CMakeLists.txt | 1 + src/rime/setup.cc | 20 +- src/rime_api.cc | 1208 +----------------------------------- src/rime_api.h | 241 ++------ src/rime_api_deprecated.h | 219 +++++++ src/rime_api_impl.h | 1230 +++++++++++++++++++++++++++++++++++++ src/rime_api_stdbool.cc | 4 + src/rime_api_stdbool.h | 22 + test/flavored_api_test.cc | 23 + test/rime_test_main.cc | 2 + 10 files changed, 1550 insertions(+), 1420 deletions(-) create mode 100644 src/rime_api_deprecated.h create mode 100644 src/rime_api_impl.h create mode 100644 src/rime_api_stdbool.cc create mode 100644 src/rime_api_stdbool.h create mode 100644 test/flavored_api_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 53f9d5374c..e167e22844 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,6 +224,7 @@ install(FILES cmake/RimeConfig.cmake DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/cmake/rime) file(GLOB rime_public_header_files ${PROJECT_SOURCE_DIR}/src/*.h) +list(FILTER rime_public_header_files EXCLUDE REGEX .*_impl\.h$) install(FILES ${rime_public_header_files} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}) if(INSTALL_PRIVATE_HEADERS) diff --git a/src/rime/setup.cc b/src/rime/setup.cc index d188beccf5..737ec0d0fa 100644 --- a/src/rime/setup.cc +++ b/src/rime/setup.cc @@ -39,31 +39,27 @@ RIME_API void LoadModules(const char* module_names[]) { } } -// assume member is a non-null pointer in struct *p. -#define PROVIDED(p, member) \ - ((p) && RIME_STRUCT_HAS_MEMBER(*(p), (p)->member) && (p)->member) - RIME_API void SetupDeployer(RimeTraits* traits) { if (!traits) return; Deployer& deployer(Service::instance().deployer()); - if (PROVIDED(traits, shared_data_dir)) + if (RIME_PROVIDED(traits, shared_data_dir)) deployer.shared_data_dir = path(traits->shared_data_dir); - if (PROVIDED(traits, user_data_dir)) + if (RIME_PROVIDED(traits, user_data_dir)) deployer.user_data_dir = path(traits->user_data_dir); - if (PROVIDED(traits, distribution_name)) + if (RIME_PROVIDED(traits, distribution_name)) deployer.distribution_name = traits->distribution_name; - if (PROVIDED(traits, distribution_code_name)) + if (RIME_PROVIDED(traits, distribution_code_name)) deployer.distribution_code_name = traits->distribution_code_name; - if (PROVIDED(traits, distribution_version)) + if (RIME_PROVIDED(traits, distribution_version)) deployer.distribution_version = traits->distribution_version; - if (PROVIDED(traits, app_name)) + if (RIME_PROVIDED(traits, app_name)) deployer.app_name = traits->app_name; - if (PROVIDED(traits, prebuilt_data_dir)) + if (RIME_PROVIDED(traits, prebuilt_data_dir)) deployer.prebuilt_data_dir = path(traits->prebuilt_data_dir); else deployer.prebuilt_data_dir = deployer.shared_data_dir / "build"; - if (PROVIDED(traits, staging_dir)) + if (RIME_PROVIDED(traits, staging_dir)) deployer.staging_dir = path(traits->staging_dir); else deployer.staging_dir = deployer.user_data_dir / "build"; diff --git a/src/rime_api.cc b/src/rime_api.cc index dd26886309..eda2fa215d 100644 --- a/src/rime_api.cc +++ b/src/rime_api.cc @@ -7,41 +7,27 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include -#include -#include +#include "rime_api.h" -using namespace rime; -using namespace std::placeholders; +#include "rime_api_impl.h" -// assume member is a non-null pointer in struct *p. -#define PROVIDED(p, member) \ - ((p) && RIME_STRUCT_HAS_MEMBER(*(p), (p)->member) && (p)->member) +using namespace rime; -RIME_API void RimeSetupLogging(const char* app_name) { +RIME_DEPRECATED void RimeSetupLogging(const char* app_name) { SetupLogging(app_name); } #if RIME_BUILD_SHARED_LIBS -#define rime_declare_module_dependencies() +void rime_declare_module_dependencies() {} #else extern void rime_require_module_core(); extern void rime_require_module_dict(); extern void rime_require_module_gears(); extern void rime_require_module_levers(); // link to default modules explicitly when building static library. -static void rime_declare_module_dependencies() { +void rime_declare_module_dependencies() { rime_require_module_core(); rime_require_module_dict(); rime_require_module_gears(); @@ -49,747 +35,6 @@ static void rime_declare_module_dependencies() { } #endif -RIME_API void RimeSetup(RimeTraits* traits) { - rime_declare_module_dependencies(); - - SetupDeployer(traits); - if (PROVIDED(traits, app_name)) { - if (RIME_STRUCT_HAS_MEMBER(*traits, traits->min_log_level) && - RIME_STRUCT_HAS_MEMBER(*traits, traits->log_dir)) { - SetupLogging(traits->app_name, traits->min_log_level, traits->log_dir); - } else { - SetupLogging(traits->app_name); - } - } -} - -RIME_API void RimeSetNotificationHandler(RimeNotificationHandler handler, - void* context_object) { - if (handler) { - Service::instance().SetNotificationHandler( - std::bind(handler, context_object, _1, _2, _3)); - } else { - Service::instance().ClearNotificationHandler(); - } -} - -RIME_API void RimeInitialize(RimeTraits* traits) { - SetupDeployer(traits); - LoadModules(PROVIDED(traits, modules) ? traits->modules : kDefaultModules); - Service::instance().StartService(); -} - -RIME_API void RimeFinalize() { - RimeJoinMaintenanceThread(); - Service::instance().StopService(); - Registry::instance().Clear(); - ModuleManager::instance().UnloadModules(); -} - -RIME_API Bool RimeStartMaintenance(Bool full_check) { - LoadModules(kDeployerModules); - Deployer& deployer(Service::instance().deployer()); - deployer.RunTask("clean_old_log_files"); - if (!deployer.RunTask("installation_update")) { - return False; - } - if (!full_check) { - TaskInitializer args{ - vector{ - deployer.user_data_dir, - deployer.shared_data_dir, - }, - }; - if (!deployer.RunTask("detect_modifications", args)) { - return False; - } - LOG(INFO) << "changes detected; starting maintenance."; - } - deployer.ScheduleTask("workspace_update"); - deployer.ScheduleTask("user_dict_upgrade"); - deployer.ScheduleTask("cleanup_trash"); - deployer.StartMaintenance(); - return True; -} - -RIME_API Bool RimeStartMaintenanceOnWorkspaceChange() { - return RimeStartMaintenance(False); -} - -RIME_API Bool RimeIsMaintenancing() { - Deployer& deployer(Service::instance().deployer()); - return Bool(deployer.IsMaintenanceMode()); -} - -RIME_API void RimeJoinMaintenanceThread() { - Deployer& deployer(Service::instance().deployer()); - deployer.JoinMaintenanceThread(); -} - -// deployment - -RIME_API void RimeDeployerInitialize(RimeTraits* traits) { - SetupDeployer(traits); - LoadModules(PROVIDED(traits, modules) ? traits->modules : kDeployerModules); -} - -RIME_API Bool RimePrebuildAllSchemas() { - Deployer& deployer(Service::instance().deployer()); - return Bool(deployer.RunTask("prebuild_all_schemas")); -} - -RIME_API Bool RimeDeployWorkspace() { - Deployer& deployer(Service::instance().deployer()); - return Bool(deployer.RunTask("installation_update") && - deployer.RunTask("workspace_update") && - deployer.RunTask("user_dict_upgrade") && - deployer.RunTask("cleanup_trash")); -} - -RIME_API Bool RimeDeploySchema(const char* schema_file) { - Deployer& deployer(Service::instance().deployer()); - return Bool(deployer.RunTask("schema_update", path(schema_file))); -} - -RIME_API Bool RimeDeployConfigFile(const char* file_name, - const char* version_key) { - Deployer& deployer(Service::instance().deployer()); - TaskInitializer args(make_pair(file_name, version_key)); - return Bool(deployer.RunTask("config_file_update", args)); -} - -RIME_API Bool RimeSyncUserData() { - RimeCleanupAllSessions(); - Deployer& deployer(Service::instance().deployer()); - deployer.ScheduleTask("installation_update"); - deployer.ScheduleTask("backup_config_files"); - deployer.ScheduleTask("user_dict_sync"); - return Bool(deployer.StartMaintenance()); -} - -// session management - -RIME_API RimeSessionId RimeCreateSession() { - return Service::instance().CreateSession(); -} - -RIME_API Bool RimeFindSession(RimeSessionId session_id) { - return Bool(session_id && Service::instance().GetSession(session_id)); -} - -RIME_API Bool RimeDestroySession(RimeSessionId session_id) { - return Bool(Service::instance().DestroySession(session_id)); -} - -RIME_API void RimeCleanupStaleSessions() { - Service::instance().CleanupStaleSessions(); -} - -RIME_API void RimeCleanupAllSessions() { - Service::instance().CleanupAllSessions(); -} - -// input - -RIME_API Bool RimeProcessKey(RimeSessionId session_id, int keycode, int mask) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - return Bool(session->ProcessKey(KeyEvent(keycode, mask))); -} - -RIME_API Bool RimeCommitComposition(RimeSessionId session_id) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - return Bool(session->CommitComposition()); -} - -RIME_API void RimeClearComposition(RimeSessionId session_id) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return; - session->ClearComposition(); -} - -// output - -static void rime_candidate_copy(RimeCandidate* dest, const an& src) { - dest->text = new char[src->text().length() + 1]; - std::strcpy(dest->text, src->text().c_str()); - string comment(src->comment()); - if (!comment.empty()) { - dest->comment = new char[comment.length() + 1]; - std::strcpy(dest->comment, comment.c_str()); - } else { - dest->comment = nullptr; - } - dest->reserved = nullptr; -} - -RIME_API Bool RimeGetContext(RimeSessionId session_id, RimeContext* context) { - if (!context || context->data_size <= 0) - return False; - RIME_STRUCT_CLEAR(*context); - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx) - return False; - if (ctx->IsComposing()) { - Preedit preedit = ctx->GetPreedit(); - context->composition.length = preedit.text.length(); - context->composition.preedit = new char[preedit.text.length() + 1]; - std::strcpy(context->composition.preedit, preedit.text.c_str()); - context->composition.cursor_pos = preedit.caret_pos; - context->composition.sel_start = preedit.sel_start; - context->composition.sel_end = preedit.sel_end; - if (RIME_STRUCT_HAS_MEMBER(*context, context->commit_text_preview)) { - string commit_text(ctx->GetCommitText()); - if (!commit_text.empty()) { - context->commit_text_preview = new char[commit_text.length() + 1]; - std::strcpy(context->commit_text_preview, commit_text.c_str()); - } - } - } - if (ctx->HasMenu()) { - Segment& seg(ctx->composition().back()); - int page_size = 5; - Schema* schema = session->schema(); - if (schema) - page_size = schema->page_size(); - int selected_index = seg.selected_index; - int page_no = selected_index / page_size; - the page(seg.menu->CreatePage(page_size, page_no)); - if (page) { - context->menu.page_size = page_size; - context->menu.page_no = page_no; - context->menu.is_last_page = Bool(page->is_last_page); - context->menu.highlighted_candidate_index = selected_index % page_size; - int i = 0; - context->menu.num_candidates = page->candidates.size(); - context->menu.candidates = new RimeCandidate[page->candidates.size()]; - for (const an& cand : page->candidates) { - RimeCandidate* dest = &context->menu.candidates[i++]; - rime_candidate_copy(dest, cand); - } - if (schema) { - const string& select_keys(schema->select_keys()); - if (!select_keys.empty()) { - context->menu.select_keys = new char[select_keys.length() + 1]; - std::strcpy(context->menu.select_keys, select_keys.c_str()); - } - Config* config = schema->config(); - an select_labels = - config->GetList("menu/alternative_select_labels"); - if (select_labels && (size_t)page_size <= select_labels->size()) { - context->select_labels = new char*[page_size]; - for (size_t i = 0; i < (size_t)page_size; ++i) { - an value = select_labels->GetValueAt(i); - string label = value->str(); - context->select_labels[i] = new char[label.length() + 1]; - std::strcpy(context->select_labels[i], label.c_str()); - } - } - } - } - } - return True; -} - -RIME_API Bool RimeFreeContext(RimeContext* context) { - if (!context || context->data_size <= 0) - return False; - delete[] context->composition.preedit; - for (int i = 0; i < context->menu.num_candidates; ++i) { - delete[] context->menu.candidates[i].text; - delete[] context->menu.candidates[i].comment; - } - delete[] context->menu.candidates; - delete[] context->menu.select_keys; - if (RIME_STRUCT_HAS_MEMBER(*context, context->select_labels) && - context->select_labels) { - for (int i = 0; i < context->menu.page_size; ++i) { - delete[] context->select_labels[i]; - } - delete[] context->select_labels; - } - if (RIME_STRUCT_HAS_MEMBER(*context, context->commit_text_preview)) { - delete[] context->commit_text_preview; - } - RIME_STRUCT_CLEAR(*context); - return True; -} - -RIME_API Bool RimeGetCommit(RimeSessionId session_id, RimeCommit* commit) { - if (!commit) - return False; - RIME_STRUCT_CLEAR(*commit); - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - const string& commit_text(session->commit_text()); - if (!commit_text.empty()) { - commit->text = new char[commit_text.length() + 1]; - std::strcpy(commit->text, commit_text.c_str()); - session->ResetCommitText(); - return True; - } - return False; -} - -RIME_API Bool RimeFreeCommit(RimeCommit* commit) { - if (!commit) - return False; - delete[] commit->text; - RIME_STRUCT_CLEAR(*commit); - return True; -} - -RIME_API Bool RimeGetStatus(RimeSessionId session_id, RimeStatus* status) { - if (!status || status->data_size <= 0) - return False; - RIME_STRUCT_CLEAR(*status); - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Schema* schema = session->schema(); - Context* ctx = session->context(); - if (!schema || !ctx) - return False; - status->schema_id = new char[schema->schema_id().length() + 1]; - std::strcpy(status->schema_id, schema->schema_id().c_str()); - status->schema_name = new char[schema->schema_name().length() + 1]; - std::strcpy(status->schema_name, schema->schema_name().c_str()); - status->is_disabled = Service::instance().disabled(); - status->is_composing = Bool(ctx->IsComposing()); - status->is_ascii_mode = Bool(ctx->get_option("ascii_mode")); - status->is_full_shape = Bool(ctx->get_option("full_shape")); - status->is_simplified = Bool(ctx->get_option("simplification")); - status->is_traditional = Bool(ctx->get_option("traditional")); - status->is_ascii_punct = Bool(ctx->get_option("ascii_punct")); - return True; -} - -RIME_API Bool RimeFreeStatus(RimeStatus* status) { - if (!status || status->data_size <= 0) - return False; - delete[] status->schema_id; - delete[] status->schema_name; - RIME_STRUCT_CLEAR(*status); - return True; -} - -// Accessing candidate list - -RIME_API Bool RimeCandidateListFromIndex(RimeSessionId session_id, - RimeCandidateListIterator* iterator, - int index) { - if (!iterator) - return False; - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx || !ctx->HasMenu()) - return False; - memset(iterator, 0, sizeof(RimeCandidateListIterator)); - iterator->ptr = ctx->composition().back().menu.get(); - iterator->index = index - 1; - return True; -} - -RIME_API Bool RimeCandidateListBegin(RimeSessionId session_id, - RimeCandidateListIterator* iterator) { - return RimeCandidateListFromIndex(session_id, iterator, 0); -} - -RIME_API Bool RimeCandidateListNext(RimeCandidateListIterator* iterator) { - if (!iterator) - return False; - Menu* menu = reinterpret_cast(iterator->ptr); - if (!menu) - return False; - ++iterator->index; - if (auto cand = menu->GetCandidateAt((size_t)iterator->index)) { - delete[] iterator->candidate.text; - delete[] iterator->candidate.comment; - rime_candidate_copy(&iterator->candidate, cand); - return True; - } - return False; -} - -RIME_API void RimeCandidateListEnd(RimeCandidateListIterator* iterator) { - if (!iterator) - return; - delete[] iterator->candidate.text; - delete[] iterator->candidate.comment; - memset(iterator, 0, sizeof(RimeCandidateListIterator)); -} - -// runtime options - -RIME_API void RimeSetOption(RimeSessionId session_id, - const char* option, - Bool value) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return; - Context* ctx = session->context(); - if (!ctx) - return; - ctx->set_option(option, !!value); -} - -RIME_API Bool RimeGetOption(RimeSessionId session_id, const char* option) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx) - return False; - return Bool(ctx->get_option(option)); -} - -RIME_API void RimeSetProperty(RimeSessionId session_id, - const char* prop, - const char* value) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return; - Context* ctx = session->context(); - if (!ctx) - return; - ctx->set_property(prop, value); -} - -RIME_API Bool RimeGetProperty(RimeSessionId session_id, - const char* prop, - char* value, - size_t buffer_size) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx) - return False; - string str_value(ctx->get_property(prop)); - if (str_value.empty()) - return False; - strncpy(value, str_value.c_str(), buffer_size); - return True; -} - -RIME_API Bool RimeGetSchemaList(RimeSchemaList* output) { - if (!output) - return False; - output->size = 0; - output->list = NULL; - Schema default_schema; - Config* config = default_schema.config(); - if (!config) - return False; - an schema_list = config->GetList("schema_list"); - if (!schema_list || schema_list->size() == 0) - return False; - output->list = new RimeSchemaListItem[schema_list->size()]; - for (size_t i = 0; i < schema_list->size(); ++i) { - an item = As(schema_list->GetAt(i)); - if (!item) - continue; - an schema_property = item->GetValue("schema"); - if (!schema_property) - continue; - const string& schema_id(schema_property->str()); - RimeSchemaListItem& x(output->list[output->size]); - x.schema_id = new char[schema_id.length() + 1]; - strcpy(x.schema_id, schema_id.c_str()); - Schema schema(schema_id); - x.name = new char[schema.schema_name().length() + 1]; - strcpy(x.name, schema.schema_name().c_str()); - x.reserved = NULL; - ++output->size; - } - if (output->size == 0) { - delete[] output->list; - output->list = NULL; - return False; - } - return True; -} - -RIME_API void RimeFreeSchemaList(RimeSchemaList* schema_list) { - if (!schema_list) - return; - if (schema_list->list) { - for (size_t i = 0; i < schema_list->size; ++i) { - delete[] schema_list->list[i].schema_id; - delete[] schema_list->list[i].name; - } - delete[] schema_list->list; - } - schema_list->size = 0; - schema_list->list = NULL; -} - -RIME_API Bool RimeGetCurrentSchema(RimeSessionId session_id, - char* schema_id, - size_t buffer_size) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Schema* schema = session->schema(); - if (!schema) - return False; - strncpy(schema_id, schema->schema_id().c_str(), buffer_size); - return True; -} - -RIME_API Bool RimeSelectSchema(RimeSessionId session_id, - const char* schema_id) { - if (!schema_id) - return False; - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - session->ApplySchema(new Schema(schema_id)); - return True; -} - -// config - -static Bool open_config_in_component(const char* config_component, - const char* config_id, - RimeConfig* config) { - if (!config_id || !config) - return False; - Config::Component* cc = Config::Require(config_component); - if (!cc) - return False; - Config* c = cc->Create(config_id); - if (!c) - return False; - config->ptr = (void*)c; - return True; -} - -RIME_API Bool RimeSchemaOpen(const char* schema_id, RimeConfig* config) { - return open_config_in_component("schema", schema_id, config); -} - -RIME_API Bool RimeConfigOpen(const char* config_id, RimeConfig* config) { - return open_config_in_component("config", config_id, config); -} - -RIME_API Bool RimeUserConfigOpen(const char* config_id, RimeConfig* config) { - return open_config_in_component("user_config", config_id, config); -} - -RIME_API Bool RimeConfigClose(RimeConfig* config) { - if (!config || !config->ptr) - return False; - Config* c = reinterpret_cast(config->ptr); - delete c; - config->ptr = NULL; - return True; -} - -RIME_API Bool RimeConfigGetBool(RimeConfig* config, - const char* key, - Bool* value) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - bool bool_value = false; - if (c->GetBool(key, &bool_value)) { - *value = Bool(bool_value); - return True; - } - return False; -} - -RIME_API Bool RimeConfigGetInt(RimeConfig* config, - const char* key, - int* value) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - return Bool(c->GetInt(key, value)); -} - -RIME_API Bool RimeConfigGetDouble(RimeConfig* config, - const char* key, - double* value) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - return Bool(c->GetDouble(key, value)); -} - -RIME_API Bool RimeConfigGetString(RimeConfig* config, - const char* key, - char* value, - size_t buffer_size) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - string str_value; - if (c->GetString(key, &str_value)) { - std::strncpy(value, str_value.c_str(), buffer_size); - return True; - } - return False; -} - -RIME_API const char* RimeConfigGetCString(RimeConfig* config, const char* key) { - if (!config || !key) - return NULL; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return NULL; - if (an v = c->GetValue(key)) { - return v->str().c_str(); - } - return NULL; -} - -RIME_API Bool RimeConfigUpdateSignature(RimeConfig* config, - const char* signer) { - if (!config || !signer) - return False; - Config* c = reinterpret_cast(config->ptr); - Deployer& deployer(Service::instance().deployer()); - Signature sig(signer); - return Bool(sig.Sign(c, &deployer)); -} - -template -struct RimeConfigIteratorImpl { - typename T::Iterator iter; - typename T::Iterator end; - string prefix; - string key; - string path; - RimeConfigIteratorImpl(T& container, const string& root_path) - : iter(container.begin()), end(container.end()) { - if (root_path.empty() || root_path == "/") { - // prefix is empty - } else { - prefix = root_path + "/"; - } - } -}; - -RIME_API Bool RimeConfigBeginList(RimeConfigIterator* iterator, - RimeConfig* config, - const char* key) { - if (!iterator || !config || !key) - return False; - iterator->list = NULL; - iterator->map = NULL; - iterator->index = -1; - iterator->key = NULL; - iterator->path = NULL; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - an list = c->GetList(key); - if (!list) - return False; - iterator->list = new RimeConfigIteratorImpl(*list, key); - return True; -} - -RIME_API Bool RimeConfigBeginMap(RimeConfigIterator* iterator, - RimeConfig* config, - const char* key) { - if (!iterator || !config || !key) - return False; - iterator->list = NULL; - iterator->map = NULL; - iterator->index = -1; - iterator->key = NULL; - iterator->path = NULL; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - an m = c->GetMap(key); - if (!m) - return False; - iterator->map = new RimeConfigIteratorImpl(*m, key); - return True; -} - -RIME_API Bool RimeConfigNext(RimeConfigIterator* iterator) { - if (!iterator->list && !iterator->map) - return False; - if (iterator->list) { - RimeConfigIteratorImpl* p = - reinterpret_cast*>(iterator->list); - if (!p) - return False; - if (++iterator->index > 0) - ++p->iter; - if (p->iter == p->end) - return False; - std::ostringstream key; - key << "@" << iterator->index; - p->key = key.str(); - p->path = p->prefix + p->key; - iterator->key = p->key.c_str(); - iterator->path = p->path.c_str(); - return True; - } - if (iterator->map) { - RimeConfigIteratorImpl* p = - reinterpret_cast*>(iterator->map); - if (!p) - return False; - if (++iterator->index > 0) - ++p->iter; - if (p->iter == p->end) - return False; - p->key = p->iter->first; - p->path = p->prefix + p->key; - iterator->key = p->key.c_str(); - iterator->path = p->path.c_str(); - return True; - } - return False; -} - -RIME_API void RimeConfigEnd(RimeConfigIterator* iterator) { - if (!iterator) - return; - if (iterator->list) - delete reinterpret_cast*>( - iterator->list); - if (iterator->map) - delete reinterpret_cast*>(iterator->map); - memset(iterator, 0, sizeof(RimeConfigIterator)); -} - -RIME_API Bool RimeSimulateKeySequence(RimeSessionId session_id, - const char* key_sequence) { - LOG(INFO) << "simulate key sequence: " << key_sequence; - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - KeySequence keys; - if (!keys.Parse(key_sequence)) { - LOG(ERROR) << "error parsing input: '" << key_sequence << "'"; - return False; - } - for (const KeyEvent& key : keys) { - session->ProcessKey(key); - } - return True; -} - RIME_API Bool RimeRegisterModule(RimeModule* module) { if (!module || !module->module_name) return False; @@ -801,59 +46,6 @@ RIME_API RimeModule* RimeFindModule(const char* module_name) { return ModuleManager::instance().Find(module_name); } -RIME_API Bool RimeRunTask(const char* task_name) { - if (!task_name) - return False; - Deployer& deployer(Service::instance().deployer()); - return Bool(deployer.RunTask(task_name)); -} - -RIME_API const char* RimeGetSharedDataDir() { - Deployer& deployer(Service::instance().deployer()); - static string string_path; - string_path = deployer.shared_data_dir.string(); - return string_path.c_str(); -} - -RIME_API const char* RimeGetUserDataDir() { - Deployer& deployer(Service::instance().deployer()); - static string string_path; - string_path = deployer.user_data_dir.string(); - return string_path.c_str(); -} - -RIME_API const char* RimeGetPrebuiltDataDir() { - Deployer& deployer(Service::instance().deployer()); - static string string_path; - string_path = deployer.prebuilt_data_dir.string(); - return string_path.c_str(); -} - -RIME_API const char* RimeGetStagingDir() { - Deployer& deployer(Service::instance().deployer()); - static string string_path; - string_path = deployer.staging_dir.string(); - return string_path.c_str(); -} - -RIME_API const char* RimeGetSyncDir() { - Deployer& deployer(Service::instance().deployer()); - static string string_path; - string_path = deployer.sync_dir.string(); - return string_path.c_str(); -} - -RIME_API const char* RimeGetUserId() { - Deployer& deployer(Service::instance().deployer()); - return deployer.user_id.c_str(); -} - -RIME_API void RimeGetUserDataSyncDir(char* dir, size_t buffer_size) { - Deployer& deployer(Service::instance().deployer()); - string string_path = deployer.user_data_sync_dir().string(); - strncpy(dir, string_path.c_str(), buffer_size); -} - void RimeGetSharedDataDirSecure(char* dir, size_t buffer_size) { string string_path = Service::instance().deployer().shared_data_dir.string(); strncpy(dir, string_path.c_str(), buffer_size); @@ -880,394 +72,6 @@ void RimeGetSyncDirSecure(char* dir, size_t buffer_size) { strncpy(dir, string_path.c_str(), buffer_size); } -RIME_API Bool RimeConfigInit(RimeConfig* config) { - if (!config || config->ptr) - return False; - config->ptr = (void*)new Config; - return True; -} - -RIME_API Bool RimeConfigLoadString(RimeConfig* config, const char* yaml) { - if (!config || !yaml) { - return False; - } - if (!config->ptr) { - RimeConfigInit(config); - } - Config* c = reinterpret_cast(config->ptr); - std::istringstream iss(yaml); - return Bool(c->LoadFromStream(iss)); -} - -RIME_API Bool RimeConfigGetItem(RimeConfig* config, - const char* key, - RimeConfig* value) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - if (!value->ptr) { - RimeConfigInit(value); - } - Config* v = reinterpret_cast(value->ptr); - *v = c->GetItem(key); - return True; -} - -RIME_API Bool RimeConfigSetItem(RimeConfig* config, - const char* key, - RimeConfig* value) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - an item; - if (value) { - if (Config* v = reinterpret_cast(value->ptr)) { - item = v->GetItem(""); - } - } - return Bool(c->SetItem(key, item)); -} - -RIME_API Bool RimeConfigSetBool(RimeConfig* config, - const char* key, - Bool value) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return c->SetBool(key, value != False); -} - -RIME_API Bool RimeConfigSetInt(RimeConfig* config, const char* key, int value) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetInt(key, value)); -} - -RIME_API Bool RimeConfigSetDouble(RimeConfig* config, - const char* key, - double value) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetDouble(key, value)); -} - -RIME_API Bool RimeConfigSetString(RimeConfig* config, - const char* key, - const char* value) { - if (!config || !key || !value) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetString(key, value)); -} - -RIME_API Bool RimeConfigClear(RimeConfig* config, const char* key) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetItem(key, nullptr)); -} - -RIME_API Bool RimeConfigCreateList(RimeConfig* config, const char* key) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetItem(key, New())); -} - -RIME_API Bool RimeConfigCreateMap(RimeConfig* config, const char* key) { - if (!config || !key) - return False; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return False; - return Bool(c->SetItem(key, New())); -} - -RIME_API size_t RimeConfigListSize(RimeConfig* config, const char* key) { - if (!config || !key) - return 0; - Config* c = reinterpret_cast(config->ptr); - if (!c) - return 0; - if (an list = c->GetList(key)) { - return list->size(); - } - return 0; -} - -const char* RimeGetInput(RimeSessionId session_id) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return NULL; - Context* ctx = session->context(); - if (!ctx) - return NULL; - return ctx->input().c_str(); -} - -size_t RimeGetCaretPos(RimeSessionId session_id) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return 0; - Context* ctx = session->context(); - if (!ctx) - return 0; - return ctx->caret_pos(); -} - -static bool do_with_candidate(RimeSessionId session_id, - size_t index, - bool (Context::*verb)(size_t index)) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx) - return False; - return (ctx->*verb)(index); -} - -static bool do_with_candidate_on_current_page( - RimeSessionId session_id, - size_t index, - bool (Context::*verb)(size_t index)) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx || !ctx->HasMenu()) - return False; - Schema* schema = session->schema(); - if (!schema) - return False; - size_t page_size = (size_t)schema->page_size(); - if (index >= page_size) - return False; - const auto& seg(ctx->composition().back()); - size_t page_start = seg.selected_index / page_size * page_size; - return (ctx->*verb)(page_start + index); -} - -Bool RimeChangePage(RimeSessionId session_id, Bool backward) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx || !ctx->HasMenu()) - return False; - Schema* schema = session->schema(); - if (!schema) - return False; - size_t page_size = (size_t)schema->page_size(); - auto& seg(ctx->composition().back()); - size_t current_index = seg.selected_index; - size_t index = - backward ? (current_index <= page_size ? 0 : current_index - page_size) - : (current_index + page_size); - DLOG(INFO) << "current selection: " << current_index << ", flipping " - << (backward ? "backward" : "forward") << ", new selection " - << index; - seg.tags.insert("paging"); - return ctx->Highlight(index); -} - -Bool RimeHighlightCandidate(RimeSessionId session_id, size_t index) { - return do_with_candidate(session_id, index, &Context::Highlight); -} - -Bool RimeHighlightCandidateOnCurrentPage(RimeSessionId session_id, - size_t index) { - return do_with_candidate_on_current_page(session_id, index, - &Context::Highlight); -} - -RIME_API Bool RimeSelectCandidate(RimeSessionId session_id, size_t index) { - return do_with_candidate(session_id, index, &Context::Select); -} - -RIME_API Bool RimeSelectCandidateOnCurrentPage(RimeSessionId session_id, - size_t index) { - return do_with_candidate_on_current_page(session_id, index, &Context::Select); -} - const char* RimeGetVersion() { return RIME_VERSION; } - -RIME_API Bool RimeDeleteCandidate(RimeSessionId session_id, size_t index) { - return do_with_candidate(session_id, index, &Context::DeleteCandidate); -} - -RIME_API Bool RimeDeleteCandidateOnCurrentPage(RimeSessionId session_id, - size_t index) { - return do_with_candidate_on_current_page(session_id, index, - &Context::DeleteCandidate); -} - -void RimeSetCaretPos(RimeSessionId session_id, size_t caret_pos) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return; - Context* ctx = session->context(); - if (!ctx) - return; - return ctx->set_caret_pos(caret_pos); -} - -RimeStringSlice RimeGetStateLabelAbbreviated(RimeSessionId session_id, - const char* option_name, - Bool state, - Bool abbreviated) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return {nullptr, 0}; - Config* config = session->schema()->config(); - if (!config) - return {nullptr, 0}; - Switches switches(config); - StringSlice label = switches.GetStateLabel(option_name, state, abbreviated); - return {label.str, label.length}; -} - -const char* RimeGetStateLabel(RimeSessionId session_id, - const char* option_name, - Bool state) { - return RimeGetStateLabelAbbreviated(session_id, option_name, state, False) - .str; -} - -RIME_API Bool RimeSetInput(RimeSessionId session_id, const char* input) { - an session(Service::instance().GetSession(session_id)); - if (!session) - return False; - Context* ctx = session->context(); - if (!ctx) - return False; - ctx->set_input(input); - return True; -} - -RIME_API RimeApi* rime_get_api() { - static RimeApi s_api = {0}; - if (!s_api.data_size) { - RIME_STRUCT_INIT(RimeApi, s_api); - s_api.setup = &RimeSetup; - s_api.set_notification_handler = &RimeSetNotificationHandler; - s_api.initialize = &RimeInitialize; - s_api.finalize = &RimeFinalize; - s_api.start_maintenance = &RimeStartMaintenance; - s_api.is_maintenance_mode = &RimeIsMaintenancing; - s_api.join_maintenance_thread = &RimeJoinMaintenanceThread; - s_api.deployer_initialize = &RimeDeployerInitialize; - s_api.prebuild = &RimePrebuildAllSchemas; - s_api.deploy = &RimeDeployWorkspace; - s_api.deploy_schema = &RimeDeploySchema; - s_api.deploy_config_file = &RimeDeployConfigFile; - s_api.sync_user_data = &RimeSyncUserData; - s_api.create_session = &RimeCreateSession; - s_api.find_session = &RimeFindSession; - s_api.destroy_session = &RimeDestroySession; - s_api.cleanup_stale_sessions = &RimeCleanupStaleSessions; - s_api.cleanup_all_sessions = &RimeCleanupAllSessions; - s_api.process_key = &RimeProcessKey; - s_api.commit_composition = &RimeCommitComposition; - s_api.clear_composition = &RimeClearComposition; - s_api.get_commit = &RimeGetCommit; - s_api.free_commit = &RimeFreeCommit; - s_api.get_context = &RimeGetContext; - s_api.free_context = &RimeFreeContext; - s_api.get_status = &RimeGetStatus; - s_api.free_status = &RimeFreeStatus; - s_api.set_option = &RimeSetOption; - s_api.get_option = &RimeGetOption; - s_api.set_property = &RimeSetProperty; - s_api.get_property = &RimeGetProperty; - s_api.get_schema_list = &RimeGetSchemaList; - s_api.free_schema_list = &RimeFreeSchemaList; - s_api.get_current_schema = &RimeGetCurrentSchema; - s_api.select_schema = &RimeSelectSchema; - s_api.schema_open = &RimeSchemaOpen; - s_api.config_open = &RimeConfigOpen; - s_api.user_config_open = &RimeUserConfigOpen; - s_api.config_close = &RimeConfigClose; - s_api.config_get_bool = &RimeConfigGetBool; - s_api.config_get_int = &RimeConfigGetInt; - s_api.config_get_double = &RimeConfigGetDouble; - s_api.config_get_string = &RimeConfigGetString; - s_api.config_get_cstring = &RimeConfigGetCString; - s_api.config_update_signature = &RimeConfigUpdateSignature; - s_api.config_begin_map = &RimeConfigBeginMap; - s_api.config_next = &RimeConfigNext; - s_api.config_end = &RimeConfigEnd; - s_api.simulate_key_sequence = &RimeSimulateKeySequence; - s_api.register_module = &RimeRegisterModule; - s_api.find_module = &RimeFindModule; - s_api.run_task = &RimeRunTask; - s_api.get_shared_data_dir = &RimeGetSharedDataDir; - s_api.get_user_data_dir = &RimeGetUserDataDir; - s_api.get_sync_dir = &RimeGetSyncDir; - s_api.get_user_id = &RimeGetUserId; - s_api.get_user_data_sync_dir = &RimeGetUserDataSyncDir; - s_api.config_init = &RimeConfigInit; - s_api.config_load_string = &RimeConfigLoadString; - s_api.config_set_bool = &RimeConfigSetBool; - s_api.config_set_int = &RimeConfigSetInt; - s_api.config_set_double = &RimeConfigSetDouble; - s_api.config_set_string = &RimeConfigSetString; - s_api.config_get_item = &RimeConfigGetItem; - s_api.config_set_item = &RimeConfigSetItem; - s_api.config_clear = &RimeConfigClear; - s_api.config_create_list = &RimeConfigCreateList; - s_api.config_create_map = &RimeConfigCreateMap; - s_api.config_list_size = &RimeConfigListSize; - s_api.config_begin_list = &RimeConfigBeginList; - s_api.get_input = &RimeGetInput; - s_api.get_caret_pos = &RimeGetCaretPos; - s_api.select_candidate = &RimeSelectCandidate; - s_api.get_version = &RimeGetVersion; - s_api.set_caret_pos = &RimeSetCaretPos; - s_api.select_candidate_on_current_page = &RimeSelectCandidateOnCurrentPage; - s_api.candidate_list_begin = &RimeCandidateListBegin; - s_api.candidate_list_next = &RimeCandidateListNext; - s_api.candidate_list_end = &RimeCandidateListEnd; - s_api.candidate_list_from_index = &RimeCandidateListFromIndex; - s_api.get_prebuilt_data_dir = &RimeGetPrebuiltDataDir; - s_api.get_staging_dir = &RimeGetStagingDir; - s_api.commit_proto = nullptr; - s_api.context_proto = nullptr; - s_api.status_proto = nullptr; - s_api.get_state_label = &RimeGetStateLabel; - s_api.delete_candidate = &RimeDeleteCandidate; - s_api.delete_candidate_on_current_page = &RimeDeleteCandidateOnCurrentPage; - s_api.get_state_label_abbreviated = &RimeGetStateLabelAbbreviated; - s_api.set_input = &RimeSetInput; - s_api.get_shared_data_dir_s = &RimeGetSharedDataDirSecure; - s_api.get_user_data_dir_s = &RimeGetUserDataDirSecure; - s_api.get_prebuilt_data_dir_s = &RimeGetPrebuiltDataDirSecure; - s_api.get_staging_dir_s = &RimeGetStagingDirSecure; - s_api.get_sync_dir_s = &RimeGetSyncDirSecure; - s_api.highlight_candidate = &RimeHighlightCandidate; - s_api.highlight_candidate_on_current_page = - &RimeHighlightCandidateOnCurrentPage; - s_api.change_page = &RimeChangePage; - } - return &s_api; -} diff --git a/src/rime_api.h b/src/rime_api.h index 44b2ea3f6b..14f3dbcaf4 100644 --- a/src/rime_api.h +++ b/src/rime_api.h @@ -30,22 +30,27 @@ extern "C" { #define RIME_API #endif /* _WIN32 */ -typedef uintptr_t RimeSessionId; +#ifndef RIME_DEPRECATED +#define RIME_DEPRECATED RIME_API +#endif + +#ifndef RIME_FLAVORED +#define RIME_FLAVORED(name) name +#endif -typedef int Bool; +#ifndef Bool +#define Bool int +#endif #ifndef False #define False 0 #endif + #ifndef True #define True 1 #endif -//! Define the max number of candidates -/*! - * \deprecated There is no limit to the number of candidates in RimeMenu - */ -#define RIME_MAX_NUM_CANDIDATES 10 +typedef uintptr_t RimeSessionId; // Version control #define RIME_STRUCT_INIT(Type, var) \ @@ -61,6 +66,10 @@ typedef int Bool; Type var = {0}; \ RIME_STRUCT_INIT(Type, var); +// tests that member is a non-null pointer in self-versioned struct *p. +#define RIME_PROVIDED(p, member) \ + ((p) && RIME_STRUCT_HAS_MEMBER(*(p), (p)->member) && (p)->member) + //! For passing pointer to capnproto builder as opaque pointer through C API. #define RIME_PROTO_BUILDER void @@ -125,7 +134,7 @@ typedef struct { int num_candidates; RimeCandidate* candidates; char* select_keys; -} RimeMenu; +} RIME_FLAVORED(RimeMenu); /*! * Should be initialized by calling RIME_STRUCT_INIT(Type, var); @@ -139,20 +148,20 @@ typedef struct rime_commit_t { /*! * Should be initialized by calling RIME_STRUCT_INIT(Type, var); */ -typedef struct rime_context_t { +typedef struct RIME_FLAVORED(rime_context_t) { int data_size; // v0.9 RimeComposition composition; - RimeMenu menu; + RIME_FLAVORED(RimeMenu) menu; // v0.9.2 char* commit_text_preview; char** select_labels; -} RimeContext; +} RIME_FLAVORED(RimeContext); /*! * Should be initialized by calling RIME_STRUCT_INIT(Type, var); */ -typedef struct rime_status_t { +typedef struct RIME_FLAVORED(rime_status_t) { int data_size; // v0.9 char* schema_id; @@ -164,7 +173,7 @@ typedef struct rime_status_t { Bool is_simplified; Bool is_traditional; Bool is_ascii_punct; -} RimeStatus; +} RIME_FLAVORED(RimeStatus); typedef struct rime_candidate_list_iterator_t { void* ptr; @@ -195,32 +204,11 @@ typedef struct rime_schema_list_t { RimeSchemaListItem* list; } RimeSchemaList; -typedef void (*RimeNotificationHandler)(void* context_object, - RimeSessionId session_id, - const char* message_type, - const char* message_value); - typedef struct rime_string_slice_t { const char* str; size_t length; } RimeStringSlice; -// Setup - -/*! - * Call this function before accessing any other API. - */ -RIME_API void RimeSetup(RimeTraits* traits); - -/*! - * Pass a C-string constant in the format "rime.x" - * where 'x' is the name of your application. - * Add prefix "rime." to ensure old log files are automatically cleaned. - * \deprecated Use RimeSetup() instead. - */ -RIME_API void RimeSetupLogging(const char* app_name); - -//! Receive notifications /*! * - on loading schema: * + message_type="schema", message_value="luna_pinyin/Luna Pinyin" @@ -236,159 +224,10 @@ RIME_API void RimeSetupLogging(const char* app_name); * every time an event occurs in librime, until RimeFinalize() is called. * when handler is NULL, notification is disabled. */ -RIME_API void RimeSetNotificationHandler(RimeNotificationHandler handler, - void* context_object); - -// Entry and exit - -RIME_API void RimeInitialize(RimeTraits* traits); -RIME_API void RimeFinalize(void); - -RIME_API Bool RimeStartMaintenance(Bool full_check); - -//! \deprecated Use RimeStartMaintenance(full_check = False) instead. -RIME_API Bool RimeStartMaintenanceOnWorkspaceChange(void); -RIME_API Bool RimeIsMaintenancing(void); -RIME_API void RimeJoinMaintenanceThread(void); - -// Deployment - -RIME_API void RimeDeployerInitialize(RimeTraits* traits); -RIME_API Bool RimePrebuildAllSchemas(void); -RIME_API Bool RimeDeployWorkspace(void); -RIME_API Bool RimeDeploySchema(const char* schema_file); -RIME_API Bool RimeDeployConfigFile(const char* file_name, - const char* version_key); - -RIME_API Bool RimeSyncUserData(void); - -// Session management - -RIME_API RimeSessionId RimeCreateSession(void); -RIME_API Bool RimeFindSession(RimeSessionId session_id); -RIME_API Bool RimeDestroySession(RimeSessionId session_id); -RIME_API void RimeCleanupStaleSessions(void); -RIME_API void RimeCleanupAllSessions(void); - -// Input - -RIME_API Bool RimeProcessKey(RimeSessionId session_id, int keycode, int mask); -/*! - * return True if there is unread commit text - */ -RIME_API Bool RimeCommitComposition(RimeSessionId session_id); -RIME_API void RimeClearComposition(RimeSessionId session_id); - -// Output - -RIME_API Bool RimeGetCommit(RimeSessionId session_id, RimeCommit* commit); -RIME_API Bool RimeFreeCommit(RimeCommit* commit); -RIME_API Bool RimeGetContext(RimeSessionId session_id, RimeContext* context); -RIME_API Bool RimeFreeContext(RimeContext* context); -RIME_API Bool RimeGetStatus(RimeSessionId session_id, RimeStatus* status); -RIME_API Bool RimeFreeStatus(RimeStatus* status); - -// Accessing candidate list -RIME_API Bool RimeCandidateListBegin(RimeSessionId session_id, - RimeCandidateListIterator* iterator); -RIME_API Bool RimeCandidateListNext(RimeCandidateListIterator* iterator); -RIME_API void RimeCandidateListEnd(RimeCandidateListIterator* iterator); -RIME_API Bool RimeCandidateListFromIndex(RimeSessionId session_id, - RimeCandidateListIterator* iterator, - int index); -RIME_API Bool RimeSelectCandidate(RimeSessionId session_id, size_t index); -RIME_API Bool RimeSelectCandidateOnCurrentPage(RimeSessionId session_id, - size_t index); -RIME_API Bool RimeDeleteCandidate(RimeSessionId session_id, size_t index); -RIME_API Bool RimeDeleteCandidateOnCurrentPage(RimeSessionId session_id, - size_t index); - -// Runtime options - -RIME_API void RimeSetOption(RimeSessionId session_id, - const char* option, - Bool value); -RIME_API Bool RimeGetOption(RimeSessionId session_id, const char* option); - -RIME_API void RimeSetProperty(RimeSessionId session_id, - const char* prop, - const char* value); -RIME_API Bool RimeGetProperty(RimeSessionId session_id, - const char* prop, - char* value, - size_t buffer_size); - -RIME_API Bool RimeGetSchemaList(RimeSchemaList* schema_list); -RIME_API void RimeFreeSchemaList(RimeSchemaList* schema_list); -RIME_API Bool RimeGetCurrentSchema(RimeSessionId session_id, - char* schema_id, - size_t buffer_size); -RIME_API Bool RimeSelectSchema(RimeSessionId session_id, const char* schema_id); - -// Configuration - -// .schema.yaml -RIME_API Bool RimeSchemaOpen(const char* schema_id, RimeConfig* config); -// .yaml -RIME_API Bool RimeConfigOpen(const char* config_id, RimeConfig* config); -// access config files in user data directory, eg. user.yaml and -// installation.yaml -RIME_API Bool RimeUserConfigOpen(const char* config_id, RimeConfig* config); -RIME_API Bool RimeConfigClose(RimeConfig* config); -RIME_API Bool RimeConfigInit(RimeConfig* config); -RIME_API Bool RimeConfigLoadString(RimeConfig* config, const char* yaml); -// Access config values -RIME_API Bool RimeConfigGetBool(RimeConfig* config, - const char* key, - Bool* value); -RIME_API Bool RimeConfigGetInt(RimeConfig* config, const char* key, int* value); -RIME_API Bool RimeConfigGetDouble(RimeConfig* config, - const char* key, - double* value); -RIME_API Bool RimeConfigGetString(RimeConfig* config, - const char* key, - char* value, - size_t buffer_size); -RIME_API const char* RimeConfigGetCString(RimeConfig* config, const char* key); -RIME_API Bool RimeConfigSetBool(RimeConfig* config, - const char* key, - Bool value); -RIME_API Bool RimeConfigSetInt(RimeConfig* config, const char* key, int value); -RIME_API Bool RimeConfigSetDouble(RimeConfig* config, - const char* key, - double value); -RIME_API Bool RimeConfigSetString(RimeConfig* config, - const char* key, - const char* value); -// Manipulate complex structures -RIME_API Bool RimeConfigGetItem(RimeConfig* config, - const char* key, - RimeConfig* value); -RIME_API Bool RimeConfigSetItem(RimeConfig* config, - const char* key, - RimeConfig* value); -RIME_API Bool RimeConfigClear(RimeConfig* config, const char* key); -RIME_API Bool RimeConfigCreateList(RimeConfig* config, const char* key); -RIME_API Bool RimeConfigCreateMap(RimeConfig* config, const char* key); -RIME_API size_t RimeConfigListSize(RimeConfig* config, const char* key); -RIME_API Bool RimeConfigBeginList(RimeConfigIterator* iterator, - RimeConfig* config, - const char* key); -RIME_API Bool RimeConfigBeginMap(RimeConfigIterator* iterator, - RimeConfig* config, - const char* key); -RIME_API Bool RimeConfigNext(RimeConfigIterator* iterator); -RIME_API void RimeConfigEnd(RimeConfigIterator* iterator); -// Utilities -RIME_API Bool RimeConfigUpdateSignature(RimeConfig* config, const char* signer); - -// Testing - -RIME_API Bool RimeSimulateKeySequence(RimeSessionId session_id, - const char* key_sequence); - -RIME_API Bool RimeSetInput(RimeSessionId session_id, const char* input); -// Module +typedef void (*RimeNotificationHandler)(void* context_object, + RimeSessionId session_id, + const char* message_type, + const char* message_value); /*! * Extend the structure to publish custom data/functions in your specific @@ -410,22 +249,10 @@ typedef struct rime_module_t { RIME_API Bool RimeRegisterModule(RimeModule* module); RIME_API RimeModule* RimeFindModule(const char* module_name); -//! Run a registered task -RIME_API Bool RimeRunTask(const char* task_name); - -//! \deprecated use RimeApi::get_shared_data_dir_s instead. -RIME_API const char* RimeGetSharedDataDir(void); -//! \deprecated use RimeApi::get_user_data_dir_s instead. -RIME_API const char* RimeGetUserDataDir(void); -//! \deprecated use RimeApi::get_sync_dir_s instead. -RIME_API const char* RimeGetSyncDir(void); - -RIME_API const char* RimeGetUserId(void); - /*! The API structure * RimeApi is for rime v1.0+ */ -typedef struct rime_api_t { +typedef struct RIME_FLAVORED(rime_api_t) { int data_size; /*! setup @@ -490,10 +317,12 @@ typedef struct rime_api_t { Bool (*get_commit)(RimeSessionId session_id, RimeCommit* commit); Bool (*free_commit)(RimeCommit* commit); - Bool (*get_context)(RimeSessionId session_id, RimeContext* context); - Bool (*free_context)(RimeContext* ctx); - Bool (*get_status)(RimeSessionId session_id, RimeStatus* status); - Bool (*free_status)(RimeStatus* status); + Bool (*get_context)(RimeSessionId session_id, + RIME_FLAVORED(RimeContext) * context); + Bool (*free_context)(RIME_FLAVORED(RimeContext) * ctx); + Bool (*get_status)(RimeSessionId session_id, + RIME_FLAVORED(RimeStatus) * status); + Bool (*free_status)(RIME_FLAVORED(RimeStatus) * status); // runtime options @@ -672,13 +501,13 @@ typedef struct rime_api_t { size_t index); Bool (*change_page)(RimeSessionId session_id, Bool backward); -} RimeApi; +} RIME_FLAVORED(RimeApi); //! API entry /*! * Acquire the version controlled RimeApi structure. */ -RIME_API RimeApi* rime_get_api(void); +RIME_API RIME_FLAVORED(RimeApi) * RIME_FLAVORED(rime_get_api)(void); //! Clients should test if an api function is available in the current version //! before calling it. diff --git a/src/rime_api_deprecated.h b/src/rime_api_deprecated.h new file mode 100644 index 0000000000..f9725e7ce7 --- /dev/null +++ b/src/rime_api_deprecated.h @@ -0,0 +1,219 @@ +#ifndef RIME_API_DEPRECATED_H_ +#define RIME_API_DEPRECATED_H_ + +#include "rime_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//! Define the max number of candidates +/*! + * \deprecated There is no limit to the number of candidates in RimeMenu + */ +#define RIME_MAX_NUM_CANDIDATES 10 + +// Setup + +/*! + * Call this function before accessing any other API. + */ +RIME_DEPRECATED void RimeSetup(RimeTraits* traits); + +/*! + * Pass a C-string constant in the format "rime.x" + * where 'x' is the name of your application. + * Add prefix "rime." to ensure old log files are automatically cleaned. + * \deprecated Use RimeSetup() instead. + */ +RIME_DEPRECATED void RimeSetupLogging(const char* app_name); + +//! Receive notifications +RIME_DEPRECATED void RimeSetNotificationHandler(RimeNotificationHandler handler, + void* context_object); + +// Entry and exit + +RIME_DEPRECATED void RimeInitialize(RimeTraits* traits); +RIME_DEPRECATED void RimeFinalize(void); + +RIME_DEPRECATED Bool RimeStartMaintenance(Bool full_check); + +//! \deprecated Use RimeStartMaintenance(full_check = False) instead. +RIME_DEPRECATED Bool RimeStartMaintenanceOnWorkspaceChange(void); +RIME_DEPRECATED Bool RimeIsMaintenancing(void); +RIME_DEPRECATED void RimeJoinMaintenanceThread(void); + +// Deployment + +RIME_DEPRECATED void RimeDeployerInitialize(RimeTraits* traits); +RIME_DEPRECATED Bool RimePrebuildAllSchemas(void); +RIME_DEPRECATED Bool RimeDeployWorkspace(void); +RIME_DEPRECATED Bool RimeDeploySchema(const char* schema_file); +RIME_DEPRECATED Bool RimeDeployConfigFile(const char* file_name, + const char* version_key); + +RIME_DEPRECATED Bool RimeSyncUserData(void); + +// Session management + +RIME_DEPRECATED RimeSessionId RimeCreateSession(void); +RIME_DEPRECATED Bool RimeFindSession(RimeSessionId session_id); +RIME_DEPRECATED Bool RimeDestroySession(RimeSessionId session_id); +RIME_DEPRECATED void RimeCleanupStaleSessions(void); +RIME_DEPRECATED void RimeCleanupAllSessions(void); + +// Input + +RIME_DEPRECATED Bool RimeProcessKey(RimeSessionId session_id, + int keycode, + int mask); +/*! + * return True if there is unread commit text + */ +RIME_DEPRECATED Bool RimeCommitComposition(RimeSessionId session_id); +RIME_DEPRECATED void RimeClearComposition(RimeSessionId session_id); + +// Output + +RIME_DEPRECATED Bool RimeGetCommit(RimeSessionId session_id, + RimeCommit* commit); +RIME_DEPRECATED Bool RimeFreeCommit(RimeCommit* commit); +RIME_DEPRECATED Bool RimeGetContext(RimeSessionId session_id, + RIME_FLAVORED(RimeContext) * context); +RIME_DEPRECATED Bool RimeFreeContext(RIME_FLAVORED(RimeContext) * context); +RIME_DEPRECATED Bool RimeGetStatus(RimeSessionId session_id, + RIME_FLAVORED(RimeStatus) * status); +RIME_DEPRECATED Bool RimeFreeStatus(RIME_FLAVORED(RimeStatus) * status); + +// Accessing candidate list +RIME_DEPRECATED Bool +RimeCandidateListBegin(RimeSessionId session_id, + RimeCandidateListIterator* iterator); +RIME_DEPRECATED Bool RimeCandidateListNext(RimeCandidateListIterator* iterator); +RIME_DEPRECATED void RimeCandidateListEnd(RimeCandidateListIterator* iterator); +RIME_DEPRECATED Bool +RimeCandidateListFromIndex(RimeSessionId session_id, + RimeCandidateListIterator* iterator, + int index); +RIME_DEPRECATED Bool RimeSelectCandidate(RimeSessionId session_id, + size_t index); +RIME_DEPRECATED Bool RimeSelectCandidateOnCurrentPage(RimeSessionId session_id, + size_t index); +RIME_DEPRECATED Bool RimeDeleteCandidate(RimeSessionId session_id, + size_t index); +RIME_DEPRECATED Bool RimeDeleteCandidateOnCurrentPage(RimeSessionId session_id, + size_t index); + +// Runtime options + +RIME_DEPRECATED void RimeSetOption(RimeSessionId session_id, + const char* option, + Bool value); +RIME_DEPRECATED Bool RimeGetOption(RimeSessionId session_id, + const char* option); + +RIME_DEPRECATED void RimeSetProperty(RimeSessionId session_id, + const char* prop, + const char* value); +RIME_DEPRECATED Bool RimeGetProperty(RimeSessionId session_id, + const char* prop, + char* value, + size_t buffer_size); + +RIME_DEPRECATED Bool RimeGetSchemaList(RimeSchemaList* schema_list); +RIME_DEPRECATED void RimeFreeSchemaList(RimeSchemaList* schema_list); +RIME_DEPRECATED Bool RimeGetCurrentSchema(RimeSessionId session_id, + char* schema_id, + size_t buffer_size); +RIME_DEPRECATED Bool RimeSelectSchema(RimeSessionId session_id, + const char* schema_id); + +// Configuration + +// .schema.yaml +RIME_DEPRECATED Bool RimeSchemaOpen(const char* schema_id, RimeConfig* config); +// .yaml +RIME_DEPRECATED Bool RimeConfigOpen(const char* config_id, RimeConfig* config); +// access config files in user data directory, eg. user.yaml and +// installation.yaml +RIME_DEPRECATED Bool RimeUserConfigOpen(const char* config_id, + RimeConfig* config); +RIME_DEPRECATED Bool RimeConfigClose(RimeConfig* config); +RIME_DEPRECATED Bool RimeConfigInit(RimeConfig* config); +RIME_DEPRECATED Bool RimeConfigLoadString(RimeConfig* config, const char* yaml); +// Access config values +RIME_DEPRECATED Bool RimeConfigGetBool(RimeConfig* config, + const char* key, + Bool* value); +RIME_DEPRECATED Bool RimeConfigGetInt(RimeConfig* config, + const char* key, + int* value); +RIME_DEPRECATED Bool RimeConfigGetDouble(RimeConfig* config, + const char* key, + double* value); +RIME_DEPRECATED Bool RimeConfigGetString(RimeConfig* config, + const char* key, + char* value, + size_t buffer_size); +RIME_DEPRECATED const char* RimeConfigGetCString(RimeConfig* config, + const char* key); +RIME_DEPRECATED Bool RimeConfigSetBool(RimeConfig* config, + const char* key, + Bool value); +RIME_DEPRECATED Bool RimeConfigSetInt(RimeConfig* config, + const char* key, + int value); +RIME_DEPRECATED Bool RimeConfigSetDouble(RimeConfig* config, + const char* key, + double value); +RIME_DEPRECATED Bool RimeConfigSetString(RimeConfig* config, + const char* key, + const char* value); +// Manipulate complex structures +RIME_DEPRECATED Bool RimeConfigGetItem(RimeConfig* config, + const char* key, + RimeConfig* value); +RIME_DEPRECATED Bool RimeConfigSetItem(RimeConfig* config, + const char* key, + RimeConfig* value); +RIME_DEPRECATED Bool RimeConfigClear(RimeConfig* config, const char* key); +RIME_DEPRECATED Bool RimeConfigCreateList(RimeConfig* config, const char* key); +RIME_DEPRECATED Bool RimeConfigCreateMap(RimeConfig* config, const char* key); +RIME_DEPRECATED size_t RimeConfigListSize(RimeConfig* config, const char* key); +RIME_DEPRECATED Bool RimeConfigBeginList(RimeConfigIterator* iterator, + RimeConfig* config, + const char* key); +RIME_DEPRECATED Bool RimeConfigBeginMap(RimeConfigIterator* iterator, + RimeConfig* config, + const char* key); +RIME_DEPRECATED Bool RimeConfigNext(RimeConfigIterator* iterator); +RIME_DEPRECATED void RimeConfigEnd(RimeConfigIterator* iterator); +// Utilities +RIME_DEPRECATED Bool RimeConfigUpdateSignature(RimeConfig* config, + const char* signer); + +// Testing + +RIME_DEPRECATED Bool RimeSimulateKeySequence(RimeSessionId session_id, + const char* key_sequence); + +RIME_DEPRECATED Bool RimeSetInput(RimeSessionId session_id, const char* input); + +//! Run a registered task +RIME_DEPRECATED Bool RimeRunTask(const char* task_name); + +//! \deprecated use RimeApi::get_shared_data_dir_s instead. +RIME_DEPRECATED const char* RimeGetSharedDataDir(void); +//! \deprecated use RimeApi::get_user_data_dir_s instead. +RIME_DEPRECATED const char* RimeGetUserDataDir(void); +//! \deprecated use RimeApi::get_sync_dir_s instead. +RIME_DEPRECATED const char* RimeGetSyncDir(void); + +RIME_DEPRECATED const char* RimeGetUserId(void); + +#ifdef __cplusplus +} +#endif + +#endif // RIME_API_DEPRECATED_H_ diff --git a/src/rime_api_impl.h b/src/rime_api_impl.h new file mode 100644 index 0000000000..f8f10ccf7e --- /dev/null +++ b/src/rime_api_impl.h @@ -0,0 +1,1230 @@ +// intended to be included multiple times in c++ source files with different +// RIME_FLAVORED macro definitions + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace rime; + +void rime_declare_module_dependencies(); + +RIME_DEPRECATED void RimeSetup(RimeTraits* traits) { + rime_declare_module_dependencies(); + + SetupDeployer(traits); + if (RIME_PROVIDED(traits, app_name)) { + if (RIME_STRUCT_HAS_MEMBER(*traits, traits->min_log_level) && + RIME_STRUCT_HAS_MEMBER(*traits, traits->log_dir)) { + SetupLogging(traits->app_name, traits->min_log_level, traits->log_dir); + } else { + SetupLogging(traits->app_name); + } + } +} + +RIME_DEPRECATED void RimeSetNotificationHandler(RimeNotificationHandler handler, + void* context_object) { + using namespace std::placeholders; + if (handler) { + Service::instance().SetNotificationHandler( + std::bind(handler, context_object, _1, _2, _3)); + } else { + Service::instance().ClearNotificationHandler(); + } +} + +RIME_DEPRECATED void RimeInitialize(RimeTraits* traits) { + SetupDeployer(traits); + LoadModules(RIME_PROVIDED(traits, modules) ? traits->modules + : kDefaultModules); + Service::instance().StartService(); +} + +RIME_DEPRECATED void RimeFinalize() { + Service::instance().deployer().JoinMaintenanceThread(); + Service::instance().StopService(); + Registry::instance().Clear(); + ModuleManager::instance().UnloadModules(); +} + +RIME_DEPRECATED Bool RimeStartMaintenance(Bool full_check) { + LoadModules(kDeployerModules); + Deployer& deployer(Service::instance().deployer()); + deployer.RunTask("clean_old_log_files"); + if (!deployer.RunTask("installation_update")) { + return False; + } + if (!full_check) { + TaskInitializer args{ + vector{ + deployer.user_data_dir, + deployer.shared_data_dir, + }, + }; + if (!deployer.RunTask("detect_modifications", args)) { + return False; + } + LOG(INFO) << "changes detected; starting maintenance."; + } + deployer.ScheduleTask("workspace_update"); + deployer.ScheduleTask("user_dict_upgrade"); + deployer.ScheduleTask("cleanup_trash"); + deployer.StartMaintenance(); + return True; +} + +RIME_DEPRECATED Bool RimeStartMaintenanceOnWorkspaceChange() { + return RimeStartMaintenance(False); +} + +RIME_DEPRECATED Bool RimeIsMaintenancing() { + Deployer& deployer(Service::instance().deployer()); + return Bool(deployer.IsMaintenanceMode()); +} + +RIME_DEPRECATED void RimeJoinMaintenanceThread() { + Deployer& deployer(Service::instance().deployer()); + deployer.JoinMaintenanceThread(); +} + +// deployment + +RIME_DEPRECATED void RimeDeployerInitialize(RimeTraits* traits) { + SetupDeployer(traits); + LoadModules(RIME_PROVIDED(traits, modules) ? traits->modules + : kDeployerModules); +} + +RIME_DEPRECATED Bool RimePrebuildAllSchemas() { + Deployer& deployer(Service::instance().deployer()); + return Bool(deployer.RunTask("prebuild_all_schemas")); +} + +RIME_DEPRECATED Bool RimeDeployWorkspace() { + Deployer& deployer(Service::instance().deployer()); + return Bool(deployer.RunTask("installation_update") && + deployer.RunTask("workspace_update") && + deployer.RunTask("user_dict_upgrade") && + deployer.RunTask("cleanup_trash")); +} + +RIME_DEPRECATED Bool RimeDeploySchema(const char* schema_file) { + Deployer& deployer(Service::instance().deployer()); + return Bool(deployer.RunTask("schema_update", path(schema_file))); +} + +RIME_DEPRECATED Bool RimeDeployConfigFile(const char* file_name, + const char* version_key) { + Deployer& deployer(Service::instance().deployer()); + TaskInitializer args(make_pair(file_name, version_key)); + return Bool(deployer.RunTask("config_file_update", args)); +} + +RIME_DEPRECATED Bool RimeSyncUserData() { + Service::instance().CleanupAllSessions(); + Deployer& deployer(Service::instance().deployer()); + deployer.ScheduleTask("installation_update"); + deployer.ScheduleTask("backup_config_files"); + deployer.ScheduleTask("user_dict_sync"); + return Bool(deployer.StartMaintenance()); +} + +// session management + +RIME_DEPRECATED RimeSessionId RimeCreateSession() { + return Service::instance().CreateSession(); +} + +RIME_DEPRECATED Bool RimeFindSession(RimeSessionId session_id) { + return Bool(session_id && Service::instance().GetSession(session_id)); +} + +RIME_DEPRECATED Bool RimeDestroySession(RimeSessionId session_id) { + return Bool(Service::instance().DestroySession(session_id)); +} + +RIME_DEPRECATED void RimeCleanupStaleSessions() { + Service::instance().CleanupStaleSessions(); +} + +RIME_DEPRECATED void RimeCleanupAllSessions() { + Service::instance().CleanupAllSessions(); +} + +// input + +RIME_DEPRECATED Bool RimeProcessKey(RimeSessionId session_id, + int keycode, + int mask) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + return Bool(session->ProcessKey(KeyEvent(keycode, mask))); +} + +RIME_DEPRECATED Bool RimeCommitComposition(RimeSessionId session_id) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + return Bool(session->CommitComposition()); +} + +RIME_DEPRECATED void RimeClearComposition(RimeSessionId session_id) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return; + session->ClearComposition(); +} + +// output + +static void rime_candidate_copy(RimeCandidate* dest, const an& src) { + dest->text = new char[src->text().length() + 1]; + std::strcpy(dest->text, src->text().c_str()); + string comment(src->comment()); + if (!comment.empty()) { + dest->comment = new char[comment.length() + 1]; + std::strcpy(dest->comment, comment.c_str()); + } else { + dest->comment = nullptr; + } + dest->reserved = nullptr; +} + +RIME_DEPRECATED Bool RimeGetContext(RimeSessionId session_id, + RIME_FLAVORED(RimeContext) * context) { + if (!context || context->data_size <= 0) + return False; + RIME_STRUCT_CLEAR(*context); + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx) + return False; + if (ctx->IsComposing()) { + Preedit preedit = ctx->GetPreedit(); + context->composition.length = preedit.text.length(); + context->composition.preedit = new char[preedit.text.length() + 1]; + std::strcpy(context->composition.preedit, preedit.text.c_str()); + context->composition.cursor_pos = preedit.caret_pos; + context->composition.sel_start = preedit.sel_start; + context->composition.sel_end = preedit.sel_end; + if (RIME_STRUCT_HAS_MEMBER(*context, context->commit_text_preview)) { + string commit_text(ctx->GetCommitText()); + if (!commit_text.empty()) { + context->commit_text_preview = new char[commit_text.length() + 1]; + std::strcpy(context->commit_text_preview, commit_text.c_str()); + } + } + } + if (ctx->HasMenu()) { + Segment& seg(ctx->composition().back()); + int page_size = 5; + Schema* schema = session->schema(); + if (schema) + page_size = schema->page_size(); + int selected_index = seg.selected_index; + int page_no = selected_index / page_size; + the page(seg.menu->CreatePage(page_size, page_no)); + if (page) { + context->menu.page_size = page_size; + context->menu.page_no = page_no; + context->menu.is_last_page = Bool(page->is_last_page); + context->menu.highlighted_candidate_index = selected_index % page_size; + int i = 0; + context->menu.num_candidates = page->candidates.size(); + context->menu.candidates = new RimeCandidate[page->candidates.size()]; + for (const an& cand : page->candidates) { + RimeCandidate* dest = &context->menu.candidates[i++]; + rime_candidate_copy(dest, cand); + } + if (schema) { + const string& select_keys(schema->select_keys()); + if (!select_keys.empty()) { + context->menu.select_keys = new char[select_keys.length() + 1]; + std::strcpy(context->menu.select_keys, select_keys.c_str()); + } + Config* config = schema->config(); + an select_labels = + config->GetList("menu/alternative_select_labels"); + if (select_labels && (size_t)page_size <= select_labels->size()) { + context->select_labels = new char*[page_size]; + for (size_t i = 0; i < (size_t)page_size; ++i) { + an value = select_labels->GetValueAt(i); + string label = value->str(); + context->select_labels[i] = new char[label.length() + 1]; + std::strcpy(context->select_labels[i], label.c_str()); + } + } + } + } + } + return True; +} + +RIME_DEPRECATED Bool RimeFreeContext(RIME_FLAVORED(RimeContext) * context) { + if (!context || context->data_size <= 0) + return False; + delete[] context->composition.preedit; + for (int i = 0; i < context->menu.num_candidates; ++i) { + delete[] context->menu.candidates[i].text; + delete[] context->menu.candidates[i].comment; + } + delete[] context->menu.candidates; + delete[] context->menu.select_keys; + if (RIME_STRUCT_HAS_MEMBER(*context, context->select_labels) && + context->select_labels) { + for (int i = 0; i < context->menu.page_size; ++i) { + delete[] context->select_labels[i]; + } + delete[] context->select_labels; + } + if (RIME_STRUCT_HAS_MEMBER(*context, context->commit_text_preview)) { + delete[] context->commit_text_preview; + } + RIME_STRUCT_CLEAR(*context); + return True; +} + +RIME_DEPRECATED Bool RimeGetCommit(RimeSessionId session_id, + RimeCommit* commit) { + if (!commit) + return False; + RIME_STRUCT_CLEAR(*commit); + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + const string& commit_text(session->commit_text()); + if (!commit_text.empty()) { + commit->text = new char[commit_text.length() + 1]; + std::strcpy(commit->text, commit_text.c_str()); + session->ResetCommitText(); + return True; + } + return False; +} + +RIME_DEPRECATED Bool RimeFreeCommit(RimeCommit* commit) { + if (!commit) + return False; + delete[] commit->text; + RIME_STRUCT_CLEAR(*commit); + return True; +} + +RIME_DEPRECATED Bool RimeGetStatus(RimeSessionId session_id, + RIME_FLAVORED(RimeStatus) * status) { + if (!status || status->data_size <= 0) + return False; + RIME_STRUCT_CLEAR(*status); + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Schema* schema = session->schema(); + Context* ctx = session->context(); + if (!schema || !ctx) + return False; + status->schema_id = new char[schema->schema_id().length() + 1]; + std::strcpy(status->schema_id, schema->schema_id().c_str()); + status->schema_name = new char[schema->schema_name().length() + 1]; + std::strcpy(status->schema_name, schema->schema_name().c_str()); + status->is_disabled = Bool(Service::instance().disabled()); + status->is_composing = Bool(ctx->IsComposing()); + status->is_ascii_mode = Bool(ctx->get_option("ascii_mode")); + status->is_full_shape = Bool(ctx->get_option("full_shape")); + status->is_simplified = Bool(ctx->get_option("simplification")); + status->is_traditional = Bool(ctx->get_option("traditional")); + status->is_ascii_punct = Bool(ctx->get_option("ascii_punct")); + return True; +} + +RIME_DEPRECATED Bool RimeFreeStatus(RIME_FLAVORED(RimeStatus) * status) { + if (!status || status->data_size <= 0) + return False; + delete[] status->schema_id; + delete[] status->schema_name; + RIME_STRUCT_CLEAR(*status); + return True; +} + +// accessing candidate list + +RIME_DEPRECATED Bool +RimeCandidateListFromIndex(RimeSessionId session_id, + RimeCandidateListIterator* iterator, + int index) { + if (!iterator) + return False; + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx || !ctx->HasMenu()) + return False; + memset(iterator, 0, sizeof(RimeCandidateListIterator)); + iterator->ptr = ctx->composition().back().menu.get(); + iterator->index = index - 1; + return True; +} + +RIME_DEPRECATED Bool +RimeCandidateListBegin(RimeSessionId session_id, + RimeCandidateListIterator* iterator) { + return RimeCandidateListFromIndex(session_id, iterator, 0); +} + +RIME_DEPRECATED Bool +RimeCandidateListNext(RimeCandidateListIterator* iterator) { + if (!iterator) + return False; + Menu* menu = reinterpret_cast(iterator->ptr); + if (!menu) + return False; + ++iterator->index; + if (auto cand = menu->GetCandidateAt((size_t)iterator->index)) { + delete[] iterator->candidate.text; + delete[] iterator->candidate.comment; + rime_candidate_copy(&iterator->candidate, cand); + return True; + } + return False; +} + +RIME_DEPRECATED void RimeCandidateListEnd(RimeCandidateListIterator* iterator) { + if (!iterator) + return; + delete[] iterator->candidate.text; + delete[] iterator->candidate.comment; + memset(iterator, 0, sizeof(RimeCandidateListIterator)); +} + +// runtime options + +RIME_DEPRECATED void RimeSetOption(RimeSessionId session_id, + const char* option, + Bool value) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return; + Context* ctx = session->context(); + if (!ctx) + return; + ctx->set_option(option, !!value); +} + +RIME_DEPRECATED Bool RimeGetOption(RimeSessionId session_id, + const char* option) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx) + return False; + return Bool(ctx->get_option(option)); +} + +RIME_DEPRECATED void RimeSetProperty(RimeSessionId session_id, + const char* prop, + const char* value) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return; + Context* ctx = session->context(); + if (!ctx) + return; + ctx->set_property(prop, value); +} + +RIME_DEPRECATED Bool RimeGetProperty(RimeSessionId session_id, + const char* prop, + char* value, + size_t buffer_size) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx) + return False; + string str_value(ctx->get_property(prop)); + if (str_value.empty()) + return False; + strncpy(value, str_value.c_str(), buffer_size); + return True; +} + +RIME_DEPRECATED Bool RimeGetSchemaList(RimeSchemaList* output) { + if (!output) + return False; + output->size = 0; + output->list = NULL; + Schema default_schema; + Config* config = default_schema.config(); + if (!config) + return False; + an schema_list = config->GetList("schema_list"); + if (!schema_list || schema_list->size() == 0) + return False; + output->list = new RimeSchemaListItem[schema_list->size()]; + for (size_t i = 0; i < schema_list->size(); ++i) { + an item = As(schema_list->GetAt(i)); + if (!item) + continue; + an schema_property = item->GetValue("schema"); + if (!schema_property) + continue; + const string& schema_id(schema_property->str()); + RimeSchemaListItem& x(output->list[output->size]); + x.schema_id = new char[schema_id.length() + 1]; + strcpy(x.schema_id, schema_id.c_str()); + Schema schema(schema_id); + x.name = new char[schema.schema_name().length() + 1]; + strcpy(x.name, schema.schema_name().c_str()); + x.reserved = NULL; + ++output->size; + } + if (output->size == 0) { + delete[] output->list; + output->list = NULL; + return False; + } + return True; +} + +RIME_DEPRECATED void RimeFreeSchemaList(RimeSchemaList* schema_list) { + if (!schema_list) + return; + if (schema_list->list) { + for (size_t i = 0; i < schema_list->size; ++i) { + delete[] schema_list->list[i].schema_id; + delete[] schema_list->list[i].name; + } + delete[] schema_list->list; + } + schema_list->size = 0; + schema_list->list = NULL; +} + +RIME_DEPRECATED Bool RimeGetCurrentSchema(RimeSessionId session_id, + char* schema_id, + size_t buffer_size) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Schema* schema = session->schema(); + if (!schema) + return False; + strncpy(schema_id, schema->schema_id().c_str(), buffer_size); + return True; +} + +RIME_DEPRECATED Bool RimeSelectSchema(RimeSessionId session_id, + const char* schema_id) { + if (!schema_id) + return False; + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + session->ApplySchema(new Schema(schema_id)); + return True; +} + +// config + +static Bool open_config_in_component(const char* config_component, + const char* config_id, + RimeConfig* config) { + if (!config_id || !config) + return False; + Config::Component* cc = Config::Require(config_component); + if (!cc) + return False; + Config* c = cc->Create(config_id); + if (!c) + return False; + config->ptr = (void*)c; + return True; +} + +RIME_DEPRECATED Bool RimeSchemaOpen(const char* schema_id, RimeConfig* config) { + return open_config_in_component("schema", schema_id, config); +} + +RIME_DEPRECATED Bool RimeConfigOpen(const char* config_id, RimeConfig* config) { + return open_config_in_component("config", config_id, config); +} + +RIME_DEPRECATED Bool RimeUserConfigOpen(const char* config_id, + RimeConfig* config) { + return open_config_in_component("user_config", config_id, config); +} + +RIME_DEPRECATED Bool RimeConfigClose(RimeConfig* config) { + if (!config || !config->ptr) + return False; + Config* c = reinterpret_cast(config->ptr); + delete c; + config->ptr = NULL; + return True; +} + +RIME_DEPRECATED Bool RimeConfigGetBool(RimeConfig* config, + const char* key, + Bool* value) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + bool bool_value = false; + if (c->GetBool(key, &bool_value)) { + *value = Bool(bool_value); + return True; + } + return False; +} + +RIME_DEPRECATED Bool RimeConfigGetInt(RimeConfig* config, + const char* key, + int* value) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + return Bool(c->GetInt(key, value)); +} + +RIME_DEPRECATED Bool RimeConfigGetDouble(RimeConfig* config, + const char* key, + double* value) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + return Bool(c->GetDouble(key, value)); +} + +RIME_DEPRECATED Bool RimeConfigGetString(RimeConfig* config, + const char* key, + char* value, + size_t buffer_size) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + string str_value; + if (c->GetString(key, &str_value)) { + std::strncpy(value, str_value.c_str(), buffer_size); + return True; + } + return False; +} + +RIME_DEPRECATED const char* RimeConfigGetCString(RimeConfig* config, + const char* key) { + if (!config || !key) + return NULL; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return NULL; + if (an v = c->GetValue(key)) { + return v->str().c_str(); + } + return NULL; +} + +RIME_DEPRECATED Bool RimeConfigUpdateSignature(RimeConfig* config, + const char* signer) { + if (!config || !signer) + return False; + Config* c = reinterpret_cast(config->ptr); + Deployer& deployer(Service::instance().deployer()); + Signature sig(signer); + return Bool(sig.Sign(c, &deployer)); +} + +template +struct RimeConfigIteratorImpl { + typename T::Iterator iter; + typename T::Iterator end; + string prefix; + string key; + string path; + RimeConfigIteratorImpl(T& container, const string& root_path) + : iter(container.begin()), end(container.end()) { + if (root_path.empty() || root_path == "/") { + // prefix is empty + } else { + prefix = root_path + "/"; + } + } +}; + +RIME_DEPRECATED Bool RimeConfigBeginList(RimeConfigIterator* iterator, + RimeConfig* config, + const char* key) { + if (!iterator || !config || !key) + return False; + iterator->list = NULL; + iterator->map = NULL; + iterator->index = -1; + iterator->key = NULL; + iterator->path = NULL; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + an list = c->GetList(key); + if (!list) + return False; + iterator->list = new RimeConfigIteratorImpl(*list, key); + return True; +} + +RIME_DEPRECATED Bool RimeConfigBeginMap(RimeConfigIterator* iterator, + RimeConfig* config, + const char* key) { + if (!iterator || !config || !key) + return False; + iterator->list = NULL; + iterator->map = NULL; + iterator->index = -1; + iterator->key = NULL; + iterator->path = NULL; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + an m = c->GetMap(key); + if (!m) + return False; + iterator->map = new RimeConfigIteratorImpl(*m, key); + return True; +} + +RIME_DEPRECATED Bool RimeConfigNext(RimeConfigIterator* iterator) { + if (!iterator->list && !iterator->map) + return False; + if (iterator->list) { + RimeConfigIteratorImpl* p = + reinterpret_cast*>(iterator->list); + if (!p) + return False; + if (++iterator->index > 0) + ++p->iter; + if (p->iter == p->end) + return False; + std::ostringstream key; + key << "@" << iterator->index; + p->key = key.str(); + p->path = p->prefix + p->key; + iterator->key = p->key.c_str(); + iterator->path = p->path.c_str(); + return True; + } + if (iterator->map) { + RimeConfigIteratorImpl* p = + reinterpret_cast*>(iterator->map); + if (!p) + return False; + if (++iterator->index > 0) + ++p->iter; + if (p->iter == p->end) + return False; + p->key = p->iter->first; + p->path = p->prefix + p->key; + iterator->key = p->key.c_str(); + iterator->path = p->path.c_str(); + return True; + } + return False; +} + +RIME_DEPRECATED void RimeConfigEnd(RimeConfigIterator* iterator) { + if (!iterator) + return; + if (iterator->list) + delete reinterpret_cast*>( + iterator->list); + if (iterator->map) + delete reinterpret_cast*>(iterator->map); + memset(iterator, 0, sizeof(RimeConfigIterator)); +} + +RIME_DEPRECATED Bool RimeSimulateKeySequence(RimeSessionId session_id, + const char* key_sequence) { + LOG(INFO) << "simulate key sequence: " << key_sequence; + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + KeySequence keys; + if (!keys.Parse(key_sequence)) { + LOG(ERROR) << "error parsing input: '" << key_sequence << "'"; + return False; + } + for (const KeyEvent& key : keys) { + session->ProcessKey(key); + } + return True; +} + +RIME_DEPRECATED Bool RimeRunTask(const char* task_name) { + if (!task_name) + return False; + Deployer& deployer(Service::instance().deployer()); + return Bool(deployer.RunTask(task_name)); +} + +RIME_DEPRECATED const char* RimeGetSharedDataDir() { + Deployer& deployer(Service::instance().deployer()); + static string string_path; + string_path = deployer.shared_data_dir.string(); + return string_path.c_str(); +} + +RIME_DEPRECATED const char* RimeGetUserDataDir() { + Deployer& deployer(Service::instance().deployer()); + static string string_path; + string_path = deployer.user_data_dir.string(); + return string_path.c_str(); +} + +RIME_DEPRECATED const char* RimeGetPrebuiltDataDir() { + Deployer& deployer(Service::instance().deployer()); + static string string_path; + string_path = deployer.prebuilt_data_dir.string(); + return string_path.c_str(); +} + +RIME_DEPRECATED const char* RimeGetStagingDir() { + Deployer& deployer(Service::instance().deployer()); + static string string_path; + string_path = deployer.staging_dir.string(); + return string_path.c_str(); +} + +RIME_DEPRECATED const char* RimeGetSyncDir() { + Deployer& deployer(Service::instance().deployer()); + static string string_path; + string_path = deployer.sync_dir.string(); + return string_path.c_str(); +} + +RIME_DEPRECATED const char* RimeGetUserId() { + Deployer& deployer(Service::instance().deployer()); + return deployer.user_id.c_str(); +} + +RIME_DEPRECATED void RimeGetUserDataSyncDir(char* dir, size_t buffer_size) { + Deployer& deployer(Service::instance().deployer()); + string string_path = deployer.user_data_sync_dir().string(); + strncpy(dir, string_path.c_str(), buffer_size); +} + +RIME_DEPRECATED Bool RimeConfigInit(RimeConfig* config) { + if (!config || config->ptr) + return False; + config->ptr = (void*)new Config; + return True; +} + +RIME_DEPRECATED Bool RimeConfigLoadString(RimeConfig* config, + const char* yaml) { + if (!config || !yaml) { + return False; + } + if (!config->ptr) { + RimeConfigInit(config); + } + Config* c = reinterpret_cast(config->ptr); + std::istringstream iss(yaml); + return Bool(c->LoadFromStream(iss)); +} + +RIME_DEPRECATED Bool RimeConfigGetItem(RimeConfig* config, + const char* key, + RimeConfig* value) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + if (!value->ptr) { + RimeConfigInit(value); + } + Config* v = reinterpret_cast(value->ptr); + *v = c->GetItem(key); + return True; +} + +RIME_DEPRECATED Bool RimeConfigSetItem(RimeConfig* config, + const char* key, + RimeConfig* value) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + an item; + if (value) { + if (Config* v = reinterpret_cast(value->ptr)) { + item = v->GetItem(""); + } + } + return Bool(c->SetItem(key, item)); +} + +RIME_DEPRECATED Bool RimeConfigSetBool(RimeConfig* config, + const char* key, + Bool value) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return c->SetBool(key, value != False); +} + +RIME_DEPRECATED Bool RimeConfigSetInt(RimeConfig* config, + const char* key, + int value) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetInt(key, value)); +} + +RIME_DEPRECATED Bool RimeConfigSetDouble(RimeConfig* config, + const char* key, + double value) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetDouble(key, value)); +} + +RIME_DEPRECATED Bool RimeConfigSetString(RimeConfig* config, + const char* key, + const char* value) { + if (!config || !key || !value) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetString(key, value)); +} + +RIME_DEPRECATED Bool RimeConfigClear(RimeConfig* config, const char* key) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetItem(key, nullptr)); +} + +RIME_DEPRECATED Bool RimeConfigCreateList(RimeConfig* config, const char* key) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetItem(key, New())); +} + +RIME_DEPRECATED Bool RimeConfigCreateMap(RimeConfig* config, const char* key) { + if (!config || !key) + return False; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return False; + return Bool(c->SetItem(key, New())); +} + +RIME_DEPRECATED size_t RimeConfigListSize(RimeConfig* config, const char* key) { + if (!config || !key) + return 0; + Config* c = reinterpret_cast(config->ptr); + if (!c) + return 0; + if (an list = c->GetList(key)) { + return list->size(); + } + return 0; +} + +static bool do_with_candidate(RimeSessionId session_id, + size_t index, + bool (Context::*verb)(size_t index)) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return false; + Context* ctx = session->context(); + if (!ctx) + return false; + return (ctx->*verb)(index); +} + +static bool do_with_candidate_on_current_page( + RimeSessionId session_id, + size_t index, + bool (Context::*verb)(size_t index)) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return false; + Context* ctx = session->context(); + if (!ctx || !ctx->HasMenu()) + return false; + Schema* schema = session->schema(); + if (!schema) + return false; + size_t page_size = (size_t)schema->page_size(); + if (index >= page_size) + return false; + const auto& seg(ctx->composition().back()); + size_t page_start = seg.selected_index / page_size * page_size; + return (ctx->*verb)(page_start + index); +} + +static Bool RimeChangePage(RimeSessionId session_id, Bool backward) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx || !ctx->HasMenu()) + return False; + Schema* schema = session->schema(); + if (!schema) + return False; + size_t page_size = (size_t)schema->page_size(); + auto& seg(ctx->composition().back()); + size_t current_index = seg.selected_index; + size_t index = + backward ? (current_index <= page_size ? 0 : current_index - page_size) + : (current_index + page_size); + DLOG(INFO) << "current selection: " << current_index << ", flipping " + << (backward ? "backward" : "forward") << ", new selection " + << index; + seg.tags.insert("paging"); + return Bool(ctx->Highlight(index)); +} + +static Bool RimeHighlightCandidate(RimeSessionId session_id, size_t index) { + return (Bool)do_with_candidate(session_id, index, &Context::Highlight); +} + +static Bool RimeHighlightCandidateOnCurrentPage(RimeSessionId session_id, + size_t index) { + return (Bool)do_with_candidate_on_current_page(session_id, index, + &Context::Highlight); +} + +RIME_DEPRECATED Bool RimeSelectCandidate(RimeSessionId session_id, + size_t index) { + return (Bool)do_with_candidate(session_id, index, &Context::Select); +} + +RIME_DEPRECATED Bool RimeSelectCandidateOnCurrentPage(RimeSessionId session_id, + size_t index) { + return (Bool)do_with_candidate_on_current_page(session_id, index, + &Context::Select); +} + +RIME_DEPRECATED Bool RimeDeleteCandidate(RimeSessionId session_id, + size_t index) { + return (Bool)do_with_candidate(session_id, index, &Context::DeleteCandidate); +} + +RIME_DEPRECATED Bool RimeDeleteCandidateOnCurrentPage(RimeSessionId session_id, + size_t index) { + return (Bool)do_with_candidate_on_current_page(session_id, index, + &Context::DeleteCandidate); +} + +static const char* RimeGetInput(RimeSessionId session_id) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return NULL; + Context* ctx = session->context(); + if (!ctx) + return NULL; + return ctx->input().c_str(); +} + +RIME_DEPRECATED Bool RimeSetInput(RimeSessionId session_id, const char* input) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return False; + Context* ctx = session->context(); + if (!ctx) + return False; + ctx->set_input(input); + return True; +} + +static size_t RimeGetCaretPos(RimeSessionId session_id) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return 0; + Context* ctx = session->context(); + if (!ctx) + return 0; + return ctx->caret_pos(); +} + +static void RimeSetCaretPos(RimeSessionId session_id, size_t caret_pos) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return; + Context* ctx = session->context(); + if (!ctx) + return; + return ctx->set_caret_pos(caret_pos); +} + +static RimeStringSlice RimeGetStateLabelAbbreviated(RimeSessionId session_id, + const char* option_name, + Bool state, + Bool abbreviated) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return {nullptr, 0}; + Config* config = session->schema()->config(); + if (!config) + return {nullptr, 0}; + Switches switches(config); + StringSlice label = switches.GetStateLabel(option_name, state, abbreviated); + return {label.str, label.length}; +} + +static const char* RimeGetStateLabel(RimeSessionId session_id, + const char* option_name, + Bool state) { + return RimeGetStateLabelAbbreviated(session_id, option_name, state, False) + .str; +} + +void RimeGetSharedDataDirSecure(char* dir, size_t buffer_size); +void RimeGetUserDataDirSecure(char* dir, size_t buffer_size); +void RimeGetPrebuiltDataDirSecure(char* dir, size_t buffer_size); +void RimeGetStagingDirSecure(char* dir, size_t buffer_size); +void RimeGetSyncDirSecure(char* dir, size_t buffer_size); +const char* RimeGetVersion(); + +RIME_API RIME_FLAVORED(RimeApi) * RIME_FLAVORED(rime_get_api)() { + static RIME_FLAVORED(RimeApi) s_api = {0}; + if (!s_api.data_size) { + RIME_STRUCT_INIT(RIME_FLAVORED(RimeApi), s_api); + s_api.setup = &RimeSetup; + s_api.set_notification_handler = &RimeSetNotificationHandler; + s_api.initialize = &RimeInitialize; + s_api.finalize = &RimeFinalize; + s_api.start_maintenance = &RimeStartMaintenance; + s_api.is_maintenance_mode = &RimeIsMaintenancing; + s_api.join_maintenance_thread = &RimeJoinMaintenanceThread; + s_api.deployer_initialize = &RimeDeployerInitialize; + s_api.prebuild = &RimePrebuildAllSchemas; + s_api.deploy = &RimeDeployWorkspace; + s_api.deploy_schema = &RimeDeploySchema; + s_api.deploy_config_file = &RimeDeployConfigFile; + s_api.sync_user_data = &RimeSyncUserData; + s_api.create_session = &RimeCreateSession; + s_api.find_session = &RimeFindSession; + s_api.destroy_session = &RimeDestroySession; + s_api.cleanup_stale_sessions = &RimeCleanupStaleSessions; + s_api.cleanup_all_sessions = &RimeCleanupAllSessions; + s_api.process_key = &RimeProcessKey; + s_api.commit_composition = &RimeCommitComposition; + s_api.clear_composition = &RimeClearComposition; + s_api.get_commit = &RimeGetCommit; + s_api.free_commit = &RimeFreeCommit; + s_api.get_context = &RimeGetContext; + s_api.free_context = &RimeFreeContext; + s_api.get_status = &RimeGetStatus; + s_api.free_status = &RimeFreeStatus; + s_api.set_option = &RimeSetOption; + s_api.get_option = &RimeGetOption; + s_api.set_property = &RimeSetProperty; + s_api.get_property = &RimeGetProperty; + s_api.get_schema_list = &RimeGetSchemaList; + s_api.free_schema_list = &RimeFreeSchemaList; + s_api.get_current_schema = &RimeGetCurrentSchema; + s_api.select_schema = &RimeSelectSchema; + s_api.schema_open = &RimeSchemaOpen; + s_api.config_open = &RimeConfigOpen; + s_api.user_config_open = &RimeUserConfigOpen; + s_api.config_close = &RimeConfigClose; + s_api.config_get_bool = &RimeConfigGetBool; + s_api.config_get_int = &RimeConfigGetInt; + s_api.config_get_double = &RimeConfigGetDouble; + s_api.config_get_string = &RimeConfigGetString; + s_api.config_get_cstring = &RimeConfigGetCString; + s_api.config_update_signature = &RimeConfigUpdateSignature; + s_api.config_begin_map = &RimeConfigBeginMap; + s_api.config_next = &RimeConfigNext; + s_api.config_end = &RimeConfigEnd; + s_api.simulate_key_sequence = &RimeSimulateKeySequence; + s_api.register_module = &RimeRegisterModule; + s_api.find_module = &RimeFindModule; + s_api.run_task = &RimeRunTask; + s_api.get_shared_data_dir = &RimeGetSharedDataDir; + s_api.get_user_data_dir = &RimeGetUserDataDir; + s_api.get_sync_dir = &RimeGetSyncDir; + s_api.get_user_id = &RimeGetUserId; + s_api.get_user_data_sync_dir = &RimeGetUserDataSyncDir; + s_api.config_init = &RimeConfigInit; + s_api.config_load_string = &RimeConfigLoadString; + s_api.config_set_bool = &RimeConfigSetBool; + s_api.config_set_int = &RimeConfigSetInt; + s_api.config_set_double = &RimeConfigSetDouble; + s_api.config_set_string = &RimeConfigSetString; + s_api.config_get_item = &RimeConfigGetItem; + s_api.config_set_item = &RimeConfigSetItem; + s_api.config_clear = &RimeConfigClear; + s_api.config_create_list = &RimeConfigCreateList; + s_api.config_create_map = &RimeConfigCreateMap; + s_api.config_list_size = &RimeConfigListSize; + s_api.config_begin_list = &RimeConfigBeginList; + s_api.get_input = &RimeGetInput; + s_api.get_caret_pos = &RimeGetCaretPos; + s_api.select_candidate = &RimeSelectCandidate; + s_api.get_version = &RimeGetVersion; + s_api.set_caret_pos = &RimeSetCaretPos; + s_api.select_candidate_on_current_page = &RimeSelectCandidateOnCurrentPage; + s_api.candidate_list_begin = &RimeCandidateListBegin; + s_api.candidate_list_next = &RimeCandidateListNext; + s_api.candidate_list_end = &RimeCandidateListEnd; + s_api.candidate_list_from_index = &RimeCandidateListFromIndex; + s_api.get_prebuilt_data_dir = &RimeGetPrebuiltDataDir; + s_api.get_staging_dir = &RimeGetStagingDir; + s_api.commit_proto = nullptr; + s_api.context_proto = nullptr; + s_api.status_proto = nullptr; + s_api.get_state_label = &RimeGetStateLabel; + s_api.delete_candidate = &RimeDeleteCandidate; + s_api.delete_candidate_on_current_page = &RimeDeleteCandidateOnCurrentPage; + s_api.get_state_label_abbreviated = &RimeGetStateLabelAbbreviated; + s_api.set_input = &RimeSetInput; + s_api.get_shared_data_dir_s = &RimeGetSharedDataDirSecure; + s_api.get_user_data_dir_s = &RimeGetUserDataDirSecure; + s_api.get_prebuilt_data_dir_s = &RimeGetPrebuiltDataDirSecure; + s_api.get_staging_dir_s = &RimeGetStagingDirSecure; + s_api.get_sync_dir_s = &RimeGetSyncDirSecure; + s_api.highlight_candidate = &RimeHighlightCandidate; + s_api.highlight_candidate_on_current_page = + &RimeHighlightCandidateOnCurrentPage; + s_api.change_page = &RimeChangePage; + } + return &s_api; +} diff --git a/src/rime_api_stdbool.cc b/src/rime_api_stdbool.cc new file mode 100644 index 0000000000..2406197c06 --- /dev/null +++ b/src/rime_api_stdbool.cc @@ -0,0 +1,4 @@ +#include "rime_api_stdbool.h" +#include "rime_api.h" +// implements stdbool flavored API +#include "rime_api_impl.h" diff --git a/src/rime_api_stdbool.h b/src/rime_api_stdbool.h new file mode 100644 index 0000000000..c10bbd47fe --- /dev/null +++ b/src/rime_api_stdbool.h @@ -0,0 +1,22 @@ +#ifndef RIME_API_STDBOOL_H_ +#define RIME_API_STDBOOL_H_ + +#include + +#undef RIME_FLAVORED +#define RIME_FLAVORED(name) name##_stdbool + +// do not export librime 0.9 API in this build variant +#undef RIME_DEPRECATED +#define RIME_DEPRECATED static + +#undef Bool +#define Bool bool + +#undef False +#define False false + +#undef True +#define True true + +#endif // RIME_API_STDBOOL_H_ diff --git a/test/flavored_api_test.cc b/test/flavored_api_test.cc new file mode 100644 index 0000000000..0e0fcd3b45 --- /dev/null +++ b/test/flavored_api_test.cc @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +TEST(RimeApiStdboolTest, GetContext) { + RIME_FLAVORED(RimeApi)* rime = RIME_FLAVORED(rime_get_api)(); + ASSERT_TRUE(bool(rime)); + + ASSERT_TRUE(RIME_API_AVAILABLE(rime, create_session)); + RimeSessionId test_session = rime->create_session(); + ASSERT_NE(0, test_session); + + ASSERT_TRUE(RIME_API_AVAILABLE(rime, get_context)); + RIME_STRUCT(RIME_FLAVORED(RimeContext), ctx); + ASSERT_TRUE(rime->get_context(test_session, &ctx)); + ASSERT_EQ(0, ctx.menu.num_candidates); + + ASSERT_TRUE(RIME_API_AVAILABLE(rime, get_status)); + RIME_STRUCT(RIME_FLAVORED(RimeStatus), status); + ASSERT_TRUE(rime->get_status(test_session, &status)); + ASSERT_FALSE(status.is_composing); +} diff --git a/test/rime_test_main.cc b/test/rime_test_main.cc index c2a6436f63..8880fab0ff 100644 --- a/test/rime_test_main.cc +++ b/test/rime_test_main.cc @@ -1,5 +1,6 @@ #include #include +#include #include int main(int argc, char** argv) { @@ -12,6 +13,7 @@ int main(int argc, char** argv) { rime::SetupDeployer(&traits); rime::SetupLogging("rime.test"); rime::LoadModules(rime::kDefaultModules); + rime::Service::instance().StartService(); return RUN_ALL_TESTS(); } From cc53e4ace1f7a89a7e0c381fcc6a033fd8ce0979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Sun, 19 May 2024 02:10:28 +0800 Subject: [PATCH 2/2] feat(rime_levers_api): stdbool flavor --- src/rime/lever/levers_api_impl.h | 278 ++++++++++++++++++++++++++++++ src/rime/lever/levers_module.cc | 282 +------------------------------ src/rime/lever/levers_stdbool.cc | 11 ++ src/rime_levers_api.h | 4 +- test/flavored_api_test.cc | 19 +++ 5 files changed, 313 insertions(+), 281 deletions(-) create mode 100644 src/rime/lever/levers_api_impl.h create mode 100644 src/rime/lever/levers_stdbool.cc diff --git a/src/rime/lever/levers_api_impl.h b/src/rime/lever/levers_api_impl.h new file mode 100644 index 0000000000..c2a60d1c49 --- /dev/null +++ b/src/rime/lever/levers_api_impl.h @@ -0,0 +1,278 @@ +// implementation of levers api + +#include +#include +#include +#include + +using namespace rime; + +static RimeCustomSettings* rime_levers_custom_settings_init( + const char* config_id, + const char* generator_id) { + return reinterpret_cast(new CustomSettings( + &Service::instance().deployer(), config_id, generator_id)); +} + +static void rime_levers_custom_settings_destroy(RimeCustomSettings* settings) { + delete reinterpret_cast(settings); +} + +static Bool rime_levers_load_settings(RimeCustomSettings* settings) { + return Bool(reinterpret_cast(settings)->Load()); +} + +static Bool rime_levers_save_settings(RimeCustomSettings* settings) { + return Bool(reinterpret_cast(settings)->Save()); +} + +static Bool rime_levers_customize_bool(RimeCustomSettings* settings, + const char* key, + Bool value) { + an item = New(bool(value)); + auto custom_settings = reinterpret_cast(settings); + return custom_settings->Customize(key, item); +} + +static Bool rime_levers_customize_int(RimeCustomSettings* settings, + const char* key, + int value) { + an item = New(value); + auto custom_settings = reinterpret_cast(settings); + return custom_settings->Customize(key, item); +} + +static Bool rime_levers_customize_double(RimeCustomSettings* settings, + const char* key, + double value) { + an item = New(value); + auto custom_settings = reinterpret_cast(settings); + return custom_settings->Customize(key, item); +} + +static Bool rime_levers_customize_string(RimeCustomSettings* settings, + const char* key, + const char* value) { + an item = New(value); + auto custom_settings = reinterpret_cast(settings); + return custom_settings->Customize(key, item); +} + +static Bool rime_levers_customize_item(RimeCustomSettings* settings, + const char* key, + RimeConfig* value) { + an item; + if (value) { + if (Config* v = reinterpret_cast(value->ptr)) { + item = v->GetItem(""); + } + } + auto custom_settings = reinterpret_cast(settings); + return custom_settings->Customize(key, item); +} + +static Bool rime_levers_is_first_run(RimeCustomSettings* settings) { + return reinterpret_cast(settings)->IsFirstRun(); +} + +static Bool rime_levers_settings_is_modified(RimeCustomSettings* settings) { + return reinterpret_cast(settings)->modified(); +} + +static Bool rime_levers_settings_get_config(RimeCustomSettings* settings, + RimeConfig* config) { + if (!config) + return False; + config->ptr = reinterpret_cast(settings)->config(); + return Bool(!!config->ptr); +} + +static RimeSwitcherSettings* rime_levers_switcher_settings_init() { + return reinterpret_cast( + new SwitcherSettings(&Service::instance().deployer())); +} + +static Bool rime_levers_get_available_schema_list( + RimeSwitcherSettings* settings, + RimeSchemaList* list) { + auto ss = reinterpret_cast(settings); + list->size = 0; + list->list = NULL; + if (ss->available().empty()) { + return False; + } + list->list = new RimeSchemaListItem[ss->available().size()]; + for (const auto& info : ss->available()) { + auto& item(list->list[list->size]); + item.schema_id = const_cast(info.schema_id.c_str()); + item.name = const_cast(info.name.c_str()); + item.reserved = const_cast(&info); + ++list->size; + } + return True; +} + +static Bool rime_levers_get_selected_schema_list(RimeSwitcherSettings* settings, + RimeSchemaList* list) { + auto ss = reinterpret_cast(settings); + list->size = 0; + list->list = NULL; + if (ss->selection().empty()) { + return False; + } + list->list = new RimeSchemaListItem[ss->selection().size()]; + for (const string& schema_id : ss->selection()) { + auto& item(list->list[list->size]); + item.schema_id = const_cast(schema_id.c_str()); + item.name = NULL; + item.reserved = NULL; + ++list->size; + } + return True; +} + +static void rime_levers_schema_list_destroy(RimeSchemaList* list) { + delete[] list->list; + list->size = 0; + list->list = NULL; +} + +static const char* rime_levers_get_schema_id(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->schema_id.empty() ? si->schema_id.c_str() : NULL; +} + +static const char* rime_levers_get_schema_name(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->name.empty() ? si->name.c_str() : NULL; +} + +static const char* rime_levers_get_schema_version(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->version.empty() ? si->version.c_str() : NULL; +} +static const char* rime_levers_get_schema_author(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->author.empty() ? si->author.c_str() : NULL; +} + +static const char* rime_levers_get_schema_description(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->description.empty() ? si->description.c_str() : NULL; +} + +static const char* rime_levers_get_schema_file_path(RimeSchemaInfo* info) { + auto si = reinterpret_cast(info); + return si && !si->file_path.empty() ? si->file_path.c_str() : NULL; +} + +static Bool rime_levers_select_schemas(RimeSwitcherSettings* settings, + const char* schema_id_list[], + int count) { + auto ss = reinterpret_cast(settings); + SwitcherSettings::Selection selection; + for (int i = 0; i < count; ++i) { + selection.push_back(schema_id_list[i]); + } + return ss->Select(selection); +} + +static const char* rime_levers_get_hotkeys(RimeSwitcherSettings* settings) { + auto ss = reinterpret_cast(settings); + return !ss->hotkeys().empty() ? ss->hotkeys().c_str() : NULL; +} + +static Bool rime_levers_set_hotkeys(RimeSwitcherSettings* settings, + const char* hotkeys) { + auto ss = reinterpret_cast(settings); + return Bool(ss->SetHotkeys(hotkeys)); +} + +static Bool rime_levers_user_dict_iterator_init(RimeUserDictIterator* iter) { + UserDictManager mgr(&Service::instance().deployer()); + UserDictList* list = new UserDictList; + mgr.GetUserDictList(list); + if (list->empty()) { + delete list; + return False; + } + iter->ptr = list; + iter->i = 0; + return True; +} + +static void rime_levers_user_dict_iterator_destroy(RimeUserDictIterator* iter) { + delete (UserDictList*)iter->ptr; + iter->ptr = NULL; + iter->i = 0; +} + +static const char* rime_levers_next_user_dict(RimeUserDictIterator* iter) { + auto list = reinterpret_cast(iter->ptr); + if (!list || iter->i >= list->size()) { + return NULL; + } + return (*list)[iter->i++].c_str(); +} + +static Bool rime_levers_backup_user_dict(const char* dict_name) { + UserDictManager mgr(&Service::instance().deployer()); + return Bool(mgr.Backup(dict_name)); +} + +static Bool rime_levers_restore_user_dict(const char* snapshot_file) { + UserDictManager mgr(&Service::instance().deployer()); + return Bool(mgr.Restore(path(snapshot_file))); +} + +static int rime_levers_export_user_dict(const char* dict_name, + const char* text_file) { + UserDictManager mgr(&Service::instance().deployer()); + return mgr.Export(dict_name, path(text_file)); +} + +static int rime_levers_import_user_dict(const char* dict_name, + const char* text_file) { + UserDictManager mgr(&Service::instance().deployer()); + return mgr.Import(dict_name, path(text_file)); +} + +static RimeCustomApi* RIME_FLAVORED(rime_levers_get_api)() { + static RIME_FLAVORED(RimeLeversApi) s_api = {0}; + if (!s_api.data_size) { + RIME_STRUCT_INIT(RIME_FLAVORED(RimeLeversApi), s_api); + s_api.custom_settings_init = rime_levers_custom_settings_init; + s_api.custom_settings_destroy = rime_levers_custom_settings_destroy; + s_api.load_settings = rime_levers_load_settings; + s_api.save_settings = rime_levers_save_settings; + s_api.customize_bool = rime_levers_customize_bool; + s_api.customize_int = rime_levers_customize_int; + s_api.customize_double = rime_levers_customize_double; + s_api.customize_string = rime_levers_customize_string; + s_api.is_first_run = rime_levers_is_first_run; + s_api.settings_is_modified = rime_levers_settings_is_modified; + s_api.settings_get_config = rime_levers_settings_get_config; + s_api.switcher_settings_init = rime_levers_switcher_settings_init; + s_api.get_available_schema_list = rime_levers_get_available_schema_list; + s_api.get_selected_schema_list = rime_levers_get_selected_schema_list; + s_api.schema_list_destroy = rime_levers_schema_list_destroy; + s_api.get_schema_id = rime_levers_get_schema_id; + s_api.get_schema_name = rime_levers_get_schema_name; + s_api.get_schema_version = rime_levers_get_schema_version; + s_api.get_schema_author = rime_levers_get_schema_author; + s_api.get_schema_description = rime_levers_get_schema_description; + s_api.get_schema_file_path = rime_levers_get_schema_file_path; + s_api.select_schemas = rime_levers_select_schemas; + s_api.get_hotkeys = rime_levers_get_hotkeys; + s_api.set_hotkeys = rime_levers_set_hotkeys; + s_api.user_dict_iterator_init = rime_levers_user_dict_iterator_init; + s_api.user_dict_iterator_destroy = rime_levers_user_dict_iterator_destroy; + s_api.next_user_dict = rime_levers_next_user_dict; + s_api.backup_user_dict = rime_levers_backup_user_dict; + s_api.restore_user_dict = rime_levers_restore_user_dict; + s_api.export_user_dict = rime_levers_export_user_dict; + s_api.import_user_dict = rime_levers_import_user_dict; + s_api.customize_item = rime_levers_customize_item; + } + return (RimeCustomApi*)&s_api; +} diff --git a/src/rime/lever/levers_module.cc b/src/rime/lever/levers_module.cc index 7bf261644f..23667e938d 100644 --- a/src/rime/lever/levers_module.cc +++ b/src/rime/lever/levers_module.cc @@ -6,15 +6,9 @@ // #include -#include #include #include -#include - -#include #include -#include -#include using namespace rime; @@ -38,279 +32,9 @@ static void rime_levers_initialize() { static void rime_levers_finalize() {} -// implementation of levers api - -static RimeCustomSettings* rime_levers_custom_settings_init( - const char* config_id, - const char* generator_id) { - return reinterpret_cast(new CustomSettings( - &Service::instance().deployer(), config_id, generator_id)); -} - -static void rime_levers_custom_settings_destroy(RimeCustomSettings* settings) { - delete reinterpret_cast(settings); -} - -static Bool rime_levers_load_settings(RimeCustomSettings* settings) { - return Bool(reinterpret_cast(settings)->Load()); -} - -static Bool rime_levers_save_settings(RimeCustomSettings* settings) { - return Bool(reinterpret_cast(settings)->Save()); -} - -static Bool rime_levers_customize_bool(RimeCustomSettings* settings, - const char* key, - Bool value) { - an item = New(bool(value)); - auto custom_settings = reinterpret_cast(settings); - return custom_settings->Customize(key, item); -} - -static Bool rime_levers_customize_int(RimeCustomSettings* settings, - const char* key, - int value) { - an item = New(value); - auto custom_settings = reinterpret_cast(settings); - return custom_settings->Customize(key, item); -} - -static Bool rime_levers_customize_double(RimeCustomSettings* settings, - const char* key, - double value) { - an item = New(value); - auto custom_settings = reinterpret_cast(settings); - return custom_settings->Customize(key, item); -} - -static Bool rime_levers_customize_string(RimeCustomSettings* settings, - const char* key, - const char* value) { - an item = New(value); - auto custom_settings = reinterpret_cast(settings); - return custom_settings->Customize(key, item); -} - -static Bool rime_levers_customize_item(RimeCustomSettings* settings, - const char* key, - RimeConfig* value) { - an item; - if (value) { - if (Config* v = reinterpret_cast(value->ptr)) { - item = v->GetItem(""); - } - } - auto custom_settings = reinterpret_cast(settings); - return custom_settings->Customize(key, item); -} - -static Bool rime_levers_is_first_run(RimeCustomSettings* settings) { - return reinterpret_cast(settings)->IsFirstRun(); -} - -static Bool rime_levers_settings_is_modified(RimeCustomSettings* settings) { - return reinterpret_cast(settings)->modified(); -} - -static Bool rime_levers_settings_get_config(RimeCustomSettings* settings, - RimeConfig* config) { - if (!config) - return False; - config->ptr = reinterpret_cast(settings)->config(); - return Bool(!!config->ptr); -} - -static RimeSwitcherSettings* rime_levers_switcher_settings_init() { - return reinterpret_cast( - new SwitcherSettings(&Service::instance().deployer())); -} - -static Bool rime_levers_get_available_schema_list( - RimeSwitcherSettings* settings, - RimeSchemaList* list) { - auto ss = reinterpret_cast(settings); - list->size = 0; - list->list = NULL; - if (ss->available().empty()) { - return False; - } - list->list = new RimeSchemaListItem[ss->available().size()]; - for (const auto& info : ss->available()) { - auto& item(list->list[list->size]); - item.schema_id = const_cast(info.schema_id.c_str()); - item.name = const_cast(info.name.c_str()); - item.reserved = const_cast(&info); - ++list->size; - } - return True; -} - -static Bool rime_levers_get_selected_schema_list(RimeSwitcherSettings* settings, - RimeSchemaList* list) { - auto ss = reinterpret_cast(settings); - list->size = 0; - list->list = NULL; - if (ss->selection().empty()) { - return False; - } - list->list = new RimeSchemaListItem[ss->selection().size()]; - for (const string& schema_id : ss->selection()) { - auto& item(list->list[list->size]); - item.schema_id = const_cast(schema_id.c_str()); - item.name = NULL; - item.reserved = NULL; - ++list->size; - } - return True; -} - -static void rime_levers_schema_list_destroy(RimeSchemaList* list) { - delete[] list->list; - list->size = 0; - list->list = NULL; -} - -static const char* rime_levers_get_schema_id(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->schema_id.empty() ? si->schema_id.c_str() : NULL; -} - -static const char* rime_levers_get_schema_name(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->name.empty() ? si->name.c_str() : NULL; -} - -static const char* rime_levers_get_schema_version(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->version.empty() ? si->version.c_str() : NULL; -} -static const char* rime_levers_get_schema_author(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->author.empty() ? si->author.c_str() : NULL; -} - -static const char* rime_levers_get_schema_description(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->description.empty() ? si->description.c_str() : NULL; -} - -static const char* rime_levers_get_schema_file_path(RimeSchemaInfo* info) { - auto si = reinterpret_cast(info); - return si && !si->file_path.empty() ? si->file_path.c_str() : NULL; -} - -static Bool rime_levers_select_schemas(RimeSwitcherSettings* settings, - const char* schema_id_list[], - int count) { - auto ss = reinterpret_cast(settings); - SwitcherSettings::Selection selection; - for (int i = 0; i < count; ++i) { - selection.push_back(schema_id_list[i]); - } - return ss->Select(selection); -} - -static const char* rime_levers_get_hotkeys(RimeSwitcherSettings* settings) { - auto ss = reinterpret_cast(settings); - return !ss->hotkeys().empty() ? ss->hotkeys().c_str() : NULL; -} - -static Bool rime_levers_set_hotkeys(RimeSwitcherSettings* settings, - const char* hotkeys) { - auto ss = reinterpret_cast(settings); - return Bool(ss->SetHotkeys(hotkeys)); -} - -static Bool rime_levers_user_dict_iterator_init(RimeUserDictIterator* iter) { - UserDictManager mgr(&Service::instance().deployer()); - UserDictList* list = new UserDictList; - mgr.GetUserDictList(list); - if (list->empty()) { - delete list; - return False; - } - iter->ptr = list; - iter->i = 0; - return True; -} - -static void rime_levers_user_dict_iterator_destroy(RimeUserDictIterator* iter) { - delete (UserDictList*)iter->ptr; - iter->ptr = NULL; - iter->i = 0; -} - -static const char* rime_levers_next_user_dict(RimeUserDictIterator* iter) { - auto list = reinterpret_cast(iter->ptr); - if (!list || iter->i >= list->size()) { - return NULL; - } - return (*list)[iter->i++].c_str(); -} - -static Bool rime_levers_backup_user_dict(const char* dict_name) { - UserDictManager mgr(&Service::instance().deployer()); - return Bool(mgr.Backup(dict_name)); -} - -static Bool rime_levers_restore_user_dict(const char* snapshot_file) { - UserDictManager mgr(&Service::instance().deployer()); - return Bool(mgr.Restore(path(snapshot_file))); -} - -static int rime_levers_export_user_dict(const char* dict_name, - const char* text_file) { - UserDictManager mgr(&Service::instance().deployer()); - return mgr.Export(dict_name, path(text_file)); -} - -static int rime_levers_import_user_dict(const char* dict_name, - const char* text_file) { - UserDictManager mgr(&Service::instance().deployer()); - return mgr.Import(dict_name, path(text_file)); -} - -// - -static RimeCustomApi* rime_levers_get_api() { - static RimeLeversApi s_api = {0}; - if (!s_api.data_size) { - RIME_STRUCT_INIT(RimeLeversApi, s_api); - s_api.custom_settings_init = rime_levers_custom_settings_init; - s_api.custom_settings_destroy = rime_levers_custom_settings_destroy; - s_api.load_settings = rime_levers_load_settings; - s_api.save_settings = rime_levers_save_settings; - s_api.customize_bool = rime_levers_customize_bool; - s_api.customize_int = rime_levers_customize_int; - s_api.customize_double = rime_levers_customize_double; - s_api.customize_string = rime_levers_customize_string; - s_api.is_first_run = rime_levers_is_first_run; - s_api.settings_is_modified = rime_levers_settings_is_modified; - s_api.settings_get_config = rime_levers_settings_get_config; - s_api.switcher_settings_init = rime_levers_switcher_settings_init; - s_api.get_available_schema_list = rime_levers_get_available_schema_list; - s_api.get_selected_schema_list = rime_levers_get_selected_schema_list; - s_api.schema_list_destroy = rime_levers_schema_list_destroy; - s_api.get_schema_id = rime_levers_get_schema_id; - s_api.get_schema_name = rime_levers_get_schema_name; - s_api.get_schema_version = rime_levers_get_schema_version; - s_api.get_schema_author = rime_levers_get_schema_author; - s_api.get_schema_description = rime_levers_get_schema_description; - s_api.get_schema_file_path = rime_levers_get_schema_file_path; - s_api.select_schemas = rime_levers_select_schemas; - s_api.get_hotkeys = rime_levers_get_hotkeys; - s_api.set_hotkeys = rime_levers_set_hotkeys; - s_api.user_dict_iterator_init = rime_levers_user_dict_iterator_init; - s_api.user_dict_iterator_destroy = rime_levers_user_dict_iterator_destroy; - s_api.next_user_dict = rime_levers_next_user_dict; - s_api.backup_user_dict = rime_levers_backup_user_dict; - s_api.restore_user_dict = rime_levers_restore_user_dict; - s_api.export_user_dict = rime_levers_export_user_dict; - s_api.import_user_dict = rime_levers_import_user_dict; - s_api.customize_item = rime_levers_customize_item; - } - return (RimeCustomApi*)&s_api; -} +#include +// defines rime_levers_get_api() +#include "levers_api_impl.h" RIME_REGISTER_CUSTOM_MODULE(levers) { module->get_api = rime_levers_get_api; diff --git a/src/rime/lever/levers_stdbool.cc b/src/rime/lever/levers_stdbool.cc new file mode 100644 index 0000000000..42d59cf681 --- /dev/null +++ b/src/rime/lever/levers_stdbool.cc @@ -0,0 +1,11 @@ +#include +#include +// defines rime_levers_get_api_stdbool() +#include "levers_api_impl.h" + +static void rime_levers_stdbool_initialize() {} +static void rime_levers_stdbool_finalize() {} + +RIME_REGISTER_CUSTOM_MODULE(levers_stdbool) { + module->get_api = rime_levers_get_api_stdbool; +} diff --git a/src/rime_levers_api.h b/src/rime_levers_api.h index fbd6332ac9..ba029b6f4d 100644 --- a/src/rime_levers_api.h +++ b/src/rime_levers_api.h @@ -30,7 +30,7 @@ typedef struct { size_t i; } RimeUserDictIterator; -typedef struct rime_levers_api_t { +typedef struct RIME_FLAVORED(rime_levers_api_t) { int data_size; RimeCustomSettings* (*custom_settings_init)(const char* config_id, @@ -85,7 +85,7 @@ typedef struct rime_levers_api_t { const char* key, RimeConfig* value); -} RimeLeversApi; +} RIME_FLAVORED(RimeLeversApi); #ifdef __cplusplus } diff --git a/test/flavored_api_test.cc b/test/flavored_api_test.cc index 0e0fcd3b45..06b5f3ed8d 100644 --- a/test/flavored_api_test.cc +++ b/test/flavored_api_test.cc @@ -21,3 +21,22 @@ TEST(RimeApiStdboolTest, GetContext) { ASSERT_TRUE(rime->get_status(test_session, &status)); ASSERT_FALSE(status.is_composing); } + +TEST(RimeLeversApiStdboolTest, CustomSettings) { + RIME_FLAVORED(RimeApi)* rime = RIME_FLAVORED(rime_get_api)(); + RimeModule* module = rime->find_module("levers_stdbool"); + ASSERT_TRUE(bool(module)); + RIME_FLAVORED(RimeLeversApi)* levers = + (RIME_FLAVORED(RimeLeversApi)*)module->get_api(); + ASSERT_TRUE(bool(levers)); + + ASSERT_TRUE(RIME_API_AVAILABLE(levers, custom_settings_init)); + RimeCustomSettings* custom_settings = + levers->custom_settings_init("flavored_api_test", "rime_test"); + ASSERT_TRUE(bool(custom_settings)); + + ASSERT_TRUE(RIME_API_AVAILABLE(levers, customize_bool)); + ASSERT_TRUE(levers->customize_bool(custom_settings, "test_key", true)); + + levers->custom_settings_destroy(custom_settings); +}