feat: auto-capitalize sentences after punctuation (#554)

* feat: auto-capitalize sentences after punctuation

Add capitalize_sentences() function that uppercases the first letter of
dictated text and after sentence-ending punctuation (., !, ?) followed by
whitespace. Preserves URLs, decimals, and abbreviations without trailing space.

- Config option text_injection.auto_capitalize (default: true)
- Settings toggle in General tab to opt out
- 17 tests covering edge cases

Fixes #553

* style: black-format auto-capitalize helpers for CI lint

Fixes the Lint Python check failure on the auto-capitalize PR.

* refactor: make auto-capitalize Vosk-only with clear UI indication

- Gate auto-capitalize feature to Vosk engine only (Whisper outputs proper casing)
- Update settings tooltip to explain Vosk-only behavior
- Update subtitle to show '(Vosk only)' for user clarity

* test(main): cover Vosk-only auto-capitalize injection path

Add callback wiring tests for enabled/disabled auto-capitalize on Vosk
and the Whisper skip path so codecov patch coverage clears the 80% bar.

Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com>

* refactor(settings): move Auto-Capitalize to Recognition tab

Auto-capitalize is dictation output post-processing, not application
lifecycle behavior, so it belongs alongside Voice Commands rather than
with autostart/clipboard settings in General.

Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Jatin K Malik <jatinkrmalik@users.noreply.github.com>
This commit is contained in:
Jatin K Malik
2026-07-29 01:39:15 +05:30
committed by GitHub
co-authored by Jatin K Malik Cursor Agent
parent 8c76578200
commit 7422bf927e
6 changed files with 320 additions and 0 deletions
@@ -304,3 +304,31 @@ class CommandProcessor:
processed_text = ""
return processed_text, actions
def capitalize_sentences(text: str) -> str:
"""Capitalize the first letter of each sentence.
Uppercases the first character of the string and any lowercase letter
that follows sentence-ending punctuation (``.``, ``!``, ``?``) plus
whitespace. Leaves URLs, decimals, and abbreviations without trailing
space untouched.
Args:
text: The text to capitalize.
Returns:
The text with sentence-initial letters uppercased.
"""
if not text:
return text
# Capitalize first character
result = text[0].upper() + text[1:]
# Capitalize after sentence-ending punctuation + whitespace
result = re.sub(
r"([.!?])(\s+)([a-z])", lambda m: m.group(1) + m.group(2) + m.group(3).upper(), result
)
return result