Skip to content

fix: auto-uppercase SQL keywords crash on space key (#667)#669

Merged
datlechin merged 1 commit intomainfrom
fix/auto-uppercase-crash
Apr 11, 2026
Merged

fix: auto-uppercase SQL keywords crash on space key (#667)#669
datlechin merged 1 commit intomainfrom
fix/auto-uppercase-crash

Conversation

@datlechin
Copy link
Copy Markdown
Collaborator

Summary

Fix crash when typing space after lowercase SQL keyword with "Auto-uppercase keywords" enabled.

Closes #667

Root Cause

uppercaseKeywordIfNeeded was called inside the didReplaceContentsIn delegate callback, which fires between textStorage.beginEditing() and endEditing(). Any text mutation inside this callback causes a re-entrant NSTextStorage crash.

First fix attempt using textView.replaceCharacters (public API) also crashed because CEUndoManager.registerMutation calls inverseMutation which asserts during the deferred edit.

Fix

Defer the uppercase mutation to DispatchQueue.main.async (runs after endEditing completes), then mutate textStorage directly with NSAttributedString (preserves typingAttributes for correct font/color). Skips CEUndoManager since auto-formatting is not a user edit.

Validates range and word content after deferral to handle IME composition and concurrent edits safely.

Additional Fixes

  • Extract pure logic into KeywordUppercaseHelper (testable, reusable)
  • Add PostgreSQL $$ dollar-quoting detection in protected context scanner
  • Add MySQL # line comment detection in protected context scanner
  • Remove duplicate DEFAULT and IF entries in SQLKeywords

Test Coverage (46 tests)

  • isWordBoundary: 9 tests (all delimiter types + negative cases)
  • isWordCharacter: 5 tests (letters, digits, underscore, special chars)
  • isInsideProtectedContext: 14 tests (quotes, comments, dollar-quoting, escapes, edge cases)
  • keywordBeforePosition: 18 tests (keyword detection, protected contexts, identifiers, all major SQL keywords)

Test plan

  • Type select with auto-uppercase enabled: no crash, uppercased to SELECT
  • Type SELECT : no change (already uppercase)
  • Type 'select : NOT uppercased (inside string)
  • Type -- select : NOT uppercased (inside comment)
  • Type $$ select : NOT uppercased (inside dollar-quote)
  • Type # select : NOT uppercased (inside hash comment)
  • Type select_count : NOT uppercased (identifier, not keyword)
  • Cmd+Z after uppercase: undoes the space only (uppercase stays, by design)
  • Multi-cursor: type keyword at 3 cursors, all uppercase

Root cause: uppercaseKeywordIfNeeded called textStorage.replaceCharacters
inside the didReplaceContentsIn delegate callback (mid beginEditing/endEditing),
causing re-entrant NSTextStorage mutation crash. Second attempt using
textView.replaceCharacters crashed in CEUndoManager.inverseMutation.

Fix: defer mutation to DispatchQueue.main.async with direct textStorage
manipulation using NSAttributedString (preserves typingAttributes).
Validates range and word content after deferral for IME safety.

Also:
- Extract pure logic into KeywordUppercaseHelper for testability
- Add $$ dollar-quoting detection (PostgreSQL)
- Add # line comment detection (MySQL)
- Remove duplicate DEFAULT and IF from SQLKeywords
- Add 46 unit tests covering all edge cases
@datlechin datlechin merged commit d1b8842 into main Apr 11, 2026
2 checks passed
@datlechin datlechin deleted the fix/auto-uppercase-crash branch April 11, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash Report: Application crashes when inputting whitespace after lowercase keywords input when enabling "Auto-uppercase keywords"

1 participant