From ebed7a4f576139585ded333e0e4479d10be34153 Mon Sep 17 00:00:00 2001 From: "Andy D.K Lee" Date: Sat, 1 Aug 2026 02:59:24 +0900 Subject: [PATCH] Improve macOS shortcuts and sound controls for v0.3.3 --- CHANGELOG.md | 11 ++++++- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 ++-- src/config/settings.rs | 6 ++-- src/input/events.rs | 7 +++-- src/main.rs | 7 ----- src/renderer/terminal.rs | 65 ++++++++++++++++++++++++++++++++++------ 8 files changed, 79 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e07ed2..9e0babf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and Termleaf uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [0.3.3] - 2026-08-01 + +### Changed + +- Consolidated typing-sound controls in the F10 panel, renamed the master + toggle to "Typing sound," reassigned F5 to the macOS-safe page-width toggle, + and made the footer shortcuts adapt to narrow terminals. + ## [0.3.2] - 2026-08-01 ### Fixed @@ -99,7 +107,8 @@ and Termleaf uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Made forward Delete work for characters and line boundaries. - Made Save As reliable through `F12`, including a Markdown default extension. -[Unreleased]: https://github.com/andy5090/termleaf/compare/v0.3.2...HEAD +[Unreleased]: https://github.com/andy5090/termleaf/compare/v0.3.3...HEAD +[0.3.3]: https://github.com/andy5090/termleaf/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/andy5090/termleaf/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/andy5090/termleaf/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/andy5090/termleaf/compare/v0.2.4...v0.3.0 diff --git a/Cargo.lock b/Cargo.lock index 43f4774..9e44969 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,7 +729,7 @@ dependencies = [ [[package]] name = "termleaf" -version = "0.3.2" +version = "0.3.3" dependencies = [ "crossterm", "rodio", diff --git a/Cargo.toml b/Cargo.toml index 4c9a5fb..92d9894 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "termleaf" -version = "0.3.2" +version = "0.3.3" edition = "2021" description = "A distraction-free terminal text editor built for focused writing." repository = "https://github.com/andy5090/termleaf" diff --git a/README.md b/README.md index 249dccc..1f69b9d 100644 --- a/README.md +++ b/README.md @@ -138,13 +138,13 @@ release artifacts. | `F2` | toggle Termleaf's optional `Live Korean` composer | | `F3` | toggle focus mode | | `F4` | toggle the big-font zone | -| `F5` | toggle system-audio keystroke sound | +| `F5` | toggle the centered page-width (paper) mode | | `F6` | cycle `paper` / `night` / `xt` / `amber` theme | | `F7` / `F8` | decrease / increase big-font size across five effective levels | | `Alt+L` | cycle document line spacing through levels 1–3 | -| `Alt+P` | toggle the centered 80-column page-width mode | +| `Alt+P` | alternate page-width shortcut where the terminal preserves Alt | | `F9` | toggle English / Korean interface guidance | -| `F10` | open detailed sound settings (master / delete / return / key style) | +| `F10` | open sound settings (typing / delete / return / key style) | | `F11` | cycle `classic` / `deep` / `soft` typewriter sound | | `Ctrl+O` | open a file (a missing path starts a new file there) | | `Ctrl+S` | save; the first save asks for a filename | diff --git a/src/config/settings.rs b/src/config/settings.rs index 2b4ff6a..dc67d10 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -19,11 +19,11 @@ pub struct Config { pub live_composition: bool, /// Focus mode hides the status bar and other chrome. pub focus_mode: bool, - /// Play mechanical key and backspace effects. + /// Enable typing sound effects and their optional delete/return sounds. pub sound: bool, - /// Play the separate backspace effect when master sound is enabled. + /// Play the separate backspace effect when typing sound is enabled. pub backspace_sound: bool, - /// Play the carriage-return bell when master sound is enabled. + /// Play the carriage-return bell when typing sound is enabled. pub return_sound: bool, /// Selected printing-key sound (`classic`, `deep`, or `soft`). pub sound_profile: String, diff --git a/src/input/events.rs b/src/input/events.rs index e8a473d..a7e9b36 100644 --- a/src/input/events.rs +++ b/src/input/events.rs @@ -24,7 +24,6 @@ pub enum Action { ShowHelp, ToggleFocus, ToggleBigFont, - ToggleSound, ToggleTheme, ToggleLanguage, ShowSoundSettings, @@ -67,7 +66,7 @@ pub fn map_key(key: KeyEvent, live_composition: bool) -> Action { KeyCode::F(2) => Action::ToggleLiveComposition, KeyCode::F(3) => Action::ToggleFocus, KeyCode::F(4) => Action::ToggleBigFont, - KeyCode::F(5) => Action::ToggleSound, + KeyCode::F(5) => Action::TogglePageWidth, KeyCode::F(6) => Action::ToggleTheme, KeyCode::F(7) => Action::FontDec, KeyCode::F(8) => Action::FontInc, @@ -145,6 +144,10 @@ mod tests { map_key(KeyEvent::new(KeyCode::F(10), KeyModifiers::NONE), false), Action::ShowSoundSettings ); + assert_eq!( + map_key(KeyEvent::new(KeyCode::F(5), KeyModifiers::NONE), false), + Action::TogglePageWidth + ); assert_eq!( map_key(KeyEvent::new(KeyCode::F(11), KeyModifiers::NONE), false), Action::CycleSoundProfile diff --git a/src/main.rs b/src/main.rs index d38282f..afed83b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -219,12 +219,6 @@ fn apply( } Action::ToggleFocus => cfg.focus_mode = !cfg.focus_mode, Action::ToggleBigFont => cfg.big_font = !cfg.big_font, - Action::ToggleSound => { - cfg.sound = !cfg.sound; - if cfg.sound { - sound.play_key(&cfg.sound_profile); - } - } Action::ToggleTheme => { cfg.theme = Theme::next(&cfg.theme).to_string(); *theme = Theme::by_name(&cfg.theme); @@ -280,7 +274,6 @@ fn handle_sound_settings_key( match key.code { KeyCode::Up => active.select_previous(), KeyCode::Down => active.select_next(), - KeyCode::F(5) => toggle_sound_option(cfg, sound, 0, true), KeyCode::F(11) => toggle_sound_option(cfg, sound, 3, true), KeyCode::Char(' ') | KeyCode::Right => { toggle_sound_option(cfg, sound, active.selected, true); diff --git a/src/renderer/terminal.rs b/src/renderer/terminal.rs index 7c25743..5c6c2d6 100644 --- a/src/renderer/terminal.rs +++ b/src/renderer/terminal.rs @@ -216,14 +216,14 @@ fn draw_sound_settings( }; let lines = if korean { [ - format!("[{}] 전체 소리 (F5)", enabled(cfg.sound)), + format!("[{}] 타이핑 소리", enabled(cfg.sound)), format!("[{}] 삭제 소리", enabled(cfg.backspace_sound)), format!("[{}] 캐리지 리턴 소리", enabled(cfg.return_sound)), format!("[{}] 타자기 종류 (F11)", cfg.sound_profile), ] } else { [ - format!("[{}] Master sound (F5)", enabled(cfg.sound)), + format!("[{}] Typing sound", enabled(cfg.sound)), format!("[{}] Delete sound", enabled(cfg.backspace_sound)), format!("[{}] Carriage-return sound", enabled(cfg.return_sound)), format!("[{}] Key style (F11)", cfg.sound_profile), @@ -397,8 +397,8 @@ fn draw_help( "", "파일: Ctrl+O 열기 · Ctrl+S 저장 · F12 다른 이름 (.md 기본)", "화면: F3 집중 · F4 큰글자 · F6 테마 · F7/F8 크기 1–5", - "보기: Alt+L 줄간격 1–3 · Alt+P 페이지 폭", - "소리: F5 전체 · F10 세부 설정(삭제/엔터) · F11 타자음", + "보기: Alt+L 줄간격 1–3 · F5 종이 폭 (Alt+P 보조)", + "소리: F10 설정(타이핑/삭제/엔터) · F11 타자음", "기타: Backspace/Delete 삭제 · F9 English · F1 도움말 · Ctrl+Q 종료", ] } else { @@ -409,8 +409,8 @@ fn draw_help( "", "Files: Ctrl+O Open · Ctrl+S Save · F12 Save as (.md default)", "View: F3 Focus · F4 Big text · F6 Theme · F7/F8 Size 1–5", - "Reading: Alt+L Line spacing 1–3 · Alt+P Page width", - "Sound: F5 Master · F10 Details (delete/return) · F11 Key style", + "Reading: Alt+L Line spacing 1–3 · F5 Page width (Alt+P alternate)", + "Sound: F10 Settings (typing/delete/return) · F11 Key style", "Other: Backspace/Delete · F9 Korean · F1 Help · Ctrl+Q Quit", ] }; @@ -925,10 +925,8 @@ fn draw_shortcuts( " Enter 저장 Esc 취소 │ 확장자 생략 시 .md F9 영어 ".to_string() } else if prompt.is_some() { " Enter Save Esc Cancel │ No extension → .md F9 Korean ".to_string() - } else if korean { - " F1 도움 ^O 열기 ^S 저장 F12 다른이름 ^Q 종료 │ Alt+L 줄간격 Alt+P 페이지폭 F2 한글 F3 집중 F4 큰글자 F5 소리 F6 테마 F7/8 크기 F9 영어 F10 소리설정 ".to_string() } else { - " F1 Help ^O Open ^S Save F12 Save-as ^Q Quit │ Alt+L Line spacing Alt+P Page width F2 Korean F3 Focus F4 Big F5 Sound F6 Theme F7/8 Size F9 한국어 F10 Sound setup ".to_string() + shortcut_guide(korean, cols).to_string() }; let bar: String = " ".repeat(cols as usize); queue!( @@ -942,6 +940,35 @@ fn draw_shortcuts( ) } +fn shortcut_guide(korean: bool, cols: u16) -> &'static str { + let choices = if korean { + [ + " F1 도움 F5 종이폭 F10 소리설정 ^O 열기 ^S 저장 F12 다른이름 ^Q 종료 │ Alt+L 줄간격 F2 한글 F3 집중 F4 큰글자 F6 테마 F7/8 크기 F9 영어 ", + " F1 도움 F5 종이폭 F10 소리설정 ^O 열기 ^S 저장 ^Q 종료 │ F3 집중 F6 테마 F7/8 크기 ", + " F1 도움 F5 종이폭 F10 소리설정 ^S 저장 ^Q 종료 ", + " F1 도움 F5 종이 F10 소리 ", + " F5 종이 F10 소리 ", + ] + } else { + [ + " F1 Help F5 Page width F10 Sound setup ^O Open ^S Save F12 Save-as ^Q Quit │ Alt+L Line spacing F2 Korean F3 Focus F4 Big F6 Theme F7/8 Size F9 한국어 ", + " F1 Help F5 Page F10 Sound ^O Open ^S Save ^Q Quit │ F3 Focus F6 Theme F7/8 Size ", + " F1 Help F5 Page F10 Sound ^S Save ^Q Quit ", + " F1 Help F5 Page F10 Sound ", + " F5 Page F10 Sound ", + ] + }; + + choices + .into_iter() + .find(|text| text_width(text) <= cols) + .unwrap_or(choices[4]) +} + +fn text_width(text: &str) -> u16 { + text.chars().map(char_width).sum() +} + fn draw_file_prompt( out: &mut Stdout, prompt: &FilePrompt, @@ -1022,6 +1049,26 @@ fn clipped_from_end(text: &str, max_width: u16) -> String { mod tests { use super::*; + #[test] + fn shortcut_guide_adapts_to_terminal_width_without_hiding_sound_settings() { + for korean in [false, true] { + for width in [24, 40, 80, 180] { + let guide = shortcut_guide(korean, width); + assert!(text_width(guide) <= width); + assert!(guide.contains("F5")); + assert!(guide.contains("F10")); + if width >= 40 { + assert!(guide.contains("F1")); + } + } + } + + assert!(!shortcut_guide(false, 40).contains("Alt+L")); + assert!(shortcut_guide(false, 180).contains("Alt+L")); + assert!(!shortcut_guide(true, 40).contains("Alt+L")); + assert!(shortcut_guide(true, 180).contains("Alt+L")); + } + #[test] fn five_font_levels_remain_distinct_on_a_standard_height() { let profiles: Vec<(u16, u16)> = (1..=5)