rlvgl_core/plugins/pinyin.rs
1//! Minimal Pinyin input method dictionary.
2use alloc::vec::Vec;
3
4/// Simplified Pinyin input method that maps Latin pinyin syllables to Chinese
5/// characters. The dictionary here only covers a small subset of words used by
6/// the tests and is not exhaustive.
7pub struct PinyinInputMethod;
8
9/// Static mapping table derived from the reference LVGL implementation.
10const DICT: &[(&str, &str)] = &[
11 ("zhong", "中种終重種眾"),
12 ("guo", "果国裏菓國過"),
13 ("ai", "愛"),
14];
15
16impl PinyinInputMethod {
17 /// Look up candidate characters for a given pinyin syllable.
18 ///
19 /// The reference LVGL implementation returns matches even when the
20 /// provided input is only a prefix of the stored syllable. For example
21 /// typing `"zh"` will return the candidates for `"zhong"`.
22 pub fn candidates(&self, input: &str) -> Option<Vec<char>> {
23 if input.is_empty() {
24 return None;
25 }
26 // In LVGL the search routine ignores inputs starting with i/u/v or a
27 // space character. Mirror that behaviour for the limited dictionary
28 // here.
29 if matches!(input.chars().next(), Some('i' | 'u' | 'v' | ' ')) {
30 return None;
31 }
32
33 for &(py, chars) in DICT {
34 if py.starts_with(input) {
35 return Some(chars.chars().collect());
36 }
37 }
38 None
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn candidates_basic_and_prefix() {
48 let ime = PinyinInputMethod;
49 let result_full = ime.candidates("zhong").unwrap();
50 assert_eq!(result_full[0], '中');
51
52 // Partial input should behave the same as the C implementation and
53 // return the same candidate list.
54 let result_prefix = ime.candidates("zho").unwrap();
55 assert_eq!(result_prefix, result_full);
56
57 // Single letter input also resolves to the first matching entry.
58 let single = ime.candidates("g").unwrap();
59 assert_eq!(single[0], '果');
60 }
61
62 #[test]
63 fn unknown_returns_none() {
64 let ime = PinyinInputMethod;
65 assert!(ime.candidates("foobar").is_none());
66 }
67}