With the new cursor as defined in the previous poss about forest cursors we can take the next step towards making a Purely Functional Semantic Forests Editor like Smos. In this post we will write a simple purely functional forest editor using brick , building on the previous simple tree editor: microsmos.

From a tree editor to a forest editor

The semantic difference between a tree and a forest is simple. A forest is just a list of trees.

That means that if we take the code from the microsmos blogpost, and change the cursor within the state to a forest cursor, we should be most of the way to a semantic forest editor.

data State = State { stateCursor :: ForestCursor TextCursor Text , stateMode :: Mode } data Mode = EditForest | EditText deriving (Show, Eq)

Constructive Compile Errors

To recap, the first type parameter to ForestCursor is the type of the selected node and Text is the type of the other nodes in the forest.

The compile errors that we'll need to fix mostly come from functions that work on a TreeCursor . In that case there are corresponding functions for ForestCursor s.

treeCursorAppend ~> forestCursorAppend

~> treeCursorRemoveElem ~> forestCursorRemoveElem

~> treeCursorRemoveSubTree ~> forestCursorRemoveSubTree

~> ...

New rendering

Since the microsmos blogpost, the new cursor-brick library has come out. This has made a lot of the rendering code redundant.

Now we can just import Cursor.Brick and simply combine verticalForestCursorWidget and treeCursorWidget to easily build a forest cursor widget for our State .

verticalForestCursorWidget drawTextCTree (treeCursorWidget wrap cur) drawTextCTree (stateCursor s)

Here we can just re-use the drawTextCTree function from microsmos .

Extra features

To finish off the forest editor, we can add two more features: promoting and demoting nodes. Fortunately, there are functions for this in the cursor library that make this change really easy. This means that all we need to do is to add the following to the case expression for what to do with user input:

KChar 'h' -> mDo $ forestCursorPromoteElem toText toTextCursor KChar 'H' -> mDo $ forestCursorPromoteSubTree toText toTextCursor KChar 'l' -> mDo $ forestCursorDemoteElem toText toTextCursor KChar 'L' -> mDo $ forestCursorDemoteSubTree toText toTextCursor

References