diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..205660b --- /dev/null +++ b/config/README.md @@ -0,0 +1,2 @@ +# Clafrica Config Manager +Manage the configuration of the clafrica input method. diff --git a/config/src/lib.rs b/config/src/lib.rs index 1b62e39..0edb20d 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,22 +1,34 @@ +//! Library to manage the configuration of the clafrica input method. +//! + +#![deny(missing_docs)] + use rhai::{Engine, AST}; use serde::Deserialize; use std::result::Result; use std::{collections::HashMap, error, fs, path::Path}; use toml::{self}; +/// Hold information about a configuration. #[derive(Deserialize, Debug, Clone)] pub struct Config { + /// The core config. pub core: Option, data: Option>, translators: Option>, translation: Option>, } +/// Core information about a configuration. #[derive(Deserialize, Debug, Clone)] pub struct CoreConfig { + /// The size of the memory (history). + /// The number of elements that should be tracked. pub buffer_size: Option, auto_capitalize: Option, + /// The max numbers of predicates to display. pub page_size: Option, + /// Whether the predicate should be automatically committed. pub auto_commit: Option, } @@ -60,6 +72,7 @@ macro_rules! insert_with_auto_capitalize { } impl Config { + /// Load the configuration from a file. pub fn from_file(filepath: &Path) -> Result> { let content = fs::read_to_string(filepath) .map_err(|err| format!("Couldn't open file `{filepath:?}`.\nCaused by:\n\t{err}."))?; @@ -155,6 +168,7 @@ impl Config { Ok(config) } + /// Extract the data from the configuration. pub fn extract_data(&self) -> HashMap { let empty = HashMap::default(); @@ -172,6 +186,7 @@ impl Config { .collect() } + /// Extract the translators from the configuration. pub fn extract_translators(&self) -> Result, Box> { let empty = HashMap::default(); let mut engine = Engine::new(); @@ -204,6 +219,7 @@ impl Config { .collect() } + /// Extract the translation from the configuration. pub fn extract_translation(&self) -> HashMap> { let empty = HashMap::new(); diff --git a/engine/preprocessor/Cargo.toml b/engine/preprocessor/Cargo.toml index 8f3b521..48d5926 100644 --- a/engine/preprocessor/Cargo.toml +++ b/engine/preprocessor/Cargo.toml @@ -2,7 +2,7 @@ name = "clafrica-preprocessor" version = "0.5.0" edition = "2021" -description = "A preprocessor for processing key input of an input method." +description = "A preprocessor to process keyboard events for an input method." keywords = ["ime", "processor", "keyboard"] repository = "https://github.com/pythonbrad/name" license = "MIT" diff --git a/engine/preprocessor/README.md b/engine/preprocessor/README.md new file mode 100644 index 0000000..136ed20 --- /dev/null +++ b/engine/preprocessor/README.md @@ -0,0 +1,2 @@ +# Clafrica Preprocessor +It generate a sequence of command to be perform to execute a particular task. diff --git a/engine/preprocessor/src/lib.rs b/engine/preprocessor/src/lib.rs index 2a30164..44e50ce 100644 --- a/engine/preprocessor/src/lib.rs +++ b/engine/preprocessor/src/lib.rs @@ -1,3 +1,46 @@ +//! Preprocessor of keyboard events for an input method. +//! +//! Example +//! +//! ```rust +//! use clafrica_preprocessor::{utils, Command, Preprocessor}; +//! use keyboard_types::{ +//! webdriver::{self, Event}, +//! Key::*, +//! }; +//! use std::collections::VecDeque; +//! +//! // We build initiate our preprocessor +//! let data = utils::load_data("cc ç"); +//! let map = utils::build_map(data); +//! let mut preprocessor = Preprocessor::new(map, 8); +//! +//! // We trigger a sequence +//! webdriver::send_keys("cc") +//! .into_iter() +//! .for_each(|e| { +//! match e { +//! Event::Keyboard(e) => preprocessor.process(e), +//! _ => unimplemented!(), +//! }; +//! }); +//! +//! // We got the generated command +//! let mut expecteds = VecDeque::from(vec![ +//! Command::Pause, +//! Command::KeyClick(Backspace), +//! Command::KeyClick(Backspace), +//! Command::CommitText("ç".to_owned()), +//! Command::Resume, +//! ]); +//! +//! while let Some(command) = preprocessor.pop_stack() { +//! assert_eq!(command, expecteds.pop_front().unwrap()); +//! } +//! ``` + +#![deny(missing_docs)] + mod message; pub use crate::message::Command; @@ -6,6 +49,7 @@ use clafrica_memory::{Cursor, Node}; pub use keyboard_types::{Key, KeyState, KeyboardEvent}; use std::collections::VecDeque; +/// The main structure of the preprocessor. #[derive(Debug)] pub struct Preprocessor { cursor: Cursor, @@ -13,6 +57,7 @@ pub struct Preprocessor { } impl Preprocessor { + /// Initiate a new preprocessor. pub fn new(map: Node, buffer_size: usize) -> Self { let cursor = Cursor::new(map, buffer_size); let stack = VecDeque::with_capacity(15); @@ -20,6 +65,7 @@ impl Preprocessor { Self { cursor, stack } } + /// Cancel the previous operation. fn rollback(&mut self) -> bool { self.stack.push_back(Command::KeyRelease(Key::Backspace)); @@ -42,6 +88,7 @@ impl Preprocessor { } } + /// Process the key event. pub fn process(&mut self, event: KeyboardEvent) -> (bool, bool) { let (mut changed, mut committed) = (false, false); @@ -97,6 +144,7 @@ impl Preprocessor { (changed, committed) } + /// Commit a text. pub fn commit(&mut self, text: &str) { self.pause(); @@ -110,14 +158,17 @@ impl Preprocessor { self.cursor.clear(); } + /// Pause the keyboard event listerner. fn pause(&mut self) { self.stack.push_back(Command::Pause); } + /// Resume the keyboard event listener. fn resume(&mut self) { self.stack.push_back(Command::Resume); } + /// Return the sequence present in the memory. pub fn get_input(&self) -> String { self.cursor .to_sequence() @@ -126,10 +177,12 @@ impl Preprocessor { .collect::() } + /// Return the next command to be executed. pub fn pop_stack(&mut self) -> Option { self.stack.pop_front() } + /// Clear the stack. pub fn clear_stack(&mut self) { self.stack.clear(); } @@ -145,7 +198,6 @@ mod tests { Key::*, }; use std::collections::VecDeque; - use std::fs; #[test] fn test_process() { @@ -248,6 +300,8 @@ mod tests { #[test] fn test_advanced() { + use std::fs; + let data = fs::read_to_string("./data/sample.txt").unwrap(); let data = utils::load_data(&data); let map = utils::build_map(data); diff --git a/engine/preprocessor/src/message.rs b/engine/preprocessor/src/message.rs index d76ea9c..b2510ec 100644 --- a/engine/preprocessor/src/message.rs +++ b/engine/preprocessor/src/message.rs @@ -1,11 +1,20 @@ +#![deny(missing_docs)] + use keyboard_types::Key; +/// Possible commands that can be generated. #[derive(Clone, Debug, Eq, PartialEq)] pub enum Command { + /// Request to commit a text. CommitText(String), + /// Request to pause the listener. Pause, + /// Request to resume the listener. Resume, + /// Request to press a key. KeyPress(Key), + /// Request to release a key. KeyRelease(Key), + /// Request to toggle a key. KeyClick(Key), } diff --git a/engine/translator/README.md b/engine/translator/README.md new file mode 100644 index 0000000..df5e8fb --- /dev/null +++ b/engine/translator/README.md @@ -0,0 +1,2 @@ +# Clafrica Translator +Handle the predication system of the clafrica input method. diff --git a/engine/translator/src/lib.rs b/engine/translator/src/lib.rs index 4be7856..3503944 100644 --- a/engine/translator/src/lib.rs +++ b/engine/translator/src/lib.rs @@ -1,6 +1,49 @@ -use rhai::{Array, Engine, Scope, AST}; +//! Engine to generate predicates based on a particular input. +//! +//! Example +//! ```rust +//! use clafrica_translator::{Engine, Translator}; +//! use std::collections::HashMap; +//! +//! // Translation via scripting +//! let engine = Engine::new(); +//! let hi = engine.compile(r#" +//! fn translate(input) { +//! if input == "hi" { +//! ["hi", "", "hello", true] +//! } +//! } +//! "#).unwrap(); +//! let mut translators = HashMap::new(); +//! translators.insert("hi".to_string(), hi); +//! +//! // Translation via dictionary +//! let mut dictionary = HashMap::new(); +//! dictionary.insert("halo".to_string(), ["hello".to_string()].to_vec()); +//! dictionary.insert("nihao".to_string(), ["hello".to_string()].to_vec()); +//! +//! // We build the translator. +//! let translator = Translator::new(dictionary, translators, true); +//! +//! assert_eq!( +//! translator.translate("hi"), +//! vec![( +//! "hi".to_owned(), +//! "".to_owned(), +//! vec!["hello".to_owned()], +//! true +//! )] +//! ); +//! ``` +//! + +#![deny(missing_docs)] + +pub use rhai::Engine; +use rhai::{Array, Scope, AST}; use std::collections::HashMap; +/// Core structure of the translator. pub struct Translator { dictionary: HashMap>, translators: HashMap, @@ -8,6 +51,7 @@ pub struct Translator { } impl Translator { + /// Initiate a new translator. pub fn new( dictionary: HashMap>, translators: HashMap, @@ -20,6 +64,7 @@ impl Translator { } } + /// Generate a list of predicates based on the input. pub fn translate(&self, input: &str) -> Vec<(String, String, Vec, bool)> { let mut scope = Scope::new(); let engine = Engine::new(); @@ -73,8 +118,7 @@ impl Translator { mod tests { #[test] fn test_translate() { - use crate::Translator; - use rhai::Engine; + use crate::{Engine, Translator}; use std::collections::HashMap; let engine = Engine::new(); diff --git a/memory/Cargo.toml b/memory/Cargo.toml index a930da5..2b4309b 100644 --- a/memory/Cargo.toml +++ b/memory/Cargo.toml @@ -2,7 +2,7 @@ name = "clafrica-memory" version = "0.3.2" edition = "2021" -description = "This library manage the memory of an input method." +description = "Make the handle of sequential codes easier for an input method." keywords = ["ime", "memory", "data-structure"] repository = "https://github.com/pythonbrad/name" license = "MIT" diff --git a/memory/src/lib.rs b/memory/src/lib.rs index 694bb53..b194f8e 100644 --- a/memory/src/lib.rs +++ b/memory/src/lib.rs @@ -1,7 +1,5 @@ -//! # Clafrica Memory -//! -//! `clafrica-memory` is a data structure to make handling -//! of sequential code more convenient. +//! Data structure to make handling of sequential +//! code more convenient. //! //! Example //! ``` @@ -21,29 +19,36 @@ //! let data = fs::read_to_string("./data/sample.txt") //! .expect("Failed to load the clafrica code file"); //! let data = utils::load_data(&data); -//! //! utils::build_map(data); //! //! // Traverse the tree //! let node = root.goto('a').and_then(|e| e.goto('f')); //! assert_eq!(node.unwrap().take(), Some("ɑ".to_owned())); //! -//! // Test our cursor +//! // We initiate our cursor //! let mut cursor = Cursor::new(root, 10); +//! // We move the cursor to the sequence //! let code = "af1"; //! code.chars().for_each(|c| {cursor.hit(c);}); +//! // We verify the current state //! assert_eq!(cursor.state(), (Some("ɑ̀".to_owned()), 3, '1')); +//! // We undo the last insertion //! assert_eq!(cursor.undo(), Some("ɑ̀".to_owned())); //! ``` +#![deny(missing_docs)] + use std::collections::{HashMap, VecDeque}; use std::{cell::RefCell, fmt, rc::Rc}; pub mod utils; +/// Extra information for a `Node`. #[derive(Clone, Debug)] pub struct Node { children: RefCell>>, + /// Depth of the node. pub depth: usize, + /// Character holded by the node. pub key: char, value: RefCell>, } @@ -86,12 +91,12 @@ impl Node { }; } - /// Move from the node to his child. + /// Move from the current node to his child. pub fn goto(&self, character: char) -> Option> { self.children.borrow().get(&character).map(Rc::clone) } - /// Extract the value from the node. + /// Extract the value of the node. pub fn take(&self) -> Option { self.value.borrow().as_ref().map(ToOwned::to_owned) } @@ -102,6 +107,7 @@ impl Node { } } +/// The Cursor permit to keep a track of the move in the memory. #[derive(Clone)] pub struct Cursor { buffer: VecDeque>, @@ -115,7 +121,7 @@ impl fmt::Debug for Cursor { } impl Cursor { - /// Initialize the cursor + /// Initialize the cursor. pub fn new(root: Node, capacity: usize) -> Self { Self { buffer: VecDeque::with_capacity(capacity), @@ -123,7 +129,7 @@ impl Cursor { } } - /// Enter a character in the sequence and return his corresponding out + /// Enter a character in the sequence and return his corresponding out. pub fn hit(&mut self, character: char) -> Option { let node = self .buffer @@ -152,7 +158,7 @@ impl Cursor { self.buffer.push_back(node); } - /// Remove the last node and return his corresponding out + /// Remove the last node and return his corresponding out. pub fn undo(&mut self) -> Option { let node = self.buffer.pop_back(); @@ -165,7 +171,7 @@ impl Cursor { }) } - /// Return the current state of the cursor + /// Return the current state of the cursor. pub fn state(&self) -> (Option, usize, char) { self.buffer .iter() @@ -174,17 +180,17 @@ impl Cursor { .unwrap_or_default() } - /// Return the current sequence in the cursor + /// Return the current sequence in the cursor. pub fn to_sequence(&self) -> Vec { self.buffer.iter().map(|node| node.key).collect() } - /// Clear the memory of the cursor + /// Clear the memory of the cursor. pub fn clear(&mut self) { self.buffer.clear(); } - /// Verify if the cursor is empty + /// Verify if the cursor is empty. pub fn is_empty(&self) -> bool { return self.buffer.iter().filter(|c| c.key != '\0').count() == 0; } diff --git a/memory/src/utils.rs b/memory/src/utils.rs index 4052143..8d8a98a 100644 --- a/memory/src/utils.rs +++ b/memory/src/utils.rs @@ -1,3 +1,9 @@ +//! Module providing a set of tools to facilitate the loading +//! of a data in the memory. +//! + +#![deny(missing_docs)] + use crate::Node; /// Load the sequential code from a plain text. diff --git a/service/Cargo.toml b/service/Cargo.toml index 408f6a1..90045bb 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -6,7 +6,7 @@ description = "Core library of the clafrica input method." keywords = ["ime", "keyboard"] repository = "https://github.com/pythonbrad/name" license = "MIT" -readme = "README.md" +readme = "../README.md" authors = ["Brady Fomegne "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/service/src/convert.rs b/service/src/convert.rs index b77a33f..6a6014a 100644 --- a/service/src/convert.rs +++ b/service/src/convert.rs @@ -1,3 +1,9 @@ +//! Set of tools to convert external event keyboards to +//! generic keyboard events and vice versa. +//! + +#![deny(missing_docs)] + use clafrica_preprocessor::{Key, KeyState, KeyboardEvent}; use enigo::{self}; use rdev::{self}; diff --git a/service/src/frontend.rs b/service/src/frontend.rs index 55630c8..ba88278 100644 --- a/service/src/frontend.rs +++ b/service/src/frontend.rs @@ -1,22 +1,40 @@ +//! API to develop a frontend interface for the clafrica. +//! + +#![deny(missing_docs)] + +/// Trait that every clafrica frontend should implement. pub trait Frontend { + /// Update the frontenfrontend d size. fn update_screen(&mut self, _screen: (u64, u64)) {} + /// Update the frontend position. fn update_position(&mut self, _position: (f64, f64)) {} + /// Set the current sequential code to display. fn set_input(&mut self, _text: &str) {} + /// Set the maximun number of predicates to be display. fn set_page_size(&mut self, _size: usize) {} + /// Add a predicate in the list of predicates. fn add_predicate(&mut self, _code: &str, _remaining_code: &str, _text: &str) {} + /// Refresh the display. fn display(&self) {} + /// Clear the list of predicates. fn clear_predicates(&mut self) {} + /// Select the previous predicate. fn previous_predicate(&mut self) {} + /// Select the next predicate. fn next_predicate(&mut self) {} + /// Return the selected predicate. fn get_selected_predicate(&self) -> Option<&(String, String, String)> { Option::None } } +/// This frontend do nothing. pub struct None; impl Frontend for None {} +/// Cli frontent interface. #[derive(Default)] pub struct Console { page_size: usize, diff --git a/service/src/lib.rs b/service/src/lib.rs index 4b653fe..b0d4650 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -9,6 +9,7 @@ use frontend::Frontend; use rdev::{self, EventType, Key as E_Key}; use std::{error, sync::mpsc, thread}; +/// Start the clafrica. pub fn run(config: Config, mut frontend: impl Frontend) -> Result<(), Box> { let map = utils::build_map( config diff --git a/service/src/main.rs b/service/src/main.rs index 6a046e1..eaa430c 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -2,14 +2,14 @@ use clafrica::{frontend, run, Config}; use clap::Parser; use std::process; -/// Clafrica CLI +/// Clafrica CLI. #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Args { - /// Path to the configuration file + /// Path to the configuration file. config_file: std::path::PathBuf, - /// Only verify if the configuration file is valid + /// Only verify if the configuration file is valid. #[arg(long, action)] check: bool, }