mirror of
https://github.com/mii443/akaza.git
synced 2025-08-22 14:55:31 +00:00
gtk で設定画面をつくった
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -26,10 +26,13 @@ dependencies = [
|
||||
name = "akaza-conf"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
"gtk4",
|
||||
"libakaza",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
@ -1533,9 +1536,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.16"
|
||||
version = "0.9.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834"
|
||||
checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 2023-01-24(Tue)
|
||||
|
||||
* 設定画面を gtk4-rs で実装した。
|
||||
|
||||
# 2022-12-23(Fri)
|
||||
|
||||
* Started development, again.
|
||||
|
30
README.md
30
README.md
@ -56,36 +56,6 @@ ibus-akaza をインストールしてください。
|
||||
|
||||
## 設定方法
|
||||
|
||||
### config.yml
|
||||
|
||||
XDG の設定ファイルディレクトリ以下、通常であれば `$HOME/.config/akaza/config.yml` に設定ファイルを書くことができます。
|
||||
|
||||
設定可能な項目は以下のもの。
|
||||
|
||||
* ユーザー辞書の設定
|
||||
|
||||
サンプルの設定は以下のような感じになります。
|
||||
akaza が提供しているシステム辞書は偏りがすごくあるので、SKK-JISYO.L を読み込むことをおすすめします。たとえば以下のように設定すると良いでしょう。
|
||||
|
||||
---
|
||||
dicts:
|
||||
- path: /usr/share/skk/SKK-JISYO.L
|
||||
encoding: EucJp
|
||||
dict_type: SKK
|
||||
- path: /usr/share/skk/SKK-JISYO.jinmei
|
||||
encoding: EucJp
|
||||
dict_type: SKK
|
||||
single_term:
|
||||
- path: /usr/share/akaza/SKK-JISYO.dynamic
|
||||
encoding: Utf8
|
||||
dict_type: SKK
|
||||
|
||||
akaza に付属する SKK-JISYO.dynamic を利用すると、「きょう」を変換すると、今日の日付がでるという機能が利用可能です。
|
||||
|
||||
↓ かな入力したい場合は以下のように設定してください。
|
||||
|
||||
romkan: kana
|
||||
|
||||
### Keymap の設定
|
||||
|
||||
Akaza は典型的には以下の順番で探します。
|
||||
|
@ -10,3 +10,6 @@ xdg = "2.4.1"
|
||||
log = "0.4.17"
|
||||
env_logger = "0.10.0"
|
||||
libakaza = { path = "../libakaza" }
|
||||
anyhow = "1.0.68"
|
||||
serde = "1.0.152"
|
||||
serde_yaml = "0.9.17"
|
||||
|
@ -1,65 +1,109 @@
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use gtk::glib::signal::Inhibit;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Application, ApplicationWindow, Button, Label, Notebook};
|
||||
use gtk4 as gtk;
|
||||
use gtk4::builders::ComboBoxTextBuilder;
|
||||
use gtk4::gio::ApplicationFlags;
|
||||
use gtk4::{ComboBoxText, Grid};
|
||||
use libakaza::config::Config;
|
||||
use log::info;
|
||||
use log::{error, info};
|
||||
|
||||
pub fn open_configuration_window() {
|
||||
use libakaza::config::{Config, DictUsage};
|
||||
|
||||
pub fn open_configuration_window() -> Result<()> {
|
||||
let config = Arc::new(Mutex::new(Config::load()?));
|
||||
let app = Application::new(Some("com.github.akaza.config"), ApplicationFlags::empty());
|
||||
|
||||
app.connect_activate(|app| {
|
||||
let window = ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.default_width(320)
|
||||
.default_height(200)
|
||||
.title("Akaza の設定")
|
||||
.build();
|
||||
|
||||
let notebook = Notebook::builder().build();
|
||||
notebook.append_page(&build_core_pane(), Some(&Label::new(Some("基本設定"))));
|
||||
notebook.append_page(&build_dict_pane(), Some(&Label::new(Some("辞書"))));
|
||||
notebook.append_page(&build_about_pane(), Some(&Label::new(Some("アバウト"))));
|
||||
|
||||
let grid = Grid::builder().build();
|
||||
|
||||
grid.attach(¬ebook, 0, 0, 6, 1);
|
||||
|
||||
let ok_button = Button::with_label("OK");
|
||||
ok_button.connect_clicked(|_| {
|
||||
eprintln!("Save the configuration...");
|
||||
// TODO: 保存処理
|
||||
});
|
||||
let cancel_button = Button::with_label("Cancel");
|
||||
{
|
||||
let window_clone = window.clone();
|
||||
cancel_button.connect_clicked(move |_| {
|
||||
eprintln!("Close the configuration window!");
|
||||
window_clone.close();
|
||||
});
|
||||
}
|
||||
grid.attach(&ok_button, 4, 1, 1, 1);
|
||||
grid.attach(&cancel_button, 5, 1, 1, 1);
|
||||
|
||||
window.set_child(Some(&grid));
|
||||
|
||||
window.connect_close_request(move |window| {
|
||||
if let Some(application) = window.application() {
|
||||
application.remove_window(window);
|
||||
}
|
||||
Inhibit(false)
|
||||
});
|
||||
|
||||
window.show();
|
||||
app.connect_activate(move |app| {
|
||||
connect_activate(app, config.clone()).unwrap();
|
||||
});
|
||||
|
||||
let v: Vec<String> = Vec::new();
|
||||
app.run_with_args(v.as_slice());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn connect_activate(app: &Application, config: Arc<Mutex<Config>>) -> Result<()> {
|
||||
let window = ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.default_width(320)
|
||||
.default_height(200)
|
||||
.title("Akaza の設定")
|
||||
.build();
|
||||
|
||||
let notebook = Notebook::builder().build();
|
||||
notebook.append_page(
|
||||
&build_core_pane(config.clone())?,
|
||||
Some(&Label::new(Some("基本設定"))),
|
||||
);
|
||||
notebook.append_page(
|
||||
&build_dict_pane(config.clone()),
|
||||
Some(&Label::new(Some("辞書"))),
|
||||
);
|
||||
notebook.append_page(&build_about_pane(), Some(&Label::new(Some("アバウト"))));
|
||||
|
||||
let grid = Grid::builder().build();
|
||||
|
||||
grid.attach(¬ebook, 0, 0, 6, 1);
|
||||
|
||||
let ok_button = Button::with_label("OK");
|
||||
let config = config;
|
||||
ok_button.connect_clicked(move |_| {
|
||||
eprintln!("Save the configuration...");
|
||||
// TODO: 保存処理
|
||||
let config = config.lock().unwrap();
|
||||
let config = Config {
|
||||
keymap: config.keymap.to_string(),
|
||||
romkan: config.romkan.to_string(),
|
||||
model: config.model.to_string(),
|
||||
dicts: config.dicts.clone(),
|
||||
};
|
||||
info!("Saving config: {}", serde_yaml::to_string(&config).unwrap());
|
||||
|
||||
config.save().unwrap();
|
||||
|
||||
// 最後に ibus restart をしちゃおう。設定の再読み込みとか実装するのは大変。
|
||||
let output = Command::new("ibus").arg("restart").output().unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
error!(
|
||||
"Cannot run `ibus restart`: out={}, err={}",
|
||||
String::from_utf8(output.stdout).unwrap(),
|
||||
String::from_utf8(output.stderr).unwrap()
|
||||
);
|
||||
} else {
|
||||
info!(
|
||||
"Ran `ibus restart`: out={}, err={}",
|
||||
String::from_utf8(output.stdout).unwrap(),
|
||||
String::from_utf8(output.stderr).unwrap()
|
||||
);
|
||||
}
|
||||
});
|
||||
let cancel_button = Button::with_label("Cancel");
|
||||
{
|
||||
let window_clone = window.clone();
|
||||
cancel_button.connect_clicked(move |_| {
|
||||
eprintln!("Close the configuration window!");
|
||||
window_clone.close();
|
||||
});
|
||||
}
|
||||
grid.attach(&ok_button, 4, 1, 1, 1);
|
||||
grid.attach(&cancel_button, 5, 1, 1, 1);
|
||||
|
||||
window.set_child(Some(&grid));
|
||||
|
||||
window.connect_close_request(move |window| {
|
||||
if let Some(application) = window.application() {
|
||||
application.remove_window(window);
|
||||
}
|
||||
Inhibit(false)
|
||||
});
|
||||
|
||||
window.show();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -68,7 +112,7 @@ struct PathConfItem {
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn get_keymap_list<P>(path: &str, filter: P) -> Vec<PathConfItem>
|
||||
fn get_list<P>(path: &str, filter: P) -> Vec<PathConfItem>
|
||||
where
|
||||
P: FnMut(&&PathBuf) -> bool,
|
||||
{
|
||||
@ -85,13 +129,14 @@ where
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
.to_string()
|
||||
.replace(".yml", ""),
|
||||
path: f.to_string_lossy().to_string(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn build_core_pane() -> Grid {
|
||||
fn build_core_pane(config: Arc<Mutex<Config>>) -> anyhow::Result<Grid> {
|
||||
// キーマップとローマ字テーブル、モデルの設定ができるようにする。
|
||||
let grid = Grid::new();
|
||||
// xalign: 0 は左寄という意味。
|
||||
@ -104,13 +149,20 @@ fn build_core_pane() -> Grid {
|
||||
);
|
||||
grid.attach(
|
||||
&{
|
||||
//TODO: 設定ファイルに書いてあるものを default value として選ぶ
|
||||
let cbt = ComboBoxText::new();
|
||||
let romkan = get_keymap_list("keymap", { |f| f.to_string_lossy().ends_with(".yml") });
|
||||
info!("keymap: {:?}", romkan);
|
||||
for item in romkan {
|
||||
let keymap = get_list("keymap", { |f| f.to_string_lossy().ends_with(".yml") });
|
||||
for item in keymap {
|
||||
cbt.append(Some(&item.path), &item.name);
|
||||
}
|
||||
cbt.set_active_id(Some(&config.lock().unwrap().keymap));
|
||||
{
|
||||
let config = config.clone();
|
||||
cbt.connect_changed(move |f| {
|
||||
if let Some(id) = f.active_id() {
|
||||
config.lock().unwrap().keymap = id.to_string();
|
||||
}
|
||||
});
|
||||
}
|
||||
cbt
|
||||
},
|
||||
1,
|
||||
@ -131,11 +183,20 @@ fn build_core_pane() -> Grid {
|
||||
grid.attach(
|
||||
&{
|
||||
let cbt = ComboBoxText::new();
|
||||
let romkan = get_keymap_list("romkan", { |f| f.to_string_lossy().ends_with(".yml") });
|
||||
let romkan = get_list("romkan", { |f| f.to_string_lossy().ends_with(".yml") });
|
||||
info!("romkan: {:?}", romkan);
|
||||
for item in romkan {
|
||||
cbt.append(Some(&item.path), &item.name);
|
||||
}
|
||||
cbt.set_active_id(Some(&config.lock().unwrap().romkan));
|
||||
|
||||
let config = config.clone();
|
||||
cbt.connect_changed(move |f| {
|
||||
if let Some(id) = f.active_id() {
|
||||
config.lock().unwrap().romkan = id.to_string();
|
||||
}
|
||||
});
|
||||
|
||||
cbt
|
||||
},
|
||||
1,
|
||||
@ -153,13 +214,21 @@ fn build_core_pane() -> Grid {
|
||||
grid.attach(
|
||||
&{
|
||||
let cbt = ComboBoxText::new();
|
||||
let romkan = get_keymap_list("model", {
|
||||
let model = get_list("model", {
|
||||
|f| !f.file_name().unwrap().to_string_lossy().starts_with('.')
|
||||
});
|
||||
info!("model: {:?}", romkan);
|
||||
for item in romkan {
|
||||
info!("model: {:?}", model);
|
||||
for item in model {
|
||||
cbt.append(Some(&item.path), &item.name);
|
||||
}
|
||||
cbt.set_active_id(Some(&config.lock().unwrap().model));
|
||||
|
||||
cbt.connect_changed(move |f| {
|
||||
if let Some(id) = f.active_id() {
|
||||
config.lock().unwrap().model = id.to_string();
|
||||
}
|
||||
});
|
||||
|
||||
cbt
|
||||
},
|
||||
1,
|
||||
@ -167,11 +236,59 @@ fn build_core_pane() -> Grid {
|
||||
1,
|
||||
1,
|
||||
);
|
||||
grid
|
||||
Ok(grid)
|
||||
}
|
||||
|
||||
fn build_dict_pane() -> Label {
|
||||
Label::new(Some("(工事中)"))
|
||||
fn build_dict_pane(config: Arc<Mutex<Config>>) -> Grid {
|
||||
let grid = Grid::builder().column_spacing(10).build();
|
||||
// TODO /usr/share/skk/ 以下のものを拾ってきて入れる
|
||||
for (i, dict_config) in config.lock().unwrap().dicts.iter().enumerate() {
|
||||
grid.attach(
|
||||
&Label::builder()
|
||||
.xalign(0_f32)
|
||||
.label(dict_config.path.as_str())
|
||||
.build(),
|
||||
0,
|
||||
i as i32,
|
||||
1,
|
||||
1,
|
||||
);
|
||||
|
||||
let cbt = ComboBoxText::builder().build();
|
||||
for usage in vec![
|
||||
DictUsage::Normal,
|
||||
DictUsage::SingleTerm,
|
||||
DictUsage::Disabled,
|
||||
] {
|
||||
cbt.append(Some(usage.as_str()), usage.text_jp());
|
||||
}
|
||||
cbt.set_active_id(Some(dict_config.usage.as_str()));
|
||||
{
|
||||
let config = config.clone();
|
||||
let path = dict_config.path.clone();
|
||||
cbt.connect_changed(move |f| {
|
||||
if let Some(id) = f.active_id() {
|
||||
let mut config = config.lock().unwrap();
|
||||
for mut dict in &mut config.dicts {
|
||||
if dict.path == path {
|
||||
dict.usage = DictUsage::from(&id).unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
grid.attach(&cbt, 1, i as i32, 1, 1);
|
||||
|
||||
grid.attach(
|
||||
&Label::new(Some(dict_config.dict_type.as_str())),
|
||||
2,
|
||||
i as i32,
|
||||
1,
|
||||
1,
|
||||
);
|
||||
}
|
||||
grid
|
||||
}
|
||||
|
||||
fn build_about_pane() -> Label {
|
||||
|
@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use log::info;
|
||||
|
||||
use libakaza::config::{Config, DictConfig, DictEncoding, DictType};
|
||||
use libakaza::config::{Config, DictConfig, DictEncoding, DictType, DictUsage};
|
||||
use libakaza::engine::bigram_word_viterbi_engine::BigramWordViterbiEngineBuilder;
|
||||
use libakaza::user_side_data::user_data::UserData;
|
||||
|
||||
@ -16,14 +16,15 @@ pub fn check(yomi: &str, expected: Option<String>, user_data: bool) -> anyhow::R
|
||||
dict_type: DictType::SKK,
|
||||
encoding: DictEncoding::EucJp,
|
||||
path: "/usr/share/skk/SKK-JISYO.L".to_string(),
|
||||
usage: DictUsage::Normal,
|
||||
},
|
||||
DictConfig {
|
||||
dict_type: DictType::SKK,
|
||||
encoding: DictEncoding::Utf8,
|
||||
path: "data/SKK-JISYO.akaza".to_string(),
|
||||
usage: DictUsage::Normal,
|
||||
},
|
||||
],
|
||||
single_term: Default::default(),
|
||||
romkan: Default::default(),
|
||||
keymap: Default::default(),
|
||||
model: Default::default(),
|
||||
|
@ -5,7 +5,7 @@ use std::time::SystemTime;
|
||||
use anyhow::Context;
|
||||
use log::info;
|
||||
|
||||
use libakaza::config::{Config, DictConfig, DictEncoding, DictType};
|
||||
use libakaza::config::{Config, DictConfig, DictEncoding, DictType, DictUsage};
|
||||
use libakaza::engine::base::HenkanEngine;
|
||||
use libakaza::engine::bigram_word_viterbi_engine::BigramWordViterbiEngineBuilder;
|
||||
|
||||
@ -58,6 +58,7 @@ pub fn evaluate(
|
||||
dict_type: DictType::SKK,
|
||||
encoding: DictEncoding::EucJp,
|
||||
path: path.clone(),
|
||||
usage: DictUsage::Normal,
|
||||
})
|
||||
}
|
||||
|
||||
@ -66,12 +67,12 @@ pub fn evaluate(
|
||||
dict_type: DictType::SKK,
|
||||
encoding: DictEncoding::Utf8,
|
||||
path: path.clone(),
|
||||
usage: DictUsage::Normal,
|
||||
})
|
||||
}
|
||||
|
||||
let mut builder = BigramWordViterbiEngineBuilder::new(Config {
|
||||
dicts,
|
||||
single_term: Default::default(),
|
||||
romkan: Default::default(),
|
||||
keymap: Default::default(),
|
||||
model: Default::default(),
|
||||
|
@ -102,7 +102,10 @@ impl AkazaContext {
|
||||
) {
|
||||
debug!("do_property_activate: {}, {}", prop_name, prop_state);
|
||||
if prop_name == "PrefPane" {
|
||||
open_configuration_window();
|
||||
match open_configuration_window() {
|
||||
Ok(_) => {}
|
||||
Err(e) => info!("Err: {}", e),
|
||||
}
|
||||
} else if prop_state == IBusPropState_PROP_STATE_CHECKED
|
||||
&& prop_name.starts_with("InputMode.")
|
||||
{
|
||||
|
@ -38,8 +38,8 @@ impl KeyMap {
|
||||
unsafe { ibus_keyval_from_name(cs.as_ptr()) }
|
||||
}
|
||||
|
||||
pub(crate) fn new(keymap_name: String) -> anyhow::Result<Self> {
|
||||
let keymap = Keymap::load(keymap_name.as_str())?;
|
||||
pub(crate) fn new(keymap_path: String) -> anyhow::Result<Self> {
|
||||
let keymap = Keymap::load(keymap_path.as_str())?;
|
||||
let mut mapping: HashMap<KeyPattern, String> = HashMap::new();
|
||||
|
||||
for (key_pattern, command) in keymap {
|
||||
|
@ -8,17 +8,21 @@ dicts:
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::io::{BufReader, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
use log::{info, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use DictEncoding::Utf8;
|
||||
|
||||
use crate::config::DictUsage::{Normal, SingleTerm};
|
||||
use crate::resource::detect_resource_path;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct Config {
|
||||
pub dicts: Vec<DictConfig>,
|
||||
pub single_term: Vec<DictConfig>,
|
||||
|
||||
/// ローマ字かな変換テーブルの指定
|
||||
/// "default", "kana", etc.
|
||||
@ -37,15 +41,15 @@ pub struct Config {
|
||||
}
|
||||
|
||||
fn default_romkan() -> String {
|
||||
"default".to_string()
|
||||
detect_resource_path("romkan", "default").unwrap()
|
||||
}
|
||||
|
||||
fn default_keymap() -> String {
|
||||
"default".to_string()
|
||||
detect_resource_path("keymap", "default").unwrap()
|
||||
}
|
||||
|
||||
fn default_model() -> String {
|
||||
"default".to_string()
|
||||
detect_resource_path("model", "default").unwrap()
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -56,9 +60,22 @@ impl Config {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn load() -> Result<Self> {
|
||||
pub fn file_name() -> Result<PathBuf> {
|
||||
let basedir = xdg::BaseDirectories::with_prefix("akaza")?;
|
||||
let configfile = basedir.get_config_file("config.yml");
|
||||
Ok(basedir.get_config_file("config.yml"))
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Result<()> {
|
||||
let file_name = Self::file_name()?;
|
||||
let yml = serde_yaml::to_string(self)?;
|
||||
info!("Write to file: {}", file_name.to_str().unwrap());
|
||||
let mut fp = File::create(file_name)?;
|
||||
fp.write_all(yml.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load() -> Result<Self> {
|
||||
let configfile = Self::file_name()?;
|
||||
let config = match Config::load_from_file(configfile.to_str().unwrap()) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
@ -85,11 +102,11 @@ pub struct DictConfig {
|
||||
|
||||
/// Encoding of the dictionary
|
||||
/// Default: UTF-8
|
||||
// #[serde(default = "default_encoding")]
|
||||
pub encoding: DictEncoding,
|
||||
|
||||
// #[serde(default = "default_dict_type")]
|
||||
pub dict_type: DictType,
|
||||
|
||||
pub usage: DictUsage,
|
||||
}
|
||||
|
||||
fn default_encoding() -> DictEncoding {
|
||||
@ -121,7 +138,7 @@ impl Display for DictEncoding {
|
||||
impl DictEncoding {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
DictEncoding::Utf8 => "UTF-8",
|
||||
Utf8 => "UTF-8",
|
||||
DictEncoding::EucJp => "EUC-JP",
|
||||
}
|
||||
}
|
||||
@ -152,6 +169,46 @@ impl DictType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum DictUsage {
|
||||
Normal,
|
||||
SingleTerm,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
impl Default for DictUsage {
|
||||
fn default() -> Self {
|
||||
Normal
|
||||
}
|
||||
}
|
||||
|
||||
impl DictUsage {
|
||||
pub fn from(s: &str) -> Result<DictUsage> {
|
||||
match s {
|
||||
"Normal" => Ok(Normal),
|
||||
"SingleTerm" => Ok(SingleTerm),
|
||||
"Disabled" => Ok(DictUsage::Disabled),
|
||||
_ => bail!("Unknown name: {:?}", s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Normal => "Normal",
|
||||
SingleTerm => "SingleTerm",
|
||||
DictUsage::Disabled => "Disabled",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_jp(&self) -> &'static str {
|
||||
match self {
|
||||
Normal => "通常辞書",
|
||||
SingleTerm => "単項",
|
||||
DictUsage::Disabled => "無効",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -166,6 +223,7 @@ mod tests {
|
||||
path: "/usr/share/skk/SKK-JISYO.L".to_string(),
|
||||
encoding: DictEncoding::EucJp,
|
||||
dict_type: DictType::SKK,
|
||||
usage: DictUsage::Normal,
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
|
@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::config::{Config, DictConfig, DictEncoding, DictType};
|
||||
use crate::config::{Config, DictConfig, DictEncoding, DictType, DictUsage};
|
||||
use crate::dict::loader::load_dicts_ex;
|
||||
use crate::engine::base::HenkanEngine;
|
||||
use crate::graph::candidate::Candidate;
|
||||
@ -124,21 +124,22 @@ impl BigramWordViterbiEngineBuilder {
|
||||
|
||||
let system_unigram_lm = match &self.model_dir {
|
||||
Some(path) => MarisaSystemUnigramLM::load(&format!("{}/unigram.model", path)),
|
||||
None => MarisaSystemUnigramLM::load(
|
||||
Self::try_load(&format!("{}/unigram.model", model_name))?.as_str(),
|
||||
),
|
||||
None => {
|
||||
MarisaSystemUnigramLM::load(Self::try_load(&model_name, "unigram.model")?.as_str())
|
||||
}
|
||||
}?;
|
||||
let system_bigram_lm = match &self.model_dir {
|
||||
Some(path) => MarisaSystemBigramLM::load(&format!("{}/bigram.model", path.clone())),
|
||||
None => MarisaSystemBigramLM::load(
|
||||
Self::try_load(&format!("{}/bigram.model", model_name))?.as_str(),
|
||||
),
|
||||
None => {
|
||||
MarisaSystemBigramLM::load(Self::try_load(&model_name, "bigram.model")?.as_str())
|
||||
}
|
||||
}?;
|
||||
// TODO Merge self.model_dir and config.model
|
||||
let system_dict = match &self.model_dir {
|
||||
Some(path) => {
|
||||
format!("{}/SKK-JISYO.akaza", path)
|
||||
}
|
||||
None => Self::try_load(&format!("{}/SKK-JISYO.akaza", model_name))?,
|
||||
None => Self::try_load(&model_name, "SKK-JISYO.akaza")?,
|
||||
};
|
||||
|
||||
let user_data = if let Some(d) = &self.user_data {
|
||||
@ -148,17 +149,33 @@ impl BigramWordViterbiEngineBuilder {
|
||||
};
|
||||
|
||||
let dict = {
|
||||
let mut dicts = self.config.dicts.to_vec();
|
||||
let mut dicts = self
|
||||
.config
|
||||
.dicts
|
||||
.iter()
|
||||
.filter(|it| it.usage == DictUsage::Normal)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
dicts.push(DictConfig {
|
||||
path: system_dict,
|
||||
dict_type: DictType::SKK,
|
||||
encoding: DictEncoding::Utf8,
|
||||
usage: DictUsage::Normal,
|
||||
});
|
||||
|
||||
load_dicts_ex(&dicts, "kana_kanji_cache.marisa")?
|
||||
};
|
||||
|
||||
let single_term = load_dicts_ex(&self.config.single_term, "single_term_cache.marisa")?;
|
||||
let single_term = load_dicts_ex(
|
||||
&self
|
||||
.config
|
||||
.dicts
|
||||
.iter()
|
||||
.filter(|it| it.usage == DictUsage::SingleTerm)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
"single_term_cache.marisa",
|
||||
)?;
|
||||
|
||||
// 辞書を元に、トライを作成していく。
|
||||
let mut kana_trie = CedarwoodKanaTrie::default();
|
||||
@ -203,7 +220,7 @@ impl BigramWordViterbiEngineBuilder {
|
||||
})
|
||||
}
|
||||
|
||||
fn try_load(name: &str) -> Result<String> {
|
||||
detect_resource_path("model", name)
|
||||
fn try_load(model_dir: &str, name: &str) -> Result<String> {
|
||||
Ok(model_dir.to_string() + "/" + name)
|
||||
}
|
||||
}
|
||||
|
@ -92,11 +92,10 @@ pub enum KeyState {
|
||||
}
|
||||
|
||||
impl Keymap {
|
||||
pub fn load(name: &str) -> Result<HashMap<KeyPattern, String>> {
|
||||
let pathstr = detect_resource_path("keymap", &format!("{}.yml", name))?;
|
||||
info!("Load {}", pathstr);
|
||||
pub fn load(keymap_path: &str) -> Result<HashMap<KeyPattern, String>> {
|
||||
info!("Load {}", keymap_path);
|
||||
let got: Keymap = serde_yaml::from_reader(BufReader::new(
|
||||
File::open(&pathstr).with_context(|| pathstr)?,
|
||||
File::open(keymap_path).with_context(|| keymap_path.to_string())?,
|
||||
))?;
|
||||
|
||||
if let Some(parent) = &got.extends {
|
||||
|
@ -11,10 +11,12 @@ pub fn detect_resource_path(base: &str, name: &str) -> anyhow::Result<String> {
|
||||
.with_context(|| "Opening xdg directory with 'akaza' prefix")?;
|
||||
let pathbuf = basedirs.find_data_file(&target_path);
|
||||
let Some(pathbuf) = pathbuf else {
|
||||
bail!("Cannot find {:?} in XDG_DATA_HOME or XDG_DATA_DIRS(XDG_DATA_HOME={:?}, XDG_DATA_DIRS={:?})",
|
||||
bail!("Cannot find {:?} in XDG_DATA_HOME or XDG_DATA_DIRS(XDG_DATA_HOME={:?}, XDG_DATA_DIRS={:?}, base={:?}, name={:?})",
|
||||
target_path,
|
||||
basedirs.get_data_home().to_string_lossy().to_string(),
|
||||
basedirs.get_data_dirs().iter().map(|x| x.to_string_lossy().to_string()).collect::<Vec<_>>(),
|
||||
base,
|
||||
name
|
||||
)
|
||||
};
|
||||
pathbuf.to_string_lossy().to_string()
|
||||
|
@ -14,11 +14,10 @@ pub struct RomKanConfig {
|
||||
extends: Option<String>,
|
||||
}
|
||||
|
||||
fn load_romkan_map(name: &str) -> anyhow::Result<HashMap<String, String>> {
|
||||
let pathstr = resource::detect_resource_path("romkan", &format!("{}.yml", name))?;
|
||||
info!("Load {}", pathstr);
|
||||
fn load_romkan_map(file_path: &str) -> anyhow::Result<HashMap<String, String>> {
|
||||
info!("Load {}", file_path);
|
||||
let got: RomKanConfig = serde_yaml::from_reader(BufReader::new(
|
||||
File::open(&pathstr).with_context(|| pathstr)?,
|
||||
File::open(file_path).with_context(|| file_path.to_string())?,
|
||||
))?;
|
||||
|
||||
if let Some(parent) = got.extends {
|
||||
|
Reference in New Issue
Block a user