Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Korean version: [CHANGELOG.md](CHANGELOG.md).

### Fixed

- Digits now supply their context to the following word, including after another word, so units such as `10cm` and `10fps` keep their Latin reading. Deleting an owned suffix preserves its numeric origin, while context changes and internal word splits prevent that origin from leaking to unrelated text.
- Explicit language corrections on unchanged input and context now learn against the reading actually shown. Hidden final scoring no longer prevents those corrections from being learned or treats a return to the original reading as a new correction. Existing scoring after editing a forced word and ordinary confirmation behavior are preserved.

## [0.10.10] - 2026-10-23
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ GitHub 릴리스 노트가 되고 대시보드의 업데이트 탭에도 그대

### 수정

- 다른 단어 뒤에 입력한 숫자를 포함해, 숫자 문맥이 바로 뒤 단어에 전달되도록 고쳐 `10cm`, `10fps` 같은 단위 입력이 라틴 표기를 유지합니다. 조합 중인 접미사를 지웠을 때는 숫자 문맥을 보존하고, 문맥 변경이나 내부 단어 분리 뒤에는 무관한 입력에 이어지지 않도록 했습니다.
- 입력 문자열과 문맥이 유지된 명시적 언어 교정은 실제로 화면에 보였던 언어를 기준으로 학습합니다. 확정용 재판별 때문에 교정을 학습하지 못하거나, 원래 표시로 돌아온 선택을 잘못 학습하던 문제를 고쳤습니다. 교정 후 입력을 편집한 경우의 판별과 일반 확정 동작은 유지합니다.

## [0.10.10] - 2026-10-23
Expand Down
3 changes: 3 additions & 0 deletions crates/core/src/session/japanese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl InputSession {
self.last_recorded = None;
self.ja.live_suppressed = false;
*self.word.keys_mut() = ch.to_string();
self.word_after_digit = false;
self.word.force(Language::Japanese, false);
self.update_preview(client);
}
Expand Down Expand Up @@ -552,6 +553,7 @@ impl InputSession {
converter.learn(&candidate, &conversion.kana);
}
client.insert_text(&candidate.text, None);
self.word_after_digit = false;
self.note_brackets(&candidate.text);
let rest: String = conversion.kana.chars().skip(candidate.kana_count).collect();
if rest.is_empty() {
Expand Down Expand Up @@ -790,6 +792,7 @@ impl InputSession {
let committed = self.committed_japanese();
client.insert_text(&committed, None);
*self.word.keys_mut() = back;
self.word_after_digit = false;
self.word.syllable_start = None;
self.previous_language = Some(Language::Japanese);
self.word.force(Language::Korean, false);
Expand Down
18 changes: 16 additions & 2 deletions crates/core/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ impl InputSession {

/// A new text field became active: pick its app's policy and forget the sentence context.
pub fn activate(&mut self, exe: Option<&str>) {
self.width.after_digit = false;
self.word_after_digit = false;
self.word.invalidate_correction_origin();
#[cfg(feature = "japanese")]
if let Some(converter) = &self.ja.converter {
Expand Down Expand Up @@ -409,6 +411,7 @@ impl InputSession {
if !eligible {
return self.handle(Key::Printable(' '), client);
}
self.width.after_digit = false;
self.close_flip_window();
if self.width.full_width_space && self.previous_language == Some(Language::Japanese) {
return false; // the app types the half-width " "
Expand All @@ -424,7 +427,9 @@ impl InputSession {
if key == Key::ShiftSpace {
return self.handle(Key::Printable(' '), client);
}
if !(matches!(key, Key::Printable(_)) && self.word.keys().is_empty()) {
if !(matches!(key, Key::Letter(_))
|| (matches!(key, Key::Printable(_)) && self.word.keys().is_empty()))
{
self.width.after_digit = false;
}
let pending = self.last_commit.take();
Expand Down Expand Up @@ -462,6 +467,7 @@ impl InputSession {
}

fn on_letter(&mut self, ch: char, client: &mut dyn TextClient) -> bool {
let after_digit = std::mem::take(&mut self.width.after_digit);
// A symbol on its own is confirmed by the next word, which is judged by itself.
#[cfg(feature = "japanese")]
if !self.word.keys().is_empty()
Expand All @@ -479,7 +485,7 @@ impl InputSession {
if self.korean_only {
self.word.force(Language::Korean, false);
}
self.word_after_digit = self.width.after_digit;
self.word_after_digit = after_digit;
#[cfg(feature = "japanese")]
{
self.ja.live_suppressed = false;
Expand Down Expand Up @@ -543,6 +549,8 @@ impl InputSession {
self.ja.added_n_marker = false;
}
if self.word.is_empty() {
// The owned suffix is gone, but its preceding digit is still in the app.
self.width.after_digit = std::mem::take(&mut self.word_after_digit);
self.word.reset();
}
self.update_preview(client);
Expand Down Expand Up @@ -632,6 +640,7 @@ impl InputSession {
self.word_before_digit = ch.is_ascii_digit();
let word = self.finish_word();
self.word_before_digit = false;
self.width.after_digit = ch.is_numeric();
// Only the word goes in; the app types the space or punctuation itself, as with
// the system's Korean input.
client.insert_text(&word.text, None);
Expand Down Expand Up @@ -704,6 +713,7 @@ impl InputSession {
};
let language = self.word.shown_language().unwrap_or(Language::English);
self.word.reset();
self.word_after_digit = false;
client.insert_text(&word, None);
if let Some(h) = &self.history {
h.record(&word);
Expand Down Expand Up @@ -737,6 +747,7 @@ impl InputSession {

/// Commits whatever is in progress as-is (focus change, shortcut, deactivation).
pub fn commit(&mut self, client: &mut dyn TextClient) {
self.width.after_digit = false;
self.close_flip_window();
#[cfg(feature = "japanese")]
if let Some(conversion) = self.ja.conversion.take() {
Expand All @@ -748,10 +759,12 @@ impl InputSession {
converter.learn(conversion.current(), &conversion.kana);
}
self.word.keys_mut().clear();
self.word_after_digit = false;
self.previous_language = Some(Language::Japanese);
return;
}
if self.word.is_empty() {
self.word_after_digit = false;
return;
}
let word = self.finish_word();
Expand Down Expand Up @@ -835,6 +848,7 @@ impl InputSession {
};
self.previous_language = Some(language.sentence_language());
self.word.reset();
self.word_after_digit = false;
#[cfg(feature = "japanese")]
{
self.ja.added_n_marker = false;
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/session/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ impl InputSession {
}
client.insert_text(&korean.text(), None);
*self.word.keys_mut() = back;
self.word_after_digit = false;
self.word.syllable_start = None;
self.previous_language = Some(Language::Korean);
self.word.forget_preview();
Expand Down
Loading
Loading