13

Is there any way to programmatically move the cursor to a specific text line or select it within a SwifUI TextEditor?

For example, if there is a TextEditor with 10 lines written in it. When the user presses a button, the cursor will navigate to, or the text will be selected on the 3rd line.

Battle Eagle
  • 166
  • 7
  • What is your definition of the text line? – El Tomato Dec 20 '20 at 00:46
  • Like lines of code, every text until a line break. e.g. swift:2:1: means the line after the first line break. – Battle Eagle Dec 20 '20 at 01:12
  • Okay. You point us to a web site and say that it's for `UITextField`. So it this question about `NSTextField` or `NSTextView` in Cocoa or SwiftUI? – El Tomato Dec 20 '20 at 01:15
  • Sorry if this was misleading, the link was just to give more idea of what I meant by setting the cursor position. But what I am asking for is to do it in the SwiftUI `TextEditor`, which is like the `NSTextView`, if that's what you meant. I was thinking of wrapping an `NSTextView` to use in SwiftUI instead of the new `TextEditor`, but I don't know if this is the only solution. – Battle Eagle Dec 20 '20 at 01:33
  • I would remove the statement concerning `UITextField`, which is not quite relevant to your question. – El Tomato Dec 20 '20 at 01:39
  • Oh okay, you are right. I removed it now. Thank you very much. – Battle Eagle Dec 20 '20 at 01:44

1 Answers1

0

This is currently not possible using the default SwiftUI TextEditor. You can achieve the desired behavior by wrapping NSTextField(/UITextField) in a NSViewRepresentable(/UIViewRepresentable).

I recently implemented this for CodeEditor. You can check out the implementation there (especially the changes from my PR).

However, since you mentioned code in one of the comments, you might also just want to use CodeEditor as a whole.

With my implementation, you can provide the editor with a binding to a Range<String.Index>.

 struct ContentView: View {
    static private let initialSource = "let a = 42\n"

    @State private var source = Self.initialSource
    @State private var selection = Self.initialSource.endIndex..<Self.initialSource.endIndex

    var body: some View {
        CodeEditor(source: $source,
                   selection: $selection,
                   language: .swift,
                   theme: .ocean,
                   autoscroll: true)
        Button("Select All") {
            selection = source.startIndex..<source.endIndex
        }
    }
}

You can move the cursor by updating selection. If the range is "empty" you just move the cursor to the start index. Otherwise the characters from start (included) to end index (excluded) get selected.

The solutions provided here should allow you to find the right String.Index for the line you want to place your cursor in.

If you want to select the whole line, scan the string from this String.Index in both directions until you find a newline character.

theMomax
  • 919
  • 7
  • 8