DEV Community

Cover image for It's 2024 so why not setup Neovim (w/ NvChad) for Haskell
Baalateja Kataru
Baalateja Kataru

Posted on • Edited on

It's 2024 so why not setup Neovim (w/ NvChad) for Haskell

Introduction

Recently, I've been spending time on a persistent penboot installation of Fedora Workstation on a 32 GB SanDisk drive.

I've avoided installing any GUI text/code editors such as VSCode (my defacto choice) or Sublime Text, and decided to stick to a basic terminal-and-vim based workflow keeping in mind the limited storage space I have to operate with.

I wanted to divide my usage between the two most popular vim editors out there by

  • Using Vim for learning from tutorials, blogs, and basic books
  • Using Neovim for projects and advanced books

Why? Vim's lack of features means it's more or less just a text editor with syntax highlighting. This makes writing code tedious, but tends to sharpen my command of what I'm learning. Whenever I find myself going back to basics (learning a language/framework/toolchain, following a book on some fundamentals), the minimalism of Vim has me paying more attention to what I'm typing onto the screen and be more careful of what I'm doing since I don't have a linter/LSP to catch me from falling if I make a mistake. Needless to say, I didn't configure my vim installation even a little as a result.

But when I'm working on projects or going through technically heavy books, I prefer to bring along my entire belt of gadgets - LSPs, linters, formatters, debuggers, what have you, so that I can maximize my developer velocity and streamline the DX as much as possible. This allows me to focus more on what I'm learning conceptually and offload the menial and tedious to as much tooling as I can. Neovim's rich and modern featureset and extensibility with its Lua-based plugin system makes it perfect for this task, while also allowing me to use my familiar vim motions to move about.


I've been playing with Neovim and trying to configure it for Haskell. I just started going through Learn Physics with Functional Programming - A Hands-on Guide to Exploring Physics with Haskell
by Scott N. Walck
so I figured this was the perfect opportunity to figure out how well Neovim and Haskell play together. After much surfing of the world wide web, I couldn't find a straightforward, up-to-date guide to setup Neovim for Haskell in 2024, so I decided I'd make one myself and document the process along the way.

Install GHCup

If you're new to Haskell, the de-facto toolchain is based around:

  1. GHC - Glasgow Haskell Compiler, the go-to standard compiler
  2. Cabal - Haskell build system
  3. Stack - Similar to and sometimes an alternative of Cabal
  4. HLS - The Haskell Language Server, Haskell's implementation of the Language Server Protocol for IDEs/code editors that speak the Language Server Protocol (such as Neovim).

This stack is managed coherently by GHCup, the de-facto toolchain manager for Haskell.

If you don't have GHCup installed on your system, first follow their well elucidated installation guide since you'll need to ensure some system dependencies are available for GHCup to operate correctly.

Since I'm on Fedora Workstation, I'll use dnf to install the system dependencies listed in System Requirements that are specific to my OS and architecture.

$ sudo dnf update -y
$ sudo dnf install -y gcc gcc-c++ gmp gmp-devel make ncurses ncurses-compat-libs xz perl
Enter fullscreen mode Exit fullscreen mode

Next, run GHCup's installation script for your platform as given in How to install. I'll run the Linux one in bash using curl

$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
Enter fullscreen mode Exit fullscreen mode

Next, make sure to choose all defaults, which will

  • Install all recommended versions of the toolchain components and set them as defaults. Read Which versions get installed? to understand the options and differences.
  • NOT install HLS (Haskell Language Server), since we will be installing it separately using Mason via NvChad, which uses GHCup underneath the hood to install HLS anyway.
  • Setup Stack to play well with GHCup's GHC version.

After installation, GHCup and the defaults will be placed in PATH and available to further shell sessions. Either restart your current shell session or type the following in Bash to source the changes into your current shell

$ . $HOME/.ghcup/env
Enter fullscreen mode Exit fullscreen mode

You can open ghcup tui to make sure that all the recommended versions are installed and set as defaults

Note that,

  • ✅ means installed
  • ✅ ✅ means installed and set as default

Install Neovim

If you don't have Neovim, the quickest way to get it is via your system package manager

Otherwise, alternate methods are listed on the same page, which contains the official installation instructions

Install NvChad

NvChad is a very opinionated but very convenient Neovim configuration to have you hit the road running with Neovim.

The quickest way to install NvChad is to clone a starter NvChad config and use :MasonInstallAll to install all necessary plugins right after, as given in quickstart/install. Visit this guide if you have issues installing NvChad, as it does require some system dependencies to be installed and for you to have a Nerd Font installed and selected as your terminal's font.

Remember to backup any preexisting Neovim config before you download NvChad as your Neovim config by running
$ mv ~/.config/nvim ~/.config/nvim-old first

Overrides and Configs

Next, we need to use Mason to install HLS for language support and Haskell's Tree Sitter configuration for syntax highlighting support

We specify this by overriding their respective Neovim plugins

~/.config/nvim/lua/plugins/init.lua

return {
  -- ...
  -- ...
  {
    "williamboman/mason.nvim",
    opts = {
      ensure_installed = {
        "haskell-language-server"
      },
    },
  },

  {
    "neovim/nvim-lspconfig",
    config = function()
      require("nvchad.configs.lspconfig").defaults()
      require "configs.lspconfig"
    end,
  },

  {
    "nvim-treesitter/nvim-treesitter",
    opts = {
      ensure_installed = {
        "haskell"
      },
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

and configure Neovim to talk LSP with our Haskell language server.

~/.config/nvim/lua/configs/lspconfig.lua

local on_attach = require("nvchad.configs.lspconfig").on_attach
local on_init = require("nvchad.configs.lspconfig").on_init
local capabilities = require("nvchad.configs.lspconfig").capabilities

local lspconfig = require "lspconfig"

-- ...
-- ...

lspconfig.hls.setup {
  on_attach = on_attach,
  on_init = on_init,
  capabilities = capabilities,
  filetypes = { 'haskell', 'lhaskell', 'cabal'},
}
Enter fullscreen mode Exit fullscreen mode

That's it! We're done.


Now, open a Haskell file using nvim

$ nvim main.hs
Enter fullscreen mode Exit fullscreen mode

Behold, your Neovim is now a powerful wielder of the wizardry that is Haskell and Functional Programming


Full disclaimer: I wrote this mainly for my own reference because I hate forgetting build/config steps. Feel free to leave any feedback and/or suggestions in the comments below!

Top comments (0)