diff --git a/main.c b/main.c index 26a3cbdb5622e72f80ab275b181fb94238bad20a..7401a75905643ab6143bf1196269eef6e51eb350 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,16 @@ #include #include #include "zero-pinyin-service.h" +#include "../sqlite3_util.h" +#include -struct _AppData -{ +typedef struct { GApplication *app; GDBusNodeInfo *introspection_data; guint owner_id; -}; - -typedef struct _AppData AppData; + sqlite3 *db; + gboolean init_done; +} AppData; static AppData appdata; @@ -18,6 +19,7 @@ static const gchar introspection_xml[] = " " " " " " + " " " " " " " " @@ -31,20 +33,33 @@ handle_method_get_candidates (GDBusMethodInvocation *invocation, GVariant *parameters) { gchar *preedit_str = NULL; + guint fetch_size = 0; GVariant *result = NULL; GVariantBuilder *candidates_builder = NULL; GVariantBuilder *matched_lengths_builder = NULL; - /* GVariant *candidates = NULL; */ - /* GVariant *matched_preedit_str_lengths = NULL; */ - g_variant_get (parameters, "(s)", &preedit_str); + g_variant_get (parameters, "(su)", &preedit_str, &fetch_size); g_return_if_fail (preedit_str != NULL); + g_return_if_fail (fetch_size > 0); + if (preedit_str == NULL || fetch_size == 0) { + g_dbus_method_invocation_return_dbus_error ( + invocation, + "org.gtk.GDBus.Failed", + "Bad param"); + if (preedit_str) + g_free (preedit_str); + return; + } + + g_message ("get_candidates for preedit_str=%s fetch_size=%u", + preedit_str, fetch_size); candidates_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); matched_lengths_builder = g_variant_builder_new (G_VARIANT_TYPE ("au")); /* test data */ - get_candidates_test (preedit_str, candidates_builder, matched_lengths_builder); + /* get_candidates_test (preedit_str, fetch_size, candidates_builder, matched_lengths_builder); */ + get_candidates (appdata->db, preedit_str, fetch_size, candidates_builder, matched_lengths_builder); result = g_variant_new ("(asau)", candidates_builder, matched_lengths_builder); g_assert_nonnull (result); @@ -176,7 +191,7 @@ config_dbus_service (AppData *appdata) g_assert (appdata->introspection_data != NULL); appdata->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "com.emacsos.zero.ZeroPinyinService", - G_BUS_NAME_OWNER_FLAGS_NONE, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT|G_BUS_NAME_OWNER_FLAGS_REPLACE, on_bus_acquired, on_name_acquired, on_name_lost, @@ -197,37 +212,43 @@ on_sigterm_received (gpointer user_data) } static void -activate (GApplication *app, - AppData *appdata) +config_db (AppData* appdata) { - /* no-op */ - g_message ("zero-pinyin-service activate()"); + gint ri = 0; + gboolean r = FALSE; + static const char* SQLITE3_MEMORY_DB = ":memory:"; + sqlite3* db = NULL; + gchar* sql = NULL; + ri = sqlite3_open (SQLITE3_MEMORY_DB, &db); + g_assert_cmpint (ri, ==, SQLITE_OK); + g_assert_nonnull (db); + + /* TODO make db path configurable */ + /* TODO remove user name in db path */ + sql = sqlite3_mprintf ("ATTACH %Q AS maindb", "/home/sylecn/.cache/ibus/pinyin/main.db"); + r = sqlite3_exec_simple (db, sql); + g_assert (r); + sqlite3_free (sql); + + /* TODO make db path configurable */ + sql = sqlite3_mprintf ("ATTACH %Q AS userdb", "/home/sylecn/.cache/ibus/pinyin/user-1.0.db"); + r = sqlite3_exec_simple (db, sql); + g_assert (r); + sqlite3_free (sql); + + appdata->db = db; } static void -startup (GApplication *app, - AppData *appdata) +zero_pinyin_service_init (GApplication *app, + AppData *appdata) { - g_message ("zero-pinyin-service startup()"); appdata->introspection_data = NULL; appdata->owner_id = 0; - config_dbus_service(appdata); - g_application_hold (app); -} - -static void -shutdown (GApplication *app, - AppData *appdata) -{ - g_message ("zero-pinyin-service shutdown()"); - if (appdata->owner_id > 0) { - g_bus_unown_name (appdata->owner_id); - appdata->owner_id = 0; - } - if (appdata->introspection_data != NULL) { - g_dbus_node_info_unref (appdata->introspection_data); - appdata->introspection_data = NULL; - } + appdata->db = NULL; + config_dbus_service (appdata); + config_db (appdata); + appdata->init_done = TRUE; } /** @@ -248,6 +269,45 @@ setup_sigint_sigterm_handler (AppData *appdata) g_source_unref (source); } +static void +startup (GApplication* app, + AppData* appdata) +{ + g_message ("zero-pinyin-service startup()"); + setup_sigint_sigterm_handler (appdata); + + g_assert_false (appdata->init_done); + zero_pinyin_service_init (app, appdata); + g_application_hold (app); +} + +static void +activate (GApplication *app, + AppData *appdata) +{ + g_message ("zero-pinyin-service activate()"); + /* as a pure service, activate is a no-op. */ +} + +static void +shutdown (GApplication *app, + AppData *appdata) +{ + g_message ("zero-pinyin-service shutdown()"); + if (appdata->owner_id > 0) { + g_bus_unown_name (appdata->owner_id); + appdata->owner_id = 0; + } + if (appdata->introspection_data != NULL) { + g_dbus_node_info_unref (appdata->introspection_data); + appdata->introspection_data = NULL; + } + if (appdata->db != NULL) { + sqlite3_close (appdata->db); + appdata->db = NULL; + } +} + /** * provide zero-pinyin-service dbus service. * it's a console app based on glib and gio. @@ -258,15 +318,15 @@ main (int argc, char *argv[]) GApplication *app = NULL; int status = 0; - app = g_application_new ("com.emacsos.zero.App.ZeroPinyinService", + app = g_application_new ("com.emacsos.zero.ZeroPinyinServiceApp", G_APPLICATION_FLAGS_NONE); g_assert_nonnull (app); appdata.app = app; + appdata.init_done = FALSE; - g_signal_connect (app, "activate", G_CALLBACK (activate), &appdata); g_signal_connect (app, "startup", G_CALLBACK (startup), &appdata); + g_signal_connect (app, "activate", G_CALLBACK (activate), &appdata); g_signal_connect (app, "shutdown", G_CALLBACK (shutdown), &appdata); - setup_sigint_sigterm_handler (&appdata); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); diff --git a/meson.build b/meson.build index 967c97c909007adce5ac47be85c29c5ac55fb40a..b59855a712538143a20cb5c55292790450125ccc 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ # -*- mode: conf -*- project('zero-pinyin-service', ['c', 'cpp'], - version: '0.1.0', + version: '0.2.0', license: 'GPL', default_options: [ 'warning_level=2', @@ -33,12 +33,22 @@ endif glib = dependency('glib-2.0') gio = dependency('gio-unix-2.0') uuid = dependency('uuid') -shared_dep = [glib, gio, uuid] +sqlite3 = dependency('sqlite3') +shared_dep = [glib, gio, uuid, sqlite3] -src = ['../PinyinParser.cc', 'parse-pinyin.cpp', 'zero-pinyin-service.cc', 'main.c'] +src = [ + '../PinyinParser.cc', + '../sqlite3_util.c', + 'parse-pinyin.cpp', + 'zero-pinyin-service.c', + 'main.c'] executable('main', src, dependencies: shared_dep) -test('zero-pinyin-service', +test('parse-pinyin', executable('parse-pinyin', ['../PinyinParser.cc', 'parse-pinyin.cpp', 'parse-pinyin-test.cpp'], dependencies: shared_dep)) +test('zero-pinyin-service-test', + executable('zero-pinyin-service-test', + ['zero-pinyin-service-test.c'], + dependencies: shared_dep)) diff --git a/parse-pinyin-test.cpp b/parse-pinyin-test.cpp index 0349f54daa97fcdfbec9f9760508f481099e1e6a..cd41862675979879c0e18313a9535238e330f967 100644 --- a/parse-pinyin-test.cpp +++ b/parse-pinyin-test.cpp @@ -1,11 +1,10 @@ -#include "parse-pinyin.hpp" +#include "parse-pinyin.h" #include -#include static void -test_parse_pinyin () +test_parse_pinyin_cpp () { - std::vector* result = parse_pinyin ("liyifeng"); + std::vector* result = parse_pinyin_cpp ("liyifeng"); g_assert_cmpint (result->size (), ==, 3); g_assert_cmpint (result->at(0)->shengmu_i, ==, 10); @@ -26,10 +25,39 @@ test_parse_pinyin () delete result; } +static void +test_parse_pinyin () +{ + GList* result = NULL; + Pinyin* thispy = NULL; + + result = parse_pinyin ("liyifeng", 15); + g_assert_cmpint (g_list_length (result), ==, 3); + + thispy = (Pinyin*) g_list_nth_data (result, 0); + g_assert_cmpint (thispy->shengmu_i, ==, 10); + g_assert_cmpint (thispy->yunmu_i, ==, 34); + g_assert_cmpint (thispy->length, ==, 2); + + thispy = (Pinyin*) g_list_nth_data (result, 1); + g_assert_cmpint (thispy->shengmu_i, ==, 21); + g_assert_cmpint (thispy->yunmu_i, ==, 34); + g_assert_cmpint (thispy->length, ==, 2); + + thispy = (Pinyin*) g_list_nth_data (result, 2); + g_assert_cmpint (thispy->shengmu_i, ==, 5); + g_assert_cmpint (thispy->yunmu_i, ==, 32); + g_assert_cmpint (thispy->length, ==, 4); + + g_list_free_full (result, g_free); +} + int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); + g_test_add_func ("/zero/test_parse_pinyin_cpp", + test_parse_pinyin_cpp); g_test_add_func ("/zero/test_parse_pinyin", test_parse_pinyin); diff --git a/parse-pinyin.cpp b/parse-pinyin.cpp index f352553bd8193b960fd67313c59332aa2f65dbe3..1b0a1de2caff786c258b0f5b73248edcdd05d8ed 100644 --- a/parse-pinyin.cpp +++ b/parse-pinyin.cpp @@ -1,4 +1,4 @@ -#include "parse-pinyin.hpp" +#include "parse-pinyin.h" #include "../PinyinArray.h" #include "../PinyinParser.h" @@ -11,7 +11,7 @@ * returns: a list of Pinyin */ std::vector* -parse_pinyin (const char* preedit_str, guint max_pinyin) +parse_pinyin_cpp (const char* preedit_str, const guint max_pinyin) { std::vector* result = new std::vector(); PyZy::PinyinArray pyar = {0}; @@ -25,3 +25,21 @@ parse_pinyin (const char* preedit_str, guint max_pinyin) } return result; } + +GList* +parse_pinyin (const char* preedit_str, const guint max_pinyin) +{ + GList* result = NULL; + PyZy::PinyinArray pyar = {0}; + Pinyin* thispy = NULL; + + PyZy::PinyinParser::parse (preedit_str, strlen(preedit_str), 0, pyar, max_pinyin); + for (guint i = 0; i < pyar.size(); ++i) { + thispy = g_new (Pinyin, 1); + thispy->shengmu_i = (int) pyar[i].pinyin->pinyin_id[0].sheng; + thispy->yunmu_i = (int) pyar[i].pinyin->pinyin_id[0].yun; + thispy->length = pyar[i].len; + result = g_list_append (result, thispy); + } + return result; +} diff --git a/parse-pinyin.h b/parse-pinyin.h new file mode 100644 index 0000000000000000000000000000000000000000..e169b1a0c6a3d3f1bfbd26fe55c4b90ffbe5d05c --- /dev/null +++ b/parse-pinyin.h @@ -0,0 +1,31 @@ +#ifndef _PARSE_PINYIN_H_ +#define _PARSE_PINYIN_H_ + +#include +#include "zero-pinyin-service.h" + +#ifdef __cplusplus + +#include + +/** + * parse preedit_str to groups of pinyin. + * caller should free each Pinyin and the vector after use. + */ +std::vector* parse_pinyin_cpp (const char* preedit_str, const guint max_pinyin=15); + +extern "C" +{ +#endif + +/** + * parse preedit_str to groups of pinyin. + * caller should free each Pinyin and the GList after use. + */ +GList* parse_pinyin (const char* preedit_str, const guint max_pinyin); + +#ifdef __cplusplus +} +#endif + +#endif /* _PARSE_PINYIN_H_ */ diff --git a/parse-pinyin.hpp b/parse-pinyin.hpp deleted file mode 100644 index 7f1cbe6cf405979bf1d80d966c738cdfc0da5c6e..0000000000000000000000000000000000000000 --- a/parse-pinyin.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _PARSE_PINYIN_H_ -#define _PARSE_PINYIN_H_ - -#include -#include "zero-pinyin-service.h" - -/** - * parse preedit_str to groups of pinyin. - * caller should free each Pinyin and the vector after use. - */ -std::vector* parse_pinyin (const char* preedit_str, guint max_pinyin=15); - -#endif /* _PARSE_PINYIN_H_ */ diff --git a/zero-pinyin-service-test.c b/zero-pinyin-service-test.c new file mode 100644 index 0000000000000000000000000000000000000000..dd29de4866daa133e1237278a856e9f64403618e --- /dev/null +++ b/zero-pinyin-service-test.c @@ -0,0 +1,22 @@ +#include "zero-pinyin-service.h" + +static void +test_GString () +{ + GString* s = NULL; + s = g_string_new (""); + g_string_append_printf (s, "s0=%d ", 1); + + g_assert_cmpstr (s->str, ==, "s0=1 "); + + g_string_free (s, TRUE); +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/zero/test_GString", + test_GString); + return g_test_run (); +} diff --git a/zero-pinyin-service.c b/zero-pinyin-service.c new file mode 100644 index 0000000000000000000000000000000000000000..ddc17a6d7993304906579c3c7f4cabc1aba89f02 --- /dev/null +++ b/zero-pinyin-service.c @@ -0,0 +1,236 @@ +#include "zero-pinyin-service.h" +#include "parse-pinyin.h" + +void +get_candidates_test (const char* preedit_str, + const guint fetch_size, + GVariantBuilder *candidates_builder, + GVariantBuilder *matched_lengths_builder) +{ + if (g_str_equal (preedit_str, "liyifeng")) { + const gchar *matches[] = {"李易峰", "利益", "礼仪", "离异", "里", "理", "力"}; + guint matched_lengths[] = {8, 4, 4, 4, 2, 2, 2}; + for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { + g_variant_builder_add (candidates_builder, "s", matches[i]); + g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); + } + } else if (g_str_equal (preedit_str, "feng")) { + const gchar *matches[] = {"风", "封", "疯", "丰", "凤"}; + guint matched_lengths[] = {4, 4, 4, 4, 4, 4}; + for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { + g_variant_builder_add (candidates_builder, "s", matches[i]); + g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); + } + } else if (g_str_equal (preedit_str, "yifeng")) { + const gchar *matches[] = {"一封", "遗风", "艺", "依", "一", "以"}; + guint matched_lengths[] = {6, 6, 2, 2, 2, 2}; + for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { + g_variant_builder_add (candidates_builder, "s", matches[i]); + g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); + } + } +} + +/** + * build where clause for build_sql_for_n_pinyin(). + * + * @pylist: the pinyin list. + * @n: number of Pinyin to use in pylist. + * + * returns: where_clause, caller should g_free() result after use. + */ +static char* +build_where_clause (GList* pylist, + const guint n) +{ + GString* s = NULL; + GList* iter = pylist; + gboolean first_condition_done = FALSE; + Pinyin* thispy = NULL; + s = g_string_new (""); + for (guint i = 0; i < n; ++i) { + g_assert_nonnull (iter); + thispy = (Pinyin*) iter->data; + if (thispy->shengmu_i) { + if (G_LIKELY (first_condition_done)) { + g_string_append_printf (s, "AND s%u=%d ", i, thispy->shengmu_i); + } else { + g_string_append_printf (s, "s%u=%d ", i, thispy->shengmu_i); + first_condition_done = TRUE; + } + } + if (thispy->yunmu_i) { + if (G_LIKELY (first_condition_done)) { + g_string_append_printf (s, "AND y%u=%d ", i, thispy->yunmu_i); + } else { + g_string_append_printf (s, "y%u=%d ", i, thispy->yunmu_i); + first_condition_done = TRUE; + } + } + iter = iter->next; + } + gchar* result = s->str; + g_string_free (s, FALSE); + return result; +} + +/** + * build a SQL to query candidates for first n pinyin in pylist. + * n can be from 1 to len(pylist). + * + * caller should free result with g_free() after use. + */ +static char* +build_sql_for_n_pinyin (GList* pylist, + const guint n, + const guint limit) +{ + GString* sql = NULL; + gchar* where_clause = NULL; + sql = g_string_new ("SELECT user_freq, phrase, freq FROM ("); + g_string_append_printf ( + sql, "SELECT 0 AS user_freq, phrase, freq FROM " + "maindb.py_phrase_%u WHERE ", n - 1); + where_clause = build_where_clause (pylist, n); + g_assert_nonnull (where_clause); + g_message ("where_clause=%s", where_clause); + sql = g_string_append (sql, where_clause); + sql = g_string_append (sql, " UNION "); + g_string_append_printf ( + sql, "SELECT user_freq, phrase, freq FROM " + "userdb.py_phrase_%u WHERE ", n - 1); + sql = g_string_append (sql, where_clause); + sql = g_string_append (sql, ") GROUP BY phrase ORDER BY user_freq DESC, freq DESC "); + g_string_append_printf (sql, "LIMIT %u", limit); + char* result = sql->str; + g_free (where_clause); + g_string_free (sql, FALSE); + return result; +} + +/** + * fetch candidates for a fixed word length. + * + * @pylist: the pinyin list. + * @group_size: the fixed word length. use this many pinyin from pinyin list. + * @limit: fetch this many result is enough for user. more is not a problem though. + * @candidates: the result candidate list. caller should free this after use. + * + * returns: how many candidates fetched. + */ +static guint +get_candidates_for_n_pinyin (sqlite3* db, + GList* pylist, + const guint group_size, + const guint limit, + GList** candidates) +{ + const guint DEFAULT_LIMIT = 50; + GList* result = NULL; /* GList of Candidate */ + + g_assert_cmpint (group_size, >=, 1); + g_assert_cmpint (group_size, <=, g_list_length (pylist)); + + gint candidates_count = 0; + gint r = 0; + /* build SQL and run SQL query */ + char* sql = NULL; + sql = build_sql_for_n_pinyin (pylist, group_size, MAX (limit, DEFAULT_LIMIT)); + g_message ("build_sql_for_n_pinyin result SQL:\n\n%s\n", sql); + + guint matched_py_length = 0; + GList* iter = pylist; + for (guint i = 0; i < group_size; ++i) { + matched_py_length += ((Pinyin*) iter->data)->length; + iter = iter->next; + } + + sqlite3_stmt* stmt = NULL; + const char* unused; + Candidate* c = NULL; + r = sqlite3_prepare_v2 (db, sql, -1, &stmt, &unused); + g_free (sql); + g_assert_nonnull (unused); + g_assert_cmpstr (unused, ==, ""); + if (strlen (unused)) { + g_warning ("part of sql is unused \"%s\" length=%zu", + unused, strlen (unused)); + } + while (TRUE) { + r = sqlite3_step (stmt); + if (r == SQLITE_DONE) { + break; + } else if (r == SQLITE_ROW) { + c = g_new (Candidate, 1); + /* sql SELECT should select these 3 columns in order */ + c->user_freq = sqlite3_column_int (stmt, 0); + c->str = g_strdup ((const char*) sqlite3_column_text (stmt, 1)); + c->freq = sqlite3_column_int (stmt, 2); + c->matched_py_length = matched_py_length; + + if (g_utf8_validate (c->str, -1, NULL)) { + result = g_list_prepend (result, c); + candidates_count++; + } else { + g_warning ("ignore non utf8 phrase: %s", c->str); + } + } else if (r == SQLITE_BUSY) { + g_warning ("sqlite3_step got SQLITE_BUSY"); + break; + } else { + g_warning ("sqlite3_step error: %d (%s)", + r, sqlite3_errmsg (db)); + break; + } + } + r = sqlite3_finalize (stmt); + if (r != SQLITE_OK) { + g_debug ("sqlite3_finalize error: %d (%s)", r, sqlite3_errmsg (db)); + } + + /* store query result in a new GList */ + *candidates = g_list_reverse (result); + return candidates_count; +} + +void +get_candidates (sqlite3* db, + const char* preedit_str, + const guint fetch_size, + GVariantBuilder *candidates_builder, + GVariantBuilder *matched_lengths_builder) +{ + GList* pylist = NULL; + guint pylist_len = 0; + + pylist = parse_pinyin (preedit_str, 15); + pylist_len = g_list_length (pylist); + + guint group_size = pylist_len; + guint fetched_size = 0; + guint r = 0; + GList* candidates = NULL; + while (fetched_size < fetch_size && group_size > 0) { + g_message ("phrase length=%u", group_size); + r = get_candidates_for_n_pinyin (db, pylist, group_size, fetch_size - fetched_size, &candidates); + if (candidates) { + GList* iter = g_list_first (candidates); + Candidate* c = NULL; + while (iter != NULL) { + c = (Candidate*) iter->data; + g_variant_builder_add (candidates_builder, "s", + c->str); + g_free (c->str); + g_variant_builder_add (matched_lengths_builder, "u", + c->matched_py_length); + iter = iter->next; + } + g_list_free_full (candidates, g_free); + } + g_message ("%u candidates found", r); + fetched_size += r; + group_size--; + } + g_message ("returning %u candidates", fetched_size); + g_list_free_full (pylist, g_free); +} diff --git a/zero-pinyin-service.cc b/zero-pinyin-service.cc deleted file mode 100644 index d88b2de39a24be7ae14b6755200fb7ad2bcbb2bd..0000000000000000000000000000000000000000 --- a/zero-pinyin-service.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include "zero-pinyin-service.h" -#include -#include "../PinyinArray.h" -#include "../PinyinParser.h" - -void -get_candidates_test (const char* preedit_str, - GVariantBuilder *candidates_builder, - GVariantBuilder *matched_lengths_builder) -{ - if (g_str_equal (preedit_str, "liyifeng")) { - const gchar *matches[] = {"李易峰", "利益", "礼仪", "离异", "里", "理", "力"}; - guint matched_lengths[] = {8, 4, 4, 4, 2, 2, 2}; - for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { - g_variant_builder_add (candidates_builder, "s", matches[i]); - g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); - } - } else if (g_str_equal (preedit_str, "feng")) { - const gchar *matches[] = {"风", "封", "疯", "丰", "凤"}; - guint matched_lengths[] = {4, 4, 4, 4, 4, 4}; - for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { - g_variant_builder_add (candidates_builder, "s", matches[i]); - g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); - } - } else if (g_str_equal (preedit_str, "yifeng")) { - const gchar *matches[] = {"一封", "遗风", "艺", "依", "一", "以"}; - guint matched_lengths[] = {6, 6, 2, 2, 2, 2}; - for (guint i = 0; i < G_N_ELEMENTS (matches); ++i) { - g_variant_builder_add (candidates_builder, "s", matches[i]); - g_variant_builder_add (matched_lengths_builder, "u", matched_lengths[i]); - } - } -} - -void -get_candidates (const char* preedit_str, - GVariantBuilder *candidates_builder, - GVariantBuilder *matched_lengths_builder) -{ - /* TODO */ -} diff --git a/zero-pinyin-service.h b/zero-pinyin-service.h index 22089ad4f55962772170a1c937d92d8aa5e16f60..6cb75c3b7788dd6792f57f8722985cd4697a7feb 100644 --- a/zero-pinyin-service.h +++ b/zero-pinyin-service.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -16,25 +17,31 @@ typedef struct { } Pinyin; typedef struct { - gchar str; - guint matched_py_length; + gchar* str; /* the candidate string */ + guint freq; /* word frequency [0, 65535] */ + guint user_freq; /* user frequency [0, 65535] */ + guint matched_py_length; /* matched preedit_str length */ } Candidate; /** * an implementation of get_candidates() with simple test data. */ void get_candidates_test (const char* preedit_str, + const guint fetch_size, GVariantBuilder *candidates_builder, GVariantBuilder *matched_lengths_builder); /** * fetch candidates for preedit_str. * - * @preedit_str - * @candidates_builder will add candidates to this builder - * @matched_lengths_builder will add matched preedit_str length to this builder + * @preedit_str the preedit_str + * @fetch_size try to fetch this many candidates if possible + * @candidates_builder candidates will be added to this builder + * @matched_lengths_builder matched preedit_str length will be added to this builder */ -void get_candidates (const char* preedit_str, +void get_candidates (sqlite3* db, + const char* preedit_str, + const guint fetch_size, GVariantBuilder *candidates_builder, GVariantBuilder *matched_lengths_builder);