diff --git a/CMakePresets.json b/CMakePresets.json index 2d3061560..3adf22ef3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -5,6 +5,14 @@ "minor": 21 }, "configurePresets": [ + { + "name": "default", + "displayName": "Default (Release)", + "description": "Default preset for release build", + "inherits": [ + "c99-release" + ] + }, { "name": "coverage-base", "displayName": "Enable Coverage", @@ -89,6 +97,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", + "BUILD_INFO": true, "WITH_RUST": false, "WITH_SQLITE3": true } @@ -145,5 +154,11 @@ "coverage-base" ] } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default" + } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 1767b10d6..cad02c231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chewing" -version = "0.6.0-alpha.1" +version = "0.6.0-alpha.2" dependencies = [ "bytemuck", "cdb2", diff --git a/Cargo.toml b/Cargo.toml index b6390a8a8..aabdb7d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "chewing" description = "The Chewing (酷音) intelligent Zhuyin input method." license = "LGPL-2.1-or-later" documentation = "https://docs.rs/chewing" -version = "0.6.0-alpha.1" +version = "0.6.0-alpha.2" rust-version = "1.70" edition = "2021" @@ -47,3 +47,7 @@ resolver = "2" lto = true debug = true panic = "abort" + +[package.metadata.docs.rs] +features = ["capi", "sqlite"] +# rustdoc-args = ["-Zunstable-options", "--sort-modules-by-appearance"] diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e9c22791d..02b5e993d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -15,9 +15,5 @@ if (BUILD_INFO AND MAKEINFO) add_custom_target(INFO ALL DEPENDS ${INFO_BIN}) add_dependencies(check INFO) - find_program(INSTALL_INFO NAMES ginstall-info install-info) - if (INSTALL_INFO) - install(FILES ${INFO_BIN} DESTINATION ${CMAKE_INSTALL_INFODIR}) - install(CODE "execute_process(COMMAND ${INSTALL_INFO} --info-dir=${CMAKE_INSTALL_INFODIR} ${INFO_BIN})") - endif() + install(FILES ${INFO_BIN} TYPE INFO) endif() \ No newline at end of file diff --git a/doc/libchewing.texi b/doc/libchewing.texi index 772e07ec2..1c590394b 100644 --- a/doc/libchewing.texi +++ b/doc/libchewing.texi @@ -640,8 +640,8 @@ This function checks if the candidates selection has finished. @section Candidates Behavior @deftypefun void chewing_set_candPerPage (ChewingContext *@var{ctx}, int @var{n}) -This function sets the candidates per page to @var{n}. If MIN_SELKEY @leq{} -@var{n} @leq{} @code{MAX_SELKEY} is not true or the number of selection keys is +This function sets the candidates per page to @var{n}. If MIN_SELKEY <= +@var{n} <= @code{MAX_SELKEY} is not true or the number of selection keys is not enough, the @var{n} will be ignored. The default candidates per page is @code{MAX_SELKEY}. @end deftypefun @@ -714,7 +714,7 @@ This function closes the candidate windows. It returns @code{0} when success, @deftypefun const char* chewing_cand_string_by_index_static (ChewingContext *@var{ctx}, int @var{index}) This function returns the candidate string by its index. The range of -@var{index} shall be @code{0} @leq{} @var{index} < +@var{index} shall be @code{0} <= @var{index} < @code{chewing_cand_TotalChoice}. This function returns @code{NULL} when no memory. @@ -725,7 +725,7 @@ be freed by the next time be used. @deftypefun int chewing_cand_choose_by_index (ChewingContext *@var{ctx}, int @var{index}) This function chooses the candidate by its index. The range of @var{index} -shall be @code{0} @leq{} @var{index} < @code{chewing_cand_TotalChoice}. This +shall be @code{0} <= @var{index} < @code{chewing_cand_TotalChoice}. This function returns @code{0} when success, @code{-1} otherwise. @end deftypefun diff --git a/src/capi/key2pho.rs b/src/capi/internal/key2pho.rs similarity index 100% rename from src/capi/key2pho.rs rename to src/capi/internal/key2pho.rs diff --git a/src/capi/internal/mod.rs b/src/capi/internal/mod.rs new file mode 100644 index 000000000..a63f798c1 --- /dev/null +++ b/src/capi/internal/mod.rs @@ -0,0 +1,9 @@ +//! Internal functions visible for tests only + +mod key2pho; +mod path; +mod utf8; + +pub use key2pho::*; +pub use path::*; +pub use utf8::*; diff --git a/src/capi/path.rs b/src/capi/internal/path.rs similarity index 100% rename from src/capi/path.rs rename to src/capi/internal/path.rs diff --git a/src/capi/utf8.rs b/src/capi/internal/utf8.rs similarity index 100% rename from src/capi/utf8.rs rename to src/capi/internal/utf8.rs diff --git a/src/capi/io.rs b/src/capi/io.rs index 9e56256e6..266386782 100644 --- a/src/capi/io.rs +++ b/src/capi/io.rs @@ -12,12 +12,9 @@ use std::{ use tracing::{debug, warn}; use crate::{ - capi::{ - public::{ - ChewingConfigData, IntervalType, CHINESE_MODE, FULLSHAPE_MODE, HALFSHAPE_MODE, - MAX_SELKEY, SYMBOL_MODE, - }, - types::{ChewingContext, SelKeys}, + capi::public::{ + ChewingConfigData, ChewingContext, IntervalType, SelKeys, CHINESE_MODE, FULLSHAPE_MODE, + HALFSHAPE_MODE, MAX_SELKEY, SYMBOL_MODE, }, conversion::{ChewingEngine, Interval, Symbol}, dictionary::{LayeredDictionary, SystemDictionaryLoader, UserDictionaryLoader}, @@ -25,9 +22,10 @@ use crate::{ keyboard::{AnyKeyboardLayout, KeyCode, KeyboardLayout, Modifiers, Qwerty}, syllable::{ DaiChien26, Et, Et26, GinYieh, Hsu, Ibm, KeyboardLayoutCompat, Pinyin, Standard, + SyllableEditor, }, BasicEditor, CharacterForm, Editor, EditorKeyBehavior, EditorOptions, LanguageMode, - LaxUserFreqEstimate, SyllableEditor, UserPhraseAddDirection, + LaxUserFreqEstimate, UserPhraseAddDirection, }, zhuyin::Syllable, }; @@ -135,8 +133,8 @@ pub extern "C" fn chewing_new2( SystemDictionaryLoader::new().sys_path(search_path).load() }; let dictionaries = match dictionaries { - Some(d) => d, - None => return null_mut(), + Ok(d) => d, + Err(_) => return null_mut(), }; let user_dictionary = if userpath.is_null() { UserDictionaryLoader::new().load() @@ -149,8 +147,8 @@ pub extern "C" fn chewing_new2( .load() }; let user_dictionary = match user_dictionary { - Some(d) => d, - None => return null_mut(), + Ok(d) => d, + Err(_) => return null_mut(), }; let estimate = LaxUserFreqEstimate::open(user_dictionary.as_ref()); @@ -1549,6 +1547,7 @@ pub extern "C" fn chewing_cursor_Current(ctx: *const ChewingContext) -> c_int { ctx.editor.cursor() as c_int } +#[deprecated(note = "The chewing_cand_TotalPage function could achieve the same effect.")] #[tracing::instrument(skip(ctx), ret)] #[no_mangle] pub extern "C" fn chewing_cand_CheckDone(ctx: *const ChewingContext) -> c_int { diff --git a/src/capi/mod.rs b/src/capi/mod.rs index b9dd08d2c..e2622a729 100644 --- a/src/capi/mod.rs +++ b/src/capi/mod.rs @@ -1,10 +1,932 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(unsafe_code)] +#![allow(deprecated)] -pub mod ffi; -pub mod io; -pub mod key2pho; -pub mod path; -pub mod public; -pub mod types; -pub mod utf8; +//! C compatible APIs. +//! +//! All items in this module are available via the C header file ``. +//! Function symbols are exposed from the libchewing shared library. +//! +//! Functions are organized into several modules according to the services +//! provided by them. + +mod ffi; +mod io; +mod public; + +#[doc(hidden)] +pub mod internal; + +/// Initializes chewing context and environment settings. +/// +/// Most of the Chewing IM APIs require a [ChewingContext]. To create a +/// ChewingContext you must use the [chewing_new] function. +/// +/// # Examples +/// +/// Create a chewing context and deletes it after use. +/// +/// ```c +/// #include +/// int main(int argc, char *argv[]) +/// { +/// ChewingContext *ctx = chewing_new(); +/// +/// /* do something */ +/// +/// chewing_delete( ctx ); +/// +/// return 0; +/// } +/// ``` +/// +/// # Environment variables +/// +/// * `CHEWING_PATH` +/// * The CHEWING_PATH environment variable is used to set the search path +/// of static data used by the Chewing IM. The format of CHEWING_PATH is +/// the same as PATH, which is multiple paths separated by ‘:’ on POSIX +/// and Unix-like platforms, or separated by ‘;’ on Windows platform. The +/// directories in CHEWING_PATH could be read-only. +/// * `CHEWING_USER_PATH` +/// * The CHEWING_USER_PATH environment variable is used to specifies the +/// path where user-defined hash data stores. This path should be writable +/// by the user, or the Chewing IM will lose the ability to remember the +/// learned phrases. +pub mod setup { + /// This function exists only for backword compatibility. + /// + /// The `chewing_Init` function is no-op now. The return value is always 0. + pub use super::io::chewing_Init; + + /// Creates a new instance of the Chewing IM. + /// + /// The return value is a pointer to the new Chewing IM instance. + /// + /// See also the [chewing_new2], and [chewing_delete] functions. + pub use super::io::chewing_new; + + /// Creates a new instance of the Chewing IM. + /// + /// The `syspath` is the directory path to system dictionary. The `userpath` + /// is file path to user dictionary. User shall have enough permission to + /// update this file. The logger and loggerdata is logger function and its + /// data. + /// + /// All parameters will be default if set to NULL. + /// + /// The return value is a pointer to the new Chewing IM instance. See also + /// the [chewing_new], [chewing_delete] function. + pub use super::io::chewing_new2; + + /// Releases the resources used by the given Chewing IM instance. + pub use super::io::chewing_delete; + + /// Sets the selectAreaLen, maxChiSymbolLen and selKey parameter from pcd. + /// + /// The pcd argument is a pointer to a Chewing configuration data structure. + /// See also the ChewingConfigData data type. + /// + /// The return value is 0 on success and -1 on failure. + /// + /// **Deprecated**, use the chewing_set_* function series to set parameters + /// instead. + pub use super::io::chewing_Configure; + + /// Resets all settings in the given Chewing IM instance. + /// + /// The return value is 0 on success and -1 on failure. + pub use super::io::chewing_Reset; + + /// Releases the memory allocated by the Chewing IM and returned to the + /// caller. + /// + /// There are functions returning pointers of strings or other data + /// structures that are allocated on the heap. These memory must be freed to + /// avoid memory leak. To avoid memory allocator mismatch between the + /// Chewing IM and the caller, use this function to free the resource. + /// + /// Do nothing if ptr is NULL. + pub use super::io::chewing_free; + + /// Sets the logger function logger. + /// + /// The logger function is used to provide log inside Chewing IM for + /// debugging. The data in chewing_set_logger is passed directly to data in + /// logger when logging. + /// + /// # Examples + /// + /// The following example shows how to use data: + /// + /// ```c + /// void logger( void *data, int level, const char *fmt, ... ) + /// { + /// FILE *fd = (FILE *) data; + /// ... + /// } + /// + /// int main() + /// { + /// ChewingContext *ctx; + /// FILE *fd; + /// ... + /// chewing_set_logger(ctx, logger, fd); + /// ... + /// } + /// ``` + /// + /// The level is log level. + pub use super::io::chewing_set_logger; + + pub use super::public::ChewingContext; + + pub use super::public::CHEWING_LOG_VERBOSE; + + pub use super::public::CHEWING_LOG_DEBUG; + + pub use super::public::CHEWING_LOG_INFO; + + pub use super::public::CHEWING_LOG_WARN; + + pub use super::public::CHEWING_LOG_ERROR; +} + +/// Keyboard input handling. +/// +/// Functions to handle key strokes. The return value of these functions is 0 on +/// success and -1 on failure. +pub mod input { + /// Handles all keys that do not have dedicated methods. + pub use super::io::chewing_handle_Default; + + /// Handles the Backspace key. + pub use super::io::chewing_handle_Backspace; + + /// Handles the Capslock key. + pub use super::io::chewing_handle_Capslock; + + /// Handles any number key with the Ctrl modifier. + /// + /// The value of key should be in the range between ASCII character code + /// from 0 to 9. + pub use super::io::chewing_handle_CtrlNum; + + /// Handles the Delete key. + pub use super::io::chewing_handle_Del; + + /// Handles the Enter or Return key. + pub use super::io::chewing_handle_Enter; + + /// Handles the Esc key. + pub use super::io::chewing_handle_Esc; + + /// Handles the Space key. + pub use super::io::chewing_handle_Space; + + /// Handles the Tab key. + pub use super::io::chewing_handle_Tab; + + /// Handles the Home key. + pub use super::io::chewing_handle_Home; + + /// Handles the End key. + pub use super::io::chewing_handle_End; + + /// Handles the Left key. + pub use super::io::chewing_handle_Left; + + /// Handles the Right key. + pub use super::io::chewing_handle_Right; + + /// Handles the Up key. + /// + /// See also [chewing_cand_close][super::candidates::chewing_cand_close] keyboardless API to close candidate + /// window. + pub use super::io::chewing_handle_Up; + + /// Handles the Down key. + /// + /// See also [super::io::chewing_cand_open] keyboardless API to open candidate window. + pub use super::io::chewing_handle_Down; + + /// Handles the Left key with the Shift modifier. + pub use super::io::chewing_handle_ShiftLeft; + + /// Handles the Right key with the Shift modifier. + pub use super::io::chewing_handle_ShiftRight; + + /// Handles the Space key with the Shift modifier. + pub use super::io::chewing_handle_ShiftSpace; + + /// Handles the PageUp key. + pub use super::io::chewing_handle_PageUp; + + /// Handles the PageDown key. + pub use super::io::chewing_handle_PageDown; + + /// Handles tapping the Tab key twice quickly. + pub use super::io::chewing_handle_DblTab; + + /// Handles any numeric key from the keypad. + /// + /// The value of key should be in the range between ASCII character code + /// from 0 to 9. + pub use super::io::chewing_handle_Numlock; +} + +/// Keyboard layout and variants setting. +/// +/// The Chewing IM supports many different keyboard layout and variants. Use +/// functions in this module to set the current keyboard layout for the context. +pub mod layout { + /// Sets the current keyboard layout for ctx. + /// + /// The kbtype argument must be a value defined in [KB]. + /// + /// The return value is 0 on success and -1 on failure. The keyboard type + /// will set to KB_DEFAULT if return value is -1. + pub use super::io::chewing_set_KBType; + + /// Returns the current keyboard layout index for ctx. + /// + /// The return value is the layout index defined in [KB]. + pub use super::io::chewing_get_KBType; + + /// Returns the the current layout name string of ctx. + /// + /// The return value is the name of the current layout, see also function + /// [chewing_KBStr2Num]. + /// + /// The returned pointer must be freed by + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_get_KBString; + + /// Converts the keyboard layout name from string to corresponding layout + /// index. + /// + /// If the string does not match any layout, this function returns + /// KB_DEFAULT. + /// + /// The string str might be one of the following layouts: + /// * KB_DEFAULT + /// * KB_HSU + /// * KB_IBM + /// * KB_GIN_YIEH + /// * KB_ET + /// * KB_ET26 + /// * KB_DVORAK + /// * KB_DVORAK_HSU + /// * KB_DVORAK_CP26 + /// * KB_HANYU_PINYIN + /// * KB_THL_PINYIN + /// * KB_MPS2_PINYIN + /// * KB_CARPALX + /// + /// See also [chewing_kbtype_Enumerate] for getting the list of supported + /// layouts programmatically. + pub use super::io::chewing_KBStr2Num; + + /// Returns the number of keyboard layouts supported by the Chewing IM. + pub use super::io::chewing_kbtype_Total; + + /// Starts the enumeration of the keyboard layouts. + /// + /// This function stores an iterator in the context. The iterator is only + /// destroyed after enumerate all keyboard layouts using + /// [chewing_kbtype_hasNext]. + pub use super::io::chewing_kbtype_Enumerate; + + /// Checks whether there are more keyboard layouts to enumerate. + /// + /// Returns 1 when there are more and 0 when it's the end of the iterator. + pub use super::io::chewing_kbtype_hasNext; + + /// Returns the current enumerated keyboard layout name. + /// + /// The returned string is emtpy string when enumeration is over. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_kbtype_String; + + /// Returns the current enumerated keyboard layout name. + /// + /// The returned string is emtpy string when enumeration is over. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_kbtype_hasNext] + /// condition. + pub use super::io::chewing_kbtype_String_static; + + pub use super::public::KB; +} + +/// Input mode settings. +/// +/// The Chewing IM can switch between Chinese input mode or English mode. The +/// English mode supports input English characters directly. These functions set +/// the current input mode. +pub mod modes { + /// Sets the input mode to Chinese or English. + /// + /// The *mode* argument is one of the [CHINESE_MODE] and [SYMBOL_MODE] + /// constants. + pub use super::io::chewing_set_ChiEngMode; + + /// Returns the current Chinese/English mode setting. + pub use super::io::chewing_get_ChiEngMode; + + /// Sets the current punctuation input mode. + /// + /// The *mode* argument is one of the [FULLSHAPE_MODE] and [HALFSHAPE_MODE] + /// constants. + pub use super::io::chewing_set_ShapeMode; + + /// Returns the current punctuation mode. + pub use super::io::chewing_get_ShapeMode; + + pub use super::public::CHINESE_MODE; + pub use super::public::SYMBOL_MODE; + + pub use super::public::FULLSHAPE_MODE; + pub use super::public::HALFSHAPE_MODE; +} + +/// Candidate selection related functions. +/// +/// These functions can be used to transit the Chewing IM into candidate +/// selection state and enumerate candidates. +/// +/// # Keyboardless APIs +/// +/// The traditional chewing APIs are coupled to keyboards. They cause some +/// problems if the program like to design its own keyboard scheme, or if a +/// platform does not have certain keyboard keys (ex: mobile device). To +/// overcome these problems, the new keyboardless APIs are provided. With these +/// APIs, program can have better control over libchewing, instead of hacking +/// libchewing via fake keyboard event. +pub mod candidates { + /// Returns the number of pages of the candidates. + /// + /// If the return value is greater than zero, then the IM interface should + /// display a selection window of the candidates for the user to choose a + /// candidate. Otherwise hide the selection window. + pub use super::io::chewing_cand_TotalPage; + + /// Returns the current candidate page number. + /// + /// # Examples + /// + /// The candidates pagination could be displayed as: + /// + /// ```c + /// sprintf(buf, "[%d / %d]", + /// chewing_cand_CurrentPage(ctx), + /// chewing_cand_TotalPage(ctx)); + /// ``` + pub use super::io::chewing_cand_CurrentPage; + + /// Returns the number of the coices per page. + /// + /// See also the [chewing_set_candPerPage] function. + pub use super::io::chewing_cand_ChoicePerPage; + + /// Returns the total number of the available choices. + pub use super::io::chewing_cand_TotalChoice; + + /// Starts the enumeration of the candidates starting from the first one in + /// the current page. + /// + /// This function stores an iterator in the context. The iterator is only + /// destroyed after enumerate candidates using + /// [chewing_cand_hasNext]. + pub use super::io::chewing_cand_Enumerate; + + /// Checks if there are more candidates to enumerate. + /// + ///

+ /// ⚠ Warning: This function checks the end of total choices + /// instead of the end of current page. + ///

+ pub use super::io::chewing_cand_hasNext; + + /// Returns the current enumerated candidate string. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_cand_String; + + /// Returns the current enumerated candidate string. + /// + /// The returned string is emtpy string when enumeration is over. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_cand_hasNext] + /// condition. + pub use super::io::chewing_cand_String_static; + + /// Checks if the candidates selection has finished. + /// + ///

+ /// ⚠ Warning: Not implemented. + ///

+ pub use super::io::chewing_cand_CheckDone; + + /// Sets the number of candidates returned per page. + /// + /// The setting is ignored if *n* is not between [MIN_SELKEY] and + /// [MAX_SELKEY] inclusive. + /// + /// The default value is MAX_SELKEY. + pub use super::io::chewing_set_candPerPage; + + /// Sets the key codes for candidate selection. + /// + /// *selkeys* is an ASCII code integer array of length [MAX_SELKEY]. The + /// second argument is unused. + /// + /// The default selection key is `1234567890`. + pub use super::io::chewing_set_selKey; + + /// Returns the current selection key setting. + /// + /// The returned value is a pointer to an integer array. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + pub use super::io::chewing_get_selKey; + + /// This function is no-op now. Use [chewing_set_selKey] instead. + pub use super::io::chewing_set_hsuSelKeyType; + + /// This function is no-op now. Use [chewing_get_selKey] instead. + pub use super::io::chewing_get_hsuSelKeyType; + + /// Opens the candidate selection window. + /// + /// This operation is only allowed when the IM editor is in entering state. + /// + /// Returns 0 when success, -1 otherwise. + pub use super::io::chewing_cand_open; + + /// Closes the candidate selection window. + /// + /// Returns 0 when success, -1 otherwise. + pub use super::io::chewing_cand_close; + + /// Returns the candidate string by its index. + /// + /// The *index* must be between 0 and [chewing_cand_TotalChoice] inclusive. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after calling this function. + pub use super::io::chewing_cand_string_by_index_static; + + /// Selects the candidate by its index. + /// + /// The *index* must be between 0 and [chewing_cand_TotalChoice] inclusive. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the *index* is out of range or the candidate + /// selection window is not currently open. + pub use super::io::chewing_cand_choose_by_index; + + /// Sets the candidate list to the first (longest) candidate list. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the candidate selection window is not currently + /// open. + pub use super::io::chewing_cand_list_first; + + /// Sets the candidate list to the last (shortest) candidate list. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the candidate selection window is not currently + /// open. + pub use super::io::chewing_cand_list_last; + + /// Checks whether there is a next (shorter) candidate list. + /// + /// Returns 1 (true) when there is a next candidate list, 0 otherwise. + pub use super::io::chewing_cand_list_has_next; + + /// Checks whether there is a previous (longer) candidate list. + /// + /// Returns 1 (true) when there is a previous candidate list, 0 otherwise. + pub use super::io::chewing_cand_list_has_prev; + + /// Changes current candidate list to next candidate list. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the candidate selection window is not currently + /// open. + pub use super::io::chewing_cand_list_next; + + /// Changes current candidate list to previous candidate list. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the candidate selection window is not currently + /// open. + pub use super::io::chewing_cand_list_prev; + + pub use super::public::MAX_SELKEY; + pub use super::public::MIN_SELKEY; + + pub use super::public::HSU_SELKEY_TYPE1; + pub use super::public::HSU_SELKEY_TYPE2; +} + +/// Output handling. +pub mod output { + /// Checks whether the commit buffer has something to read. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_commit_Check; + + /// Returns the string in the commit buffer. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_commit_String; + + /// Returns the string in the commit buffer. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_commit_Check] + /// condition. + pub use super::io::chewing_commit_String_static; + + /// Checks whether the previous keystroke is ignored or not. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_keystroke_CheckIgnore; + + /// Checks whether the previous keystroke is absorbed or not. + /// + /// Returns 1 when true, 0 when false. + /// + /// Absorbed key means the Chewing IM state machine has accepted the key and + /// changed its state accordingly. Caller should check various output + /// buffers to see if they need to update the display. + pub use super::io::chewing_keystroke_CheckAbsorb; + + /// Checks whether there is output in the pre-edit buffer. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_buffer_Check; + + /// Returns the length of the string in current pre-edit buffer. + /// + ///

+ /// ⚠ Warning: The length is calculated in terms of + /// unicode characters. One character might occupy multiple bytes. + ///

+ pub use super::io::chewing_buffer_Len; + + /// Returns the current output in the pre-edit buffer. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_buffer_String; + + /// Returns the current output in the pre-edit buffer. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_buffer_Check] + /// condition. + pub use super::io::chewing_buffer_String_static; + + /// Returns whether there are phonetic pre-edit string in the buffer. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_bopomofo_Check; + + /// Returns whether there are phonetic pre-edit string in the buffer. Here + /// “zuin” means bopomofo, a phonetic system for transcribing Chinese, + /// especially Mandarin. + /// + /// Returns **0** when true, **1** when false. + /// + ///

+ /// ⚠ Warning: The return value of this function is + /// different from other newer functions that returns boolean value. + ///

+ pub use super::io::chewing_zuin_Check; + + /// Returns the phonetic characters in the pre-edit buffer. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_bopomofo_Check] + /// condition. + pub use super::io::chewing_bopomofo_String_static; + + /// Returns the phonetic characters in the pre-edit buffer. + /// + /// The bopomofo_count argument is a output argument. It will contain the + /// number of phonetic characters in the returned string. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_zuin_String; + + /// Returns the current cursor position in the pre-edit buffer. + pub use super::io::chewing_cursor_Current; + + /// Starts the enumeration of intervals of recognized phrases. + /// + /// This function stores an iterator in the context. The iterator is only + /// destroyed after enumerate all intervals using + /// [chewing_interval_hasNext]. + pub use super::io::chewing_interval_Enumerate; + + /// Checks whether there are more intervals or not. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_interval_hasNext; + + /// Returns the current enumerated interval. + /// + /// The *it* argument is an output argument. + pub use super::io::chewing_interval_Get; + + /// Returns whether there is auxiliary string in the auxiliary buffer. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_aux_Check; + + /// Returns the length of the auxiliary string in the auxiliary buffer. + /// + ///

+ /// ⚠ Warning: The length is calculated in terms of + /// unicode characters. One character might occupy multiple bytes. + ///

+ pub use super::io::chewing_aux_Length; + + /// Returns the current auxiliary string. + /// + /// The returned value is a pointer to a character string. The memory must + /// be freed by the caller using function + /// [chewing_free][super::setup::chewing_free]. + /// + /// # Failures + /// + /// This function returns NULL when memory allocation fails. + pub use super::io::chewing_aux_String; + + /// Returns the current auxiliary string. + /// + /// The return value is a const pointer to a character string. The pointer + /// is only valid immediately after checking the [chewing_aux_Check] + /// condition. + pub use super::io::chewing_aux_String_static; + + /// Returns the phonetic sequence in the Chewing IM internal state machine. + /// + /// The return value is a pointer to a unsigned short array. The values in + /// the array is encoded Bopomofo phone. The memory must be freed by the + /// caller using function [chewing_free][super::setup::chewing_free]. + pub use super::io::chewing_get_phoneSeq; + + /// Returns the length of the phonetic sequence in the Chewing IM internal + /// state machine. + pub use super::io::chewing_get_phoneSeqLen; + + /// Converts the u16 encoded syllables to a bopomofo string. + /// + /// If both of the buf and the len are 0, this function will return buf + /// length for bopomofo including the null character so that caller can + /// prepare enough buffer for it. + /// + /// Returns 0 on success, -1 on failure. + pub use super::io::chewing_phone_to_bopomofo; + + /// Commits the current preedit buffer content to the commit buffer. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the IM editor is not in entering state. + pub use super::io::chewing_commit_preedit_buf; + + /// Clears the current preedit buffer content. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the IM editor is not in entering state. + pub use super::io::chewing_clean_preedit_buf; + + /// Clears the current bopomofo buffer content. + /// + /// Returns 0 when success, -1 otherwise. + /// + /// # Errors + /// + /// This function fails if the IM editor is not in entering state. + pub use super::io::chewing_clean_bopomofo_buf; + + pub use super::public::IntervalType; +} + +/// Userphrase handling. +pub mod userphrase { + /// Starts a userphrase enumeration. + /// + /// Caller shall call this function prior [chewing_userphrase_has_next] and + /// [chewing_userphrase_get] in order to enumerate userphrase correctly. + /// + /// This function stores an iterator in the context. The iterator is only + /// destroyed after enumerate all userphrases using + /// [chewing_userphrase_has_next]. + /// + /// Returns 0 on success, -1 on failure. + /// + /// # Examples + /// + /// ```c + /// chewing_userphrase_enumerate(ctx); + /// while (chewing_userphrase_has_next(ctx, &phrase_len, &bopomofo_len)) { + /// phrase = malloc(phrase_len); + /// if (!phrase) goto error; + /// bopomofo = malloc(bopomofo_len); + /// if (!bopomofo) goto error; + /// + /// chewing_userphrase_get(ctx, phrase, phrase_len, bopomofo, bopomofo_len); + /// /* do somthing */ + /// } + /// ``` + pub use super::io::chewing_userphrase_enumerate; + + /// Checks if there is another userphrase in current enumeration. + /// + /// The *phrase_len* and *bopomofo_len* are output buffer length needed by the userphrase and its bopomofo string. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_userphrase_has_next; + + /// Gets the current enumerated userphrase. + /// + /// The *phrase_buf* and *bopomofo_buf* are userphrase and its bopomofo + /// buffer provided by caller. The length of the buffers can be retrived + /// from [chewing_userphrase_has_next]. + /// + /// Returns 0 on success, -1 on failure. + pub use super::io::chewing_userphrase_get; + + /// Adds new userphrase to the user dictionary. + /// + /// Returns how many phrases are added, -1 on failure. + pub use super::io::chewing_userphrase_add; + + /// Removes a userphrase from the user dictionary. + /// + /// Returns how many phrases are removed, -1 on failure. + pub use super::io::chewing_userphrase_remove; + + /// Searchs if a userphrase is in the user dictionary. + /// + /// Returns 1 when true, 0 when false. + pub use super::io::chewing_userphrase_lookup; +} + +/// Global settings. +/// +/// The Chewing IM could be customized in some small details. These functions +/// provide the configuration interfaces to the front-end. +pub mod globals { + /// Sets the maximum number of the Chinese characters allowed in the + /// pre-edit buffer. + /// + /// If the pre-edit string is longer than this number then the leading part + /// will be committed automatically. The range of n shall between + /// [MIN_CHI_SYMBOL_LEN] and [MAX_CHI_SYMBOL_LEN]. + pub use super::io::chewing_set_maxChiSymbolLen; + + /// Returns the maximum number of the Chinese characters allowed in the + /// pre-edit buffer. + pub use super::io::chewing_get_maxChiSymbolLen; + + /// Sets the direction to add new phrases when using CtrlNum. + /// + /// The direction argument is 0 when the direction is backward and 1 when + /// the direction is forward. + pub use super::io::chewing_set_addPhraseDirection; + + /// Returns the direction to add new phrases when using CtrlNum. + /// + /// The direction argument is 0 when the direction is backward and 1 when + /// the direction is forward. + pub use super::io::chewing_get_addPhraseDirection; + + /// Sets whether the Space key is treated as a selection key. + /// + /// When the mode argument is 1, the Space key will initiate the candidates + /// selection mode. + pub use super::io::chewing_set_spaceAsSelection; + + /// Returns whether the Space key is treated as a selection key. + /// + /// Returns 1 when the Space key will initiate the candidates selection + /// mode. + pub use super::io::chewing_get_spaceAsSelection; + + /// Sets whether the Esc key will flush the current pre-edit buffer. + /// + /// When the mode argument is 1, the Esc key will flush the pre-edit buffer. + pub use super::io::chewing_set_escCleanAllBuf; + + /// Returns whether the Esc key will flush the current pre-edit buffer. + /// + /// Returns 1 when the Esc key will flush the pre-edit buffer. + pub use super::io::chewing_get_escCleanAllBuf; + + /// Sets whether the Chewing IM will automatically shift cursor after + /// selection. + pub use super::io::chewing_set_autoShiftCur; + + /// Returns whether the Chewing IM will automatically shift cursor after + /// selection. + pub use super::io::chewing_get_autoShiftCur; + + /// Sets the current normal/easy symbol mode. + /// + /// In easy symbol mode, the key be will changed to its related easy symbol + /// in swkb.dat. The format of swkb.dat is key symbol pair per line. The + /// valid value of key is [0-9A-Z]. The lower case character in key will be + /// changed to upper case when loading swkb.dat. However, in easy symbol + /// mode, only [0-9A-Z] are accepted. + /// + /// The mode argument is 0 for normal mode or other for easy symbol mode. + pub use super::io::chewing_set_easySymbolInput; + + /// Sets whether the phrase for candidates selection is before the cursor or + /// after the cursor. + pub use super::io::chewing_set_phraseChoiceRearward; + + /// Returns the phrase choice rearward setting. + pub use super::io::chewing_get_phraseChoiceRearward; + + /// Sets enable or disable the automatic learning. + /// + /// The mode argument is be one of the [AUTOLEARN_ENABLED] and + /// [AUTOLEARN_DISABLED] constants. + pub use super::io::chewing_set_autoLearn; + + /// Returns whether the automatic learning is enabled or disabled. + pub use super::io::chewing_get_autoLearn; + + pub use super::public::MAX_CHI_SYMBOL_LEN; + pub use super::public::MIN_CHI_SYMBOL_LEN; + + pub use super::public::MAX_PHONE_SEQ_LEN; + pub use super::public::MAX_PHRASE_LEN; + + pub use super::public::AUTOLEARN_DISABLED; + pub use super::public::AUTOLEARN_ENABLED; +} diff --git a/src/capi/public.rs b/src/capi/public.rs index c7cb06b8e..6085704ce 100644 --- a/src/capi/public.rs +++ b/src/capi/public.rs @@ -1,29 +1,64 @@ -use std::ffi::c_int; +use std::{ffi::c_int, fmt::Debug, iter::Peekable}; +use crate::{ + conversion::{ChewingEngine, Interval}, + dictionary::DictEntries, + editor::{keyboard::AnyKeyboardLayout, syllable::KeyboardLayoutCompat, Editor}, +}; + +/// Indicates chewing will translate keystrokes to Chinese characters. pub const CHINESE_MODE: c_int = 1; +/// Indicates the input mode is translating keystrokes to symbols. pub const SYMBOL_MODE: c_int = 0; +/// Indicates chewing will translate latin and puctuation characters to +/// double-with characters. pub const FULLSHAPE_MODE: c_int = 1; +/// Indicates chewing will not translate latin and puctuation characters. pub const HALFSHAPE_MODE: c_int = 0; +/// Indicates automatic user phrase learning is disabled. pub const AUTOLEARN_DISABLED: usize = 1; +/// Indicates automatic user phrase learning is enabled. pub const AUTOLEARN_ENABLED: usize = 0; +/// The minimal size of pre-edit buffer. +pub const MIN_CHI_SYMBOL_LEN: usize = 0; +/// The maximum size of pre-edit buffer. +pub const MAX_CHI_SYMBOL_LEN: usize = MAX_PHONE_SEQ_LEN - MAX_PHRASE_LEN; +/// The size of internal buffer for pre-edit buffer. +pub const MAX_PHONE_SEQ_LEN: usize = 50; +/// The maximum phrase size. +pub const MAX_PHRASE_LEN: usize = 11; +/// The number of minimum candidates that are selectable via shortcut keys. pub const MIN_SELKEY: usize = 1; +/// The number of maximum candidates that are selectable via shortcut keys. pub const MAX_SELKEY: usize = 10; +/// Log level. pub const CHEWING_LOG_VERBOSE: usize = 1; +/// Log level. pub const CHEWING_LOG_DEBUG: usize = 2; +/// Log level. pub const CHEWING_LOG_INFO: usize = 3; +/// Log level. pub const CHEWING_LOG_WARN: usize = 4; +/// Log level. pub const CHEWING_LOG_ERROR: usize = 5; -/// Use "asdfjkl789" as selection key +/// Use "asdfjkl789" as selection key. +#[deprecated] pub const HSU_SELKEY_TYPE1: usize = 1; -/// Use "asdfzxcv89" as selection key +/// Use "asdfzxcv89" as selection key. +#[deprecated] pub const HSU_SELKEY_TYPE2: usize = 2; +/// Configuration for chewing runtime features. +/// /// Deprecated, use chewing_set_ series of functions to set parameters instead. +/// /// cbindgen:rename-all=CamelCase #[repr(C)] +#[deprecated] +#[derive(Debug)] pub struct ChewingConfigData { pub cand_per_page: c_int, pub max_chi_symbol_len: c_int, @@ -37,10 +72,67 @@ pub struct ChewingConfigData { pub hsu_sel_key_type: c_int, } +/// Specifies the interval of a phrase segment in the pre-editng area #[repr(C)] +#[derive(Debug)] pub struct IntervalType { /// Starting position of certain interval pub from: c_int, /// Ending position of certain interval (exclusive) pub to: c_int, } + +/// Keyboard layout index. +/// +/// cbindgen:prefix-with-name +/// cbindgen:enum-trailing-values=[TypeNum] +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +pub enum KB { + Default, + Hsu, + Ibm, + GinYieh, + Et, + Et26, + Dvorak, + DvorakHsu, + DachenCp26, + HanyuPinyin, + ThlPinyin, + Mps2Pinyin, + Carpalx, +} + +/// Opaque context handle used for chewing APIs. +/// +/// cbindgen:rename-all=None +pub struct ChewingContext { + pub(crate) kb_compat: KeyboardLayoutCompat, + pub(crate) keyboard: AnyKeyboardLayout, + pub(crate) editor: Editor, + pub(crate) kbcompat_iter: Option>>>, + pub(crate) cand_iter: Option>>>, + pub(crate) interval_iter: Option>>>, + pub(crate) userphrase_iter: Option>, + pub(crate) sel_keys: SelKeys, +} + +impl Debug for ChewingContext { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ChewingContext") + .field("kb_compat", &self.kb_compat) + .field("keyboard", &self.keyboard) + .field("editor", &self.editor) + .field("kbcompat_iter.is_some()", &self.kbcompat_iter.is_some()) + .field("cand_iter.is_some()", &self.cand_iter.is_some()) + .field("interval_iter.is_some()", &self.interval_iter.is_some()) + .field("userphrase_iter.is_some()", &self.userphrase_iter.is_some()) + .field("sel_keys", &self.sel_keys) + .finish_non_exhaustive() + } +} + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct SelKeys(pub(crate) [c_int; MAX_SELKEY]); diff --git a/src/capi/types.rs b/src/capi/types.rs index 1008fbcfd..8b1378917 100644 --- a/src/capi/types.rs +++ b/src/capi/types.rs @@ -1,43 +1 @@ -use std::{ffi::c_int, iter::Peekable}; -use crate::{ - capi::public::MAX_SELKEY, - conversion::{ChewingEngine, Interval}, - dictionary::DictEntries, - editor::{keyboard::AnyKeyboardLayout, syllable::KeyboardLayoutCompat, Editor}, -}; - -/// cbindgen:prefix-with-name -/// cbindgen:enum-trailing-values=[TypeNum] -#[derive(Clone, Copy, Debug, PartialEq)] -#[repr(C)] -pub enum KB { - Default, - Hsu, - Ibm, - GinYieh, - Et, - Et26, - Dvorak, - DvorakHsu, - DachenCp26, - HanyuPinyin, - ThlPinyin, - Mps2Pinyin, - Carpalx, -} - -/// cbindgen:rename-all=None -pub struct ChewingContext { - pub(crate) kb_compat: KeyboardLayoutCompat, - pub(crate) keyboard: AnyKeyboardLayout, - pub(crate) editor: Editor, - pub(crate) kbcompat_iter: Option>>>, - pub(crate) cand_iter: Option>>>, - pub(crate) interval_iter: Option>>>, - pub(crate) userphrase_iter: Option>, - pub(crate) sel_keys: SelKeys, -} - -#[repr(C)] -pub(crate) struct SelKeys(pub(crate) [c_int; MAX_SELKEY]); diff --git a/src/conversion/mod.rs b/src/conversion/mod.rs index 330425413..2f6a11960 100644 --- a/src/conversion/mod.rs +++ b/src/conversion/mod.rs @@ -1,4 +1,4 @@ -//! TODO: docs +//! Algorithms to convert syllables to Chinese characters. mod chewing; mod symbol; diff --git a/src/dictionary/loader.rs b/src/dictionary/loader.rs index a7ed4601b..7556c864f 100644 --- a/src/dictionary/loader.rs +++ b/src/dictionary/loader.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + marker::PhantomData, + path::{Path, PathBuf}, +}; use crate::path::{find_path_by_files, sys_path_from_env_var, userphrase_path}; @@ -19,45 +22,33 @@ impl SystemDictionaryLoader { self.sys_path = Some(path.into()); self } - pub fn load(self) -> Option>> { + pub fn load(self) -> Result>, &'static str> { + let mut db_loaders: Vec> = vec![]; + #[cfg(feature = "sqlite")] + { + db_loaders.push(LoaderWrapper::::new()); + } + db_loaders.push(LoaderWrapper::::new()); + let search_path = if let Some(sys_path) = self.sys_path { sys_path } else { sys_path_from_env_var() }; - let sys_path = find_path_by_files(&search_path, &["tsi.dat", "word.dat"])?; + let sys_path = find_path_by_files(&search_path, &["tsi.dat", "word.dat"]) + .ok_or("SystemDictionaryNotFound")?; - let mut tsi_db_path = sys_path.clone(); - tsi_db_path.push("tsi.dat"); - let mut tsi_db = None; - #[cfg(feature = "sqlite")] - { - tsi_db = SqliteDictionary::open_read_only(&tsi_db_path) - .map(|db| Box::new(db) as Box) - .ok(); - } - if tsi_db.is_none() { - tsi_db = TrieDictionary::open(&tsi_db_path) - .map(|db| Box::new(db) as Box) - .ok(); - } + let tsi_db_path = sys_path.join("tsi.dat"); + let tsi_db = db_loaders + .iter() + .find_map(|loader| loader.open_read_only(&tsi_db_path)); - let mut word_db_path = sys_path; - word_db_path.push("word.dat"); - let mut word_db = None; - #[cfg(feature = "sqlite")] - { - word_db = SqliteDictionary::open_read_only(&word_db_path) - .map(|db| Box::new(db) as Box) - .ok(); - } - if word_db.is_none() { - word_db = TrieDictionary::open(&word_db_path) - .map(|db| Box::new(db) as Box) - .ok(); - } + let word_db_path = sys_path.join("word.dat"); + let word_db = db_loaders + .iter() + .find_map(|loader| loader.open_read_only(&word_db_path)); - Some(vec![word_db.unwrap(), tsi_db.unwrap()]) + Ok(vec![word_db.unwrap(), tsi_db.unwrap()]) } } @@ -74,26 +65,79 @@ impl UserDictionaryLoader { self.data_path = Some(path.as_ref().to_path_buf()); self } - pub fn load(self) -> Option> { + pub fn load(self) -> Result, &'static str> { + let mut db_loaders: Vec> = vec![]; + #[cfg(feature = "sqlite")] + { + db_loaders.push(LoaderWrapper::::new()); + } + db_loaders.push(LoaderWrapper::::new()); + let data_path = if let Some(data_path) = self.data_path { data_path } else { - userphrase_path()? + userphrase_path().ok_or("UserDictionaryNotFound")? }; - let mut dict = None; - #[cfg(feature = "sqlite")] - { - dict = dbg!(SqliteDictionary::open(&data_path)) - .map(|db| Box::new(db) as Box) - .ok(); - } - if dict.is_none() { - dict = CdbDictionary::open(&data_path) - .map(|db| Box::new(db) as Box) - .ok(); - } + db_loaders + .iter() + .find_map(|loader| loader.open(&data_path)) + .ok_or("ErrorOpenUserDictionary") + } +} + +trait DictionaryLoader { + fn open(&self, path: &PathBuf) -> Option>; + fn open_read_only(&self, path: &PathBuf) -> Option>; +} + +struct LoaderWrapper { + _marker: PhantomData, +} + +impl LoaderWrapper { + fn new() -> Box> { + Box::new(LoaderWrapper { + _marker: PhantomData, + }) + } +} + +#[cfg(feature = "sqlite")] +impl DictionaryLoader for LoaderWrapper { + fn open(&self, path: &PathBuf) -> Option> { + SqliteDictionary::open(path) + .map(|dict| Box::new(dict) as Box) + .ok() + } + + fn open_read_only(&self, path: &PathBuf) -> Option> { + SqliteDictionary::open_read_only(path) + .map(|dict| Box::new(dict) as Box) + .ok() + } +} + +impl DictionaryLoader for LoaderWrapper { + fn open(&self, path: &PathBuf) -> Option> { + TrieDictionary::open(path) + .map(|dict| Box::new(dict) as Box) + .ok() + } + + fn open_read_only(&self, path: &PathBuf) -> Option> { + self.open(path) + } +} + +impl DictionaryLoader for LoaderWrapper { + fn open(&self, path: &PathBuf) -> Option> { + CdbDictionary::open(path) + .map(|dict| Box::new(dict) as Box) + .ok() + } - dict + fn open_read_only(&self, path: &PathBuf) -> Option> { + self.open(path) } } diff --git a/src/dictionary/mod.rs b/src/dictionary/mod.rs index 16cec8789..d260c7698 100644 --- a/src/dictionary/mod.rs +++ b/src/dictionary/mod.rs @@ -1,4 +1,4 @@ -//! Dictionaries for looking up phrases. +//! Systems and user phrase dictionaries. use std::{ any::Any, diff --git a/src/editor/composition_editor.rs b/src/editor/composition_editor.rs index 315d13261..b3d192e6f 100644 --- a/src/editor/composition_editor.rs +++ b/src/editor/composition_editor.rs @@ -6,7 +6,7 @@ use crate::conversion::{Break, Composition, Glue, Interval, Symbol}; /// TODO #[derive(Debug, Default, Clone)] -pub struct CompositionEditor { +pub(crate) struct CompositionEditor { /// TODO cursor: usize, cursor_stack: Vec, diff --git a/src/editor/mod.rs b/src/editor/mod.rs index e4c855686..d1aab6403 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,7 +1,7 @@ -//! TODO: doc +//! Abstract input method editors. mod abbrev; -pub mod composition_editor; +mod composition_editor; mod estimate; pub mod keyboard; mod selection; @@ -13,14 +13,14 @@ use std::{ }; pub use estimate::{EstimateError, LaxUserFreqEstimate, UserFreqEstimate}; -pub use syllable::SyllableEditor; use tracing::{debug, trace, warn}; use crate::{ conversion::{ - full_width_symbol_input, special_symbol_input, ConversionEngine, Interval, Symbol, + full_width_symbol_input, special_symbol_input, ChewingEngine, ConversionEngine, Interval, + Symbol, }, - dictionary::{Dictionary, LayeredDictionary}, + dictionary::{Dictionary, LayeredDictionary, SystemDictionaryLoader, UserDictionaryLoader}, editor::keyboard::KeyCode, zhuyin::{Syllable, SyllableSlice}, }; @@ -33,7 +33,7 @@ use self::{ phrase::PhraseSelector, symbol::{SpecialSymbolSelector, SymbolSelector}, }, - syllable::{KeyBehavior, Standard}, + syllable::{KeyBehavior, Standard, SyllableEditor}, }; #[derive(Debug, Clone, Copy)] @@ -107,10 +107,7 @@ pub enum EditorKeyBehavior { } #[derive(Debug)] -pub struct Editor -where - C: ConversionEngine, -{ +pub struct Editor { com: CompositionEditor, syl: Box, conv: C, @@ -126,6 +123,18 @@ where notice_buffer: String, } +impl Editor { + pub fn chewing() -> Result, Box> { + let system_dict = SystemDictionaryLoader::new().load()?; + let user_dict = UserDictionaryLoader::new().load()?; + let estimate = LaxUserFreqEstimate::open(user_dict.as_ref())?; + let dict = LayeredDictionary::new(system_dict, user_dict); + let conversion_engine = ChewingEngine::new(); + let editor = Editor::new(conversion_engine, dict, estimate); + Ok(editor) + } +} + impl Editor where C: ConversionEngine, diff --git a/src/lib.rs b/src/lib.rs index 5bd60478f..7982f9c90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![deny(elided_lifetimes_in_paths)] #![deny(macro_use_extern_crate)] #![deny(missing_abi)] -// #![warn(missing_debug_implementations)] +#![warn(missing_debug_implementations)] // #![deny(missing_docs)] #![warn(noop_method_call)] #![warn(single_use_lifetimes)] @@ -12,14 +12,40 @@ #![warn(unused_macro_rules)] #![warn(unused_qualifications)] #![warn(unused_tuple_struct_fields)] -// #![warn(variant_size_differences)] +#![warn(variant_size_differences)] -//! TODO: docs +//! The Chewing (酷音) intelligent phonetic input method library. //! -//! # Glossary +//! This crate provides the core algorithms and facilities that can be used to +//! implement input methods and manipulate user dictionaries. //! -//! 1. **Phonetic Key** - +//! # Behavior +//! +//! The [Editor][editor::Editor] implements the behavior of the Chewing input +//! method. Chewing is a bopomofo phonetics input method that can convert +//! keystrokes to Zhuyin/Bopomofo and then to Chinese characters. The state +//! machine powering the input method can detect the current input context and +//! translate the input to symbols, latin characters, or Chinese characters. The +//! Editor also has an option that is enabled by default to auto-learn new +//! phrases from users' input to provide more personalized intelligence. +//! +//! ```rust,no_run +//! # fn main() -> Result<(), Box> { +//! use chewing::editor::{BasicEditor, Editor}; +//! use chewing::editor::keyboard::{KeyboardLayout, KeyCode, Qwerty}; +//! +//! let keyboard = Qwerty; +//! let mut editor = Editor::chewing()?; +//! +//! editor.process_keyevent(keyboard.map(KeyCode::D)); +//! editor.process_keyevent(keyboard.map(KeyCode::J)); +//! editor.process_keyevent(keyboard.map(KeyCode::N4)); +//! editor.process_keyevent(keyboard.map(KeyCode::Down)); +//! editor.process_keyevent(keyboard.map(KeyCode::N3)); +//! +//! assert_eq!("酷", editor.display()); +//! # Ok(()) } +//! ``` #[cfg(feature = "capi")] pub mod capi; pub mod conversion; diff --git a/src/zhuyin/mod.rs b/src/zhuyin/mod.rs index b2bfa5b36..e00d38701 100644 --- a/src/zhuyin/mod.rs +++ b/src/zhuyin/mod.rs @@ -1,4 +1,4 @@ -//! TODO: docs +//! Chinese syllables and bopomofo phonetic symbols. mod bopomofo; mod syllable;