(non) Tech Self Notes / Setting Up Neovim as a Universal IDE

Step-by-step Neovim setup with LSP, Tree-sitter, and autocompletion for HTML, CSS, JavaScript, Python, PHP, Go, templates, and system configurations.

Goal

Configure Neovim on Artix Linux as a fast and lightweight IDE for modern languages and technologies, including:


Environment preparation

sudo pacman -S neovim git nodejs npm go python-pip php composer docker xclip

Set up user-scoped npm:

mkdir -p ~/.local/npm-global
npm config set prefix ~/.local/npm-global

In ~/.zshrc or ~/.bashrc add:

export PATH="$HOME/.local/npm-global/bin:$PATH"

Then:

source ~/.zshrc  # or ~/.bashrc

Install global npm packages

npm install -g \
  typescript typescript-language-server \
  graphql-language-service-cli \
  vscode-langservers-extracted \
  emmet-ls bash-language-server \
  @tailwindcss/language-server \
  yaml-language-server \
  dockerfile-language-server-nodejs

Neovim config structure

Create the config file:

mkdir -p ~/.config/nvim
nvim ~/.config/nvim/init.lua

init.lua contents:

-- Initialize Lazy package manager
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git", "clone", "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git", lazypath
  })
end
vim.opt.rtp:prepend(lazypath)

-- Plugins
require("lazy").setup({
  "neovim/nvim-lspconfig",
  { "williamboman/mason.nvim", build = ":MasonUpdate" },
  "williamboman/mason-lspconfig.nvim",
  "hrsh7th/nvim-cmp",
  "hrsh7th/cmp-nvim-lsp",
  "L3MON4D3/LuaSnip",
  "saadparwaiz1/cmp_luasnip",
  { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate" },
  "lumiliet/vim-twig",
  "jwalton512/vim-blade",
  "mustache/vim-mustache-handlebars",
  "chr4/nginx.vim",
})

-- Mason and LSP setup
require("mason").setup()
require("mason-lspconfig").setup({
  ensure_installed = {
    "pyright", "ts_ls", "html", "cssls", "emmet_ls",
    "graphql", "phpactor", "gopls", "dockerls", "yamlls", "bashls"
  }
})

local lspconfig = require("lspconfig")
local capabilities = require("cmp_nvim_lsp").default_capabilities()
for _, lsp in ipairs({
  "pyright", "ts_ls", "html", "cssls", "emmet_ls",
  "graphql", "phpactor", "gopls", "dockerls", "yamlls", "bashls"
}) do
  lspconfig[lsp].setup({ capabilities = capabilities })
end

-- Tree-sitter configuration
require("nvim-treesitter.configs").setup {
  ensure_installed = {
    "bash", "lua", "json", "yaml", "toml", "dockerfile",
    "python", "php", "go", "graphql",
    "html", "css", "scss", "javascript", "typescript", "tsx",
    "gotmpl"
  },
  highlight = {
    enable = true,
    additional_vim_regex_highlighting = false,
  },
}

-- Completion
local cmp = require("cmp")
cmp.setup({
  snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end },
  mapping = cmp.mapping.preset.insert({
    ['<Tab>'] = cmp.mapping.select_next_item(),
    ['<S-Tab>'] = cmp.mapping.select_prev_item(),
    ['<CR>'] = cmp.mapping.confirm({ select = true }),
  }),
  sources = {
    { name = "nvim_lsp" },
    { name = "luasnip" },
  },
})

-- Filetype detection for templates and configs
vim.filetype.add({
  pattern = {
    ['.*%.txp%.html'] = 'html',
    ['.*nginx%.conf'] = 'nginx',
    ['.*%.nginx'] = 'nginx',
    ['.*httpd%.conf'] = 'apache',
  },
})

-- Editor UI settings
vim.opt.scrolloff = math.floor(vim.o.lines / 2)
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.mouse = "" -- allows X11 mouse selection
vim.opt.clipboard = "unnamed" -- for "*y to work properly

Mouse selection and X11 buffer

If mouse selection inside Neovim does not copy text to the X11 buffer, it’s due to mouse capture mode inside the editor.

I use visual mode and:

vselect
"*y → copy to X11 PRIMARY buffer

The * register corresponds to the PRIMARY buffer used in X11 mouse selections. Make sure Neovim is compiled with +clipboard support and X11 is active. In vim type: :version. The output must contain:

+clipboard

Completion

After launching nvim, plugins will install automatically. To install Go I ran sudo pacman -S go. After that I ran vim, opened Mason with :Mason, selected gopls, and pressed i to install the Go LSP server.

Now I have a full-featured, multi-language IDE based on Neovim!