{-# START_FILE {{name}}.cabal #-} name: {{name}} version: 0.1.0.0 synopsis: Haskell Neovim plugins description: Personal project to manage plugin dependencies. author: {{author-name}}{{^author-name}}Author name here{{/author-name}} maintainer: {{author-email}}{{^author-email}}example@example.com{{/author-email}} copyright: {{copyright}}{{^copyright}}{{year}}{{^year}}2019{{/year}} {{author-name}}{{^author-name}}Author name here{{/author-name}}{{/copyright}} -- Take a license that you like. Only relevant if you want to make your config -- used by other people. --license: BSD3 --license-file: LICENSE category: Neovim build-type: Simple --extra-source-files: README.md cabal-version: >=1.10 executable my-nvim-hs main-is: nvim.hs hs-source-dirs: ., nvim-hs other-modules: Neovim.Example.Plugin , Neovim.Example.Plugin.Fibonacci , Neovim.Example.Plugin.Random build-depends: base >= 4.7 && < 5 , nvim-hs >= 2 && < 3 -- The dependencies below are only needed for the example plugin , random , unliftio default-language: Haskell2010 {-# START_FILE nvim-hs/Neovim/Example/Plugin.hs #-} {-# LANGUAGE TemplateHaskell #-} -- Template Haskell is used to remove a lot of manual boiler-plate from -- declaring the functions you want to export. module Neovim.Example.Plugin ( plugin ) where import Neovim import Neovim.Example.Plugin.Random (nextRandom, setNextRandom, randomNumbers) import Neovim.Example.Plugin.Fibonacci (fibonacci) plugin :: Neovim () NeovimPlugin plugin = do randomPluginState <- randomNumbers wrapPlugin Plugin { environment = randomPluginState , exports = [ $(function' 'fibonacci) Sync -- Notice the quotation mark before the functin name, this is -- important! , $(function' 'nextRandom) Sync , $(function "SetNextRandom" 'setNextRandom) Async ] } {-# START_FILE nvim-hs/Neovim/Example/Plugin/Random.hs #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-} module Neovim.Example.Plugin.Random ( nextRandom , setNextRandom , randomNumbers ) where import Neovim import System.Random (newStdGen, randoms) import UnliftIO.STM (TVar, atomically, readTVar, modifyTVar, newTVarIO) -- | This type alias encodes the type of your plugin's environment, namely -- '(TVar [Int16)' in this case. -- -- Since this plugin needs to store some state, we have to put it in a mutable -- variable. I chose TVar here because I like the Software Transactional Memory -- library. type MyNeovim a = Neovim (TVar [Int16]) a -- | This is the start up code. It initializes the random number generator and -- returns a convenient list of random numbers. It returns the environment and -- is executed in the startup code, so this is the only place where you can't -- use the type alias defined above. -- -- Neovim isn't so good with big numbers, so limit to 16 bits. randomNumbers :: Neovim startupEnv (TVar [Int16]) randomNumbers = do g <- liftIO newStdGen -- Create a new seed for a pseudo random number generator newTVarIO (randoms g) -- Put an infinite list of random numbers into a TVar -- | Get the next random number and update the state of the list. nextRandom :: MyNeovim Int16 nextRandom = do tVarWithRandomNumbers <- ask atomically $ do -- pick the head of our list of random numbers r <- head <$> readTVar tVarWithRandomNumbers -- Since we do not want to return the same number all over the place -- remove the head of our list of random numbers modifyTVar tVarWithRandomNumbers tail return r -- | You probably don't want this in a random number generator, but this shows -- hoy you can edit the state of a stateful plugin. setNextRandom :: Int16 -> MyNeovim () setNextRandom n = do tVarWithRandomNumbers <- ask -- cons n to the front of the infinite list atomically $ modifyTVar tVarWithRandomNumbers (n:) {-# START_FILE nvim-hs/Neovim/Example/Plugin/Fibonacci.hs #-} module Neovim.Example.Plugin.Fibonacci ( fibonacci ) where import Neovim -- | All fibonacci numbers. fibonacciNumbers :: [Integer] fibonacciNumbers = 0:fibs -- Since were using !! to index an element in a list, we need a 0 in front where fibs = 1:scanl1 (+) fibs -- | Neovim is not really good with big numbers, so we return a 'String' here. fibonacci :: Int -> Neovim env String fibonacci n = return . show $ fibonacciNumbers !! n {-# START_FILE nvim.hs #-} import Neovim import qualified Neovim.Example.Plugin as Example main :: IO () main = do neovim defaultConfig { plugins = plugins defaultConfig ++ [ Example.plugin ] } {-# START_FILE plugin/nvim-hs.vim #-} call nvimhs#start(expand(':p:h:h'), '{{{name}}}', [])