diff --git a/src/completers/pos-completer-presage.c b/src/completers/pos-completer-presage.c index b733359a46af799c6a14317fa4f238a451bb74d3..2ac03a7f63b6f65788a240db5ea77939b89b7033 100644 --- a/src/completers/pos-completer-presage.c +++ b/src/completers/pos-completer-presage.c @@ -15,9 +15,6 @@ #include "pos-completer-base.h" #include "pos-completer-priv.h" #include "pos-completer-presage.h" -#include "pos-emoji-db.h" - -#include "util.h" #include @@ -64,11 +61,11 @@ struct _PosCompleterPresage { char *name; GString *preedit; GStrv completions; + GHashTable *compmap; /* key: displayed completion, value: actual completion to use */ guint max_completions; presage_t presage; char *presage_past; - char *presage_future; char *dict_dir; char *lang; @@ -89,11 +86,40 @@ G_DEFINE_TYPE_WITH_CODE (PosCompleterPresage, pos_completer_presage, POS_TYPE_CO static void -pos_completer_presage_set_completions (PosCompleter *iface, - GStrv completions, - gboolean additional_sources) +pos_completer_presage_update_compmap (PosCompleterPresage *self, + GStrv completions, + GStrv caps_completions, + GHashTable *compmap) +{ + g_hash_table_remove_all (self->compmap); + + if (g_strv_length (completions) != g_strv_length (caps_completions)) { + g_warning ("Capitalized completions don't match: %d != %d", + g_strv_length (completions), + g_strv_length (caps_completions)); + return; + } + + if (!compmap) + return; + + /* Transform the keys from lowercase to their capitalized versions */ + for (int i = 0; completions[i]; i++) { + gpointer value; + + /* No need to free key as passed in `compmap` doesn't have key ownership */ + if (g_hash_table_steal_extended (compmap, completions[i], NULL, &value)) + g_hash_table_insert (self->compmap, g_strdup (caps_completions[i]), value); + } +} + + +static void +pos_completer_presage_set_completions (PosCompleterPresage *self, + GStrv completions, + gboolean additional_sources, + GHashTable *compmap) { - PosCompleterPresage *self = POS_COMPLETER_PRESAGE (iface); g_auto (GStrv) additional_results = NULL; g_auto (GStrv) caps_completions = NULL; g_autoptr (GStrvBuilder) builder = g_strv_builder_new (); @@ -104,8 +130,11 @@ pos_completer_presage_set_completions (PosCompleter *iface, MAX_ADDITIONAL_RESULTS); caps_completions = pos_completer_capitalize_by_template (self->preedit->str, completions); - if (caps_completions) + + if (caps_completions) { g_strv_builder_addv (builder, (const char **)caps_completions); + pos_completer_presage_update_compmap (self, completions, caps_completions, compmap); + } if (additional_results) g_strv_builder_addv (builder, (const char **)additional_results); g_strfreev (self->completions); @@ -119,15 +148,32 @@ static void pos_completer_presage_predict (PosCompleterPresage *self) { presage_error_code_t result; - g_auto (GStrv) completions = NULL; + g_auto (GStrv) predictions = NULL; - result = presage_predict (self->presage, &completions); + result = presage_predict (self->presage, &predictions); if (result == PRESAGE_OK) { - pos_completer_presage_set_completions (POS_COMPLETER (self), completions, TRUE); + g_autoptr (GStrvBuilder) builder = g_strv_builder_new (); + g_auto (GStrv) completions = NULL; + g_autoptr (GHashTable) compmap = NULL; + + compmap = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + for (int i = 0; predictions[i]; i++) { + g_autofree char *str = NULL; + g_autofree char *compl = NULL; + + result = presage_completion (self->presage, predictions[i], &str); + if (result != PRESAGE_OK) + continue; + + /* preedit is part of `presage_past` so we need to add it to the completion */ + compl = g_strdup_printf ("%s%s", self->preedit->str, str); + g_hash_table_insert (compmap, predictions[i], g_steal_pointer (&compl)); + } + pos_completer_presage_set_completions (self, predictions, TRUE, compmap); } else { g_warning ("Failed to complete %s", self->preedit->str); - pos_completer_presage_set_completions (POS_COMPLETER (self), NULL, FALSE); + pos_completer_presage_set_completions (self, NULL, FALSE, NULL); } } @@ -154,7 +200,7 @@ pos_completer_presage_set_preedit (PosCompleter *iface, const char *preedit) g_string_append (self->preedit, preedit); else { /* No string: reset completions */ - pos_completer_presage_set_completions (POS_COMPLETER (self), NULL, FALSE); + pos_completer_presage_set_completions (self, NULL, FALSE, NULL); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PREEDIT]); @@ -268,6 +314,17 @@ pos_completer_presage_set_language (PosCompleter *completer, } +static const char * +pos_completer_presage_lookup_completion (PosCompleter *completer, const char *completion) +{ + PosCompleterPresage *self = POS_COMPLETER_PRESAGE (completer); + const char *lookup; + + lookup = g_hash_table_lookup (self->compmap, completion); + return lookup ? lookup : completion; +} + + static void pos_completer_presage_set_property (GObject *object, guint property_id, @@ -321,9 +378,9 @@ pos_completer_presage_finalize (GObject *object) PosCompleterPresage *self = POS_COMPLETER_PRESAGE (object); g_clear_pointer (&self->completions, g_strfreev); + g_clear_pointer (&self->compmap, g_hash_table_unref); g_string_free (self->preedit, TRUE); g_clear_pointer (&self->presage_past, g_free); - g_clear_pointer (&self->presage_future, g_free); g_clear_pointer (&self->lang, g_free); g_clear_pointer (&self->dict_dir, g_free); presage_free (self->presage); @@ -493,6 +550,7 @@ pos_completer_presage_interface_init (PosCompleterInterface *iface) iface->set_preedit = pos_completer_presage_set_preedit; iface->set_surrounding_text = pos_completer_presage_set_surrounding_text; iface->set_language = pos_completer_presage_set_language; + iface->lookup_completion = pos_completer_presage_lookup_completion; } @@ -502,6 +560,7 @@ pos_completer_presage_init (PosCompleterPresage *self) self->max_completions = MAX_COMPLETIONS; self->preedit = g_string_new (NULL); self->name = "presage"; + self->compmap = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } /** diff --git a/src/contrib/util.h b/src/contrib/util.h index e0a39d847d815e54f5bf50d9da63caf1951c68ff..09b5deabfb0ebfcdf27117313785140863a6cd33 100644 --- a/src/contrib/util.h +++ b/src/contrib/util.h @@ -10,8 +10,6 @@ #include #include -#define STR_IS_NULL_OR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') - #define phosh_async_error_warn(err, ...) \ phosh_error_warnv (G_LOG_DOMAIN, err, G_IO_ERROR, G_IO_ERROR_CANCELLED, __VA_ARGS__) diff --git a/src/pos-completer-manager.c b/src/pos-completer-manager.c index f38724c393511929ffb09c34ac34ec04f4f6bac1..1a5dc311a07001b05dfb43cfe9287afa01feb0d4 100644 --- a/src/pos-completer-manager.c +++ b/src/pos-completer-manager.c @@ -23,7 +23,7 @@ # include "completers/pos-completer-varnam.h" #endif -#include "contrib/util.h" +#include "gmobile.h" #include @@ -144,7 +144,7 @@ on_default_completer_changed (PosCompleterManager *self) g_assert (POS_IS_COMPLETER_MANAGER (self)); default_name = g_settings_get_string (self->settings, "default"); - if (!STR_IS_NULL_OR_EMPTY (default_name)) { + if (!gm_str_is_null_or_empty (default_name)) { default_ = init_completer (self, default_name, &err); if (default_ == NULL) { g_critical ("Failed to init default completer '%s': %s", default_name, diff --git a/src/pos-completer.c b/src/pos-completer.c index eee45c53c96186a5f71fb09821a4599b8a7c88a7..17cdc04e8e51a9eb27d2a8b2dc536b9902c3ea18 100644 --- a/src/pos-completer.c +++ b/src/pos-completer.c @@ -15,6 +15,8 @@ #include "pos-completer-priv.h" #include "util.h" +#include "gmobile.h" + #include /** @@ -204,6 +206,32 @@ pos_completer_get_completions (PosCompleter *self) return completions; } +/** + * pos_completer_lookup_completion: + * @self: the completer + * @completion: The completion to lookup + * + * Given a given completion string lookup what should actually + * be completed. This allows completers to e.g. provide the full + * word as completion "handle" and fill in just the last chars as + * actual completions. + * + * Returns: the actual completion string + */ +const char * +pos_completer_lookup_completion (PosCompleter *self, const char *completion) +{ + PosCompleterInterface *iface; + + g_return_val_if_fail (POS_IS_COMPLETER (self), NULL); + + iface = POS_COMPLETER_GET_IFACE (self); + if (!iface->lookup_completion) + return NULL; + + return (iface->lookup_completion)(self, completion); +} + /** * pos_completer_get_preedit: * @self: the completer @@ -460,7 +488,7 @@ pos_completer_grab_last_word (const char *text, char **new_text, char **word) g_return_val_if_fail (word && *word == NULL, FALSE); /* Nothing to parse */ - if (STR_IS_NULL_OR_EMPTY (text)) + if (gm_str_is_null_or_empty (text)) return FALSE; /* text ends with whitespace */ @@ -509,7 +537,7 @@ pos_completer_find_prev_word_break (const char *text) g_autofree char *symbol = NULL; /* Nothing to parse */ - if (STR_IS_NULL_OR_EMPTY (text)) + if (gm_str_is_null_or_empty (text)) return -1; len = g_utf8_strlen (text, -1); @@ -563,7 +591,7 @@ pos_completer_capitalize_by_template (const char *template, const GStrv completi g_autoptr (GStrvBuilder) builder = NULL; g_autofree gunichar *utemplate = NULL; - if (completions == NULL || STR_IS_NULL_OR_EMPTY (template)) + if (completions == NULL || gm_str_is_null_or_empty (template)) return g_strdupv (completions); utemplate = g_utf8_to_ucs4_fast (template, -1, &templ_len); diff --git a/src/pos-completer.h b/src/pos-completer.h index d8e9a0aac4113be61c5660b287dc1c412a4e22b8..25a63a9eaa35dc09c8b19044afa06281c9e05b72 100644 --- a/src/pos-completer.h +++ b/src/pos-completer.h @@ -56,12 +56,14 @@ struct _PosCompleterInterface GError **error); char * (*get_display_name) (PosCompleter *self); void (*learn_accepted) (PosCompleter *self, const char *word); + const char * (*lookup_completion) (PosCompleter *self, const char *completion); }; /* Used by completion users */ const char *pos_completer_get_name (PosCompleter *self); gboolean pos_completer_feed_symbol (PosCompleter *self, const char *symbol); GStrv pos_completer_get_completions (PosCompleter *self); +const char *pos_completer_lookup_completion (PosCompleter *self, const char *completion); const char *pos_completer_get_preedit (PosCompleter *self); void pos_completer_set_preedit (PosCompleter *self, const char *preedit); void pos_completer_set_surrounding_text (PosCompleter *self, diff --git a/src/pos-input-surface.c b/src/pos-input-surface.c index 35d24ca0af36bbcc0dc6cf79b72543e4d9871191..fd6a4cd672cc6c447dc5e8ed84a7ecfdce5499e5 100644 --- a/src/pos-input-surface.c +++ b/src/pos-input-surface.c @@ -409,12 +409,18 @@ static void on_completion_selected (PosInputSurface *self, const char *completion) { g_autofree char *send = NULL; + const char *lookup; g_return_if_fail (POS_IS_INPUT_SURFACE (self)); g_return_if_fail (completion != NULL); - g_debug ("completion: %s", completion); - send = g_strdup_printf ("%s ", completion); + lookup = pos_completer_lookup_completion (self->completer, completion); + g_debug ("completion: %s -> lookup: %s", completion, lookup); + + if (lookup) + send = g_strdup (lookup); + else + send = g_strdup_printf ("%s ", completion); pos_input_method_send_string (self->input_method, send, TRUE); @@ -1893,7 +1899,7 @@ build_layout_name (const char *engine, const char *layout, const char *variant) { char *name; - if (STR_IS_NULL_OR_EMPTY (variant)) + if (gm_str_is_null_or_empty (variant)) name = g_strdup_printf ("%s:%s", engine, layout); else name = g_strdup_printf ("%s:%s+%s", engine, layout, variant); diff --git a/src/pos-osk-widget.c b/src/pos-osk-widget.c index 7721df2e03962f37fb85318bfdab3f7afdab3ed2..229d9ae3877970366ee8522b498bd9a7d78f1a4e 100644 --- a/src/pos-osk-widget.c +++ b/src/pos-osk-widget.c @@ -20,6 +20,8 @@ #include "pos-osk-key.h" #include "pos-osk-widget.h" +#include "gmobile.h" + #include #include @@ -1896,7 +1898,7 @@ parse_lang (PosOskWidget *self, const char *layout, const char *variant) /* Keyboard layout has language (`en`), region is from layout (`us`) */ self->lang = g_strdup (self->layout.locale); - if (STR_IS_NULL_OR_EMPTY (variant)) { + if (gm_str_is_null_or_empty (variant)) { self->region = g_strdup (layout); return; } @@ -1950,7 +1952,7 @@ pos_osk_widget_set_layout (PosOskWidget *self, g_free (self->layout_id); self->layout_id = g_strdup (layout_id); - if (!STR_IS_NULL_OR_EMPTY (variant)) + if (!gm_str_is_null_or_empty (variant)) path = g_strdup_printf ("/mobi/phosh/stevia/layouts/%s+%s.json", layout, variant); else path = g_strdup_printf ("/mobi/phosh/stevia/layouts/%s.json", layout);