1

Swift 5, Xcode 11

In a Stack Overflow text editor, you can select some text (like "selected" below), click the bold button, and it replaces:

Text selected here.

...with this:

Text **selected** here.

I'm trying to pull off the same thing with an NSTextView using Swift 5.

I can get the selectedRange of the text like this:

@IBAction func clickBold(_ sender: NSButton) {
  let range = content.selectedRange() //content is my NSTextView
}

But I can't figure out how to proceed from here. I found replaceSubrange but it seems to accept only a Range<String.Index> and not an NSRange.

@IBAction func clickBold(_ sender: NSButton) {
  let range = content.selectedRange() //content is my NSTextView
  var markdownText = content.string
  markdownText.replaceSubrange(range, with: "**\(markdownText)**") 
}

Has anyone done this before and can help me see what I'm missing? Thanks!

Clifton Labrum
  • 13,053
  • 9
  • 65
  • 128
  • 2
    Have a look at https://stackoverflow.com/a/30404532/1187415 for conversions between `NSRange` and `Range` – Martin R Aug 08 '19 at 19:42

2 Answers2

1

You should use the replaceCharacters(in:with:) method of NSText (whose subclass NSTextView is).

@IBAction func clickBold(_ sender: NSButton) {
  let range = content.selectedRange()
  let selectedText = (content.string as NSString).substring(with: range)
  content.replaceCharacters(in: range, with: "**\(selectedText)**") 
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Thanks for your reply. `replaceCharacters` looks pretty handy. It looks like I still need to parse the substring out of `markdownText`, though. This replaces the selected portion with the entire string. Using my example above, it turns it into `Text **Text selected here.** here.` – Clifton Labrum Aug 08 '19 at 19:56
  • @CliftonLabrum my bad, forgot to get the selected substring from the whole `NSTextField`, check my updated answer – Dávid Pásztor Aug 09 '19 at 08:49
0

It looks like this works:

let range = content.selectedRange()
markdownText = content.string

if let index = Range(range, in: markdownText){
  content.replaceCharacters(in: range, with: "**\(markdownText[index])**")
}

It provides the selected text snippet I need to wrap it in ** **. @MartinR's linked SO post helped me see that I can convert the string index with Range().

Clifton Labrum
  • 13,053
  • 9
  • 65
  • 128