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}