Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge new changes into master #10

Merged
merged 10 commits into from
Jun 11, 2024
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -fsanitize=address,undefined -fsanitize-undefined-trap-on-error -fstack-protector-strong")
else ()
add_compile_options(-Ofast -flto -march=native -g)
add_compile_options(-Ofast -flto -march=native -mtune=native -g)
endif ()

add_definitions(${GTK3_CFLAGS_OTHER} ${NOTIFY_CFLAGS_OTHER}
Expand Down Expand Up @@ -117,7 +117,8 @@ endif ()
# Install
# ##############################################################################
install(TARGETS dictpopup dictpopup-create DESTINATION bin)
install(FILES config.ini DESTINATION share)
install(FILES config.ini DESTINATION share/dictpopup)
install(FILES data.mdb DESTINATION share/dictpopup)
install(
DIRECTORY man1/
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
Expand Down
Binary file modified data.mdb
Binary file not shown.
28 changes: 2 additions & 26 deletions include/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,13 @@ __attribute__((unused)) static bool debug_mode_enabled(void) {
#ifdef NOTIFICATIONS
#define msg(fmt, ...) \
do { \
const char *ORIGIN; \
if (s8equals(S(__FILE__), S("src/jppron.c"))) \
ORIGIN = "jppron"; \
else \
ORIGIN = "dictpopup"; \
notify(ORIGIN, 0, fmt, ##__VA_ARGS__); \
printf("(%s): ", ORIGIN); \
notify(0, fmt, ##__VA_ARGS__); \
printf(fmt, ##__VA_ARGS__); \
putchar('\n'); \
} while (0)
#else
#define msg(fmt, ...) \
do { \
const char *ORIGIN; \
if (s8equals(S(__FILE__), S("src/jppron.c"))) \
ORIGIN = "jppron"; \
else \
ORIGIN = "dictpopup"; \
printf("(%s) ", ORIGIN); \
printf(fmt, ##__VA_ARGS__); \
putchar('\n'); \
} while (0)
Expand All @@ -63,26 +51,14 @@ __attribute__((unused)) static bool debug_mode_enabled(void) {
#ifdef NOTIFICATIONS
#define err(fmt, ...) \
do { \
const char *ORIGIN; \
if (s8equals(S(__FILE__), S("src/jppron.c"))) \
ORIGIN = "jppron"; \
else \
ORIGIN = "dictpopup"; \
notify(ORIGIN, 1, fmt, ##__VA_ARGS__); \
fprintf(stderr, "(%s): ", ORIGIN); \
notify(1, fmt, ##__VA_ARGS__); \
fprintf(stderr, "\033[0;31mERROR\033[0m: %s(%d): ", __FILE__, __LINE__); \
fprintf(stderr, fmt, ##__VA_ARGS__); \
fputc('\n', stderr); \
} while (0)
#else
#define err(fmt, ...) \
do { \
const char *ORIGIN; \
if (s8equals(S(__FILE__), S("src/jppron.c"))) \
ORIGIN = "jppron"; \
else \
ORIGIN = "dictpopup"; \
fprintf(stderr, "(%s) ", ORIGIN); \
fprintf(stderr, "\033[0;31mERROR\033[0m: %s(%d): ", __FILE__, __LINE__); \
fprintf(stderr, fmt, ##__VA_ARGS__); \
fputc('\n', stderr); \
Expand Down
4 changes: 3 additions & 1 deletion include/platformdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
#define PLATFORMDEP_H

#include "util.h"
#include <stdbool.h>

void _nonnull_n_(1) notify(const char *title, _Bool urgent, char const *fmt, ...);
void notify(_Bool urgent, char const *fmt, ...);
s8 get_selection(void);
s8 get_clipboard(void);
s8 get_next_clipboard(void);
Expand All @@ -12,5 +13,6 @@ void free_windowname(s8 windowname);
void play_audio(s8 filepath);
void _nonnull_ createdir(char *dirpath);
const char *get_user_data_dir(void);
bool check_file_exists(const char *fn);

#endif // PLATFORMDEP_H
5 changes: 3 additions & 2 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "db.h"
#include "messages.h"
#include "platformdep.h"
#include "util.h"

DEFINE_DROP_FUNC(MDB_cursor *, mdb_cursor_close)
Expand Down Expand Up @@ -33,7 +34,7 @@ database_t *db_open(char *dbpath, bool readonly) {

if (readonly) {
die_on(!db_check_exists(fromcstr_(dbpath)),
"There is no database in '%s'. You must create it first with dictpopup-create.",
"There is no database in '%s'. You must create one first with dictpopup-create.",
dbpath);

C(mdb_env_open(db->env, dbpath, MDB_RDONLY | MDB_NOLOCK | MDB_NORDAHEAD, 0664));
Expand Down Expand Up @@ -235,7 +236,7 @@ void db_get_dictents(const database_t *db, s8 headword, dictentry *dict[static 1

i32 db_check_exists(s8 dbpath) {
_drop_(frees8) s8 dbfile = buildpath(dbpath, S("data.mdb"));
return (access((char *)dbfile.s, R_OK) == 0);
return check_file_exists((char *)dbfile.s);
}

void db_remove(s8 dbpath) {
Expand Down
25 changes: 25 additions & 0 deletions src/dictpopup.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include "settings.h"
#include "util.h"

#include <gio/gio.h>

// This only applies for substring search
// 60 are 20 Japanese characters
#define MAX_LOOKUP_LEN 60 // in bytes
Expand Down Expand Up @@ -180,11 +182,34 @@ static s8 convert_to_utf8(char *str) {
return ret;
}

static void copy_default_database(char *dbdir) {
// TODO: Make default loc OS independent
const char *default_database_location = "/usr/local/share/dictpopup/data.mdb";
die_on(!check_file_exists(default_database_location),
"Could not access the default database either. You need to create your own with"
"dictpopup-create or download data.mdb from the repository.");

_drop_(frees8) s8 dbpath = buildpath(fromcstr_(dbdir), S("data.mdb"));
createdir(dbdir);

GFile *source = g_file_new_for_path(default_database_location);
GFile *dest = g_file_new_for_path((char *)dbpath.s);
g_file_copy(source, dest, G_FILE_COPY_NONE, NULL, NULL, NULL, NULL);
g_object_unref(source);
g_object_unref(dest);
}

dictpopup_t dictpopup_init(int argc, char **argv) {
setlocale(LC_ALL, "");
read_user_settings(POSSIBLE_ENTRIES_S_NMEMB);
int nextarg = parse_cmd_line_opts(argc, argv); // Should be second to overwrite settings

if (!db_check_exists(fromcstr_(cfg.general.dbpth))) {
msg("No database found. We recommend creating your own database with dictpopup-create, but "
"copying default dictionary for now..");
copy_default_database(cfg.general.dbpth);
}

possible_entries_s p = {0};

p.windowname = get_windowname();
Expand Down
9 changes: 5 additions & 4 deletions src/frontends/gtk3popup.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,20 @@ static void play_pronunciation(void) {
}

static void draw_dot(cairo_t *cr) {
// The colors are the same Anki uses
switch (exists_in_anki) {
case -1:
// Don't draw on error
// TODO: Draw when Anki gets started?
return;
case 0:
cairo_set_source_rgb(cr, 1, 0, 0); // red
cairo_set_source_rgb(cr, 0.9490, 0.4431, 0.4431); // red
break;
case 1:
cairo_set_source_rgb(cr, 0, 1, 0); // green
cairo_set_source_rgb(cr, 0.1333, 0.7725, 0.3686); // green
break;
case 2:
cairo_set_source_rgb(cr, 0, 0, 1); // blue
cairo_set_source_rgb(cr, 0.5765, 0.7725, 0.9922); // blue
break;
case 3:
cairo_set_source_rgb(cr, 1, 0.5, 0); // orange
Expand Down Expand Up @@ -233,7 +234,7 @@ static void prepare_add_to_anki(window_ret_s *ret) {
static void show_add_anki_button_menu(GtkWidget *button, window_ret_s *ret) {
GtkWidget *menu = gtk_menu_new();

GtkWidget *menu_item = gtk_menu_item_new_with_label("Add from clipboard");
GtkWidget *menu_item = gtk_menu_item_new_with_label("Add with clipboard content as definition");
g_signal_connect(menu_item, "activate", G_CALLBACK(add_anki_from_clipboard), ret);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);

Expand Down
8 changes: 6 additions & 2 deletions src/platformdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "platformdep.h"

#ifdef NOTIFICATIONS
void notify(const char *title, _Bool urgent, char const *fmt, ...) {
void notify(_Bool urgent, char const *fmt, ...) {
va_list argp;
va_start(argp, fmt);
g_autofree char *txt = g_strdup_vprintf(fmt, argp);
Expand All @@ -23,7 +23,7 @@ void notify(const char *title, _Bool urgent, char const *fmt, ...) {
return;

notify_init("dictpopup");
NotifyNotification *n = notify_notification_new(title, txt, NULL);
NotifyNotification *n = notify_notification_new("dictpopup", txt, NULL);
notify_notification_set_urgency(n, urgent ? NOTIFY_URGENCY_CRITICAL : NOTIFY_URGENCY_NORMAL);
notify_notification_set_timeout(n, 10000);

Expand Down Expand Up @@ -129,3 +129,7 @@ void createdir(char *dirpath) {
const char *get_user_data_dir(void) {
return g_get_user_data_dir();
}

bool check_file_exists(const char *fn) {
return access(fn, R_OK) == 0;
}
4 changes: 4 additions & 0 deletions src/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ static void copy_ready_callback(GObject *source_object, GAsyncResult *res, gpoin
static void copy_default_config(char *cfgfile) {
// TODO: Make default loc OS independent
const char *default_config_location = "/usr/local/share/dictpopup/config.ini";
if (!check_file_exists(default_config_location)) {
dbg("Could not access default config");
return;
}

char *cfgdir = dirname(cfgfile);
createdir(cfgdir);
Expand Down
57 changes: 33 additions & 24 deletions src/yomichan_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ static s8 unzip_file(zip_t *archive, const char *filename) {
/* -------------------- */

static s8 parse_liststyletype(s8 lst) {
// TODO: This is a memory leak
if (startswith(lst, S("\"")) && endswith(lst, S("\"")))
if ((startswith(lst, S("\"")) && endswith(lst, S("\""))) ||
(startswith(lst, S("'")) && endswith(lst, S("'"))))
return cuttail(cuthead(lst, 1), 1);
else if (s8equals(lst, S("circle")))
return S("◦");
Expand All @@ -82,13 +82,19 @@ static s8 parse_liststyletype(s8 lst) {
return lst; // そのまま
}

static void ensure_ends_on_newline(stringbuilder_s *sb) {
if (sb->len != 0 && sb->data[sb->len - 1] != '\n')
sb_append(sb, S("\n"));
}

static void append_structured_content(yyjson_val *obj, stringbuilder_s sb[static 1], s8 liststyle,
i32 listdepth) {
enum tag_type tag = TAG_UNKNOWN;

if (!yyjson_is_obj(obj))
err("Structured content is not an object.");

enum tag_type tag = TAG_UNKNOWN;
yyjson_val *content = NULL;

size_t idx, max;
yyjson_val *key, *val;
yyjson_obj_foreach(obj, idx, max, key, val) {
Expand All @@ -104,7 +110,8 @@ static void append_structured_content(yyjson_val *obj, stringbuilder_s sb[static
tag = TAG_UL;
listdepth++;

liststyle = S("•"); // default
if (!liststyle.len)
liststyle = S("•"); // default value
} else if (s8equals(s8val, S("ol"))) {
tag = TAG_OL;
listdepth++;
Expand All @@ -115,9 +122,8 @@ static void append_structured_content(yyjson_val *obj, stringbuilder_s sb[static
tag = TAG_RUBY_RT;
} else
tag = TAG_UNKNOWN;
} else if ((tag == TAG_UL || tag == TAG_LI) && s8equals(s8key, S("style"))) {
} else if (s8equals(s8key, S("style"))) {
if (yyjson_is_obj(val)) {

size_t idx2, max2;
yyjson_val *key2, *val2;
yyjson_obj_foreach(val, idx2, max2, key2, val2) {
Expand All @@ -128,25 +134,28 @@ static void append_structured_content(yyjson_val *obj, stringbuilder_s sb[static
} else
dbg("Could not parse style of list. Skipping..");
} else if (s8equals(s8key, S("content"))) {
if (tag == TAG_RUBY_RT) {
continue;
}

if (tag == TAG_DIV || tag == TAG_LI) {
if (sb->len != 0 && sb->data[sb->len - 1] != '\n')
sb_append(sb, S("\n"));
}

if (tag == TAG_LI) {
for (i32 i = 0; i < listdepth - 1; i++)
sb_append(sb, S("\t"));
sb_append(sb, liststyle);
sb_append(sb, S(" "));
}

append_definition(val, sb, liststyle, listdepth, false);
content = val; // parse content last
}
}

switch (tag) {
case TAG_RUBY_RT:
// Don't display ruby (for now)
return;
case TAG_DIV:
ensure_ends_on_newline(sb);
break;
case TAG_LI:
ensure_ends_on_newline(sb);
for (i32 i = 0; i < listdepth - 1; i++)
sb_append(sb, S("\t"));
sb_append(sb, liststyle);
sb_append(sb, S(" "));
break;
default:;
}

append_definition(content, sb, liststyle, listdepth, false);
}

static void append_definition(yyjson_val *def, stringbuilder_s sb[static 1], s8 liststyle,
Expand Down
4 changes: 3 additions & 1 deletion tests/files/dictionary_entries/6_entry
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
],
"data":{"content":"glossary"},
"lang":"en",
"style":{"listStyleType":"circle"},"tag":"ul"},
"style":{"listStyleType":"circle"},
"tag":"ul"
},
{
"content":
[
Expand Down
4 changes: 2 additions & 2 deletions tests/files/dictionary_entries/6_expected
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
◦ competent
◦ domineering
◦ tough
🇯🇵 その釣り人は釣り糸に強い引きを感じた。
🇬🇧 The angler felt a strong tug on the line.
🇯🇵 その釣り人は釣り糸に強い引きを感じた。
🇬🇧 The angler felt a strong tug on the line.
Loading