{
  pkgs,
  lib,
  ...
}: let
  lua = cmd: {__raw = cmd;};
  luaFunc = cmd:
    lua ''
      function ()
        ${cmd}
      end'';
in {
  colorschemes.base16 = {
    enable = true;
    colorscheme = "gruvbox-dark-hard";
  };
  globals = {
    mapleader = " ";
  };
  opts = {
    number = true;
    relativenumber = true;
    tabstop = 4;
    shiftwidth = 2;
    expandtab = true;
    smartindent = true;
    scrolloff = 4;
    smoothscroll = true;
    ignorecase = true;

    undofile = true;
    undodir = lua ''vim.fn.expand("$HOME/.local/share/nvim/undo")'';
    list = true;
    listchars = builtins.concatStringsSep "," [
      "tab:  >"
      "leadmultispace: |"
      "trail:."
      "extends:>"
      "precedes:<"
    ];

    foldlevel = 2;
  };
  extraPlugins = [
    (pkgs.vimPlugins.actions-preview-nvim)
    (pkgs.vimPlugins.vimwiki)
  ];
  extraConfigLua = ''
    require("actions-preview").setup {
      highlight_command = {
        require("actions-preview.highlight").delta("${pkgs.delta}/bin/delta --no-gitconfig --side-by-side"),
      },
        telescope = {
        sorting_strategy = "ascending",
        layout_strategy = "vertical",
        layout_config = {
          width = 0.8,
          height = 0.9,
          prompt_position = "top",
          preview_cutoff = 20,
          preview_height = function(_, _, max_lines)
            return max_lines - 10
          end,
        },
      },
    }
    vim.keymap.set({ "v", "n" }, "<C-.>", require("actions-preview").code_actions)
    vim.keymap.set({ "n" }, "<leader>ca", require("actions-preview").code_actions)
  '';
  keymaps = [
    {
      key = "<C-c>";
      action = ''"+y'';
      options.desc = "copy to clipboard";
    }
    {
      key = "<leader>ca";
      action = ''
        require("actions-preview").code_actions
      '';
    }
    {
      key = "<C-Tab>";
      action = "<CMD>tabnext<CR>";
    }
    {
      key = "<C-S-Tab>";
      action = "<CMD>tabprev<CR>";
    }
    {
      key = "<leader>bn";
      action = "<CMD>bnext<CR>";
    }
    {
      key = "<leader>bp";
      action = "<CMD>bprevious<CR>";
    }
    {
      key = "gl";
      action = "g$";
    }
    {
      key = "gh";
      action = "g0";
    }
    {
      mode = "v";
      key = ">";
      action = ">gv";
      options.desc = "indent";
      options.silent = true;
    }
    {
      mode = "v";
      key = "<";
      action = "<gv";
      options.desc = "deindent";
      options.silent = true;
    }
    {
      key = "<leader>q";
      action = "<CMD>bd<CR>";
      options.desc = "close buffer";
    }
    {
      key = "<leader>g";
      action = "";
      options.desc = "Gitsigns";
    }
    {
      key = "<leader>gs";
      action = "<CMD>Gitsigns stage_hunk<CR>";
      options.desc = "git stage hunk";
    }
    {
      key = "<leader>gn";
      action = "<CMD>Gitsigns next_hunk<CR>zz";
      options.desc = "next git hunk";
    }
    {
      key = "<leader>gd";
      action = "<CMD>Gitsigns preview_hunk_inline<CR>";
      options.desc = "git diff hunk";
    }
    {
      key = "<leader>gD";
      action = "<CMD>Gitsigns diffthis<CR>";
      options.desc = "git diff buffer";
    }
    {
      key = "<leader>gr";
      action = "<CMD>Gitsigns reset_hunk<CR>";
      options.desc = "git restore hunk";
    }
    {
      key = "<leader>gb";
      action = "<CMD>Gitsigns blame<CR>";
      options.desc = "show git blame";
    }
    {
      key = "<leader>gg";
      action = "<CMD>LazyGit<CR>";
      options.desc = "open lazygit";
    }
    {
      key = "<leader>-";
      action = "<CMD>Oil<CR>";
      options.desc = "open dir in Oil";
    }
    {
      key = "<leader>f";
      action = "";
      options.desc = "Telescope";
    }
    {
      key = "<leader>c";
      action = "";
      options.desc = "LSP";
    }
    {
      key = "<F5>";
      action = luaFunc "require('dap').continue()";
      options.desc = "DAP continue";
    }
    {
      key = "<leader>dc";
      action = luaFunc "require('dap').continue()";
      options.desc = "DAP continue";
    }
    {
      key = "<leader>db";
      action = luaFunc "require('dap').toggle_breakpoint()";
      options.desc = "DAP toggle breakpoint";
    }
    {
      key = "<leader>dn";
      action = luaFunc "require('dap').step_over()";
      options.desc = "DAP step over";
    }
    {
      key = "<leader>di";
      action = luaFunc "require('dap').step_into()";
      options.desc = "DAP step into";
    }
    {
      key = "<leader>do";
      action = luaFunc "require('dap').step_out()";
      options.desc = "DAP step out";
    }
    {
      key = "<leader>du";
      action = luaFunc "require('dapui').toggle()";
      options.desc = "DAP UI Toggle";
    }
  ];

  autoCmd = [
    {
      event = "BufWritePre";
      pattern = "*.go";
      # https://github.com/golang/tools/blob/master/gopls/doc/vim.md#imports-and-formatting
      callback = luaFunc ''
        local params = vim.lsp.util.make_range_params()
        params.context = {only = {"source.organizeImports"}}
        -- buf_request_sync defaults to a 1000ms timeout. Depending on your
        -- machine and codebase, you may want longer. Add an additional
        -- argument after params if you find that you have to write the file
        -- twice for changes to be saved.
        -- E.g., vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, 3000)
        local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params)
        for cid, res in pairs(result or {}) do
          for _, r in pairs(res.result or {}) do
            if r.edit then
              local enc = (vim.lsp.get_client_by_id(cid) or {}).offset_encoding or "utf-16"
              vim.lsp.util.apply_workspace_edit(r.edit, enc)
            end
          end
        end
        vim.lsp.buf.format({async = false})
      '';
    }
  ];

  plugins = {
    bufferline.enable = true;
    web-devicons.enable = true;
    vim-surround.enable = true;
    comment.enable = true;

    markdown-preview.enable = true;

    telescope = {
      enable = true;
      settings = {
        defaults = {
          file_ignore_patterns = [".*lock.*"];
        };
      };
      keymaps = {
        "<leader>fg" = "live_grep";
        "<leader>/" = "live_grep";
        "<leader>ff" = "find_files";
        "<leader>fb" = "buffers";
        "<leader>fh" = "help_tags";
        "<leader>:" = "commands";
        "<leader>ft" = "treesitter";
        "<leader>fr" = "lsp_references";
        "<leader>cr" = "lsp_definition";
      };
    };

    lsp = {
      enable = true;
      servers = {
        ts_ls.enable = true;
        nixd = {
          enable = true;
          settings = {
            nixpkgs.expr = ''import <nixpkgs> {}'';
            options.zenix.expr = ''(builtins.getFlake "git+https://git.tristans.cloud/tristan/nix").nixosConfigurations.zenix.options'';
            formatting.command = [(lib.getExe pkgs.alejandra)];
          };
        };
        yamlls.enable = true;
        gopls.enable = true;
        ansiblels.enable = true;
      };
      keymaps = {
        lspBuf = {
          "<leader>ck" = "hover";
          "K" = "hover";
          "<leader>cr" = "rename";
          "<F2>" = "rename";
        };
      };
    };

    dap = {
      enable = true;
    };
    dap-go = {
      enable = true;
    };
    dap-ui = {
      enable = true;
    };

    cmp = {
      enable = true;
      settings = {
        mapping = {
          "<C-Space>" = "cmp.mapping.complete()";
          "<C-u>" = "cmp.mapping.scroll_docs(4)";
          "<C-d>" = "cmp.mapping.scroll_docs(-4)";
          "<C-e>" = "cmp.mapping.close()";
          "<CR>" = "cmp.mapping.confirm({ select = true })";
          "<C-p>" = "cmp.mapping(cmp.mapping.select_prev_item(), {'i', 's'})";
          "<C-n>" = "cmp.mapping(cmp.mapping.select_next_item(), {'i', 's'})";
        };
        sources = [
          {name = "nvim_lsp";}
          {name = "path";}
          {name = "buffer";}
        ];
      };
    };
    cmp-nvim-lsp.enable = true;
    cmp-nvim-lsp-signature-help.enable = true;
    cmp-path.enable = true;
    cmp-buffer.enable = true;

    trouble.enable = true;

    gitsigns.enable = true;
    git-worktree = {
      enable = true;
      enableTelescope = true;
    };

    lazygit.enable = true;
    which-key.enable = true;

    vim-css-color.enable = true;

    treesitter = {
      enable = true;
      folding = true;
    };
    treesitter-textobjects = {
      enable = true;
      select = {
        enable = true;
        lookahead = true;
        keymaps = {
          "af" = {
            query = "@function.outer";
            desc = "Function Outer";
          };
          "ac" = {
            query = "@comment.outer";
            desc = "Comment Outer";
          };
          "if" = {
            query = "@function.inner";
            desc = "Function Inner";
          };
        };
      };
    };

    oil = {
      enable = true;
      settings = {
        keymaps = {
          "<C-r>" = "actions.refresh";
          "zh" = "actions.toggle_hidden";
        };
        view_options.show_hidden = true;
      };
    };
    ts-autotag.enable = true;
    guess-indent.enable = true;

    codesnap = {
      enable = true;
      settings = {
        has_line_number = true;
        mac_window_bar = false;
        save_path = "~/Pictures/Screenshots/";
        watermark = "";
        bg_padding = 5;
      };
    };
  };
}
