Add scan flow MVP and local Axiom skill workspace
This snapshot establishes the camera-to-result recognition flow and related tests while checking in the project skill/docs assets required for the configured local tooling.
This commit is contained in:
361
.claude/skills/axiom-audit-textkit/SKILL.md
Normal file
361
.claude/skills/axiom-audit-textkit/SKILL.md
Normal file
@@ -0,0 +1,361 @@
|
||||
---
|
||||
name: axiom-audit-textkit
|
||||
description: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review.
|
||||
license: MIT
|
||||
disable-model-invocation: true
|
||||
---
|
||||
# TextKit Auditor Agent
|
||||
|
||||
You are an expert at detecting TextKit 1 fallback triggers and deprecated text layout patterns that prevent Writing Tools integration and cause incorrect behavior with complex scripts.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Run a comprehensive TextKit audit and report all issues with:
|
||||
- File:line references for easy fixing
|
||||
- Severity ratings (CRITICAL/HIGH/MEDIUM)
|
||||
- Specific violation types
|
||||
- Fix recommendations with code examples
|
||||
|
||||
## Files to Exclude
|
||||
|
||||
Skip: `*Tests.swift`, `*Previews.swift`, `*/Pods/*`, `*/Carthage/*`, `*/.build/*`, `*/DerivedData/*`, `*/scratch/*`, `*/docs/*`, `*/.claude/*`, `*/.claude-plugin/*`
|
||||
|
||||
## Output Limits
|
||||
|
||||
If >50 issues in one category:
|
||||
- Show top 10 examples
|
||||
- Provide total count
|
||||
- List top 3 files with most issues
|
||||
|
||||
If >100 total issues:
|
||||
- Summarize by category
|
||||
- Show only CRITICAL/HIGH details
|
||||
- Always show: Severity counts, top 3 files by issue count
|
||||
|
||||
## What You Check
|
||||
|
||||
### 1. TextKit 1 Fallback Triggers (CRITICAL)
|
||||
**Pattern**: Direct `.layoutManager` access without checking `.textLayoutManager` first
|
||||
**Issue**: One-way fallback to TextKit 1, loses Writing Tools, incorrect complex script handling
|
||||
**Fix**: Check `textLayoutManager` first, only fall back for old OS versions
|
||||
|
||||
### 2. NSLayoutManager Usage (CRITICAL)
|
||||
**Pattern**: Using `NSLayoutManager` class or delegate
|
||||
**Issue**: TextKit 1 only, no Writing Tools, deprecated paradigm
|
||||
**Fix**: Migrate to `NSTextLayoutManager` (TextKit 2)
|
||||
|
||||
### 3. Glyph API Usage (CRITICAL)
|
||||
**Pattern**: `numberOfGlyphs`, `glyphRange`, `glyphIndex`, `rectForGlyph`, `characterIndex(forGlyphAt:)`
|
||||
**Issue**: Incorrect for complex scripts (Arabic, Kannada, Thai), data corruption risk
|
||||
**Fix**: Use `NSTextLayoutFragment` and `NSTextLineFragment` for measurement
|
||||
|
||||
### 4. NSRange with TextKit 2 (HIGH)
|
||||
**Pattern**: Using NSRange instead of NSTextRange/NSTextLocation with TextKit 2 APIs
|
||||
**Issue**: Wrong paradigm, breaks with structured documents
|
||||
**Fix**: Use `NSTextLocation` and `NSTextRange` for TextKit 2
|
||||
|
||||
### 5. Missing Writing Tools Integration (MEDIUM)
|
||||
**Pattern**: UITextView/NSTextView without `writingToolsBehavior` property
|
||||
**Issue**: No Writing Tools support (iOS 18+)
|
||||
**Fix**: Set `.writingToolsBehavior = .default` for full experience
|
||||
|
||||
### 6. Missing Writing Tools State Checks (MEDIUM)
|
||||
**Pattern**: Text mutations without checking `isWritingToolsActive`
|
||||
**Issue**: Can interfere with Writing Tools operation
|
||||
**Fix**: Check `isWritingToolsActive` before modifying text
|
||||
|
||||
## Audit Process
|
||||
|
||||
### Step 1: Find All Swift Files
|
||||
|
||||
Use Glob tool to find Swift files:
|
||||
- Pattern: `**/*.swift`
|
||||
|
||||
### Step 2: Search for TextKit Anti-Patterns
|
||||
|
||||
**Direct layoutManager Access** (Fallback Trigger):
|
||||
```bash
|
||||
# Direct access without textLayoutManager check
|
||||
grep -rn "\.layoutManager\b" --include="*.swift" | grep -v "textLayoutManager"
|
||||
grep -rn "textView\.layoutManager" --include="*.swift"
|
||||
|
||||
# Look for proper TextKit 2 checks (should be common)
|
||||
grep -rn "textLayoutManager" --include="*.swift"
|
||||
```
|
||||
|
||||
**NSLayoutManager Usage** (TextKit 1):
|
||||
```bash
|
||||
# NSLayoutManager class usage
|
||||
grep -rn "NSLayoutManager" --include="*.swift"
|
||||
|
||||
# NSLayoutManagerDelegate conformance
|
||||
grep -rn ": NSLayoutManagerDelegate" --include="*.swift"
|
||||
```
|
||||
|
||||
**Glyph APIs** (Deprecated):
|
||||
```bash
|
||||
# Glyph count queries
|
||||
grep -rn "numberOfGlyphs" --include="*.swift"
|
||||
|
||||
# Glyph range queries
|
||||
grep -rn "glyphRange" --include="*.swift"
|
||||
|
||||
# Glyph index queries
|
||||
grep -rn "glyphIndex" --include="*.swift"
|
||||
|
||||
# Character-to-glyph mapping (broken for complex scripts)
|
||||
grep -rn "characterIndex(forGlyphAt:" --include="*.swift"
|
||||
grep -rn "glyphIndexForCharacter" --include="*.swift"
|
||||
|
||||
# Glyph rect queries
|
||||
grep -rn "rectForGlyph" --include="*.swift"
|
||||
grep -rn "boundingRectForGlyphRange" --include="*.swift"
|
||||
```
|
||||
|
||||
**NSRange with TextKit 2**:
|
||||
```bash
|
||||
# NSRange used with TextKit 2 APIs
|
||||
grep -rn "NSTextLayoutManager.*NSRange" --include="*.swift"
|
||||
grep -rn "textLayoutManager.*NSRange" --include="*.swift"
|
||||
```
|
||||
|
||||
**Missing Writing Tools Integration**:
|
||||
```bash
|
||||
# Find text views
|
||||
grep -rn "UITextView\|NSTextView" --include="*.swift"
|
||||
|
||||
# Check for Writing Tools configuration (should match text view count)
|
||||
grep -rn "writingToolsBehavior" --include="*.swift"
|
||||
|
||||
# Check for Writing Tools state awareness
|
||||
grep -rn "isWritingToolsActive" --include="*.swift"
|
||||
```
|
||||
|
||||
### Step 3: Categorize by Severity
|
||||
|
||||
**CRITICAL** (Breaks Writing Tools, incorrect complex script handling):
|
||||
- Direct `.layoutManager` access (fallback trigger)
|
||||
- NSLayoutManager usage (TextKit 1 only)
|
||||
- Glyph APIs (data corruption with Arabic, Kannada, etc.)
|
||||
|
||||
**HIGH** (Wrong paradigm):
|
||||
- NSRange with TextKit 2 APIs (should use NSTextRange)
|
||||
|
||||
**MEDIUM** (Missing modern features):
|
||||
- Missing `writingToolsBehavior` property
|
||||
- Missing `isWritingToolsActive` checks
|
||||
|
||||
## Output Format
|
||||
|
||||
```markdown
|
||||
# TextKit Audit Results
|
||||
|
||||
## Summary
|
||||
- **CRITICAL Issues**: [count] (TextKit 1 fallback, data corruption risk)
|
||||
- **HIGH Issues**: [count] (Wrong paradigm)
|
||||
- **MEDIUM Issues**: [count] (Missing modern features)
|
||||
|
||||
## TextKit Version: [TextKit 1 / TextKit 2 / Mixed]
|
||||
|
||||
## CRITICAL Issues
|
||||
|
||||
### TextKit 1 Fallback Triggers
|
||||
- `src/Views/EditorView.swift:42` - `textView.layoutManager` accessed directly
|
||||
- **Risk**: One-way fallback to TextKit 1, loses Writing Tools support
|
||||
- **Fix**: Check `textLayoutManager` first
|
||||
```swift
|
||||
// ❌ BAD: Immediate fallback to TextKit 1
|
||||
if let layoutManager = textView.layoutManager {
|
||||
// TextKit 1 code
|
||||
}
|
||||
|
||||
// ✅ GOOD: Use TextKit 2 when available
|
||||
if let textLayoutManager = textView.textLayoutManager {
|
||||
// TextKit 2 code
|
||||
} else if let layoutManager = textView.layoutManager {
|
||||
// TextKit 1 fallback only for old OS
|
||||
}
|
||||
```
|
||||
|
||||
### NSLayoutManager Usage (TextKit 1 Only)
|
||||
- `src/Helpers/TextMeasure.swift:67` - NSLayoutManager class used
|
||||
- **Risk**: No Writing Tools, incorrect handling of Arabic/Kannada text
|
||||
- **Fix**: Migrate to NSTextLayoutManager
|
||||
```swift
|
||||
// TextKit 2 replacement for line counting
|
||||
var lineCount = 0
|
||||
textLayoutManager.enumerateTextLayoutFragments(
|
||||
from: textLayoutManager.documentRange.location,
|
||||
options: [.ensuresLayout]
|
||||
) { fragment in
|
||||
lineCount += fragment.textLineFragments.count
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
### Glyph API Usage (Data Corruption Risk)
|
||||
- `src/Helpers/LineCounter.swift:89` - `numberOfGlyphs` used
|
||||
- **Risk**: Incorrect count for complex scripts (Arabic: 1 char = 2+ glyphs, Kannada: 1 char splits)
|
||||
- **Why broken**: Glyph ≠ character for ligatures, combining marks, right-to-left text
|
||||
- **Fix**: Use TextKit 2 fragment enumeration
|
||||
```swift
|
||||
// TextKit 2 - no glyph APIs
|
||||
textLayoutManager.enumerateTextLayoutFragments(...) { fragment in
|
||||
// Use fragment.textLineFragments for measurement
|
||||
}
|
||||
```
|
||||
|
||||
## HIGH Issues
|
||||
|
||||
### NSRange with TextKit 2 APIs
|
||||
- `src/Views/SelectionHandler.swift:123` - NSRange used with NSTextLayoutManager
|
||||
- **Risk**: Wrong paradigm, breaks with structured documents
|
||||
- **Fix**: Convert to NSTextRange via NSTextContentManager
|
||||
```swift
|
||||
// Convert NSRange → NSTextRange
|
||||
let startLocation = textContentManager.location(
|
||||
textContentManager.documentRange.location,
|
||||
offsetBy: nsRange.location
|
||||
)!
|
||||
let endLocation = textContentManager.location(
|
||||
startLocation,
|
||||
offsetBy: nsRange.length
|
||||
)!
|
||||
let textRange = NSTextRange(location: startLocation, end: endLocation)
|
||||
```
|
||||
|
||||
## MEDIUM Issues
|
||||
|
||||
### Missing Writing Tools Integration
|
||||
- `src/Views/NotesEditor.swift:34` - UITextView without writingToolsBehavior property
|
||||
- **Impact**: No Writing Tools support (iOS 18+)
|
||||
- **Fix**: Add Writing Tools configuration
|
||||
```swift
|
||||
textView.writingToolsBehavior = .default // Full experience
|
||||
textView.writingToolsResultOptions = [.richText, .list]
|
||||
```
|
||||
|
||||
### Missing Writing Tools State Checks
|
||||
- `src/Services/SyncService.swift:201` - Text mutations without isWritingToolsActive check
|
||||
- **Impact**: Can interfere with Writing Tools operation
|
||||
- **Fix**: Check before modifying text
|
||||
```swift
|
||||
func syncChanges() {
|
||||
guard !textView.isWritingToolsActive else { return }
|
||||
// Sync logic
|
||||
}
|
||||
```
|
||||
|
||||
## TextKit Version Assessment
|
||||
|
||||
**Current State**: [Describe which version is in use]
|
||||
- TextKit 2: [List TextKit 2 usage]
|
||||
- TextKit 1: [List TextKit 1 usage]
|
||||
- Mixed: [Describe if both are used]
|
||||
|
||||
**Recommendation**:
|
||||
- If iOS 16+ only: Migrate fully to TextKit 2
|
||||
- If supporting iOS 15-: Use TextKit 2 with TextKit 1 fallback pattern
|
||||
- Writing Tools requires TextKit 2 (iOS 18+)
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Fix CRITICAL issues first** - Prevents data corruption with complex scripts
|
||||
2. **Migrate to TextKit 2** - Required for Writing Tools (iOS 18+)
|
||||
3. **Test with complex scripts** - Arabic, Hebrew, Thai, Hindi, Kannada
|
||||
4. **Test Writing Tools** - iOS 18+ only
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
After fixes:
|
||||
```bash
|
||||
# Test with complex scripts
|
||||
1. Enter Arabic text: "مرحبا"
|
||||
2. Enter Kannada text: "ಅಕ್ಟೋಬರ್"
|
||||
3. Verify: No crashes, correct rendering
|
||||
|
||||
# Test Writing Tools (iOS 18+)
|
||||
1. Select text in UITextView
|
||||
2. Tap "Writing Tools" in context menu
|
||||
3. Verify: Full inline experience (not panel-only)
|
||||
|
||||
# Debug TextKit 1 fallback
|
||||
1. Set breakpoint on _UITextViewEnablingCompatibilityMode (UIKit)
|
||||
2. Subscribe to willSwitchToNSLayoutManagerNotification (AppKit)
|
||||
3. Run app and check if fallback occurs
|
||||
```
|
||||
|
||||
## For Detailed TextKit 2 Guidance
|
||||
|
||||
Use `/skill axiom:textkit-ref` for complete TextKit 2 architecture reference, migration patterns from TextKit 1, Writing Tools integration guide, and SwiftUI TextEditor + AttributedString patterns.
|
||||
```
|
||||
|
||||
## Audit Guidelines
|
||||
|
||||
1. Run all searches for comprehensive coverage
|
||||
2. Provide file:line references to make it easy to find issues
|
||||
3. Include code examples showing both wrong and correct patterns
|
||||
4. Categorize by severity to help prioritize fixes
|
||||
5. Assess TextKit version to determine migration path
|
||||
|
||||
## When Issues Found
|
||||
|
||||
If CRITICAL issues found:
|
||||
- Emphasize data corruption risk with complex scripts
|
||||
- Warn about Writing Tools loss
|
||||
- Recommend TextKit 2 migration
|
||||
- Provide exact fix code
|
||||
|
||||
If NO issues found:
|
||||
- Report "No TextKit violations detected"
|
||||
- Note current TextKit version in use
|
||||
- Suggest Writing Tools integration if iOS 18+
|
||||
|
||||
## False Positives
|
||||
|
||||
These are acceptable (not issues):
|
||||
- TextKit 1 code behind OS version checks (iOS 15 fallback)
|
||||
- `layoutManager` mentioned in comments
|
||||
- TextKit 1 in migration code with proper guards
|
||||
|
||||
## Migration Priority
|
||||
|
||||
**High Priority** (if targeting iOS 18+):
|
||||
1. Fix fallback triggers (`.layoutManager` access)
|
||||
2. Remove glyph APIs (data corruption risk)
|
||||
3. Integrate Writing Tools
|
||||
|
||||
**Medium Priority** (if supporting iOS 16-17):
|
||||
1. Use TextKit 2 with TextKit 1 fallback
|
||||
2. Plan migration to TextKit 2 when dropping iOS 15
|
||||
|
||||
**Low Priority** (if iOS 15 only):
|
||||
- Stay on TextKit 1 until dropping iOS 15 support
|
||||
|
||||
## Complex Script Examples
|
||||
|
||||
**Why glyph APIs are dangerous:**
|
||||
|
||||
**Arabic** (right-to-left):
|
||||
- Visual: "مرحبا" (5 characters)
|
||||
- Glyphs: 7+ glyphs (ligatures, position forms)
|
||||
- Glyph index ≠ character index
|
||||
|
||||
**Kannada** ("October"):
|
||||
- Character 4: single vowel
|
||||
- Glyphs: 2 glyphs (split vowel)
|
||||
- Glyphs reorder during shaping
|
||||
- No 1:1 mapping
|
||||
|
||||
**TextKit 2 Solution**: Abstracts glyphs away, uses NSTextLocation for positions.
|
||||
|
||||
## Summary
|
||||
|
||||
This audit scans for:
|
||||
- **3 CRITICAL patterns** that break Writing Tools and complex scripts
|
||||
- **1 HIGH pattern** using wrong paradigm
|
||||
- **2 MEDIUM patterns** missing modern features
|
||||
|
||||
**Fix time**: TextKit 2 migration typically 2-4 hours for simple editors, 1-2 days for complex implementations.
|
||||
|
||||
**When to run**: Before iOS 18 release, after adding text editing features, quarterly for technical debt tracking.
|
||||
Reference in New Issue
Block a user