Skip to main content

plat/
ime.rs

1//! Bounded preedit snapshots. Composition is separate from committed E_TEXT events.
2use alloc::{string::String, vec::Vec};
3use rt::sync::SpinLock;
4#[derive(Clone, Default, PartialEq, Eq)]
5pub struct Preedit { pub text: String, pub cursor: usize }
6static PREEDIT: SpinLock<Vec<(u8,Preedit)>> = SpinLock::new(Vec::new());
7static COMMITS: SpinLock<(u32,Vec<(u32,String)>)> = SpinLock::new((0,Vec::new()));
8/// One composition commit is one event, avoiding truncation by the character ring.
9pub fn ime_commit_set(win:u8,text:&str) -> bool {
10    if win as usize>=crate::PW_MAX || text.len()>4096 { return false; }
11    if text.is_empty() { return true; }
12    let mut q=COMMITS.lock();
13    // Keep already queued input intact when the bounded payload queue is full.
14    if q.1.len()>=16 { return false; }
15    q.0=q.0.wrapping_add(1); let token=q.0;
16    q.1.push((token,String::from(text)));
17    if crate::evq_push(crate::Event {typ:crate::E_IME_COMMIT,win,data:token,..Default::default()}) { true }
18    else { q.1.pop(); false }
19}
20/// Committed text of any length: commits of at most 4096 bytes, split between characters ->
21/// the bytes queued (fewer: the commit queue or the event ring is full, the rest can follow
22/// once the app took these).
23pub fn ime_commit_text(win:u8,text:&str) -> usize {
24    let mut at=0;
25    while at<text.len() {
26        let mut end=(at+4096).min(text.len());
27        while !text.is_char_boundary(end) { end-=1; }
28        if !ime_commit_set(win,&text[at..end]) { break; }
29        at=end;
30    }
31    at
32}
33pub fn ime_commit_take(token:u32) -> Option<String> {
34    let mut q=COMMITS.lock(); let i=q.1.iter().position(|v|v.0==token)?; Some(q.1.remove(i).1)
35}
36pub fn ime_preedit(win: u8) -> Preedit { PREEDIT.lock().iter().find(|v| v.0==win).map_or_else(Default::default,|v| v.1.clone()) }
37/// Publish valid UTF-8 and a byte caret; invalid/oversized updates clear composition.
38pub fn ime_preedit_set(win: u8, text: &str, cursor: usize) {
39    if win as usize >= crate::PW_MAX { return; }
40    let value=if text.len()<=4096 && text.is_char_boundary(cursor.min(text.len())) { Preedit { text:String::from(text),cursor:cursor.min(text.len()) } } else { Preedit::default() };
41    let mut slots=PREEDIT.lock();
42    if let Some(slot)=slots.iter_mut().find(|v| v.0==win) { slot.1=value; } else { slots.push((win,value)); }
43    drop(slots);
44    crate::evq_push(crate::Event { typ:crate::E_PREEDIT,win,..Default::default() });
45}