Skip to content

Commit

Permalink
refactor(linux): Add more tests for keymanutil.c 🏘️
Browse files Browse the repository at this point in the history
  • Loading branch information
ermshiperete committed Sep 27, 2023
1 parent 445a19e commit ceb937f
Show file tree
Hide file tree
Showing 9 changed files with 1,348 additions and 390 deletions.
265 changes: 148 additions & 117 deletions linux/ibus-keyman/src/keymanutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@
#include <keyman/keyboardprocessor.h>

#include "bcp47util.h"
#include "keymanutil.h"
#include "kmpdetails.h"
#include "keyman-version.h"
#include "keymanutil.h"
#include "keymanutil_internal.h"

#define N_(text) text

// change to keyman_get_kmpdirs_fromdir
// returns list of directories with kmp.json
GList * keyman_get_kmpdirs_fromdir( GList *keyboard_list, const gchar * path)
GList * keyman_get_kmpdirs_fromdir(GList *kmpdir_list, const gchar * path)
{
DIR *dir = opendir(path);

Expand All @@ -80,21 +81,21 @@ GList * keyman_get_kmpdirs_fromdir( GList *keyboard_list, const gchar * path)
if (S_ISDIR(filestat.st_mode))
{
if(g_strcmp0(file->d_name, ".") != 0 && g_strcmp0(file->d_name, "..") != 0)
keyboard_list = keyman_get_kmpdirs_fromdir(keyboard_list, absfn);
kmpdir_list = keyman_get_kmpdirs_fromdir(kmpdir_list, absfn);
}
// Looking for kmp.json
else if (S_ISREG(filestat.st_mode) && g_strcmp0(file->d_name, "kmp.json") == 0)
{
g_message("adding kmp path %s", path);
keyboard_list=g_list_append(keyboard_list, g_strdup(path));
kmpdir_list=g_list_append(kmpdir_list, g_strdup(path));
}
g_free(absfn);

file = readdir(dir);
}
closedir(dir);
}
return keyboard_list;
return kmpdir_list;
}

gchar * keyman_get_icon_file(const gchar *kmx_file)
Expand All @@ -115,7 +116,7 @@ gchar * keyman_get_icon_file(const gchar *kmx_file)
return full_path_to_icon_file;
}

static IBusEngineDesc *
IBusEngineDesc *
ibus_keyman_engine_desc_new (gchar * file_name,
gchar *name,
gchar *description,
Expand Down Expand Up @@ -152,127 +153,157 @@ ibus_keyman_engine_desc_new (gchar * file_name,
return engine_desc;
}

GList *
ibus_keyman_add_engines(GList * engines, GList * kmpdir_list)
{
GList *p, *k, *l, *e;

for (p=kmpdir_list; p != NULL; p = p->next) {
gchar * kmp_dir = (gchar *) p->data;

kmp_details *details = g_new0(kmp_details, 1);
get_kmp_details(kmp_dir, details);

for (k=details->keyboards; k != NULL; k = k->next) {
kmp_keyboard *keyboard = (kmp_keyboard *) k->data;
gboolean alreadyexists = FALSE;

for (e=engines; e != NULL && alreadyexists == FALSE; e = e->next) {
IBusEngineDesc *engine_desc = (IBusEngineDesc *) e->data;
const gchar *version = ibus_engine_desc_get_version(engine_desc);
const gchar *engine_name = ibus_engine_desc_get_name(engine_desc);
gchar *kmx_file = g_path_get_basename(engine_name);
if (g_strcmp0(kmx_file, keyboard->kmx_file) == 0 && g_strcmp0(version, keyboard->version) >= 0) {
alreadyexists = TRUE;
g_debug("keyboard %s already exists at version %s which is newer or same as %s", kmx_file, version, keyboard->version);
}
g_free(kmx_file);
}
IBusEngineDesc *
get_engine_for_language(
kmp_keyboard *keyboard,
kmp_info *info,
keyboard_details *kbd_details,
gchar *kmp_dir,
gchar *lang_id,
gchar *lang_name) {
IBusEngineDesc* engine_desc = NULL;
if (!lang_id || !strlen(lang_id))
return engine_desc;

if (!alreadyexists) {
gchar *abs_kmx = g_strjoin("/", kmp_dir, keyboard->kmx_file, NULL);
gchar *json_file = g_strjoin(".", keyboard->id, "json", NULL);
keyboard_details *kbd_details = g_new0(keyboard_details, 1);
get_keyboard_details(kmp_dir, json_file, kbd_details);
g_free(json_file);

if (keyboard->languages != NULL) {
for (l=keyboard->languages; l != NULL; l = l->next) {
kmp_language *language = (kmp_language *) l->data;
if (language->id != NULL) {
int capacity = 255;
gchar *name_with_lang = NULL;
gchar *minimized_tag = g_new0(gchar, capacity);
int result = bcp47_minimize(language->id, minimized_tag, capacity);
if (result < 0) {
g_strlcpy(minimized_tag, language->id, capacity);
}

gchar *lang_code = g_new0(gchar, capacity);
if (!bcp47_get_language_code(minimized_tag, lang_code, capacity)) {
g_strlcpy(lang_code, minimized_tag, capacity);
}

// If ibus doesn't know about the language then append the
// language name to the keyboard name
if (language->name != NULL) {
gchar *ibus_lang = ibus_get_untranslated_language_name(lang_code);
g_debug("%s: untranslated ibus language for %s: %s", __FUNCTION__, minimized_tag, ibus_lang);
if (g_strcmp0(ibus_lang, "Other") == 0) {
name_with_lang = g_strjoin(" - ", keyboard->name, language->name, NULL);
}
g_free(ibus_lang);
}

gchar *id_with_lang = g_strjoin(":", minimized_tag, abs_kmx, NULL);

g_message("adding engine %s", id_with_lang);
engines = g_list_append(
engines,
ibus_keyman_engine_desc_new(
id_with_lang, // lang:kmx full path
name_with_lang ? name_with_lang : keyboard->name, // longname
kbd_details->description, // description
details->info.copyright, // copyright if available
lang_code, // language, most are ignored by ibus except major languages
kbd_details->license, // license
details->info.author_desc, // author name only, not email
keyman_get_icon_file(abs_kmx), // icon full path
"us", // layout defaulting to us (en-US)
keyboard->version));
g_free(lang_code);
g_free(minimized_tag);
g_free(id_with_lang);
g_free(name_with_lang);
}
}
}
else {
g_message("adding engine %s", abs_kmx);
engines = g_list_append (engines,
ibus_keyman_engine_desc_new (abs_kmx, // kmx full path
keyboard->name, // longname
kbd_details->description, // description
details->info.copyright, // copyright if available
NULL, // language, most are ignored by ibus except major languages
kbd_details->license, // license
details->info.author_desc, // author name only, not email
keyman_get_icon_file(abs_kmx), // icon full path
"us", // layout defaulting to us (en-US)
keyboard->version));
}
free_keyboard_details(kbd_details);
g_free(kbd_details);
g_free(abs_kmx);
}
int capacity = 255;
gchar *name_with_lang = NULL;
gchar *minimized_tag = g_new0(gchar, capacity);
int result = bcp47_minimize(lang_id, minimized_tag, capacity);
if (result < 0) {
g_strlcpy(minimized_tag, lang_id, capacity);
}

gchar *lang_code = g_new0(gchar, capacity);
if (!bcp47_get_language_code(minimized_tag, lang_code, capacity)) {
g_strlcpy(lang_code, minimized_tag, capacity);
}

// If ibus doesn't know about the language then append the
// language name to the keyboard name
if (lang_name != NULL) {
gchar *ibus_lang = ibus_get_untranslated_language_name(lang_code);
g_debug("%s: untranslated ibus language for %s: %s", __FUNCTION__, minimized_tag, ibus_lang);
if (g_strcmp0(ibus_lang, "Other") == 0) {
name_with_lang = g_strjoin(" - ", keyboard->name, lang_name, NULL);
}
g_free(ibus_lang);
}

gchar *abs_kmx = g_strjoin("/", kmp_dir, keyboard->kmx_file, NULL);
gchar *id_with_lang = g_strjoin(":", minimized_tag, abs_kmx, NULL);

g_message("adding engine %s", id_with_lang);
engine_desc = ibus_keyman_engine_desc_new(
id_with_lang, // lang:kmx full path
name_with_lang ? name_with_lang : keyboard->name, // longname
kbd_details->description, // description
info->copyright, // copyright if available
lang_code, // language, most are ignored by ibus except major languages
kbd_details->license, // license
info->author_desc, // author name only, not email
keyman_get_icon_file(abs_kmx), // icon full path
"us", // layout defaulting to us (en-US)
keyboard->version);
g_free(abs_kmx);
g_free(lang_code);
g_free(minimized_tag);
g_free(id_with_lang);
g_free(name_with_lang);
return engine_desc;
}

// Add a keyboard (ibus engine) to the list of engines
void
keyman_add_keyboard(gpointer data, gpointer user_data) {
kmp_keyboard *keyboard = (kmp_keyboard *)data;
add_keyboard_data *kb_data = (add_keyboard_data *)user_data;
gboolean alreadyexists = FALSE;

for (GList *e = kb_data->engines_list; e != NULL && alreadyexists == FALSE; e = e->next) {
IBusEngineDesc *engine_desc = (IBusEngineDesc *)e->data;
const gchar *version = ibus_engine_desc_get_version(engine_desc);
const gchar *engine_name = ibus_engine_desc_get_name(engine_desc);
gchar *kmx_file = g_path_get_basename(engine_name);
// If we already have an engine for this keyboard (in a different area), we
// don't want to add it again since we wouldn't add anything new
// if it's the same version
// TODO: fix version comparison (#9593)
if (g_strcmp0(kmx_file, keyboard->kmx_file) == 0 && g_strcmp0(version, keyboard->version) >= 0) {
alreadyexists = TRUE;
g_debug("keyboard %s already exists at version %s which is newer or same as %s", kmx_file, version, keyboard->version);
}
g_free(kmx_file);
}

if (!alreadyexists) {
gchar *json_file = g_strjoin(".", keyboard->id, "json", NULL);
keyboard_details *kbd_details = g_new0(keyboard_details, 1);
get_keyboard_details(kb_data->kmp_dir, json_file, kbd_details);
g_free(json_file);

if (keyboard->languages != NULL) {
for (GList *l = keyboard->languages; l != NULL; l = l->next) {
kmp_language *language = (kmp_language *)l->data;
IBusEngineDesc *engine_desc =
get_engine_for_language(keyboard, kb_data->info, kbd_details, kb_data->kmp_dir, language->id, language->name);
if (engine_desc) {
kb_data->engines_list = g_list_append(kb_data->engines_list, engine_desc);
}
free_kmp_details(details);
g_free(details);
}
} else {
gchar *abs_kmx = g_strjoin("/", kb_data->kmp_dir, keyboard->kmx_file, NULL);
g_message("adding engine %s", abs_kmx);
kb_data->engines_list = g_list_append(
kb_data->engines_list,
ibus_keyman_engine_desc_new(
abs_kmx, // kmx full path
keyboard->name, // longname
kbd_details->description, // description
kb_data->info->copyright, // copyright if available
NULL, // language, most are ignored by ibus except major languages
kbd_details->license, // license
kb_data->info->author_desc, // author name only, not email
keyman_get_icon_file(abs_kmx), // icon full path
"us", // layout defaulting to us (en-US)
keyboard->version));
g_free(abs_kmx);
}
return engines;
free_keyboard_details(kbd_details);
g_free(kbd_details);
}
}

// Add keyboards found in {kmp_dir}/kmp.json to engines_list
void
keyman_add_keyboards_from_dir(gpointer data, gpointer user_data) {
gchar * kmp_dir = (gchar *) data;
GList ** engines_list = (GList **)user_data;

kmp_details *details = g_new0(kmp_details, 1);
if (get_kmp_details(kmp_dir, details) == JSON_OK) {
add_keyboard_data kb_data;
kb_data.engines_list = *engines_list;
kb_data.info = &details->info;
kb_data.kmp_dir = kmp_dir;

g_list_foreach(details->keyboards, keyman_add_keyboard, &kb_data);
*engines_list = kb_data.engines_list;
}
free_kmp_details(details);
g_free(details);
}

GList *
ibus_keyman_list_engines (void)
{
GList *engines = NULL;
GList *keyboard_list;
GList *kmpdir_list;
gchar *local_keyboard_path, *xdgenv;

g_debug("adding from /usr/share/keyman");
keyboard_list = keyman_get_kmpdirs_fromdir(NULL, "/usr/share/keyman");
kmpdir_list = keyman_get_kmpdirs_fromdir(NULL, "/usr/share/keyman");
g_debug("adding from /usr/local/share/keyman");
keyboard_list = keyman_get_kmpdirs_fromdir(keyboard_list, "/usr/local/share/keyman");
kmpdir_list = keyman_get_kmpdirs_fromdir(kmpdir_list, "/usr/local/share/keyman");
xdgenv = getenv("XDG_DATA_HOME");
if (xdgenv != NULL){
local_keyboard_path= g_strdup_printf("%s/keyman", xdgenv);
Expand All @@ -282,10 +313,10 @@ ibus_keyman_list_engines (void)
local_keyboard_path= g_strdup_printf("%s/.local/share/keyman", xdgenv);
}
g_debug("adding from %s", local_keyboard_path);
keyboard_list = keyman_get_kmpdirs_fromdir(keyboard_list, local_keyboard_path);
kmpdir_list = keyman_get_kmpdirs_fromdir(kmpdir_list, local_keyboard_path);
g_free(local_keyboard_path);
engines = ibus_keyman_add_engines(engines, keyboard_list);
g_list_free(keyboard_list);
g_list_foreach(kmpdir_list, keyman_add_keyboards_from_dir, &engines);
g_list_free(kmpdir_list);

return engines;
}
Expand Down
39 changes: 39 additions & 0 deletions linux/ibus-keyman/src/keymanutil_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Internal data structures used in the implementation of keymanutil methods
// and exposed for unit testing.

#ifndef __KEYMANUTIL_INTERNAL_H__
#define __KEYMANUTIL_INTERNAL_H__

#include <gmodule.h>
#include "kmpdetails.h"

typedef struct {
GList *engines_list;
kmp_info *info;
gchar *kmp_dir;
} add_keyboard_data;

IBusEngineDesc *ibus_keyman_engine_desc_new(
gchar *file_name,
gchar *name,
gchar *description,
gchar *copyright,
gchar *lang,
gchar *license,
gchar *author,
gchar *icon,
gchar *layout,
gchar *version);

IBusEngineDesc *get_engine_for_language(
kmp_keyboard *keyboard,
kmp_info *info,
keyboard_details *kbd_details,
gchar *kmp_dir,
gchar *lang_id,
gchar *lang_name);

void keyman_add_keyboard(gpointer data, gpointer user_data);
void keyman_add_keyboards_from_dir(gpointer data, gpointer user_data);

#endif // __KEYMANUTIL_INTERNAL_H__
Loading

0 comments on commit ceb937f

Please sign in to comment.