Setup dan Config Neovim Secara Modular di Nixos (LSP, Mason, Telescope, Tresitter, etc)
Cara setup dan config neovim di nixos, lengkap dengan LSP, Mason, Tresitter, Telescope, NeoTree, dll
mrfdn.com - Jika menggunakan neovim, ada 2 cara untuk setup dan config neovim.
Cara pertama, yaitu install neovim, lalu isi config pada folder ~/.config/nvim/
. Ini sama seperti config neovim distro linux pada umumnya.
Cara kedua, yaitu install dan config neovim langsung dari home-manager. Dengan cara ini neovim akan berjalan secara modular.
Tidak perlu lagi menggunakan plugin manager, karena plugin didefinisikan pada konfigurasi nvim di home-manager.
Apa saja yang aktif?
- LSP
- Completion
- Mason
- Tresitter
- Telescope
- Neotree
- Toggleterm
dan banyak lagi…
Di sini saya akan menunjukkan config neovim yang saya definisikan pada nixos flakes saya , silahkan diedit sesuai kebutuhan.
Jadi langsung saja begini caranya:
Folder structure
.
└── home
└── neovim
└── default.nix
├── options.lua
└── plugin
├── cmp.lua
├── lsp.lua
├── telescope.lua
├── toggleterm.lua
└── treesitter.lua
Config default.nix
Pada file default.nix
isi dengan :
{config, pkgs, input, ...}:
{
programs.neovim =
let
toLua = str: "lua << EOF\n${str}\nEOF\n";
toLuaFile = file: "lua << EOF\n${builtins.readFile file}\nEOF\n";
in
{
enable = true;
defaultEditor = true;
withNodeJs = true;
viAlias = true;
vimAlias = true;
extraPackages = with pkgs; [
# install the languages
rnix-lsp
# clipboard tool
xclip
wl-clipboard
cargo
];
plugins = with pkgs.vimPlugins; [
vim-solarized8
# status bar
{
plugin = lualine-nvim;
config = toLua "require(\"lualine\").setup({icons_enabled = true, theme = \'solarized8\'})";
}
# nvim-treesitter.withAllGrammars
neo-tree-nvim
plenary-nvim
nui-nvim
nvim-web-devicons
{
plugin = nvim-treesitter.withAllGrammars;
config = toLuaFile ./plugin/treesitter.lua;
}
# completion
{
plugin = nvim-cmp;
config = toLuaFile ./plugin/cmp.lua;
}
## Snippet Engine & its associated nvim-cmp source
luasnip
cmp_luasnip
## Adds LSP completion capabilities
cmp-nvim-lsp
cmp-path
# Adds a number of user-friendly snippets
friendly-snippets
# LSP
{
plugin = mason-nvim;
config = toLuaFile ./plugin/lsp.lua;
}
mason-lspconfig-nvim
nvim-lspconfig
neodev-nvim
#comment
{
plugin = comment-nvim;
config = toLua "require(\"Comment\").setup()";
}
# telescope
{
plugin = telescope-nvim;
config = toLuaFile ./plugin/telescope.lua;
}
# include this with telescope
telescope-fzf-native-nvim
# toggleterm
{
plugin = toggleterm-nvim;
config = toLuaFile ./plugin/toggleterm.lua;
}
vim-nix
];
extraLuaConfig = ''
${builtins.readFile ./options.lua}
'';
};
}
Options.lua
Kemudian pada file options.lua
set dengan config options lua anda:
-- this is kickstart.nvim from teej
-- Set <space> as the leader key
-- See `:help mapleader`
-- NOTE: Must happen before plugins are required (otherwise wrong leader will be used)
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
-- from my old option config
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv")
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv")
vim.keymap.set("n", "J", "mzJ`z")
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
vim.keymap.set("n", "n", "nzzzv")
vim.keymap.set("n", "N", "Nzzzv")
-- greatest remap ever
vim.keymap.set("x", "<leader>p", [["_dP]])
-- next greatest remap ever : asbjornHaland
vim.keymap.set({"n", "v"}, "<leader>y", [["+y]])
vim.keymap.set("n", "<leader>Y", [["+Y]])
vim.keymap.set({"n", "v"}, "<leader>d", [["_d]])
-- This is going to get me cancelled
vim.keymap.set("i", "<C-c>", "<Esc>")
vim.keymap.set("n", "Q", "<nop>")
vim.keymap.set("n", "<leader>f", vim.lsp.buf.format)
vim.keymap.set("n", "<C-k>", "<cmd>cnext<CR>zz")
vim.keymap.set("n", "<C-j>", "<cmd>cprev<CR>zz")
vim.keymap.set("n", "<leader>k", "<cmd>lnext<CR>zz")
vim.keymap.set("n", "<leader>j", "<cmd>lprev<CR>zz")
vim.keymap.set("n", "<leader>x", "<cmd>!chmod +x %<CR>", { silent = true })
-- Navigate vim panes better
vim.keymap.set('n', '<c-k>', ':wincmd k<CR>')
vim.keymap.set('n', '<c-j>', ':wincmd j<CR>')
vim.keymap.set('n', '<c-h>', ':wincmd h<CR>')
vim.keymap.set('n', '<c-l>', ':wincmd l<CR>')
-- call neotree
vim.keymap.set('n', '<F4>', ':Neotree right toggle<CR>')
vim.o.relativenumber = true -- set relative numbered lines
vim.g.maplocalleader = ' '
vim.o.backspace = '2'
vim.o.showcmd = true
vim.o.laststatus = 2
vim.o.autoread = true
vim.o.shiftround = true
vim.o.pumheight = 10 -- pop up menu height
vim.o.showmode = false -- we don't need to see things like -- INSERT -- anymore
vim.o.splitbelow = true -- force all horizontal splits to go below current window
vim.o.splitright = true -- force all vertical splits to go to the right of current window
vim.o.swapfile = false -- creates a swapfile
vim.o.writebackup = false -- if a file is being edited by another program (or was written to file while editing with another program), it is not allowed to be edited
vim.o.expandtab = true -- convert tabs to spaces
vim.o.shiftwidth = 4 -- the number of spaces inserted for each indentation
vim.o.tabstop = 4 -- insert 2 spaces for a tab
vim.o.conceallevel = 0
vim.o.wrap = false -- display lines as one long line
vim.o.linebreak = true -- companion to wrap, don't split words
vim.o.scrolloff = 8 -- minimal number of screen lines to keep above and below the cursor
vim.o.sidescrolloff = 8 -- minimal number of screen columns either side of cursor if wrap is `false`
vim.o.guifont = "monospace:h17" -- the font used in graphical neovim applications
vim.o.whichwrap = "bs<>[]hl" -- which "horizontal" keys are allowed to travel to prev/next line
-- end from my option config
-- Set highlight on search
vim.o.hlsearch = false
-- Make line numbers default
vim.wo.number = true
-- Enable mouse mode
vim.o.mouse = 'a'
-- Sync clipboard between OS and Neovim.
-- Remove this option if you want your OS clipboard to remain independent.
-- See `:help 'clipboard'`
vim.o.clipboard = 'unnamedplus'
-- Enable break indent
vim.o.breakindent = true
-- Save undo history
vim.o.undofile = true
-- Case-insensitive searching UNLESS \C or capital in search
vim.o.ignorecase = true
vim.o.smartcase = true
-- Keep signcolumn on by default
vim.wo.signcolumn = 'yes'
-- Decrease update time
vim.o.updatetime = 250
vim.o.timeoutlen = 300
-- Set completeopt to have a better completion experience
vim.o.completeopt = 'menuone,noselect'
-- NOTE: You should make sure your terminal supports this
vim.o.termguicolors = true
-- set solarize color scheme
-- vim.cmd("set background=dark")
vim.cmd.colorscheme 'solarized8'
-- teej kickstart feature
-- [[ Highlight on yank ]]
-- See `:help vim.highlight.on_yank()`
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true })
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
group = highlight_group,
pattern = '*',
})
-- Lualine
-- require("lualine").setup({
-- icons_enabled = true,
-- -- theme = 'onedark',
-- -- theme = 'solarized',
-- })
Completion
Kemudian pada file plugin/cmp.lua
isi dengan ini:
-- teej kickstart neovim completion config
-- nvim-cmp supports additional completion capabilities, so broadcast that to servers
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities)
-- [[ Configure nvim-cmp ]]
-- See `:help cmp`
local cmp = require 'cmp'
local luasnip = require 'luasnip'
require('luasnip.loaders.from_vscode').lazy_load()
luasnip.config.setup {}
cmp.setup {
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
completion = {
completeopt = 'menu,menuone,noinsert',
},
mapping = cmp.mapping.preset.insert {
['<C-n>'] = cmp.mapping.select_next_item(),
['<C-p>'] = cmp.mapping.select_prev_item(),
['<C-b>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete {},
['<CR>'] = cmp.mapping.confirm {
behavior = cmp.ConfirmBehavior.Replace,
select = true,
},
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { 'i', 's' }),
['<S-Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.locally_jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { 'i', 's' }),
},
sources = {
{ name = 'nvim_lsp' },
{ name = 'luasnip' },
{ name = 'path' },
},
}
LSP
Kemudian pada file plugin/lsp.lua
isi dengan ini:
-- before setting up the servers.
require('mason').setup()
require('mason-lspconfig').setup()
local servers = {
lua_ls = {
Lua = {
workspace = { checkThirdParty = false },
telemetry = { enable = false },
},
},
}
-- Setup neovim lua configuration
require('neodev').setup()
-- nvim-cmp supports additional completion capabilities, so broadcast that to servers
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities)
-- Ensure the servers above are installed
local mason_lspconfig = require 'mason-lspconfig'
mason_lspconfig.setup {
ensure_installed = vim.tbl_keys(servers),
}
mason_lspconfig.setup_handlers {
function(server_name)
require('lspconfig')[server_name].setup {
capabilities = capabilities,
on_attach = on_attach,
settings = servers[server_name],
filetypes = (servers[server_name] or {}).filetypes,
}
end,
}
Telescope
Pada file plugin/telescope.lua
isi dengan config ini:
require('telescope').setup({
extensions = {
fzf = {
fuzzy = true, -- false will only do exact matching
override_generic_sorter = true, -- override the generic sorter
override_file_sorter = true, -- override the file sorter
case_mode = "smart_case", -- or "ignore_case" or "respect_case"
-- the default case_mode is "smart_case"
}
}
})
local builtin = require('telescope.builtin')
--vim.keymap.set('n', '<c-p>', builtin.find_files, {})
vim.keymap.set('n', '<Space>ff', builtin.find_files, {})
vim.keymap.set('n', '<Space><Space>', builtin.oldfiles, {})
vim.keymap.set('n', '<Space>fg', builtin.live_grep, {})
vim.keymap.set('n', '<Space>fh', builtin.help_tags, {})
require('telescope').load_extension('fzf')
Toggleterm
local status_ok, toggleterm = pcall(require, "toggleterm")
if not status_ok then
return
end
toggleterm.setup({
size = 10,
open_mapping = [[<c-\>]], -- then to open new terminal type 2<c-\>, 3<c-\> and so on
hide_numbers = true,
shade_filetypes = {},
shade_terminals = true,
shading_factor = 2,
start_in_insert = true,
insert_mappings = true,
persist_size = true,
direction = "horizontal",
close_on_exit = true,
shell = vim.o.shell,
float_opts = {
border = "curved",
winblend = 0,
highlights = {
border = "Normal",
background = "Normal",
},
},
})
function _G.set_terminal_keymaps()
local opts = {noremap = true}
vim.api.nvim_buf_set_keymap(0, 't', '<esc>', [[<C-\><C-n>]], opts)
vim.api.nvim_buf_set_keymap(0, 't', 'jk', [[<C-\><C-n>]], opts)
vim.api.nvim_buf_set_keymap(0, 't', '<C-h>', [[<C-\><C-n><C-W>h]], opts)
vim.api.nvim_buf_set_keymap(0, 't', '<C-j>', [[<C-\><C-n><C-W>j]], opts)
vim.api.nvim_buf_set_keymap(0, 't', '<C-k>', [[<C-\><C-n><C-W>k]], opts)
vim.api.nvim_buf_set_keymap(0, 't', '<C-l>', [[<C-\><C-n><C-W>l]], opts)
end
vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')
local Terminal = require("toggleterm.terminal").Terminal
local lazygit = Terminal:new({ cmd = "lazygit", hidden = true })
function _LAZYGIT_TOGGLE()
lazygit:toggle()
end
-- vim.api.nvim_set_keymap("n", "<leader>tg", "<cmd>lua _lazygit_toggle()<CR>", {noremap = true, silent = true})
local node = Terminal:new({ cmd = "node", hidden = true })
function _NODE_TOGGLE()
node:toggle()
end
vim.api.nvim_set_keymap("n", "<leader>tn", "<cmd>lua _NODE_TOGGLE()<CR>", {noremap = true, silent = true})
local ncdu = Terminal:new({ cmd = "ncdu", hidden = true })
function _NCDU_TOGGLE()
ncdu:toggle()
end
local htop = Terminal:new({ cmd = "htop", hidden = true })
function _HTOP_TOGGLE()
htop:toggle()
end
local python = Terminal:new({ cmd = "python", hidden = true })
function _PYTHON_TOGGLE()
python:toggle()
end
Treesitter
-- teej kickstart neovim config
vim.defer_fn(function()
require('nvim-treesitter.configs').setup {
-- Add languages to be installed here that you want installed for treesitter
-- ensure_installed = { 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'javascript', 'typescript', 'vimdoc', 'vim', 'bash' },
ensure_installed = {},
-- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!)
auto_install = false,
highlight = { enable = true },
indent = { enable = true },
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<c-space>',
node_incremental = '<c-space>',
scope_incremental = '<c-s>',
node_decremental = '<M-space>',
},
},
textobjects = {
select = {
enable = true,
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
keymaps = {
-- You can use the capture groups defined in textobjects.scm
['aa'] = '@parameter.outer',
['ia'] = '@parameter.inner',
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
},
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
[']m'] = '@function.outer',
[']]'] = '@class.outer',
},
goto_next_end = {
[']M'] = '@function.outer',
[']['] = '@class.outer',
},
goto_previous_start = {
['[m'] = '@function.outer',
['[['] = '@class.outer',
},
goto_previous_end = {
['[M'] = '@function.outer',
['[]'] = '@class.outer',
},
},
swap = {
enable = true,
swap_next = {
['<leader>a'] = '@parameter.inner',
},
swap_previous = {
['<leader>A'] = '@parameter.inner',
},
},
},
}
end, 0)
Demikian full setup config neovim secara modular pada nixos.
Inspirasi mendapatkan config ini adalah dari nvim.kickstart.