feat(keyboard): add English QuickType bar and system lexicon
Show verbatim/correction/completion slots, mmap a 40k-word list, and use UITextChecker plus supplementary lexicon for conservative autocorrect.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
// EnglishSystemLexicon.swift
|
||||
// OSGKeyboard · Shared
|
||||
//
|
||||
// Apple's sanctioned English sources for a custom keyboard: UITextChecker
|
||||
// completions / guesses, plus UILexicon names from
|
||||
// `requestSupplementaryLexicon`. The engine stays pure; the keyboard
|
||||
// extension fills these fields on each refresh.
|
||||
|
||||
import Foundation
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
@MainActor
|
||||
public protocol EnglishSystemLexiconProviding: AnyObject {
|
||||
func completions(prefix: String, limit: Int) -> [String]
|
||||
func guesses(for word: String, limit: Int) -> [String]
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public final class EmptyEnglishSystemLexicon: EnglishSystemLexiconProviding {
|
||||
public init() {}
|
||||
|
||||
public func completions(prefix: String, limit: Int) -> [String] {
|
||||
[]
|
||||
}
|
||||
|
||||
public func guesses(for word: String, limit: Int) -> [String] {
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
/// System spellchecker. Always called from `TypingSessionController` (@MainActor).
|
||||
@MainActor
|
||||
public final class UIKitEnglishSystemLexicon: EnglishSystemLexiconProviding {
|
||||
public var language: String
|
||||
|
||||
public init(language: String = "en_US") {
|
||||
self.language = language
|
||||
}
|
||||
|
||||
public func completions(prefix: String, limit: Int) -> [String] {
|
||||
guard !prefix.isEmpty, limit > 0 else { return [] }
|
||||
let checker = UITextChecker()
|
||||
let range = NSRange(location: 0, length: (prefix as NSString).length)
|
||||
let hits = checker.completions(forPartialWordRange: range, in: prefix, language: language) ?? []
|
||||
return Array(hits.prefix(limit))
|
||||
}
|
||||
|
||||
public func guesses(for word: String, limit: Int) -> [String] {
|
||||
guard word.count >= 3, limit > 0 else { return [] }
|
||||
let checker = UITextChecker()
|
||||
let range = NSRange(location: 0, length: (word as NSString).length)
|
||||
let hits = checker.guesses(forWordRange: range, in: word, language: language) ?? []
|
||||
return Array(hits.prefix(limit))
|
||||
}
|
||||
|
||||
public static func learnWord(_ word: String) {
|
||||
let trimmed = word.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return }
|
||||
if !UITextChecker.hasLearnedWord(trimmed) {
|
||||
UITextChecker.learnWord(trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user