millismos and incidentally also
smos, I noticed that I was duplicating a lot of functionality to draw cursors to the screen. Now, cursors in the
cursor library are defined independent of the machinery that will manipulate or draw them, but I'm still using them mostly only together with
Folds and widgets
As of the latest release, all cursors in the
cursor library have fold helper functions. For example, for nonempty list cursors, there is now a
foldNonEmptyCursor helper function:
This allowed certain convenience functions like the following specialisation to
Widget n from
Easy enough, but
cursor-brick also offers more practical combinators like this:
There is a similar
verticalNonEmptyCursorWidget and there are also effectful versions of these combinators:
Text cursor and TextField cursor widgets
Drawing text to a screen is suprisingly complex. Brick takes care of most of the complexity, but there are some pieces that you still have to take care of.
Brick has two (modulo
Text -> String conversion) functions to draw text to the screen:
txtWrap. One wraps text that goes off-screen and the other one does not. We need to use the appropriate version for our use-case.
The next bit of complexity is that
txtWrap both require their input to be sanitised. Indeed, the documentation says:
The input string must not contain tab characters.
cursor-brick library has some helper functions to take care of this:
Next, to draw the blink-y box to the screen that we call a cursor,
brick has a
showCursor function. This function can be used to draw a
TextCursor in such a way that the blink-y box ends up in the right place. The
cursor-brick library also takes care of that:
Note that text will not be wrapped, because otherwise the blink-y box will not be in the right place on the screen.
There are similar functions for textfield cursors:
Tree cursor fold and widgets
The tree cursor folds and widgets have already been alluded to in the previous blogpost about
microsmos. A tree cursor is a strange beast, and conceptualising how to render it took a few iterations. The currently selected node needs to be rendered possibly differently from the other nodes. (Otherwise there would be no difference between rendering a tree and rendering a tree cursor.)
The way this happens is that you supply a function to draw the currently selected tree, and another function that can wrap whatever you made with that. This wrapping function will then add onto what you just made with the surrounding trees.
There is also an effectful version of this combinator.
cursor-brick library is available on Hackage. Cursors originated in the work on Smos. This post is part of an effort to encourage contributions to Smos. The simplest contribution could be to just try out smos and provide feedback on the experience. Smos is a purely functional semantic forest editor of a subset of YAML that is intended to replace Emacs' Org-mode for Getting Things Done.