Skip to content

Commit

Permalink
Merge pull request #608 from chewing/refactor-input-mode
Browse files Browse the repository at this point in the history
refactor: Merge fuzzy_search_mode and conversion_engine options
  • Loading branch information
kanru authored Jul 15, 2024
2 parents dfe0e82 + 8c59342 commit 3d1acef
Show file tree
Hide file tree
Showing 17 changed files with 424 additions and 234 deletions.
41 changes: 22 additions & 19 deletions capi/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ use std::{
};

use chewing::{
conversion::{ChewingEngine, Interval, SimpleEngine, Symbol},
conversion::{ChewingEngine, FuzzyChewingEngine, Interval, SimpleEngine, Symbol},
dictionary::{
Dictionary, Layered, LoadDictionaryError, SystemDictionaryLoader, Trie,
UserDictionaryLoader,
Dictionary, Layered, LookupStrategy, SystemDictionaryLoader, Trie, UserDictionaryLoader,
},
editor::{
keyboard::{AnyKeyboardLayout, KeyCode, KeyboardLayout, Modifiers, Qwerty},
Expand All @@ -28,8 +27,9 @@ use chewing::{
use log::{debug, error, info};

use crate::public::{
ChewingConfigData, ChewingContext, IntervalType, SelKeys, CHINESE_MODE, FULLSHAPE_MODE,
HALFSHAPE_MODE, MAX_SELKEY, SYMBOL_MODE,
ChewingConfigData, ChewingContext, IntervalType, SelKeys, CHEWING_CONVERSION_ENGINE,
CHINESE_MODE, FULLSHAPE_MODE, FUZZY_CHEWING_CONVERSION_ENGINE, HALFSHAPE_MODE, MAX_SELKEY,
SIMPLE_CONVERSION_ENGINE, SYMBOL_MODE,
};

use super::logger::ChewingLogger;
Expand Down Expand Up @@ -310,7 +310,6 @@ pub unsafe extern "C" fn chewing_config_has_option(
| "chewing.selection_keys"
| "chewing.character_form"
| "chewing.space_is_select_key"
| "chewing.fuzzy_search_mode"
| "chewing.conversion_engine"
| "chewing.enable_fullwidth_toggle_key" => true,
_ => false,
Expand Down Expand Up @@ -354,10 +353,10 @@ pub unsafe extern "C" fn chewing_config_get_int(
CharacterForm::Fullwidth => FULLSHAPE_MODE,
},
"chewing.space_is_select_key" => option.space_is_select_key as c_int,
"chewing.fuzzy_search_mode" => option.fuzzy_search as c_int,
"chewing.conversion_engine" => match option.conversion_engine {
ConversionEngineKind::ChewingEngine => 0,
ConversionEngineKind::SimpleEngine => 1,
ConversionEngineKind::SimpleEngine => SIMPLE_CONVERSION_ENGINE,
ConversionEngineKind::ChewingEngine => CHEWING_CONVERSION_ENGINE,
ConversionEngineKind::FuzzyChewingEngine => FUZZY_CHEWING_CONVERSION_ENGINE,
},
"chewing.enable_fullwidth_toggle_key" => option.enable_fullwidth_toggle_key as c_int,
_ => ERROR,
Expand Down Expand Up @@ -448,21 +447,25 @@ pub unsafe extern "C" fn chewing_config_set_int(
ensure_bool!(value);
options.space_is_select_key = value > 0;
}
"chewing.fuzzy_search_mode" => {
ensure_bool!(value);
options.fuzzy_search = value > 0;
}
"chewing.conversion_engine" => {
options.conversion_engine = match value {
0 => {
SIMPLE_CONVERSION_ENGINE => {
ctx.editor
.set_conversion_engine(Box::new(SimpleEngine::new()));
options.lookup_strategy = LookupStrategy::Standard;
ConversionEngineKind::SimpleEngine
}
CHEWING_CONVERSION_ENGINE => {
ctx.editor
.set_conversion_engine(Box::new(ChewingEngine::new()));
options.lookup_strategy = LookupStrategy::Standard;
ConversionEngineKind::ChewingEngine
}
1 => {
FUZZY_CHEWING_CONVERSION_ENGINE => {
ctx.editor
.set_conversion_engine(Box::new(SimpleEngine::new()));
ConversionEngineKind::SimpleEngine
.set_conversion_engine(Box::new(FuzzyChewingEngine::new()));
options.lookup_strategy = LookupStrategy::FuzzyPartialPrefix;
ConversionEngineKind::ChewingEngine
}
_ => return ERROR,
}
Expand Down Expand Up @@ -1138,13 +1141,13 @@ pub unsafe extern "C" fn chewing_userphrase_lookup(
Some(phrase) => ctx
.editor
.user_dict()
.lookup_all_phrases(&syllables)
.lookup_all_phrases(&syllables, LookupStrategy::Standard)
.iter()
.any(|ph| ph.as_str() == phrase) as c_int,
None => ctx
.editor
.user_dict()
.lookup_first_phrase(&syllables)
.lookup_first_phrase(&syllables, LookupStrategy::Standard)
.is_some() as c_int,
}
}
Expand Down
6 changes: 6 additions & 0 deletions capi/src/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ pub const SYMBOL_MODE: c_int = 0;
pub const FULLSHAPE_MODE: c_int = 1;
/// Indicates chewing will not translate latin and puctuation characters.
pub const HALFSHAPE_MODE: c_int = 0;
/// Use conversion engine that doesn't perform intelligent phrasing.
pub const SIMPLE_CONVERSION_ENGINE: c_int = 0;
/// Use the original Chewing intelligent phrasing.
pub const CHEWING_CONVERSION_ENGINE: c_int = 1;
/// Use original Chewing intelligent phrasing with fuzzy prefix search.
pub const FUZZY_CHEWING_CONVERSION_ENGINE: c_int = 2;
/// Indicates automatic user phrase learning is disabled.
pub const AUTOLEARN_DISABLED: usize = 1;
/// Indicates automatic user phrase learning is enabled.
Expand Down
15 changes: 15 additions & 0 deletions include/chewing.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ typedef struct ChewingContext ChewingContext;
*/
#define HALFSHAPE_MODE 0

/**
* Use conversion engine that doesn't perform intelligent phrasing.
*/
#define SIMPLE_CONVERSION_ENGINE 0

/**
* Use the original Chewing intelligent phrasing.
*/
#define CHEWING_CONVERSION_ENGINE 1

/**
* Use original Chewing intelligent phrasing with fuzzy prefix search.
*/
#define FUZZY_CHEWING_CONVERSION_ENGINE 2

/**
* Indicates automatic user phrase learning is disabled.
*/
Expand Down
72 changes: 8 additions & 64 deletions src/conversion/chewing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ use std::{

use log::trace;

use crate::dictionary::{Dictionary, Phrase};
use crate::dictionary::{Dictionary, LookupStrategy, Phrase};

use super::{Composition, ConversionEngine, Gap, Interval, Symbol};

/// TODO: doc
#[derive(Debug, Default)]
pub struct ChewingEngine;
pub struct ChewingEngine {
pub(crate) lookup_strategy: LookupStrategy,
}

impl ChewingEngine {
const MAX_OUT_PATHS: usize = 100;
/// TODO: doc
pub fn new() -> ChewingEngine {
ChewingEngine
ChewingEngine {
lookup_strategy: LookupStrategy::Standard,
}
}
pub fn convert<'a>(
&'a self,
Expand Down Expand Up @@ -61,66 +65,6 @@ impl ConversionEngine for ChewingEngine {
}
}

/// Simple engine does not perform any intelligent conversion.
#[derive(Debug, Default)]
pub struct SimpleEngine;

impl SimpleEngine {
pub fn new() -> SimpleEngine {
SimpleEngine
}
pub fn convert<'a>(
&'a self,
dict: &'a dyn Dictionary,
comp: &'a Composition,
) -> impl Iterator<Item = Vec<Interval>> + Clone + 'a {
let mut intervals = vec![];

for (i, sym) in comp.symbols().iter().enumerate() {
if comp
.selections
.iter()
.any(|selection| selection.intersect_range(i, i + 1))
{
continue;
}
if sym.is_char() {
intervals.push(Interval {
start: i,
end: i + 1,
is_phrase: false,
str: sym.to_char().unwrap().to_string().into_boxed_str(),
});
} else {
let phrase = dict.lookup_first_phrase(&[sym.to_syllable().unwrap()]);
let phrase_str = phrase.map_or_else(
|| sym.to_syllable().unwrap().to_string(),
|phrase| phrase.to_string(),
);
intervals.push(Interval {
start: i,
end: i + 1,
is_phrase: true,
str: phrase_str.into_boxed_str(),
})
}
}
intervals.extend_from_slice(comp.selections());
intervals.sort_by_key(|int| int.start);
iter::once(intervals)
}
}

impl ConversionEngine for SimpleEngine {
fn convert<'a>(
&'a self,
dict: &'a dyn Dictionary,
comp: &'a Composition,
) -> Box<dyn Iterator<Item = Vec<Interval>> + 'a> {
Box::new(SimpleEngine::convert(self, dict, comp))
}
}

fn glue_fn(com: &Composition, mut acc: Vec<Interval>, interval: Interval) -> Vec<Interval> {
if acc.is_empty() {
acc.push(interval);
Expand Down Expand Up @@ -184,7 +128,7 @@ impl ChewingEngine {

let mut max_freq = 0;
let mut best_phrase = None;
'next_phrase: for phrase in dict.lookup_all_phrases(&symbols) {
'next_phrase: for phrase in dict.lookup_all_phrases(&symbols, self.lookup_strategy) {
// If there exists a user selected interval which is a
// sub-interval of this phrase but the substring is
// different then we can skip this phrase.
Expand Down
29 changes: 29 additions & 0 deletions src/conversion/fuzzy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::dictionary::LookupStrategy;

use super::{ChewingEngine, ConversionEngine};

/// TODO: doc
#[derive(Debug, Default)]
pub struct FuzzyChewingEngine {
inner: ChewingEngine,
}

impl FuzzyChewingEngine {
pub fn new() -> FuzzyChewingEngine {
FuzzyChewingEngine {
inner: ChewingEngine {
lookup_strategy: LookupStrategy::FuzzyPartialPrefix,
},
}
}
}

impl ConversionEngine for FuzzyChewingEngine {
fn convert<'a>(
&'a self,
dict: &'a dyn crate::dictionary::Dictionary,
comp: &'a super::Composition,
) -> Box<dyn Iterator<Item = Vec<super::Interval>> + 'a> {
Box::new(ChewingEngine::convert(&self.inner, dict, comp))
}
}
6 changes: 5 additions & 1 deletion src/conversion/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Algorithms to convert syllables to Chinese characters.
mod chewing;
mod fuzzy;
mod simple;
mod symbol;

use std::{
Expand All @@ -14,7 +16,9 @@ use crate::{
zhuyin::{Syllable, SyllableSlice},
};

pub use self::chewing::{ChewingEngine, SimpleEngine};
pub use self::chewing::ChewingEngine;
pub use self::fuzzy::FuzzyChewingEngine;
pub use self::simple::SimpleEngine;
pub(crate) use self::symbol::{full_width_symbol_input, special_symbol_input};

pub trait ConversionEngine: Debug {
Expand Down
68 changes: 68 additions & 0 deletions src/conversion/simple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::iter;

use crate::dictionary::Dictionary;

use super::{Composition, ConversionEngine, Interval};

/// Simple engine does not perform any intelligent conversion.
#[derive(Debug, Default)]
pub struct SimpleEngine;

impl SimpleEngine {
pub fn new() -> SimpleEngine {
SimpleEngine
}
pub fn convert<'a>(
&'a self,
dict: &'a dyn Dictionary,
comp: &'a Composition,
) -> impl Iterator<Item = Vec<Interval>> + Clone + 'a {
let mut intervals = vec![];

for (i, sym) in comp.symbols().iter().enumerate() {
if comp
.selections
.iter()
.any(|selection| selection.intersect_range(i, i + 1))
{
continue;
}
if sym.is_char() {
intervals.push(Interval {
start: i,
end: i + 1,
is_phrase: false,
str: sym.to_char().unwrap().to_string().into_boxed_str(),
});
} else {
let phrase = dict.lookup_first_phrase(
&[sym.to_syllable().unwrap()],
crate::dictionary::LookupStrategy::Standard,
);
let phrase_str = phrase.map_or_else(
|| sym.to_syllable().unwrap().to_string(),
|phrase| phrase.to_string(),
);
intervals.push(Interval {
start: i,
end: i + 1,
is_phrase: true,
str: phrase_str.into_boxed_str(),
})
}
}
intervals.extend_from_slice(comp.selections());
intervals.sort_by_key(|int| int.start);
iter::once(intervals)
}
}

impl ConversionEngine for SimpleEngine {
fn convert<'a>(
&'a self,
dict: &'a dyn Dictionary,
comp: &'a Composition,
) -> Box<dyn Iterator<Item = Vec<Interval>> + 'a> {
Box::new(SimpleEngine::convert(self, dict, comp))
}
}
Loading

0 comments on commit 3d1acef

Please sign in to comment.