Logical Ranges and Character Ranges
In my recent post titled “The Rake and Its Prongs” I introduced a function towards the end, called NSRange.isValidInsertionPointLocation(at:)
. It’s used to consider the after-end location as part of the range.
In my recent post titled “The Rake and Its Prongs” I introduced a function towards the end, called NSRange.isValidInsertionPointLocation(at:)
. It’s used to consider the after-end location as part of the range.
When you type in a text editor, you always type out of some range. When your insertion point or cursor is blinking at the end of a word you just typed, you expect to still be “in touch” with the word, and that the next key you press will for example add a character to that word. This is a useful deception for us human users. It’s not actually part of the technological underpinnings.
I figured out a way to consistently change a NSRange
, e.g. of a selection of text or the insertion point in a text view, to select surrounding words in DeclarativeTextKit
. But first off: Dear heavens! This wasn’t easy. I’m still not happy with the solution. While there are three to four hundred test cases (the vast majority is generated) that helped me narrow things down, I can tell you up front that I’m not proud of the resulting 160 lines of code.
I’ve now finished adding an example adapter to get a structural representation of a Markdown code block to my app. It bridges the abstract syntax tree (or “token tree”) of libMultiMarkdown
to NSTextStorage
-compatible UTF-16 substring ranges – which DeclarativeTextKit
works with, reducing code size and potential for errors even further:
I started working on DeclarativeTextKit mostly out of desperation, because the naive approach wouldn’t do the trick any longer. I complained about this on Mastodon in the beginning, but until now, I haven’t actually shown the code that made me want to change things.
In DeclarativeTextKit
, I found the abstraction of an “expression” in my vocabulary to represent the Domain-Specific Language’s instructions useful. Here is an example of a valid block of changes: This uses two kinds of Swift Result Builder to define the DSL’s grammar: The rules of the grammar are essentially this:
There’s been progress on the Declarative Text Kit API idea, and today I want to share an insight into building a DSL with Swift Result Builders. A detail that I didn’t grok until I built it. {{TOC}} Inserting text into a string, text view, or other kind of text buffer is simple enough: you need a location and then use the appropriate API to put a string into the target there.
I invested the past two weeks into making the Markdown highlighting component of my app The Archive better overall. More secure C token pointer handling, more performant token tree mutations, so faster highlighting and fewer pitfalls to worry about.