Add Morse code output mode with Vietnamese support - #341
Conversation
Implement ITU standard Morse code encoding with Vietnamese extensions to convert Vietnamese text to Morse code on space press. - New morse.rs module with encode() function supporting ITU standard characters and Vietnamese tone marks - Engine morse_mode flag with setter in mod.rs - FFI function ime_morse_mode() in lib.rs for platform integration - macOS implementation: MenuBar checkbox, AppState property, Swift FFI - Fallback to normal text if Morse output exceeds buffer capacity - Integrates with shortcut and auto-restore features
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 365b330dfe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| self.word_history.push(self.buf.clone()); | ||
| self.spaces_after_commit = 1; |
There was a problem hiding this comment.
Avoid storing plain-word history in Morse mode
Committing a word in Morse mode currently pushes the original Vietnamese buffer into word_history and marks one committed space, so the backspace-after-space flow later restores/edit that plain word while the on-screen text is Morse. In practice, after typing a Morse word and pressing backspace once, subsequent edits/backspaces operate on mismatched internal/external text and can produce incorrect replacements. Morse commits should not reuse normal word-history restore semantics unless the stored history matches the emitted Morse text.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR adds a "Morse code output mode" as a fun/experimental feature to the Vietnamese IME. When enabled, typed words are converted to Morse code (using Unicode · and — characters) when the user presses Space. Vietnamese diacritics are decomposed into base character + modifier prosign + tone prosign. The feature is accessible via the menu bar and persisted in UserDefaults.
Changes:
- New
core/src/engine/morse.rsmodule implementing Vietnamese-aware Morse encoding - Morse mode flag added to the engine (
Enginestruct, FFI, and Swift bridge) - macOS menu bar and app state wired to expose and persist the setting
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
core/src/engine/morse.rs |
New module: Vietnamese Morse encoding with ITU standard + custom prosigns for diacritics |
core/src/engine/mod.rs |
morse_mode field added to Engine, set_morse_mode() method, Morse conversion on Space key |
core/src/lib.rs |
ime_morse_mode FFI function + three new integration tests |
platforms/macos/RustBridge.swift |
FFI declaration + setMorseMode(_:) Swift wrapper |
platforms/macos/AppMetadata.swift |
SettingsKey.morseMode constant added |
platforms/macos/MainSettingsView.swift |
morseMode @Published property with persistence and engine sync |
platforms/macos/MenuBar.swift |
Menu item "Chế độ Morse" (tag 12) + toggleMorse() action |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| menu.item(withTag: 10)?.state = appState.currentMethod == .telex ? .on : .off | ||
| menu.item(withTag: 11)?.state = appState.currentMethod == .vni ? .on : .off | ||
| menu.item(withTag: 12)?.state = appState.morseMode ? .on : .off |
There was a problem hiding this comment.
The setupNotifications() method subscribes to appState.$isEnabled and appState.$currentMethod to trigger updateMenu(). However, appState.$morseMode is not included in this subscription chain. As a result, the Morse code menu item checkmark (tag 12) will not update when morseMode is changed from the Settings UI. The checkmark will remain stale until isEnabled or currentMethod changes.
The fix is to add appState.$morseMode to the combineLatest chain (or as a separate subscription) so that updateMenu() is also called when morseMode changes.
| #[test] | ||
| fn test_encode_vietnamese_with_tone() { | ||
| let result: String = encode("á").into_iter().collect(); | ||
| // á = A (.-) + space + sắc (.-.-.) |
There was a problem hiding this comment.
The inline comment says // á = A (.-) + space + sắc (.-.-.), but the actual sắc Morse prosign defined in tone_mark_morse is ".--.-." (6 elements), not .-.-. (the ITU Morse code for a period/full stop). The comment is misleading.
| // á = A (.-) + space + sắc (.-.-.) | |
| // á = A (.-) + space + sắc (.--.-.) |
| } | ||
|
|
||
| @objc private func toggleMorse() { | ||
| appState.morseMode.toggle() |
There was a problem hiding this comment.
The startEngine() function syncs individual engine settings after calling RustBridge.initialize(), but it does not call RustBridge.setMorseMode(appState.morseMode). Since AppState.init() calls syncAllToEngine() before the engine is initialized (i.e., before ime_init() is called), the Morse mode setting is set as a no-op. startEngine() is the correct place to set this value, just like other settings. As a result, if the user had Morse mode enabled in a previous session, the Rust engine will always start with Morse mode disabled and the menu item's state on first open will be inconsistent with the actual engine state.
| appState.morseMode.toggle() | |
| appState.morseMode.toggle() | |
| appState.syncAllToEngine() |
Mô tả
Thêm tính năng vui vẻ hơn.
1 đoạn convert từ chữ thường sang mã Morse.
Loại thay đổi