Explore the transition to Lua support in Neovim configurations. Follow along as settings are tweaked and personalized, discovering plugin choices, themes, and the challenges faced along the way.
Disclaimer: I am not proficient in Lua. If there are any mistakes, please inform me.
Prologue
I’ve been using Vim for many years since my college days, during which time I’ve also developed several plugins1 2 for my personal use. Then, driven by curiosity, I switched to using Neovim about two years ago3. Most of the configurations and plugins were migrated from Vim. Fortunately, the legacy tools are still working.
Lua for Neovim
Let’s talk about now. Many new, advanced tools are being made for Neovim. Using Lua is a big change for Neovim, and lots of plugins are being redone in Lua. Some only show how to use Lua. I only knew a bit about Lua—it’s a type of code often used for making games, known for being light and easy to manage compared to Vimscript. (I get that spending time learning a language, like Vimscript, just for a text editor might seem a bit silly. But since I don’t use Lua every day, it might be the second language I learn just for an editor…)
I like using fancy plugins. However, to use those Lua plugins, I have to change the init system. I’ve made three or four attempts to convert my legacy settings to the Lua version, but it was quite painful. I believe a breakdown is necessary. I understand the benefit of Lua, especially its module system, which allows easy importing of various modules from files. However, after many years of using Vim, the experience made me gradually attempt to consolidate all settings into one file4.
Thus, let’s start from scratch.
$ mv ~/.config/nvim ~/.config/nvim_goodbye_vimscript
My environments
- Ubuntu 20.04
- WSL2 with Ubuntu 20.04
- Rust: website
Recommended font
- ryanoasis/nerd-fonts; My choice: CascadiaCode.zip
- Install Caskaydia Cove Nerd Font Complete Mono Regular, Italic, Bold
Preinstall packages
$ sudo apt install lldb # lldb tool for rustaceanvim
$ sudo apt install build-essential cmake # for compiling rust package
$ curl -L https://deb.nodesource.com/nsolid_setup_deb.sh | sudo bash -s -- 20 && sudo apt install -y nodejs # nodejs for mason-lspconfig.nvim
$ cargo install stylua # to format lua code
$ cargo install tree-sitter-cli # for nvim-treesitter/nvim-treesitter
$ cargo install ripgrep # for telescope 's live_grep
$ rustup component add rust-src rust-analyzer # for mrcjkb/rustaceanvim
Install Neovim
I have tried using apt, snap, and binary downloading, all of which have been messy. Recently, I found a tool that seems to be a good choice for installing Neovim, and that tool is bob (Install Rust environment first). Uninstalling your old Neovim is recommanded before you run following commands.
$ cargo install bob-nvim
$ bob install 0.9.4
$ bob use 0.9.4
$ bob ls
┌───────────┬─────────────┐
│ Version │ Status │
├───────────┼─────────────┤
│ v0.9.4 │ Used │
└───────────┴─────────────┘
$ echo "export PATH=\$PATH:\$HOME/.local/share/bob/nvim-bin" >> ~/.bashrc
Setup for Virtual Environment
Install pyenv and target python version
$ sudo apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev curl libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev # https://github.com/pyenv/pyenv/wiki#suggested-build-environment
$ sudo apt install unzip # lsp clangd
$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
$ echo 'export PATH="/home/'`whoami`'/.pyenv/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
$ source ~/.bashrc
$ pyenv install --list | grep " 3\.[8]"
$ pyenv install -v 3.8.10
Setup for neovim
$ pyenv virtualenv 3.8.10 neovim3
$ pyenv activate neovim3
$ ~/.pyenv/versions/neovim3/bin/python -m pip install pynvim
Config via Lua
$ mkdir ~/.config/nvim -p
$ vim ~/.config/nvim/init.lua
Mapping from VimL to Lua
key-value assignment
The global set is changed to vim.opt
.
set tabstop=4
set softtabstop=4
vim.opt.tabstop = 4
vim.opt.softtabstop = 4
on/off setting
Same as key-value set.
" nobackup + writebackup = backup current file, deleted afterwards (default)
set nobackup
set writebackup
-- nobackup + writebackup = backup current file, deleted afterwards (default)
vim.opt.backup = false
vim.opt.writebackup = true
value append
" let labels not auto indent
set cinoptions+=L0
-- let labels not auto indent
vim.opt.cinoptions:append({ "L0" })
global, plugin functions
line("$")
codeium#Accept()
vim.fn.line("$")
vim.fn["codeium#Accept"]()
exec normal
:exec "normal! \zz"
vim.cmd.normal('\zz"')
autocmd
" let cursor in the middle of screen when entering vim
autocmd VimEnter * :exec "normal! \zz"
" return to last edit position when opening files
autocmd BufReadPost *
\ if line("'\"") > 0 && line("'\"") <= line('$') |
\ exe "normal! g`\"" |
\ endif
local autocmd = vim.api.nvim_create_autocmd -- Create autocommand
-- let cursor in the middle of screen when entering vim
autocmd("VimEnter", { command = vim.cmd.normal('\zz"') })
-- return to last edit position when opening files
autocmd("BufReadPost", {
callback = function()
if vim.fn.line("'\"") > 0 and vim.fn.line("'\"") <= vim.fn.line("$") then
vim.cmd.normal('g`"')
end
end,
})
keymap
" cancel highlight after searching
noremap <M-n> :noh<CR>
" background vim
inoremap <C-z> <C-o><C-z>
-- " cancel highlight after searching
vim.keymap.set("n", "<M-n>", ":noh<CR>",
{ noremap = true, desc = "Cancel highlight" })
-- background vim in insert mode
vim.keymap.set("i", "<C-z>", "<C-o><C-z>",
{ noremap = true, desc = "Background vim in insert mode" })
Plugins
The plugin manager comes first. I’ve opted for lazy.nvim, which doesn’t need an ‘install’ command. Great choice. For the editor’s appearance, I’ve been using gruvbox for about a year. It has a nice color setting. My plugins are functioning well, and I might add the comment format for Lua5. Telescope serves as a powerful search tool with a fuzzy finder, making it a smart replacement for my limited brain power. LSP configuration is quite challenging. I’m struggling to find a simple, unified example for setup. I’m starting to miss coc.vim…
Plugin Manager: Lazy.nvim
Automatically install all listed plugins. Use :Lazy check
to manually verify the updates for the installed plugins.
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",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
Selected plugins
ellisonleao/gruvbox.nvim
: colorschemefolke/neodev.nvim
: neovimrhysd/committia.vim
: git commit message editorlewis6991/gitsigns.nvim
: git inline statusRRethy/vim-illuminate
: automatically highlighting other uses of the word under the cursorkarb94/neoscroll.nvim
: smooth scrollingalpertuna/vim-header
: header of the filelukas-reineke/indent-blankline.nvim
: improved Yggdroot/indentLinetpope/vim-sleuth
: automatically adjusts ‘shiftwidth’ and ’expandtab’aben20807/vim-runner
: My muscle for runneraben20807/vim-commenter
: My muscle for code commentnvim-telescope/telescope.nvim
: improved junegunn/fzfjustinmk/vim-sneak
: the missing motion for Vimmbbill/undotree
: undo historyfolke/which-key.nvim
: helpnvim-treesitter/nvim-treesitter
: syntaxExafunction/codeium.vim
: AI codingneovim/nvim-lspconfig
: LSPhrsh7th/nvim-cmp
: completionnvim-lualine/lualine.nvim
: status line
One for All: init.lua
Show the full configuration (init.lua
)
--[[--
File : init.lua
Author : Huang, Po-Hsuan <aben20807@gmail.com>
Last Modified Date: 2023-11-09 09:58:25
--]]
-- "alpertuna/vim-header" --
vim.g.header_field_author = "Huang, Po-Hsuan"
vim.g.header_field_author_email = "aben20807@gmail.com"
vim.g.mapleader = " "
-- Setup for Virtual Environment
vim.g.python3_host_prog = "~/.pyenv/versions/neovim3/bin/python"
-- "aben20807/vim-commenter" --
vim.g.commenter_use_default_mapping = false
--------------------
-- Plugin 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",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
--------------------
-- Plugins --
--------------------
require("lazy").setup({
{
"ellisonleao/gruvbox.nvim",
priority = 1000,
config = function()
vim.o.background = "dark"
vim.cmd([[colorscheme gruvbox]])
end,
opts = ...,
},
{ "folke/neodev.nvim", opts = {} },
{
-- git commit message editor
"rhysd/committia.vim",
event = 'BufEnter',
},
{
"lewis6991/gitsigns.nvim",
event = 'BufEnter',
config = function()
require('gitsigns').setup()
end
},
{
-- automatically highlighting other uses of the word under the cursor
"RRethy/vim-illuminate",
event = 'BufEnter',
},
{
-- smooth scrolling
"karb94/neoscroll.nvim",
event = 'BufEnter',
config = function()
require("neoscroll").setup()
end,
},
{
"alpertuna/vim-header",
event = 'BufEnter',
config = function()
vim.g.header_field_timestamp_format = "%Y-%m-%d %H:%M:%S"
vim.g.header_field_timestamp = 0
vim.g.header_field_modified_by = 0
vim.keymap.set("n", "<F4>", ":AddHeader<CR>", { desc = "Add Header" })
end,
},
{
"lukas-reineke/indent-blankline.nvim",
main = "ibl",
opts = {},
config = function()
require("ibl").setup()
end,
},
{
-- automatically adjusts 'shiftwidth' and 'expandtab'
"tpope/vim-sleuth",
},
{
"aben20807/vim-runner",
event = 'BufEnter',
config = function()
-- c
vim.g.runner_c_executable = "gcc-8"
vim.g.runner_c_compile_options = "-std=gnu99 -Wall -O2"
-- c++
vim.g.runner_cpp_executable = "g++-8"
vim.g.runner_cpp_compile_options = "-std=c++17 -Wall -lm -O2 -pipe"
end,
},
{
"aben20807/vim-commenter",
event = 'BufEnter',
config = function()
vim.keymap.set("n", "<C-j>", ":<C-u>call commenter#Comment()<CR>", { noremap = true, desc = "Comment" })
vim.keymap.set("i", "<C-j>", "<ESC>l:<C-u>call commenter#Comment()<CR>i",
{ noremap = true, desc = "Comment" })
vim.keymap.set("v", "<C-j>", ":<C-u>call commenter#CommentV(visualmode())<CR>",
{ noremap = true, desc = "Comment" })
end,
},
{
"nvim-telescope/telescope.nvim",
tag = "0.1.4",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
local builtin = require("telescope.builtin")
vim.keymap.set("n", "<leader>ff", builtin.find_files, { desc = "Find files" })
vim.keymap.set("n", "<leader>fg", builtin.live_grep, { desc = "Live grep" })
vim.keymap.set("n", "<leader>fb", builtin.buffers, { desc = "Find buffers" })
vim.keymap.set("n", "<leader>fh", builtin.help_tags, { desc = "Help tags" })
end,
},
{
"justinmk/vim-sneak",
event = 'BufEnter',
config = function()
vim.cmd("let g:sneak#s_next = 1")
end,
},
{
"mbbill/undotree",
config = function()
vim.keymap.set("n", "<leader>un", vim.cmd.UndotreeToggle, { desc = "Toggle undotree" })
end,
},
{
"folke/which-key.nvim",
event = "VeryLazy",
init = function()
vim.o.timeout = true
vim.o.timeoutlen = 300
end,
},
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
local configs = require("nvim-treesitter.configs")
configs.setup({
ensure_installed = { "c", "cpp", "lua", "vim", "vimdoc", "rust", "gitcommit", "make", "python" },
sync_install = false,
highlight = { enable = true },
indent = { enable = true },
})
end,
},
{
"Exafunction/codeium.vim",
branch = "main",
event = 'BufEnter',
config = function()
vim.g.codeium_no_map_tab = true
vim.keymap.set("i", "<C-g>", function()
return vim.fn["codeium#Accept"]()
end, { expr = true, desc = "Accept [AI]" })
vim.keymap.set("i", "<c-t>", function()
return vim.fn["codeium#CycleCompletions"](1)
end, { expr = true, desc = "Next [AI]" })
vim.keymap.set("i", "<c-b>", function()
return vim.fn["codeium#CycleCompletions"](-1)
end, { expr = true, desc = "Prev [AI]" })
vim.keymap.set("i", "<c-x>", function()
return vim.fn["codeium#Clear"]()
end, { expr = true, desc = "Clear [AI]" })
end,
},
{
"neovim/nvim-lspconfig",
dependencies = {
{
"williamboman/mason-lspconfig.nvim",
dependencies = { "williamboman/mason.nvim" },
},
{
"mrcjkb/rustaceanvim",
version = "^3", -- Recommended
ft = { "rust" },
dependencies = { "mfussenegger/nvim-dap" },
},
},
opts = {
inlay_hints = { enabled = true },
},
config = function()
require("mason").setup({
PATH = "prepend", -- "skip" seems to cause the spawning error
})
require("mason-lspconfig").setup({
ensure_installed = {
-- "rust_analyzer",
"pyright",
"marksman",
"bashls",
"clangd",
"lua_ls",
},
-- handlers = {
-- rust_analyzer = function() end, -- use rustaceanvim
-- },
})
local lspconfig = require("lspconfig")
-- lspconfig.rust_analyzer.setup({})
lspconfig.pyright.setup({})
lspconfig.marksman.setup({})
lspconfig.bashls.setup({})
lspconfig.clangd.setup({})
lspconfig.lua_ls.setup({
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = "LuaJIT",
},
diagnostics = {
-- https://github.com/neovim/neovim/issues/21686
-- Get the language server to recognize the `vim` global
globals = {
"vim",
"buffer",
"require",
},
},
-- Do not send telemetry data containing a randomized but unique identifier
telemetry = {
enable = false,
},
hint = { enable = true },
},
},
})
end,
},
{
"https://git.sr.ht/~whynothugo/lsp_lines.nvim",
config = function()
require("lsp_lines").setup()
vim.diagnostic.config({
virtual_text = false,
})
vim.keymap.set("n", "<Leader>l", require("lsp_lines").toggle, { desc = "Toggle lsp_lines" }
)
end,
},
{
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-nvim-lua",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-cmdline",
-- luasnip
"saadparwaiz1/cmp_luasnip",
"L3MON4D3/LuaSnip",
-- "simrat39/rust-tools.nvim",
},
config = function()
--Set completeopt to have a better completion experience
-- :help completeopt
-- menuone: popup even when there's only one match
-- noinsert: Do not insert text until a selection is made
-- noselect: Do not select, force to select one from the menu
-- shortness: avoid showing extra messages when using completion
-- updatetime: set updatetime for CursorHold
vim.opt.completeopt = { "menuone", "noselect", "noinsert" }
vim.opt.shortmess = vim.opt.shortmess + { c = true }
vim.api.nvim_set_option("updatetime", 300)
vim.diagnostic.config({
virtual_text = false,
signs = true,
update_in_insert = true,
underline = true,
severity_sort = false,
float = {
border = "rounded",
source = "always",
header = "",
prefix = "",
format = function(diagnostic)
return string.format(
"%s (%s) [%s]",
diagnostic.message,
diagnostic.source,
diagnostic.code or diagnostic.user_data.lsp.code
)
end,
},
})
vim.keymap.set('n', '<space>e', vim.diagnostic.open_float, { desc = "Open diagnostic [CMP]" })
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = "Previous diagnostic [CMP]" })
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = "Next diagnostic [CMP]" })
vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist, { desc = "Open diagnostics list [CMP]" })
local cmp = require("cmp")
cmp.setup({
-- Enable LSP snippets
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
mapping = {
["<S-Tab>"] = cmp.mapping.select_prev_item(),
["<Tab>"] = cmp.mapping.select_next_item(),
["<C-S-f>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.close(),
["<CR>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Insert,
select = true,
}),
},
-- Installed sources:
sources = {
{ name = "path" }, -- file paths
{ name = "nvim_lsp", keyword_length = 3 }, -- from language server
{ name = "nvim_lsp_signature_help" }, -- display function signatures with current parameter emphasized
{ name = "nvim_lua", keyword_length = 2 }, -- complete neovim's Lua runtime API such vim.lsp.*
{ name = "buffer", keyword_length = 2 }, -- source current buffer
{ name = "vsnip", keyword_length = 2 }, -- nvim-cmp source for vim-vsnip
{ name = "calc" }, -- source for math calculation
},
window = {
completion = cmp.config.window.bordered(),
documentation = cmp.config.window.bordered(),
},
formatting = {
fields = { "menu", "abbr", "kind" },
format = function(entry, item)
local menu_icon = {
nvim_lsp = "L",
vsnip = "S",
buffer = "B",
path = "P",
}
item.menu = menu_icon[entry.source.name]
return item
end,
},
})
-- local rt = require("rust-tools")
-- rt.setup({
-- server = {
-- on_attach = function(_, bufnr)
-- -- Hover actions
-- vim.keymap.set("n", "<C-space>", rt.hover_actions.hover_actions,
-- { buffer = bufnr, desc = "Hover actions [RUST]" })
-- -- Code action groups
-- vim.keymap.set("n", "<Leader>aa", rt.code_action_group.code_action_group,
-- { buffer = bufnr, desc = "Code action groups [RUST]" })
-- end,
-- },
-- })
end,
},
{
'nvim-lualine/lualine.nvim',
requires = { 'nvim-tree/nvim-web-devicons', opt = true },
config = function()
require('lualine').setup {
options = {
icons_enabled = true,
theme = 'gruvbox',
component_separators = { left = '', right = '' },
section_separators = { left = '', right = '' },
disabled_filetypes = {
statusline = {},
winbar = {},
},
ignore_focus = {},
always_divide_middle = true,
globalstatus = false,
refresh = {
statusline = 1000,
tabline = 1000,
winbar = 1000,
}
},
sections = {
lualine_a = { { 'mode', fmt = function(str) return str:sub(1, 1) end } },
lualine_b = { 'branch', {
'diff',
symbols = { added = '+', modified = '~', removed = '-' },
}, {
'diagnostics',
symbols = { error = 'E', warn = 'W', info = 'I', hint = 'H' },
} },
lualine_c = { 'filename' },
lualine_x = { 'encoding', 'fileformat', 'filetype' },
lualine_y = { 'progress' },
lualine_z = { 'location' }
},
inactive_sections = {
lualine_a = {},
lualine_b = {},
lualine_c = { 'filename' },
lualine_x = { 'location' },
lualine_y = {},
lualine_z = {}
},
tabline = {},
winbar = {},
inactive_winbar = {},
extensions = {}
}
end
},
})
------------
-- Keymap --
------------
vim.keymap.set("n", "<leader>pv", vim.cmd.Ex, { desc = "Open file explorer" })
-- background vim in insert mode
vim.keymap.set("i", "<C-z>", "<C-o><C-z>", { noremap = true, desc = "Background vim in insert mode" })
-- indent
vim.keymap.set("n", "<", "<<", { desc = "Indent left" })
vim.keymap.set("n", ">", ">>", { desc = "Indent right" })
vim.keymap.set("v", "<", "<gv", { desc = "Indent left" })
vim.keymap.set("v", ">", ">gv", { desc = "Indent right" })
-- move screen smoothly
vim.keymap.set("n", "<up>", ":lua require('neoscroll').scroll(-0.10, false, 100)<CR>",
{ noremap = true, desc = "Scroll up" })
vim.keymap.set("n", "<down>", ":lua require('neoscroll').scroll(0.10, false, 100)<CR>",
{ noremap = true, desc = "Scroll down" })
vim.keymap.set("n", "<C-up>", ":lua require('neoscroll').scroll(-vim.wo.scroll, true, 200)<CR>",
{ noremap = true, desc = "Scroll up multiline" })
vim.keymap.set("n", "<C-down>", ":lua require('neoscroll').scroll(vim.wo.scroll, true, 200)<CR>",
{ noremap = true, desc = "Scroll down multiline" })
-- left and right can switch buffers
vim.keymap.set("n", "<left>", ":bp<CR>", { noremap = true, desc = "Previous buffer" })
vim.keymap.set("n", "<right>", ":bn<CR>", { noremap = true, desc = "Next buffer" })
-- Move by line
vim.keymap.set("n", "j", "(v:count == 0 ? 'gj' : 'j')", { silent = true, expr = true, remap = false })
vim.keymap.set("n", "k", "(v:count == 0 ? 'gk' : 'k')", { silent = true, expr = true, remap = false })
-- Search results centered please
vim.keymap.set("n", "n", "nzz", { noremap = true, silent = true })
vim.keymap.set("n", "N", "Nzz", { noremap = true, silent = true })
vim.keymap.set("n", "*", "*zz", { noremap = true, silent = true })
vim.keymap.set("n", "#", "#zz", { noremap = true, silent = true })
vim.keymap.set("n", "g*", "g*zz", { noremap = true, silent = true })
-- " cancel highlight after searching
vim.keymap.set("n", "<M-n>", ":noh<CR>", { noremap = true, desc = "Cancel highlight" })
-- " search select text by pressing // in visual mode
-- " Ref: http://vim.wikia.com/wiki/Search_for_visually_selected_text
vim.keymap.set("v", "//", "y/<C-r>=escape(@\",'/')<CR><CR>", { noremap = true, desc = "Search select text" })
-- " map ctrl-a to select whole text
vim.keymap.set("n", "<C-a>", "ggVG", { noremap = true, desc = "Select whole text" })
-- Not overwrite paste buffer after pasting
vim.keymap.set("x", "p", "P", { noremap = true, desc = "Paste without overwriting buffer" })
if vim.lsp.inlay_hint then
vim.keymap.set("n", "<leader>in", function()
vim.lsp.inlay_hint(0, nil)
end, { desc = "Toggle Inlay Hints" })
end
vim.keymap.set("n", "<leader>gD", vim.lsp.buf.declaration,
{ noremap = true, silent = true, desc = "Go to declaration [LSP]" })
vim.keymap.set("n", "<leader>gd", vim.lsp.buf.definition,
{ noremap = true, silent = true, desc = "Go to definition [LSP]" })
vim.keymap.set("n", "<leader>gi", vim.lsp.buf.implementation,
{ noremap = true, silent = true, desc = "Go to implementation [LSP]" })
vim.keymap.set("n", "<leader>gr", vim.lsp.buf.references,
{ noremap = true, silent = true, desc = "Go to references [LSP]" })
vim.keymap.set("n", "<leader>gy", vim.lsp.buf.type_definition,
{ noremap = true, silent = true, desc = "Go to type definition [LSP]" })
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, { noremap = true, silent = true, desc = "Rename [LSP]" })
vim.keymap.set("n", "<leader>fs", vim.lsp.buf.format, { noremap = true, silent = true, desc = "Format [LSP]" })
----------------
-- Automation --
----------------
-- https://github.com/brainfucksec/neovim-lua/blob/dc7ba6f850bd576b3777ab56d081aa845ed5c946/nvim/lua/core/autocmds.lua
local augroup = vim.api.nvim_create_augroup -- Create/get autocommand group
local autocmd = vim.api.nvim_create_autocmd -- Create autocommand
-- Highlight on yank
augroup("YankHighlight", { clear = true })
autocmd("TextYankPost", {
group = "YankHighlight",
callback = function()
vim.highlight.on_yank({ higroup = "IncSearch", timeout = "1000" })
end,
})
-- Don't auto commenting new lines
autocmd("BufEnter", {
pattern = "",
command = "set fo-=c fo-=r fo-=o",
})
-- let cursor in the middle of screen when entering vim
autocmd("VimEnter", { command = vim.cmd.normal('\zz"') })
-- return to last edit position when opening files
autocmd("BufReadPost", {
callback = function()
if vim.fn.line("'\"") > 0 and vim.fn.line("'\"") <= vim.fn.line("$") then
vim.cmd.normal('g`"')
end
end,
})
-- Autoformat on save
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = buffer,
callback = function()
vim.lsp.buf.format { async = false }
end
})
-- Check if file changed on disk
autocmd("FileChangedShellPost", {
callback = function()
vim.api.nvim_echo({ { "File changed on disk. Buffer reloaded.", "WarningMsg" } }, true, {})
vim.api.nvim_command('checktime')
end
})
-- Set up a timer to run the 'fresh' function every 5000 milliseconds
local timer = vim.loop.new_timer()
timer:start(5000, 0, vim.schedule_wrap(function()
-- Check if buffer "[Command Line]" exists and then perform a checktime
if vim.fn.bufexists("[Command Line]") == false then
vim.api.nvim_command('checktime')
end
end))
------------
-- Editor --
------------
-- https://github.com/arturgoms/nvim/blob/a8c23e36010746c6bc8e6b6b567433894833ca1d/lua/user/options.lua
local options = {
updatetime = 300, -- faster completion (4000ms default)
autoindent = true, -- copy indent from current line when starting new
smartindent = true, -- make indenting smarter again
timeoutlen = 1000, -- time to wait for a mapped sequence to complete (in milliseconds)
encoding = "utf-8", -- the encoding written to a file
fileencoding = "utf-8", -- the encoding written to a file
scrolloff = 2, -- minimal number of screen lines to keep above and below the cursor
showmode = false, -- we don't need to see things like -- INSERT -- anymore
hidden = true, -- allow buffer switching without saving
wrap = false, -- don't wrap lines
joinspaces = false, -- insert two spaces after a '.', '?' and '!'
signcolumn = "yes", -- always show the sign column, otherwise it would shift the text each time
splitright = true, -- force all vertical splits to go to the right of current window
splitbelow = true, -- force all horizontal splits to go below current window
incsearch = true, -- incremental search
ignorecase = true, -- ignore case
smartcase = true, -- smart case
gdefault = true, -- use g flag on search
-- nobackup + writebackup = backup current file, deleted afterwards (default)
backup = false,
writebackup = true,
swapfile = false,
tabstop = 4, -- insert 4 spaces for a tab
softtabstop = 4, -- insert 4 spaces for a tab
expandtab = true, -- convert tabs to spaces
shiftwidth = 4, -- the number of spaces inserted for each indentation
virtualedit = "onemore", -- allow the cursor to move just past the end of the line
mouse = "a", -- allow the mouse to be used in neovim
cmdheight = 1, -- more space in the neovim command line for displaying messages
cursorline = true, -- highlight the current line
termguicolors = true, -- set term gui colors (most terminals support this)
number = true, -- set numbered lines
numberwidth = 4, -- set number column width to 2 {default 4}
conceallevel = 0, -- so that `` is visible in markdown files
history = 1000, -- sets how many lines of history VIM has to remember
modifiable = true, -- allow changing the buffer
autoread = true, -- automatically read changed files
}
for k, v in pairs(options) do
vim.opt[k] = v
end
vim.opt.wildignore:append({ "*.o", "*.obj", "*.pyc" })
-- let labels not auto indent
vim.opt.cinoptions:append({ "L0" })
------------
-- Legacy --
------------
vim.api.nvim_exec(
[[
" let undo history not be clear after changing buffer
" Ref: https://stackoverflow.com/a/22676189/6734174
let vimDir = '$HOME/.config/nvim/'
let &runtimepath .= ',' . vimDir
" Keep undo history across sessions by storing it in a file
if has('persistent_undo')
let myUndoDir = expand(vimDir . '/undodir')
" Create dirs
silent! call mkdir(myUndoDir, 'p')
let &undodir = myUndoDir
set undofile
set undolevels=1000
set undoreload=10000
endif
" TMUX key
" Ref: https://superuser.com/a/402084
if &term =~ '^screen'
" tmux will send xterm-style keys when its xterm-keys option is on
execute "set <xUp>=\e[1;*A"
execute "set <xDown>=\e[1;*B"
execute "set <xRight>=\e[1;*C"
execute "set <xLeft>=\e[1;*D"
endif
]],
false
)
----------------------
-- disable provider --
----------------------
vim.g.loaded_node_provider = 0
vim.g.loaded_perl_provider = 0
vim.g.loaded_ruby_provider = 0
:Codeium Auth
: add token from the given url
Epilogue
Finally, all configurations are in place. However, these settings might undergo frequent modifications as I use this version. The journey to transition to Lua support has been lengthy but rewarding. Let’s continue to explore and refine.
Chat-GPT has fine-tuned some grammar and words in this post.