Andrew Birkett's nobugs.org
So you’ve got Yi up and running. Now what?
Edit your ~/.yi/YiConfig.hs file by adding the following code:
helloWorld :: YiM () helloWorld = do withBuffer $ insertN "Hello, world!"
Also change the very first line to look like this:
module YiConfig (yiMain,helloWorld) where
Now do M-x reconfigE to reload the config, and then M-x helloWorld should insert text into the current buffer.
The ‘insertN’ function inserts a string (n stands for ‘n characters’) into the current buffer. Since haskell is a pure language, executing insertN can’t actually mutate the current buffer. Instead, it returns a value of type BufferM, which I think of as a recipe describing how you’d like buffer to be modified.
At first glance, it looks like BufferM is just the state monad: the contents of the buffer being the state. That’s almost correct; in addition to changing the buffer state, BufferM values also produce “Update” values which are used for the undo/redo queue (eg. vaguely like the Command design pattern).
Of course, the Yi application has much more state than just a single buffer’s contents. Yi knows which windows it has open, what buffers are open, what input/output streams it has and so on. The entire application state is bundled up in the “Yi” datatype (in Keymap.hs). It’s the most important datatype in the application.
Again, because haskell is a pure language, we can’t ever directly mutate the application state. Instead we create and combine values of type “YiM” (yi monad) which describe how we’d like the state to be changed. YiM is a combination of the Reader monad and the IO monad, so values of type YiM (again, I think of these as recipes) can read the current application state and perform I/O.
Let’s return back to the insertN function above. The insertN function has type BufferM, which is a recipe to modify a buffer. We need to turn that modify-a-buffer recipe into a modify-the-whole-app-state recipe, and the ‘withBuffer : BufferM a → YiM a’ function does just that.
Yi is actually pretty smart, and allows you to run BufferM commands directly without requiring them to be wrapped up into a YiM monad. I found this pretty surprising, but then Yi is much more ‘dynamic’ than your average haskell application. So we could replace the above example with this code:
module YiConfig (yiMain,helloWorld2) where ... helloWorld2 :: BufferM () helloWorld2 = do insertN "Hello, world!"
.. and Yi will apply that buffer-modifying recipe to the current buffer.
Next, let’s move on to more examples.