Skip to content

Commit

Permalink
Merge pull request #612 from chewing/autoload-additional-dict
Browse files Browse the repository at this point in the history
feat(dict): Automatically load extra dictionaries found in search path
  • Loading branch information
kanru authored Jul 15, 2024
2 parents 2a23796 + 2ea6f5b commit b31ac2a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 6 deletions.
25 changes: 19 additions & 6 deletions src/dictionary/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use std::{
path::{Path, PathBuf},
};

use log::info;
use log::{info, warn};

use crate::{
editor::{AbbrevTable, SymbolSelector},
path::{find_path_by_files, sys_path_from_env_var, userphrase_path},
path::{find_extra_dat_by_path, find_path_by_files, sys_path_from_env_var, userphrase_path},
};

#[cfg(feature = "sqlite")]
Expand Down Expand Up @@ -70,15 +70,28 @@ impl SystemDictionaryLoader {
let sys_path = find_path_by_files(&search_path, &[SD_WORD_FILE_NAME, SD_TSI_FILE_NAME])
.ok_or(LoadDictionaryError::NotFound)?;

let tsi_dict_path = sys_path.join(SD_TSI_FILE_NAME);
info!("Loading {SD_TSI_FILE_NAME}");
let tsi_dict = Trie::open(tsi_dict_path).map_err(io_err)?;
let mut results: Vec<Box<dyn Dictionary>> = vec![];

let word_dict_path = sys_path.join(SD_WORD_FILE_NAME);
info!("Loading {SD_WORD_FILE_NAME}");
let word_dict = Trie::open(word_dict_path).map_err(io_err)?;
results.push(Box::new(word_dict));

let tsi_dict_path = sys_path.join(SD_TSI_FILE_NAME);
info!("Loading {SD_TSI_FILE_NAME}");
let tsi_dict = Trie::open(tsi_dict_path).map_err(io_err)?;
results.push(Box::new(tsi_dict));

let extra_files = find_extra_dat_by_path(&search_path);
for path in extra_files {
info!("Loading {}", path.display());
match Trie::open(&path) {
Ok(dict) => results.push(Box::new(dict)),
Err(e) => warn!("Failed to load {}: {e}", path.display()),
}
}

Ok(vec![Box::new(word_dict), Box::new(tsi_dict)])
Ok(results)
}
pub fn load_abbrev(&self) -> Result<AbbrevTable, LoadDictionaryError> {
let search_path = if let Some(sys_path) = &self.sys_path {
Expand Down
30 changes: 30 additions & 0 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::{
env,
ffi::OsStr,
path::{Path, PathBuf},
};

Expand All @@ -17,6 +18,8 @@ const SEARCH_PATH_SEP: char = ';';
#[cfg(target_family = "unix")]
const SEARCH_PATH_SEP: char = ':';

const DICT_FOLDER: &str = "dictionary.d";

pub(crate) fn sys_path_from_env_var() -> String {
let chewing_path = env::var("CHEWING_PATH");
if let Ok(chewing_path) = chewing_path {
Expand Down Expand Up @@ -55,6 +58,33 @@ pub(crate) fn find_path_by_files(search_path: &str, files: &[&str]) -> Option<Pa
None
}

pub(crate) fn find_extra_dat_by_path(search_path: &str) -> Vec<PathBuf> {
let mut results = vec![];
for path in search_path.split(SEARCH_PATH_SEP) {
let prefix = Path::new(path).join(DICT_FOLDER);
info!("Search dictionary files in {}", prefix.display());
if let Ok(read_dir) = prefix.read_dir() {
let mut files = vec![];
for entry in read_dir {
if let Ok(entry) = entry {
let path = entry.path();
let is_dat = path
.extension()
.and_then(OsStr::to_str)
.map_or(false, |ext| ext == "dat");
if path.is_file() && is_dat {
info!("Found {}", path.display());
files.push(path);
}
}
}
files.sort();
results.extend(files);
}
}
results
}

/// Returns the path to the user's default chewing data directory.
///
/// The returned value depends on the operating system and is either a
Expand Down
Binary file added tests/data/dictionary.d/01-extra.dat
Binary file not shown.
Empty file.
2 changes: 2 additions & 0 deletions tests/data/extra.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
額 0 ㄜˊ
外 0 ㄨㄞˋ
17 changes: 17 additions & 0 deletions tests/test-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,21 @@ void test_runtime_version()
ok(strcmp(buf, version) == 0, "chewing_version can be created from components");
}

void test_dictionary_d()
{
ChewingContext *ctx;

ctx = chewing_new2(TEST_DATA_DIR, NULL, logger, fd);
start_testcase(ctx, fd);

ok(ctx != NULL, "chewing_new2 returns `%#p' shall not be `%#p'", ctx, NULL);

type_keystroke_by_string(ctx, "k6j94<E>");
ok_commit_buffer(ctx, "額外");

chewing_delete(ctx);
}

int main(int argc, char *argv[])
{
char *logname;
Expand Down Expand Up @@ -785,6 +800,8 @@ int main(int argc, char *argv[])

test_runtime_version();

test_dictionary_d();

fclose(fd);

return exit_status();
Expand Down

0 comments on commit b31ac2a

Please sign in to comment.