Reduce per-keystroke latency and fix marked-text range handling - #16
Merged
Conversation
getInputStrategy was re-deriving the strategy on every key event, and for apps not in the knownApps table this meant a synchronous validAttributesForMarkedText() round-trip to the client process per keystroke. Store the resolved strategy in a per-session bundleId cache so each app is probed at most once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
NSRange and setMarkedText operate on UTF-16 code units, but the cursor position and replacement range were computed with String.count, which counts grapheme clusters. For precomposed syllables the two match, but the NFD fallback path (old Hangul, araea) emits one grapheme spanning multiple UTF-16 units, misplacing the cursor and the backspace replacement range. Also drop the min(NSNotFound, ...) clamp, which never took effect. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
The composedKey cache was updated manually in a few mutating helpers, but composingKeys is a public var: direct assignment (HangulProcessor's composing/preedit setters) and the convenience inits bypassed the manual updates, leaving the cache stale or empty and silently breaking compound vowel/final-consonant matching. Recompute the cache in didSet and delegate the convenience inits to the designated init so every mutation path stays consistent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
symbolExtensionConfig was a computed property that allocated a fresh config (two Sets plus the struct) on every access, and it is consulted on every keystroke while composing when the trait is enabled. Build the config once as a static constant and return it conditionally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
inputText resolved the same key code through KeyCodeMapper twice: once inside verifyProcessable and again in processKeyCodeInput. Compute the mapping once in inputText, pass it into verifyProcessable, and drop the now-unused processKeyCodeInput helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Swift 6 기준 성능 검토에서 발견된 항목을 우선순위 순서대로 커밋 5개에 나눠 반영했습니다. 메모리 누수는 발견되지 않았고, 레이턴시·정확성 관련 항목만 수정했습니다.
변경 내용 (커밋 순서대로)
getInputStrategy가 매 키 이벤트마다 전략을 재판정했고,knownApps에 없는 앱은 키 입력마다validAttributesForMarkedText()동기 IPC 왕복이 발생했습니다. bundleId별 캐시를 추가해 앱당 1회로 제한합니다. 키당 레이턴시 개선 폭이 가장 큰 변경입니다.String.count(자소 수)로 계산하고 있었습니다. 완성형 한글은 1:1이지만 NFD 폴백(옛한글·아래아)은 자소 1개가 UTF-16 여러 유닛이라 커서/범위가 어긋납니다.utf16.count로 교체하고, 항상 무시되던min(NSNotFound, ...)도 제거했습니다.composedKey캐시 didSet 동기화 —composingKeys가 public var라 직접 대입 경로(HangulProcessor의composing/preeditsetter, convenience init)에서 캐시가 어긋나 겹모음/겹받침 판정이 조용히 깨질 수 있었습니다. didSet으로 재계산하고 convenience init은 designated init에 위임합니다.SymbolExtensionConfigstatic 캐시 — 계산 프로퍼티가 접근마다 Set 2개 + 구조체를 새로 할당했고, 기호확장 활성 시 조합 중 매 키마다 접근됩니다. 레이아웃별 static 상수로 1회만 생성합니다.verifyProcessable와processKeyCodeInput이 같은 키코드를 두 번 변환하던 것을inputText에서 한 번 계산해 공유하고, 사용처가 없어진processKeyCodeInput을 제거했습니다.검토했으나 수정하지 않은 항목
updateLayout시 조합 중 글자 유실: client 핸들이 없는 시점이라 구조 변경 필요, 보류테스트
이 작업 환경(Linux 컨테이너)에서는 xcodebuild를 실행할 수 없어 정적 검토만 거쳤습니다. 머지 전에 로컬에서
make test실행을 권장합니다. 기존 테스트 API(verifyProcessable기본 인자 호출)는 그대로 호환됩니다.🤖 Generated with Claude Code
https://claude.ai/code/session_01DXPSfN3YMi7PeunChUCuLW
Generated by Claude Code