Skip to content

Commit

Permalink
Extend support for pronunciation
Browse files Browse the repository at this point in the history
* Allow creating pronunciation index in preferences window
* Show a menu on right click with all possible pronunciations
  • Loading branch information
btrkeks committed Aug 20, 2024
1 parent 9252435 commit 6150957
Show file tree
Hide file tree
Showing 23 changed files with 466 additions and 158 deletions.
55 changes: 50 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.5)

project(dictpopup
VERSION 0.3
HOMEPAGE_URL "https://github.com/Ajatt-Tools/dictpopup"
LANGUAGES C
project(dictpopup
VERSION 0.3
HOMEPAGE_URL "https://github.com/Ajatt-Tools/dictpopup"
LANGUAGES C
)

include(GNUInstallDirs)
Expand Down Expand Up @@ -90,8 +90,9 @@ add_definitions(${GTK3_CFLAGS_OTHER} ${NOTIFY_CFLAGS_OTHER} ${LIBZIP_DEFINITIONS

set(JPPRON_SRCS
src/jppron/jppron.c
src/jppron/database.c
src/jppron/jppron_database.c
src/jppron/ajt_audio_index_parser.c
src/jppron/jppron_objects.c
lib/yyjson.c
src/objects/dict.c
include/objects/freqentry.h
Expand Down Expand Up @@ -344,6 +345,7 @@ if (BUILD_TESTS)
enable_testing()
find_package(cgreen REQUIRED)
add_dictpopup_executable(c_tests
tests/dp_application_tests.c
src/utils/util.c
src/utils/utf8.c
src/utils/str.c
Expand Down Expand Up @@ -381,6 +383,49 @@ if (BUILD_TESTS)
# add_test(NAME run_shell_test COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/full_cycle_test.sh)
endif ()

#add_dictpopup_executable(gui_tests
# tests/dp_application_tests.c
# src/frontends/gtk3popup/dictpopup-application.c
# src/frontends/gtk3popup/dp-settings.c
# src/frontends/gtk3popup/dp-preferences-window.c
# src/frontends/gtk3popup/dict_state_manager.c
# src/frontends/gtk3popup/callbacks.c
# src/utils/util.c
# src/utils/utf8.c
# src/utils/str.c
# src/platformdep/audio.c
# src/platformdep/notifications.c
# src/platformdep/clipboard.c
# src/platformdep/file_operations.c
# src/platformdep/windowtitle.c
# src/objects/freqentry.c
# ${JPPRON_SRCS}
# ${ANKI_SRCS}
# ${DICTLOOKUP_SRCS}
# ${GRESOURCE_C}
# ${DEINFLECTION_RULES_C}
# ${COMPILED_SETTINGS_SCHEMA}
#)
#target_compile_definitions(gui_tests PRIVATE UNIT_TEST CLIPBOARD)
#target_include_directories(gui_tests PRIVATE
# ${GTK3_INCLUDE_DIRS}
# ${CGREEN_INCLUDE_DIRS}
# lib/
# include/
# src/
# src/jppron
#)
#target_link_libraries(gui_tests PRIVATE
# ${CGREEN_LIBRARIES}
# MECAB::MECAB
# PkgConfig::GTK3
# libzip::zip
# LMDB::LMDB
# CURL::libcurl
# PkgConfig::NOTIFY
#)
#add_test(NAME run_gui_tests COMMAND $<TARGET_FILE:gui_tests>)

# ##############################################################################
# Install
# ##############################################################################
Expand Down
23 changes: 18 additions & 5 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
## dictpopup
- Implement 'anki_set_entry_of_field'
- Save selected mappings to GSettings
- When no entries -> Show "No entries" in definition instead of notification
- Allows changing settings when no dictionaries yet
- Disable pronunciation button if nothing found

- Add Anki button right click menu

- Create pronounce button right click menu only when needed
- Cache pronfiles per kanji/reading pair

- What happens if jppron create gets called twice?
-> Move to preferences

- Suspended + new cards indicator?

- Proper error handling on faulty Anki settings
- Allow creating dictpopup db from preferences window

- Add version to database

- What happens if some random folder was selected for pronunciation index?
-> Proper error message

Mid priority
- Move pronunciation button initialization to a different thread?
- Settings should work without a database
- Check if sentence is mapped to some field and only prompt for it in that case
- Implement the reading label as a text view to allow for editing -> initiate new search on Enter press
- Group terms by reading, allow for switching between different readings
Expand Down
10 changes: 2 additions & 8 deletions include/jppron/ajt_audio_index_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@
#define AUDIO_INDEX_PARSER_H

#include "utils/str.h"

typedef struct {
s8 origin;
s8 hira_reading;
s8 pitch_number;
s8 pitch_pattern;
} fileinfo_s;
#include "jppron_objects.h"

void parse_audio_index_from_file(s8 curdir, const char *index_filepath,
void (*foreach_headword)(void *, s8, s8), void *userdata_hw,
void (*foreach_file)(void *, s8, fileinfo_s), void *userdata_f);
void (*foreach_file)(void *, s8, FileInfo), void *userdata_f);

#endif // AUDIO_INDEX_PARSER_H
27 changes: 0 additions & 27 deletions include/jppron/database.h

This file was deleted.

2 changes: 1 addition & 1 deletion include/jppron/jppron.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ void jppron(Word word, char *audio_folders_path);
/* _deallocator_(free_pronfile_buffer) */ // TODO: Check why this gives compiler errors
Pronfile *get_pronfiles_for(Word word);

void jppron_create_if_not_existing(char *audio_folders_path);
void jppron_create_index(const char *audio_folders_path);

#endif // JPPRON_H
5 changes: 3 additions & 2 deletions include/objects/dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ typedef struct {
} Word;

Word word_dup(Word word);
void word_ptr_free(Word *word);
void word_free(Word word);
DEFINE_DROP_FUNC(Word, word_free)

typedef struct {
s8 dictname;
Expand All @@ -31,7 +32,7 @@ typedef struct {
Dict newDict(void);
bool isEmpty(Dict dict);
void _nonnull_ dictionary_add(Dict *dict, dictentry de);
size_t num_of_dictentries(Dict dict);
size_t num_entries(Dict dict);

// Sorts @dict in place
// Not thread safe
Expand Down
3 changes: 2 additions & 1 deletion include/platformdep/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <utils/str.h>

void play_audio(s8 filepath);
void play_audio_sync(s8 filepath);
void play_audio_async(s8 filepath);

#endif // AUDIO_H
7 changes: 3 additions & 4 deletions include/utils/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ typedef __PTRDIFF_TYPE__ isize;
/**
* Memory allocation wrapper which abort on failure
*/
__attribute__((malloc, returns_nonnull)) _deallocator_(free) void *xcalloc(size_t nmemb,
size_t size);
__attribute__((malloc, returns_nonnull))
_deallocator_(free) void *xcalloc(size_t nmemb, size_t size);
__attribute__((malloc, returns_nonnull)) _deallocator_(free) void *xrealloc(void *ptr, size_t size);
// clang-format off
#define new(type, num) xcalloc(num, sizeof(type))
Expand All @@ -58,8 +58,7 @@ size_t _printf_(3, 4) snprintf_safe(char *buf, size_t len, const char *fmt, ...)
}
#define DEFINE_DROP_FUNC(type, func) \
static inline void drop_##func(type *p) { \
if (*p) \
func(*p); \
func(*p); \
}
#define DEFINE_DROP_FUNC_VOID(func) \
static inline void drop_##func(void *p) { \
Expand Down
52 changes: 26 additions & 26 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct database_s {
bool readonly;
};

#define DB_TRY(call) \
#define MDB_CHECK(call) \
do { \
int _rc = (call); \
die_on(_rc != MDB_SUCCESS, "Database error: %s", mdb_strerror(_rc)); \
Expand All @@ -44,37 +44,37 @@ database_t *db_open(s8 dbdir, bool readonly) {
database_t *db = new (database_t, 1);
db->readonly = readonly;

DB_TRY(mdb_env_create(&db->env));
MDB_CHECK(mdb_env_create(&db->env));
mdb_env_set_maxdbs(db->env, DB_MAX_DBS);

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

DB_TRY(
MDB_CHECK(
mdb_env_open(db->env, (char *)dbdir.s, MDB_RDONLY | MDB_NOLOCK | MDB_NORDAHEAD, 0664));
DB_TRY(mdb_txn_begin(db->env, NULL, MDB_RDONLY, &db->txn));
MDB_CHECK(mdb_txn_begin(db->env, NULL, MDB_RDONLY, &db->txn));

DB_TRY(
MDB_CHECK(
mdb_dbi_open(db->txn, DB_WORDS_TO_ID, MDB_DUPSORT | MDB_DUPFIXED, &db->db_words_to_id));
DB_TRY(
MDB_CHECK(
mdb_dbi_open(db->txn, DB_ID_TO_DEFINITIONS, MDB_INTEGERKEY, &db->db_id_to_definition));
DB_TRY(mdb_dbi_open(db->txn, DB_FREQUENCIES, 0, &db->db_frequencies));
DB_TRY(mdb_dbi_open(db->txn, DB_METADATA, 0, &db->db_metadata));
MDB_CHECK(mdb_dbi_open(db->txn, DB_FREQUENCIES, 0, &db->db_frequencies));
MDB_CHECK(mdb_dbi_open(db->txn, DB_METADATA, 0, &db->db_metadata));
} else {
unsigned int mapsize = 2097152000; // 2Gb
DB_TRY(mdb_env_set_mapsize(db->env, mapsize));
MDB_CHECK(mdb_env_set_mapsize(db->env, mapsize));

DB_TRY(mdb_env_open(db->env, (char *)dbdir.s, 0, 0664));
DB_TRY(mdb_txn_begin(db->env, NULL, 0, &db->txn));
MDB_CHECK(mdb_env_open(db->env, (char *)dbdir.s, 0, 0664));
MDB_CHECK(mdb_txn_begin(db->env, NULL, 0, &db->txn));

DB_TRY(mdb_dbi_open(db->txn, DB_WORDS_TO_ID, MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE,
MDB_CHECK(mdb_dbi_open(db->txn, DB_WORDS_TO_ID, MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE,
&db->db_words_to_id));
DB_TRY(mdb_dbi_open(db->txn, DB_ID_TO_DEFINITIONS, MDB_INTEGERKEY | MDB_CREATE,
MDB_CHECK(mdb_dbi_open(db->txn, DB_ID_TO_DEFINITIONS, MDB_INTEGERKEY | MDB_CREATE,
&db->db_id_to_definition));
DB_TRY(mdb_dbi_open(db->txn, DB_FREQUENCIES, MDB_CREATE, &db->db_frequencies));
DB_TRY(mdb_dbi_open(db->txn, DB_METADATA, MDB_CREATE, &db->db_metadata));
MDB_CHECK(mdb_dbi_open(db->txn, DB_FREQUENCIES, MDB_CREATE, &db->db_frequencies));
MDB_CHECK(mdb_dbi_open(db->txn, DB_METADATA, MDB_CREATE, &db->db_metadata));

db->datastr = sb_init(200);
db->lastdatastr = sb_init(200);
Expand All @@ -87,7 +87,7 @@ void db_close(database_t *db) {
if (db->readonly) {
mdb_txn_abort(db->txn);
} else {
DB_TRY(mdb_txn_commit(db->txn));
MDB_CHECK(mdb_txn_commit(db->txn));

sb_free(&db->datastr);
sb_free(&db->lastdatastr);
Expand Down Expand Up @@ -123,7 +123,7 @@ static void put_de_if_new(database_t *db, dictentry de) {
s8 datastr = sb_gets8(db->datastr);
db->last_id++; // Note: The above id struct updates too
MDB_val val_mdb = {.mv_data = datastr.s, .mv_size = datastr.len};
DB_TRY(mdb_put(db->txn, db->db_id_to_definition, &id_mdb, &val_mdb,
MDB_CHECK(mdb_put(db->txn, db->db_id_to_definition, &id_mdb, &val_mdb,
MDB_NOOVERWRITE | MDB_APPEND));

stringbuilder_s tmp = db->lastdatastr;
Expand Down Expand Up @@ -161,14 +161,14 @@ static u32 *get_ids(const database_t *db, s8 word, size_t *num) {
MDB_val val_mdb = {0};

_drop_(mdb_cursor_close) MDB_cursor *cursor;
DB_TRY(mdb_cursor_open(db->txn, db->db_words_to_id, &cursor));
MDB_CHECK(mdb_cursor_open(db->txn, db->db_words_to_id, &cursor));

int rc = mdb_cursor_get(cursor, &key_mdb, &val_mdb, MDB_SET);
if (rc == MDB_NOTFOUND)
return NULL;
DB_TRY(rc);
MDB_CHECK(rc);
// This reads up to a page, i.e. max 1024 entries, which should be enough
DB_TRY(mdb_cursor_get(cursor, &key_mdb, &val_mdb, MDB_GET_MULTIPLE));
MDB_CHECK(mdb_cursor_get(cursor, &key_mdb, &val_mdb, MDB_GET_MULTIPLE));

*num = val_mdb.mv_size / sizeof(u32);
assume(*num * sizeof(u32) == val_mdb.mv_size); // divides cleanly
Expand All @@ -184,7 +184,7 @@ void db_put_freq(database_t *db, freqentry fe) {
MDB_val key_mdb = {.mv_data = key.s, .mv_size = key.len};
MDB_val val_mdb = {.mv_data = &fe.frequency, .mv_size = sizeof(fe.frequency)};

DB_TRY(mdb_put(db->txn, db->db_frequencies, &key_mdb, &val_mdb, MDB_NODUPDATA));
MDB_CHECK(mdb_put(db->txn, db->db_frequencies, &key_mdb, &val_mdb, MDB_NODUPDATA));
}

static u32 db_get_freq(const database_t *db, s8 word, s8 reading) {
Expand All @@ -195,7 +195,7 @@ static u32 db_get_freq(const database_t *db, s8 word, s8 reading) {
int rc = mdb_get(db->txn, db->db_frequencies, &key_m, &val_m);
if (rc == MDB_NOTFOUND)
return 0;
DB_TRY(rc);
MDB_CHECK(rc);

u32 freq;
assume(sizeof(freq) == val_m.mv_size);
Expand Down Expand Up @@ -240,7 +240,7 @@ static dictentry data_to_dictent(const database_t *db, s8 data) {
static s8 getdata(const database_t *db, u32 id) {
MDB_val key = (MDB_val){.mv_data = &id, .mv_size = sizeof(id)};
MDB_val data = {0};
DB_TRY(mdb_get(db->txn, db->db_id_to_definition, &key, &data));
MDB_CHECK(mdb_get(db->txn, db->db_id_to_definition, &key, &data));
return (s8){.s = data.mv_data, .len = data.mv_size};
}

Expand Down Expand Up @@ -279,10 +279,10 @@ void _nonnull_ db_put_dictname(database_t *db, s8 dictname) {
data.mv_size = new_value.len;
data.mv_data = new_value.s;
} else {
DB_TRY(rc);
MDB_CHECK(rc);
}

DB_TRY(mdb_put(db->txn, db->db_metadata, &key, &data, 0));
MDB_CHECK(mdb_put(db->txn, db->db_metadata, &key, &data, 0));

if (data.mv_data != dictname.s) {
free(data.mv_data);
Expand All @@ -298,7 +298,7 @@ s8Buf db_get_dictnames(database_t *db) {
if (rc == MDB_NOTFOUND) {
return NULL;
}
DB_TRY(rc);
MDB_CHECK(rc);

s8 all_names = {.s = data.mv_data, .len = data.mv_size};
s8 *names = NULL;
Expand Down
Loading

0 comments on commit 6150957

Please sign in to comment.