self: {
  config,
  lib,
  pkgs,
  ...
}: let
  inherit (self.inputs) vimplugin-ts-error-translator-src;
  inherit (self.lib.${pkgs.system}) buildPlugin;

  inherit (lib) mkIf;

  cfg = config.programs.neovim;
  flakeEnv = config.programs.bash.sessionVariables.FLAKE;
in {
  config = mkIf cfg.enable {
    programs = {
      neovim = {
        withNodeJs = true;

        extraLuaConfig =
          # lua
          ''
            local lsp = require('lspconfig');
            local tsserver = require('typescript-tools');
            local default_capabilities = require('cmp_nvim_lsp').default_capabilities();

            local loadDevShell = function()
                if (devShells['web'] == nil) then
                    devShells['web'] = 1;

                    require('nix-develop').nix_develop_extend({'${flakeEnv}#web'}, function()
                        vim.cmd[[LspStart]];
                    end);
                end
            end;

            vim.api.nvim_create_autocmd('FileType', {
                pattern = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx', 'css', 'scss' },

                callback = function()
                    vim.cmd[[setlocal ts=4 sw=4 sts=0 expandtab]];

                    loadDevShell();
                end,
            });

            vim.api.nvim_create_autocmd('FileType', {
                pattern = 'html',

                callback = function()
                    vim.cmd[[setlocal ts=4 sw=4 expandtab]];

                    loadDevShell();
                end,
            });

            vim.api.nvim_create_autocmd('FileType', {
                pattern = 'scss',
                command = 'setlocal iskeyword+=@-@',
            });

            tsserver.setup({
                capabilities = default_capabilities,
                autostart = false,

                handlers = {
                    -- format error code with better error message
                    ['textDocument/publishDiagnostics'] = function(err, result, ctx, config)
                        require('ts-error-translator').translate_diagnostics(err, result, ctx, config)
                        vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
                    end,
                },
            });

            lsp.eslint.setup({
                capabilities = default_capabilities,
                autostart = false,

                -- auto-save
                on_attach = function(client, bufnr)
                    vim.api.nvim_create_autocmd('BufWritePre', {
                        buffer = bufnr,
                        command = 'EslintFixAll',
                    });
                end,

                settings = {
                    validate = 'on',
                    packageManager = 'npm',
                    useESLintClass = true,
                    useFlatConfig = true,
                    experimental = {
                        useFlatConfig = true,
                    },
                    codeAction = {
                        disableRuleComment = {
                            enable = true,
                            location = 'separateLine'
                        },
                        showDocumentation = {
                            enable = true,
                        },
                    },
                    codeActionOnSave = {
                        mode = 'all',
                        rules = {},
                    },
                    format = true,
                    quiet = false,
                    onIgnoredFiles = 'off',
                    rulesCustomizations = {},
                    run = 'onType',
                    problems = {
                        shortenToSingleLine = false,
                    },
                    nodePath = "",
                    workingDirectory = {
                        mode = 'location',
                    },
                },
            });

            lsp.cssls.setup({
                capabilities = default_capabilities,
                autostart = false,

                settings = {
                    css = {
                        validate = false,
                    },
                    less = {
                        validate = false,
                    },
                    scss = {
                        validate = false,
                    },
                },
            });

            lsp.somesass_ls.setup({
                capabilities = default_capabilities,
                autostart = false,
            });
            lsp.somesass_ls.manager.config.settings = {
                somesass = {
                    scss = {
                        completion = {
                            suggestFromUseOnly = true,
                        },
                    },
                },
            };

            local html_caps = default_capabilities;
            html_caps.textDocument.completion.completionItem.snippetSupport = true;

            lsp.html.setup({
                capabilities = html_caps,
                autostart = false,

                settings = {
                    configurationSection = { "html", "css", "javascript" },
                    embeddedLanguages = {
                        css = true,
                        javascript = true,
                    },
                    provideFormatter = true,
                    tabSize = 4,
                    insertSpaces = true,
                    indentEmptyLines = false,
                    wrapAttributes = 'auto',
                    wrapAttributesIndentSize = 4,
                    endWithNewline = true,
                },
            });
          '';

        plugins = [
          pkgs.vimPlugins.typescript-tools-nvim
          (buildPlugin "ts-error-translator" vimplugin-ts-error-translator-src)

          {
            plugin = pkgs.vimPlugins.package-info-nvim;
            type = "lua";
            config =
              # lua
              ''
                local packageInfo = require('package-info');

                packageInfo.setup({
                    hide_up_to_date = true,
                    package_manager = 'npm',
                });

                vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
                    pattern = { 'package.json' },

                    callback = function()
                        packageInfo.show({ force = true });
                    end,
                });
              '';
          }
        ];
      };
    };
  };

  # For accurate stack trace
  _file = ./default.nix;
}