Skip to content

Commit

Permalink
Merge 4c102a1 into 1e00bd4
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonbrad committed Aug 20, 2023
2 parents 1e00bd4 + 4c102a1 commit a3a8fc5
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 96 deletions.
1 change: 0 additions & 1 deletion clafrica/data/blank_sample.toml
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
[data]
4 changes: 4 additions & 0 deletions clafrica/data/config_sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ auto_capitalize = false

[data]
sample = { path = "./data_sample.toml" }

[translation]
mydict = { path = "./dictionary.toml" }

3 changes: 3 additions & 0 deletions clafrica/data/dictionary.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[translation]
halo = "hello"
hi = { value = "hello", alias = ["hey"] }
3 changes: 3 additions & 0 deletions clafrica/data/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ c_ = { value = "ç", alias = ["c_ced", "c8", "c8ced"]}
uu = "ʉ"
uu3 = { value = "ʉ̄", alias = ["uu\""] }
uuaf3 = { value = "ʉ̄ɑ̄", alias = ["uuqf\""] }

[translation]
hello = "hi"
17 changes: 12 additions & 5 deletions clafrica/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub trait Frontend {
fn update_screen(&mut self, _screen: (u64, u64)) {}
fn update_position(&mut self, _position: (f64, f64)) {}
fn update_text(&mut self, _text: Vec<char>) {}
fn update_text(&mut self, _text: &str) {}
fn add_predicate(&mut self, _remaining_code: &str, _text: &str) {}
fn clear_predicates(&mut self) {}
}

pub struct None;
Expand All @@ -11,8 +13,11 @@ impl Frontend for None {}
pub struct Console;

impl Frontend for Console {
fn update_text(&mut self, text: Vec<char>) {
println!("{:?}", text);
fn update_text(&mut self, text: &str) {
println!("text: {:?}", text);
}
fn add_predicate(&mut self, remaining_code: &str, text: &str) {
println!("predicate: {} ~{}", text, remaining_code);
}
}

Expand All @@ -22,6 +27,8 @@ fn test_console() {
let mut none = None;
console.update_screen((0, 0));
console.update_position((0.0, 0.0));
console.update_text(vec!['h', 'e', 'l', 'l', 'o']);
none.update_text(vec!['h', 'e', 'l', 'l', 'o']);
console.update_text("hello");
console.add_predicate("_", "10/12/2003");
console.clear_predicates();
none.update_text("hello");
}
94 changes: 79 additions & 15 deletions clafrica/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use toml::{self};
#[derive(Deserialize, Debug, Clone)]
pub struct Config {
pub core: Option<CoreConfig>,
data: HashMap<String, Data>,
data: Option<HashMap<String, Data>>,
translation: Option<HashMap<String, Data>>,
}

#[derive(Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -43,17 +44,16 @@ impl Config {

let config_path = filepath.parent().unwrap();

// Data
let mut data = HashMap::new();

config
.data
.iter()
.try_for_each(|(key, value)| -> Result<(), Box<dyn error::Error>> {
config.data.unwrap_or_default().iter().try_for_each(
|(key, value)| -> Result<(), Box<dyn error::Error>> {
match value {
Data::File(DataFile { path }) => {
let filepath = config_path.join(path);
let conf = Config::from_file(&filepath)?;
data.extend(conf.data);
data.extend(conf.data.unwrap_or_default());
}
Data::Simple(_) => {
data.insert(key.to_owned(), value.clone());
Expand All @@ -65,21 +65,53 @@ impl Config {
}
};
Ok(())
})?;
},
)?;
config.data = Some(data);

config.data = data;
// Translation
let mut translation = HashMap::new();

config.translation.unwrap_or_default().iter().try_for_each(
|(key, value)| -> Result<(), Box<dyn error::Error>> {
match value {
Data::File(DataFile { path }) => {
let filepath = config_path.join(path);
let conf = Config::from_file(&filepath)?;
translation.extend(conf.translation.unwrap_or_default());
}
Data::Simple(_) => {
translation.insert(key.to_owned(), value.clone());
}
Data::Detailed(DetailedData { value, alias }) => {
alias.iter().chain([key.to_owned()].iter()).for_each(|e| {
translation.insert(e.to_owned(), Data::Simple(value.to_owned()));
});
}
};
Ok(())
},
)?;

config.translation = Some(translation);

Ok(config)
}

pub fn extract_data(&self) -> HashMap<String, String> {
let data = self.data.iter().filter_map(|(k, v)| {
let v = match v {
Data::Simple(value) => Some(value),
_ => None,
};
v.map(|v| (k.to_owned(), v.to_owned()))
});
let empty = HashMap::default();
let data = self
.data
.as_ref()
.unwrap_or(&empty)
.iter()
.filter_map(|(k, v)| {
let v = match v {
Data::Simple(value) => Some(value),
_ => None,
};
v.map(|v| (k.to_owned(), v.to_owned()))
});

if self
.core
Expand All @@ -101,6 +133,24 @@ impl Config {
data.collect()
}
}

pub fn extract_translation(&self) -> HashMap<String, String> {
let empty = HashMap::new();

self.translation
.as_ref()
.unwrap_or(&empty)
.iter()
.filter_map(|(k, v)| {
let v = match v {
Data::Simple(v) => Some(v),
_ => None,
};

v.map(|v| (k.to_owned(), v.to_owned()))
})
.collect()
}
}

#[cfg(test)]
Expand Down Expand Up @@ -130,4 +180,18 @@ mod tests {
let data = conf.extract_data();
assert_eq!(data.keys().len(), 0);
}

#[test]
fn from_file_with_translation() {
use crate::config::Config;
use std::path::Path;

let conf = Config::from_file(Path::new("./data/config_sample.toml")).unwrap();
let translation = conf.extract_translation();
assert_eq!(translation.keys().len(), 3);

let conf = Config::from_file(Path::new("./data/blank_sample.toml")).unwrap();
let translation = conf.extract_translation();
assert_eq!(translation.keys().len(), 0);
}
}
115 changes: 40 additions & 75 deletions clafrica/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
pub mod api;
pub mod config;
pub mod processor;
pub mod translator;

use crate::api::Frontend;
use clafrica_lib::{text_buffer, utils};
use enigo::{Enigo, Key, KeyboardControllable};
use crate::processor::Processor;
use crate::translator::Translator;
use clafrica_lib::utils;
use rdev::{self, EventType, Key as E_Key};
use std::{error, sync::mpsc, thread};

Expand All @@ -22,9 +25,11 @@ pub fn run(
.map(|(k, v)| [k.as_str(), v.as_str()])
.collect(),
);
let mut cursor = text_buffer::Cursor::new(map, config.core.map(|e| e.buffer_size).unwrap_or(8));

let mut keyboard = Enigo::new();
let mut processor = Processor::new(
map,
config.core.as_ref().map(|e| e.buffer_size).unwrap_or(8),
);
let translator = Translator::new(config.extract_translation());

frontend.update_screen(rdev::display_size().unwrap());

Expand Down Expand Up @@ -62,79 +67,31 @@ pub fn run(
});

for event in rx.iter() {
let character = event.name.and_then(|s| s.chars().next());
let is_valid = character
.map(|c| c.is_alphanumeric() || c.is_ascii_punctuation())
.unwrap_or_default();

match event.event_type {
EventType::KeyPress(E_Key::Backspace) => {
if let Some(out) = cursor.undo() {
rdev::simulate(&EventType::KeyPress(E_Key::Pause))
.expect("We could pause the listeners");
keyboard.key_up(Key::Backspace);

let i = out.chars().count();
(1..i).for_each(|_| keyboard.key_click(Key::Backspace));

rdev::simulate(&EventType::KeyRelease(E_Key::Pause))
.expect("We could resume the listeners");

// Clear the remaining code
while let (None, 1.., ..) = cursor.state() {
cursor.undo();
}

if let (Some(_in), ..) = cursor.state() {
keyboard.key_sequence(&_in);
}
}

frontend.update_text(cursor.to_sequence());
}
EventType::KeyPress(
E_Key::Unknown(_) | E_Key::ShiftLeft | E_Key::ShiftRight | E_Key::CapsLock,
) => {
// println!("[ignore] {:?}", event.event_type)
}
EventType::ButtonPress(_) | EventType::KeyPress(_) if !is_valid => {
cursor.clear();
frontend.update_text(cursor.to_sequence());
}
EventType::KeyPress(_) => {
let character = character.unwrap();

let mut prev_cursor = cursor.clone();

if let Some(_in) = cursor.hit(character) {
rdev::simulate(&EventType::KeyPress(E_Key::Pause))
.expect("We could pause the listeners");

keyboard.key_click(Key::Backspace);

// Remove the remaining code
while let (None, 1.., ..) = prev_cursor.state() {
prev_cursor.undo();
keyboard.key_click(Key::Backspace);
}

if let (Some(out), ..) = prev_cursor.state() {
(0..out.chars().count()).for_each(|_| keyboard.key_click(Key::Backspace))
}

keyboard.key_sequence(&_in);

rdev::simulate(&EventType::KeyRelease(E_Key::Pause))
.expect("We could resume the listeners");
if let EventType::MouseMove { x, y } = &event.event_type {
frontend.update_position((*x, *y));
} else {
let (changed, committed) = processor.process(event);

if changed {
let input = processor.get_input();

frontend.clear_predicates();

if !committed {
translator.translate(&input).iter().for_each(
|(remaining_code, text, translated)| {
if *translated {
processor.commit(&input, text);
} else if !remaining_code.is_empty() {
frontend.add_predicate(remaining_code, text);
}
},
);
};

frontend.update_text(cursor.to_sequence());
frontend.update_text(&input);
}
EventType::MouseMove { x, y } => {
frontend.update_position((x, y));
}
_ => (),
};
}
}

Ok(())
Expand Down Expand Up @@ -254,6 +211,14 @@ mod tests {
input!(KeyA KeyF KeyF, typing_speed_ms);
output!(textfield, format!("{LIMIT}αⱭⱭɑɑ"));

(0..5).for_each(|_| {
input!(Backspace, typing_speed_ms);
});

// We verify that the translation work as expected
input!(KeyH KeyE KeyL KeyL KeyO, typing_speed_ms);
output!(textfield, format!("{LIMIT}hi"));

rstk::end_wish();
}
}
Loading

0 comments on commit a3a8fc5

Please sign in to comment.