<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Den</title><link href="https://rogue87.gitlab.io"/><link rel="self" href="https://rogue87.gitlab.io/rss.xml"/><updated>2026-04-06T10:24:06.772Z</updated><id>https://rogue87.gitlab.io</id><author><name>Rogue87</name><email>rogue87@tuta.io</email></author><subtitle>I like doing random things :)</subtitle><entry><title>Alternatives to mason.nvim</title><link href="https://rogue87.gitlab.io/blog/alternatives-to-mason-nvim"/><updated>2026-02-07</updated><id>https://rogue87.gitlab.io/blog/alternatives-to-mason-nvim</id><content type="html">&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;First, I should say that mason.nvim really simplifies installing and managing tools; it covers a huge amount of packages. However, I've always been a fan of the Unix philosophy, "do one thing well," and I find that an editor plugin handling system-level package management is outside of its ideal scope.&lt;/p&gt;
&lt;p&gt;I still use mason.nvim on Termux because, unfortunately, it's difficult to use these tools natively there. While you can use &lt;code&gt;proot-distro&lt;/code&gt;, it is prohibitively slow.&lt;/p&gt;
&lt;p&gt;You might be wondering why even bother? Well, mason.nvim's approach to security and reproducibility is limited. It essentially downloads a package and adds it to your &lt;code&gt;$PATH&lt;/code&gt; for Neovim to use. While convenient, it doesn't offer robust version locking or integrity verification.&lt;/p&gt;
&lt;p&gt;So if you're looking for a separate tool for managing installations of &lt;code&gt;language servers&lt;/code&gt;, &lt;code&gt;formatters&lt;/code&gt;, &lt;code&gt;linters&lt;/code&gt; and &lt;code&gt;other cli tools&lt;/code&gt;, you may want to keep reading.&lt;/p&gt;
&lt;h2&gt;Alternatives&lt;/h2&gt;
&lt;h3&gt;1. Default Package Manager&lt;/h3&gt;
&lt;p&gt;Most Linux distributions software repositories offer some tooling, but they are often outdated or incomplete, which is why mason.nvim exists.&lt;/p&gt;
&lt;p&gt;It's also possible to use language-specific package managers (e.g., &lt;code&gt;npm install -g typescript-language-server&lt;/code&gt;). While straightforward, it requires manual upkeep and forces the user to manage updates for every tool individually.&lt;/p&gt;
&lt;p&gt;One could argue that shell scripts can automate this process, but they tend to be brittle and break easily.&lt;/p&gt;
&lt;h3&gt;2.  &lt;a href="https://mise.jdx.dev/"&gt;mise-en-place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This tool is pretty much a more modern and faster &lt;a href="https://asdf-vm.com/"&gt;asdf&lt;/a&gt;. It supports installing directly from GitHub and other services like GitLab and Codeberg. It works similarly to mason.nvim but is more flexible; since it operates at the shell level, you can use these tools with any editor, such as Helix or Sublime, not just Neovim (Any LSP compliant editor in general).&lt;/p&gt;
&lt;p&gt;Mise identifies itself as a polyglot tool manager. It uses &lt;code&gt;toml&lt;/code&gt; for configuration, making it easy to set up and maintain. Here is an example of what a configuration file looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-toml"&gt;[tools]
# shell
shfmt = "latest"
shellcheck = "latest"
"npm:bash-language-server" = "5.6.0"
stylua = "latest"
"github:EmmyLuaLs/emmylua-analyzer-rust" = "latest"
ruff = "latest"
uv = "latest"
flutter = "latest"
gemini-cli = "latest"
node = "latest"
bun = "latest"
deno = "latest"
taplo = "latest"

[settings]
cargo.binstall = true
experimental = true
jobs = 4
npm.bun = true
paranoid = false
verbose = false
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Installing mise&lt;/h4&gt;
&lt;p&gt;Here's how to install mise on fedora&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo dnf copr enable jdxcode/mise
sudo dnf install mise
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's also possible to install mise from &lt;a href="https://terra.fyralabs.com/"&gt;terra repos&lt;/a&gt;. Here's how:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;# add terra repository to dnf
sudo dnf install --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release
sudo dnf install mise
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Terra comes with a lot more packages, so I suggest looking more into it.&lt;/p&gt;
&lt;p&gt;Anyway, I'm not going to cover every linux distro/OS out there so consider looking at this page:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mise.jdx.dev/getting-started.html"&gt;https://mise.jdx.dev/getting-started.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And please don't use &lt;code&gt;curl&lt;/code&gt; for installing programs directly on your system!&lt;/p&gt;
&lt;p&gt;After you're done installing mise, you should load it into your shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# bash
echo 'eval "$(mise activate bash)"' &gt;&gt; ~/.bashrc
# zsh
echo 'eval "$(mise activate zsh)"' &gt;&gt; ~/.zshrc
# fish
echo 'mise activate fish | source' &gt;&gt; ~/.config/fish/config.fish
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Global vs Project-Local Config&lt;/h4&gt;
&lt;p&gt;To install a package globally, run &lt;code&gt;mise use -g &amp;lt;package&gt;&lt;/code&gt;. Running &lt;code&gt;mise use &amp;lt;package&gt;&lt;/code&gt; without the &lt;code&gt;-g&lt;/code&gt; flag will add it to a &lt;code&gt;mise.toml&lt;/code&gt; in your current directory, making the tool available only when you are in that project.&lt;/p&gt;
&lt;h3&gt;3.  &lt;a href="https://brew.sh/"&gt;Brew/LinuxBrew&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Brew is a popular alternative package manager written in Ruby. On Linux, it installs packages and their dependencies into a separate directory in your home folder. This isolation is convenient because it doesn't interfere with your system libraries, though it does mean downloading extra copies of common dependencies.&lt;/p&gt;
&lt;p&gt;It is very user-friendly, operating like a standard package manager. For example, you can simply run &lt;code&gt;brew install lua-language-server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It covers a wide range of language servers, linters, and formatters. However, there is one small drawback:&lt;/p&gt;
&lt;p&gt;&lt;img src="/posts/alternatives-to-mason-nvim/brew-really-loves-macos.png" alt="macOS fanboy package manager"&gt;&lt;/p&gt;
&lt;p&gt;It favors macOS over other platforms sometimes.&lt;/p&gt;
&lt;h3&gt;4.  &lt;a href="https://nixos.org/"&gt;Nix Package Manager&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Nix has a steeper learning curve because it uses its own functional language, but it isn't as daunting as it might seem; however, the language wasn't made with beauty in mind (bit of an eye sore sometimes).&lt;/p&gt;
&lt;p&gt;A major advantage of the Nix package manager is its massive repository. It is one of the largest in the world! You can be rest assured that almost any tool you need is available.&lt;/p&gt;
&lt;p&gt;&lt;img src="/posts/alternatives-to-mason-nvim/repos_size_graph.svg" alt="repology-repo-sizes-graph"&gt;&lt;/p&gt;
&lt;p&gt;On recent versions of Fedora (42+), you can install Nix directly from the official repositories. If you are on an older version, I recommend the &lt;a href="https://github.com/DeterminateSystems/nix-installer"&gt;Determinate Nix Installer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Why don't I use Nix? Personally, I find Mise easier to manage for my specific needs. I've had issues in the past where software compiled with Nix-installed tools couldn't find necessary system libraries. I also prefer Fedora's workflow over NixOS, having switched back after encountering hardware driver issues.&lt;/p&gt;
&lt;p&gt;Similar to Brew, Nix pulls its own system libraries to ensure reproducibility. However, the sheer volume of dependencies it downloads can be overwhelming for slower internet connections. Perhaps that was the reason why my wifi card died 😅.&lt;/p&gt;
&lt;p&gt;&lt;img src="/posts/alternatives-to-mason-nvim/nix-packages-taking-too-long-to-install.png" alt="nix taking forever to install things"&gt;&lt;/p&gt;
&lt;p&gt;Okay I've been holding you from seeing how a nix config file looks like. Take a look:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-nix"&gt;{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  outputs =
    { nixpkgs, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in
    {
      packages.${system}.default = pkgs.buildEnv {
        name = "devtools";
        paths = with pkgs; [
          # LSPs
          lua-language-server
          nil
          nodePackages.bash-language-server
          nodePackages.typescript-language-server
          taplo
          tinymist
          vscode-langservers-extracted
          # Formatters
          nixfmt
          nodePackages.prettier
          shfmt
          stylua
        ];
      };
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It looks like over glorified json now that I think about it.&lt;/p&gt;
&lt;p&gt;I'm pretty sure some nix fanatics are screaming right now because I'm using &lt;code&gt;nix profile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Trust me when I say, try to keep your config as small as possible. If you happen to be intrigued by the idea of nix and it's philosophy, I guess you should just switch entirely to NixOS and perhaps try &lt;a href="https://nix-community.github.io/home-manager/"&gt;home-manager&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Bringing it into Neovim&lt;/h2&gt;
&lt;p&gt;Once you move away from Mason, you might wonder how to actually use these tools. Since &lt;code&gt;mise&lt;/code&gt;, &lt;code&gt;brew&lt;/code&gt;, or &lt;code&gt;nix&lt;/code&gt; place binaries directly in your &lt;code&gt;$PATH&lt;/code&gt;, integration is simpler than you might expect.&lt;/p&gt;
&lt;h3&gt;1. LSP Configuration&lt;/h3&gt;
&lt;p&gt;You no longer need &lt;code&gt;mason-lspconfig.nvim&lt;/code&gt;. You can simply call the setup function for any server you've installed:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-lua"&gt;-- If 'emmylua_ls' is in your PATH, this just works
require('lspconfig').emmylua_ls.setup({})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I personally prefer defining my LSP configurations in &lt;code&gt;lsp/&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;I simply grab those configurations from &lt;a href="https://github.com/neovim/nvim-lspconfig"&gt;nvim-lspconfig&lt;/a&gt; repository and put them in &lt;code&gt;lsp/&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-lua"&gt;-- lsp/emmylua_ls.lua (relative to neovim config directory)

---@brief
---
--- https://github.com/EmmyLuaLs/emmylua-analyzer-rust
---
--- Emmylua Analyzer Rust. Language Server for Lua.
---
--- `emmylua_ls` can be installed using `cargo` by following the instructions[here]
--- (https://github.com/EmmyLuaLs/emmylua-analyzer-rust?tab=readme-ov-file#install).
---
--- The default `cmd` assumes that the `emmylua_ls` binary can be found in `$PATH`.
--- It might require you to provide cargo binaries installation path in it.

---@type vim.lsp.Config
return {
    cmd = { "emmylua_ls" },
    filetypes = { "lua" },
    root_markers = {
        ".luarc.json",
        ".emmyrc.json",
        ".luacheckrc",
        ".git",
    },
    workspace_required = false,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then call &lt;code&gt;vim.lsp.enable({...})&lt;/code&gt; in &lt;code&gt;init.lua&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-lua"&gt;-- ...
vim.lsp.enable({
  "emmylua_ls",
})
-- ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Formatting &amp; Linting with Guard&lt;/h3&gt;
&lt;p&gt;While many people use &lt;code&gt;conform.nvim&lt;/code&gt; + &lt;code&gt;nvim-lint&lt;/code&gt; combo, I personally recommend &lt;a href="https://github.com/nvimdev/guard.nvim"&gt;guard.nvim&lt;/a&gt; by nvimdev. It is a lightweight, async formatting and linting plugin that is extremely easy to configure once your tools are globally available.&lt;/p&gt;
&lt;p&gt;Here's how to install and configure it using &lt;a href="https://lazy.folke.io/"&gt;lazy.nvim&lt;/a&gt; plugin manager:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-lua"&gt;---@type LazySpec
return {
    "nvimdev/guard.nvim",
    dependencies = { "nvimdev/guard-collection" },
    lazy = false,
    init = function()
        vim.g.guard_config = {
            always_save = false, -- always save file after call Guard fmt
            auto_lint = true, -- automatic linting
            fmt_on_save = false, -- format on write to buffer
            lint_interval = 500, -- how frequently can linters be called
            lsp_as_default_formatter = true, -- use lsp if no formatter was defined for this filetype
            refresh_diagnostic = true, -- show diagnostic after format done
            save_on_fmt = false, -- whether or not to save the buffer after formatting
        }
    end,
    config = function()
        local ft = require("guard.filetype")

        ft("bash"):fmt("shfmt")
        ft("dart"):fmt("lsp")
        ft("fish"):fmt("fish_indent")
        ft("lua"):fmt("stylua")
        ft("rust"):fmt("rustfmt")
        ft("toml"):fmt("taplo")

        ft("markdown"):fmt({
            cmd = "deno",
            args = { "fmt", "--ext=md", "--prose-wrap=preserve", "-" },
            stdin = true,
        })
    end,
    keys = {
        { "&amp;lt;localleader&gt;df", "&amp;lt;cmd&gt;Guard fmt&amp;lt;cr&gt;", desc = "format (guard.nvim)", mode = { "n" } },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;My Recommendation&lt;/h2&gt;
&lt;p&gt;Start with mise. It is really easy and simple to use. You can use it like a regular package manager or specify your packages in the config file.&lt;/p&gt;
&lt;p&gt;Mise does more than just package management. It also has a &lt;a href="https://mise.jdx.dev/tasks/"&gt;builtin task runner&lt;/a&gt; which I find really good and can &lt;a href="https://mise.jdx.dev/environments/"&gt;store/manage environment variables&lt;/a&gt; in the config file.&lt;/p&gt;</content><summary>Looking for another way to manage tools in nvim</summary></entry><entry><title>Hello Cruel World!</title><link href="https://rogue87.gitlab.io/blog/hello-cruel-world"/><updated>2024-08-03</updated><id>https://rogue87.gitlab.io/blog/hello-cruel-world</id><content type="html">&lt;h2&gt;So what's up?&lt;/h2&gt;
&lt;p&gt;There isn't much. I'm just soo happy that I actually finished making the blogs page work :D&lt;/p&gt;
&lt;p&gt;Initially, I wanted to use a &lt;a href="https://en.wikipedia.org/wiki/Headless_CMS"&gt;headless CMS&lt;/a&gt; for managing my content, but turns out! I'm too poor to afford one, so I'm sticking with &lt;a href="https://en.wikipedia.org/wiki/Static_site_generator"&gt;SSG&lt;/a&gt; for now. I also had the idea to use &lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt; to make my blogs, but honestly I just want something that works, and simple.&lt;/p&gt;
&lt;p&gt;once I'm satisfied with my website, I'll finally start working on some REEEEEAAAAAAL projects. I'm also close to finishing this semester, so I'll get more time to work on stuff.&lt;/p&gt;
&lt;h2&gt;Who are you?&lt;/h2&gt;
&lt;p&gt;Just a random webdev wannabe, but if you wanna know more about me, then check &lt;a href="https://rogue87.gitlab.io/whoami/"&gt;whoami&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;okay I really need to sleep, it's almost 3am lol.&lt;/p&gt;</content><summary>Finally! my actual first post!</summary></entry></feed>