{ config, lib, pkgs, ... }: let inherit (builtins) attrNames isList; inherit (lib) genAttrs; inherit (lib.types) either package enum listOf str; inherit (lib.options) mkEnableOption mkOption literalExpression; inherit (lib.strings) optionalString; inherit (lib.modules) mkIf mkMerge; inherit (lib.nvim.types) mkGrammarOption; inherit (lib.nvim.lua) toLuaObject; inherit (lib.nvim.dag) entryAfter; inherit (lib.meta) getExe'; inherit (pkgs) haskellPackages; cfg = config.vim.languages.haskell; defaultServers = ["hls"]; servers = { hls = {}; }; in { options.vim.languages.haskell = { enable = mkEnableOption "Haskell support"; treesitter = { enable = mkEnableOption "Treesitter support for Haskell" // { default = config.vim.languages.enableTreesitter; defaultText = literalExpression "config.vim.languages.enableTreesitter"; }; package = mkGrammarOption pkgs "haskell"; }; lsp = { enable = mkEnableOption "Haskell LSP support" // { default = config.vim.lsp.enable; defaultText = literalExpression "config.vim.lsp.enable"; }; servers = mkOption { type = listOf (enum (attrNames servers)); default = defaultServers; description = "Haskell LSP server to use"; }; formattingProvider = mkOption { type = enum ["ormolu" "fourmolu" "stylish-haskell" "brittany" "floskell" "none"]; default = "ormolu"; description = "Formatter used by HLS"; }; }; dap = { enable = mkEnableOption "DAP support for Haskell" // { default = config.vim.languages.enableDAP; defaultText = literalExpression "config.vim.languages.enableDAP"; }; package = mkOption { default = haskellPackages.haskell-debug-adapter; type = either package (listOf str); description = "Haskell DAP package or command to run the Haskell DAP"; }; }; extensions = { haskell-tools = { enable = mkEnableOption "haskell-tools.nvim"; }; }; }; config = mkIf cfg.enable (mkMerge [ (mkIf cfg.treesitter.enable { vim.treesitter = { enable = true; grammars = [cfg.treesitter.package]; }; }) (mkIf (cfg.lsp.enable && !cfg.extensions.haskell-tools.enable) { vim.lsp = { presets = genAttrs cfg.lsp.servers (_: {enable = true;}); servers = genAttrs cfg.lsp.servers (_: { filetypes = ["haskell" "lhaskell"]; settings.haskell.formattingProvider = cfg.lsp.formattingProvider; }); }; }) (mkIf cfg.extensions.haskell-tools.enable { vim = { startPlugins = ["haskell-tools-nvim"]; luaConfigRC.haskell-tools-nvim = entryAfter ["lsp-servers"] '' vim.g.haskell_tools = { tools = { hover = { stylize_markdown = false, auto_focus = false, }, }, hls = { auto_attach = true, cmd = {"${getExe' haskellPackages.haskell-language-server "haskell-language-server-wrapper"}", "--lsp"}, on_attach = function(client, bufnr) local ht = require("haskell-tools") local opts = { noremap = true, silent = true, buffer = bufnr } vim.keymap.set('n', 'cl', vim.lsp.codelens.run, opts) vim.keymap.set('n', 'hs', ht.hoogle.hoogle_signature, opts) vim.keymap.set('n', 'ea', ht.lsp.buf_eval_all, opts) vim.keymap.set('n', 'rr', function() vim.cmd('Haskell repl toggle') end, opts) vim.keymap.set('n', 'rf', function() vim.cmd('Haskell repl toggle ' .. vim.api.nvim_buf_get_name(0)) end, opts) vim.keymap.set('n', 'rq', function() vim.cmd('Haskell repl quit') end, opts) end, settings = { haskell = { formattingProvider = "${cfg.lsp.formattingProvider}", cabalFormattingProvider = "cabal-fmt", }, }, }, ${optionalString cfg.dap.enable '' dap = { cmd = ${ if isList cfg.dap.package then toLuaObject cfg.dap.package else ''{"${cfg.dap.package}/bin/haskell-debug-adapter"}'' }, }, ''} } ''; }; }) ]); }