spellcheck.swift

 1import Cocoa
 2
 3// Compilation: swiftc spellcheck.swift -o spellcheck
 4// Usage: ./spellcheck "Your text with typos here"
 5
 6struct Misspelling: Codable {
 7    let word: String
 8    let suggestions: [String]
 9    let range: [Int] // [location, length]
10}
11
12func checkSpelling(text: String) {
13    let spellChecker = NSSpellChecker.shared
14    let range = NSRange(location: 0, length: text.utf16.count)
15    var misspellings: [Misspelling] = []
16    
17    var offset = 0
18    while offset < range.length {
19        let currentRange = NSRange(location: offset, length: range.length - offset)
20        let misspelledRange = spellChecker.checkSpelling(of: text, startingAt: currentRange.location)
21        
22        if misspelledRange.location == NSNotFound || misspelledRange.length == 0 {
23            break
24        }
25        
26        let word = (text as NSString).substring(with: misspelledRange)
27        let suggestions = spellChecker.guesses(forWordRange: misspelledRange, in: text, language: nil, inSpellDocumentWithTag: 0) ?? []
28        
29        misspellings.append(Misspelling(
30            word: word,
31            suggestions: Array(suggestions.prefix(3)), // Top 3 suggestions
32            range: [misspelledRange.location, misspelledRange.length]
33        ))
34        
35        offset = misspelledRange.location + misspelledRange.length
36    }
37    
38    let encoder = JSONEncoder()
39    if let data = try? encoder.encode(misspellings),
40       let jsonString = String(data: data, encoding: .utf8) {
41        print(jsonString)
42    }
43}
44
45let args = ProcessInfo.processInfo.arguments
46if args.count > 1 {
47    checkSpelling(text: args[1])
48} else {
49    // Read from stdin if no arg provided
50    let input = FileHandle.standardInput.readDataToEndOfFile()
51    if let text = String(data: input, encoding: .utf8) {
52        checkSpelling(text: text)
53    }
54}