fix: skip forced capitalization when the cursor context is unknown - #855
fix: skip forced capitalization when the cursor context is unknown#855abhiramasonny wants to merge 1 commit into
Conversation
Greptile SummaryThis PR distinguishes an empty field from unavailable cursor context so dictation formatting does not force capitalization or spacing when the focused app cannot expose its text state.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1423706309
ℹ️ 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".
| let spacingEnabled = SettingsStore.shared.continuousDictationSpacingEnabled | ||
| let smartCapsEnabled = SettingsStore.shared.contextAwareCapitalizationEnabled | ||
| guard spacingEnabled || smartCapsEnabled else { return text } | ||
| guard spacingEnabled || smartCapsEnabled, let precedingText else { return text } |
There was a problem hiding this comment.
Preserve trailing spacing without cursor context
When Space Between Dictations is enabled but the focused app does not expose readable cursor context, this guard returns before the spacing block because precedingText is nil. That removes the trailing separator the spacing setting is supposed to add, so repeated dictations in apps with unavailable AX context can concatenate text instead of chaining cleanly. Consider skipping only the context-dependent capitalization/leading-space behavior while still appending the trailing space when spacing is enabled.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Fixes Smart Capitalization incorrectly uppercasing the first dictated word when the app can’t read the focused field context (e.g., apps that don’t expose accessibility value/selection), by distinguishing “empty preceding text” from “unknown preceding text” and skipping context-based formatting when context is unavailable.
Changes:
- Change
TypingService.textBeforeCursorInFocusedField()to returnnil(instead of"") when the focused field context can’t be read. - Update Continuous Dictation formatting to skip spacing/capitalization adjustments when
precedingTextisnil. - Add an integration test covering the capitalization behavior difference between
precedingText == nilvsprecedingText == "".
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Tests/FluidDictationIntegrationTests/DictationE2ETests.swift | Adds coverage for precedingText == nil vs empty string behavior in continuous dictation formatting. |
| Sources/Fluid/Services/TypingService.swift | Returns nil when focused-field/cursor context can’t be captured, avoiding ambiguous empty-string results. |
| Sources/Fluid/Services/ASRService.swift | Makes continuous dictation formatting context-aware by bailing out when precedingText is unavailable. |
| Sources/Fluid/ContentView.swift | Plumbs optional preceding-text context through capture/storage and formatting calls. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| DebugLogger.shared.debug( | ||
| "Captured preceding text for continuous dictation (chars=\(self.recordingPrecedingText.count))", | ||
| "Captured preceding text for continuous dictation (chars=\(self.recordingPrecedingText?.count ?? -1))", | ||
| source: "ContentView" | ||
| ) |
| func testContinuousDictationFormattingSkipsCapitalizationWhenPrecedingTextUnknown() { | ||
| self.withRestoredDefaults(keys: [ | ||
| "ContinuousDictationSpacingEnabled", | ||
| "ContextAwareCapitalizationEnabled", | ||
| ]) { | ||
| UserDefaults.standard.set(false, forKey: "ContinuousDictationSpacingEnabled") | ||
| UserDefaults.standard.set(true, forKey: "ContextAwareCapitalizationEnabled") | ||
|
|
||
| XCTAssertEqual( | ||
| ASRService.applyContinuousDictationFormatting("and then i continued", precedingText: nil), | ||
| "and then i continued" | ||
| ) | ||
| XCTAssertEqual( | ||
| ASRService.applyContinuousDictationFormatting("and then i continued", precedingText: "i am speaking"), | ||
| "and then i continued" | ||
| ) | ||
| XCTAssertEqual( | ||
| ASRService.applyContinuousDictationFormatting("and then i continued", precedingText: ""), | ||
| "And then i continued" | ||
| ) | ||
| } | ||
| } |
Description
Smart capitalization was always uppercasing the first dictated word, even while in mid-sentence, bc TypingService.textBeforeCursorInFocusedField() returned "" both when there wasnt any text before the cursor and also when it couldn’t read the focused field at all, which is common in apps that don’t expose the AX value or selected range (example, Slack).
my PR changes the capture method to return nil when the preceding text can’t be read, and skips capitalization and spacing adjustments when that context is unavailable so the transcription is inserted as-is.
Type of Change
Related Issue or Discussion
Closes #840
Testing
swiftlint --strict --config .swiftlint.yml Sourcesswiftformat --config .swiftformat SourcesScreenshots / Video
Notes
pretty minimal update