Keeping parts of the text unchanged by Writing Tools

Keeping parts of the text unchanged by Writing Tools

Learn how to define parts of the text in which Writing Tools should not apply changes to.

When it comes to supporting Writing Tools for a UITextView , we can exclude specific parts of the text editor's textual content, which may contain content that should not be modified by AI features such as quotes, templates, code, or legal text.

To exclude specific chunk of text from being modified by Writing Tools, a new method named textView(_:writingToolsIgnoredRangesInEnclosingRange:) needs to be defined within the Coordinator class.

func textView(_ textView: UITextView, writingToolsIgnoredRangesInEnclosingRange enclosingRange: NSRange) -> [NSValue] {
    // Convert the text of the UITextView to NSString for range operations
    let fullText = textView.text as NSString
    
    // Define the specific text to ignore by writing tools
    let searchString = "Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently"
    
    // Find the range of the specified string
    let range = fullText.range(of: searchString)
    
    // If the string is found, return the range wrapped in NSValue
    if range.location != NSNotFound {
        return [NSValue(range: range)]
    }
    
    // If the string is not found, return an empty array
    return []
}

In the example above the method searches for a predefined String within the text view, converting the text to an NSString for executing some range operations. If the specified string is found, its range is returned as an array of NSValue objects, allowing the Writing Tools to ignore that portion of the text.

The following is an example of a SwiftUI view with a UITextView component applying the ignored range method example mentioned before.

import SwiftUI
import UIKit

struct CustomTextView: UIViewRepresentable {
    
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.text = text
        textView.isEditable = true
        textView.font = UIFont.systemFont(ofSize: 17, weight: .regular)
        textView.delegate = context.coordinator
        textView.writingToolsBehavior = .complete
        
        
        return textView
    }
    
    func updateUIView(_ textView: UITextView, context: Context) {
        if textView.text != text {
            textView.text = text
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomTextView
        
        init(parent: CustomTextView) {
            self.parent = parent
        }
        
        func textViewDidChange(_ textView: UITextView) {
           if parent.text != textView.text {
                parent.text = textView.text
            }
        }
        
        func textView(_ textView: UITextView, writingToolsIgnoredRangesInEnclosingRange enclosingRange: NSRange) -> [NSValue] {
            let fullText = textView.text as NSString
            let searchString = "Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently"
            
            let range = fullText.range(of: searchString)
            
            if range.location != NSNotFound {
                return [NSValue(range: range)]
            }
            
            return []
        }
    }
}

struct ContentView: View {
    
    @State var textContent: String = """
        Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently. They're not fond of rules. And they have no respect for the status quo. You can quote them, disagree with them, glorify or vilify them. About the only thing you can't do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world, are the ones who do.
    """
    
    var body: some View {
        NavigationStack {
            
            Form {
                CustomTextView(text: $textContent)
                    .frame(height: 300)
            }
            .navigationTitle("Writing Tools ✏️")
            
        }
    }
}
0:00
/0:23