Lets focus on some appearance
nvim-web-devicons - this is in so many packages as an “optional” item, but it makes it look so nice when you have these UI elements. Because this is with so many other packages, we will start here.
For any NVim plugin using Lazy, you need to return a lua table. A lua table is very straightforward, its like a JSON object, where you have the curly braces, some key value pairs, can contain strings, numbers, arrays (which are also defined by having square brackets) and booleans. Alsoa lua table can also contain lua functions as a value that is being passed.
I am not a lua expert, I know more than enough, but I won’t get into too much detail here. More on the little that I do know in another post. NOTE that a comment in lua is preceeded by a double dash -- and can be inline. And unlike JSON, a lua table is still part of the programming language so it can’t be condensed down to one long line effectively.
The minimum that is needed for any plugin, is just the statement return {}. Inside those curly braces is where the table goes.
For nvim-web-devicons all we need is the following saved into a file named nvim-web-devicons.lua in the plugins/ directory ( ~/.config/nvim/lua/plugins/nvim-webdevicons.lua ).
return {
"nvim-tree/nvim-web-devicons",
}
Here we see the return statement, followed by those curly braces, which also closes out the file as well. Then on the next line its the reference to the plugin.
I believe that Lazy, as well as other packages, inject ‘https://www.github.com/' before that string. So this means that the plugin should be found on github publicly open sourced and not bitbucket or gitlab or local. I believe if you do want to source from a local directory or another repo network you have to have the full path. This is interesting to me as I will research this more.
Going to any of these github pages is easy, and you can find the install and config options for each one there as well. Not every repo will have a ton of information and install or config options for Lazy.
What this will do is generate icons based on certain things for you. If you have “tabs” at the top to show the different buffers in NVim, it will help detect the file type and display the appropriate icon. If you have an explorer tree, it will show an icon next to all the files. If you have a status line with directories and branches and the file it will do the same thing there as well. And many more locations will this popup. I like the icons as a visual indicator, some don’t. All this will appear in those locations assuming you have the plugin and you configure the plugin to do that. You can easily have buffers displayed as “tabs” without icons and still have it look nice, if you don’t configure that options.
NOTE: tabs in Vim are different than the normal tabs we talk about with browsers and windows and such, but that is another post, but I will use the term “tabs” so a beginner knows what is implied and a more experienced person hopefully knows its not a legit Vim thing).
With this plugin, I went over more than normal, but its a very basic plugin and its a good thing to start with. Additionally, I probably explained things backwards.
Looking at the documentation we can do A TON more config with it, such as making custom icons and colors for different situations, but for now we will leave it as is.
gitsigns
gitSigns is similar to nvim-web-devicons except that its specific to git and the actions associated with it.
NOTE: I am curious if nvim-web-devicons has a set of git icons or not.
Again, same directory, plugins/ or ~/.config/nvim/lua/plugins/ create a file named gitsigns.lua and have the following code.
-- git commit, and also lets you interactively stage & unstage
-- hunks in a commit.
return {
"lewis6991/gitsigns.nvim",
event = "LazyFile",
opts = {
signs = {
add = { text = "▎" },
change = { text = "▎" },
delete = { text = "" },
topdelete = { text = "" },
changedelete = { text = "▎" },
untracked = { text = "▎" },
},
on_attach = function(buffer)
local gs = package.loaded.gitsigns
local function map(mode, l, r, desc)
vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc })
end
-- stylua: ignore start
map("n", "]h", gs.next_hunk, "Next Hunk")
map("n", "[h", gs.prev_hunk, "Prev Hunk")
map({ "n", "v" }, "<leader>ghs", ":Gitsigns stage_hunk<CR>", "Stage Hunk")
map({ "n", "v" }, "<leader>ghr", ":Gitsigns reset_hunk<CR>", "Reset Hunk")
map("n", "<leader>ghS", gs.stage_buffer, "Stage Buffer")
map("n", "<leader>ghu", gs.undo_stage_hunk, "Undo Stage Hunk")
map("n", "<leader>ghR", gs.reset_buffer, "Reset Buffer")
map("n", "<leader>ghp", gs.preview_hunk, "Preview Hunk")
map("n", "<leader>ghb", function() gs.blame_line({ full = true }) end, "Blame Line")
map("n", "<leader>ghd", gs.diffthis, "Diff This")
map("n", "<leader>ghD", function() gs.diffthis("~") end, "Diff This ~")
map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns Select Hunk")
end,
},
}
Here we see so much more. We start off the same way with that string reference for the repo, and then we move to more code.
Some of this is from Lazy, and some is from the code repo.
The line right after the repo has the key “event” and says “LazyFile”. LazyFile is a shortcut in LazyVim for the event { "BufReadPost", "BufWritePost", "BufNewFile" } and defers and re-triggers. This is when the buffer is read or written or buffer creates a new file.
We will look more into this in a different post. In general, there are few different options, and you can also have a function as an option to really customize things.
After that is the opts section. Here you will see the options for the config that is defined based on the actual repo. As previously said, every repo is a little different and many don’t have it listed specifically for Lazy, but that is Ok as the spec options listed should go within here.
Inside the “opts” you will notice there is different “options” for a config.
One of the major things here is the map functions. These Map keybindings for different actions related to that sepecific plugin. How awesome is that. This can be placed here, or very often its moved to a different keybindings.lua folder that is often in a config folder.
Not much of a change yet, but some foundation is laid.
Now lets start to r ll…
Lualine
This is where things start to become visual. The first two were merely to to look and explain how the whole plugin thing works.
The Lualine is the status line. Initially it is set at the bottom and gives you some good information. It tells you what mode you are in (which is a huge relief for those of use noobs out there), the branch, directory, file, git status, and more. TRhere is some great themes with this.
return {
"nvim-lualine/lualine.nvim",
enabled = true,
dependencies = {
"nvim-tree/nvim-web-devicons",
},
event = "VeryLazy",
opts = {
options = {
icons_enabled = true,
theme = "onedark", -- "wombat",
},
},
init = function()
vim.g.lualine_laststatus = vim.o.laststatus
if vim.fn.argc(-1) > 0 then
-- set an empty statusline till lualine loads
vim.o.statusline = " "
else
-- hide the statusline on the starter page
vim.o.laststatus = 0
end
end,
}
Check out the themes page with this. I personally can’t decide what theme I like best, I have a few top ones.
If you open up NVim right now with these 3 plugins, you will be able to see the status line at the bottom with some icons based on the file and if that is in a git repo you will see some icons related to that as well.
You can also see some great functions and actions you can do by going through the options. You like your git status on the left, great you can do that.
Addition to the options, we see a couple other new things in the config.
First we see the enabled = true. This is not needed, because typically if you want a plugin, you have it in the folder and its automatically enabled. However, by adding this line and toggling it from true/false you can turn off that specific plugin. Maybe you are making some config adjustments and changes, this is great as you can have 2 files and one will be the “old” and the other will be the “new” then you can see which works and how. This is beneficial if you see a few different plugins and aren’t sure which one you like better as well.
Next after that is the dependencies = { "nvim-tree/nvim-web-devicons" } . If there is any dependencies, load them here. NVim will make sure these get loaded first before these. You may have noticed this is the first plugin we loaded. While its not required to load it even if its a “dependency” like above, by loading it in the plugins folder we get the option to make it clean with any additional options we may want. This is great, as the alternative to just leaving it in that “dependencies” section is to get the default, which is usually good enough. For this example, its more than good enough and even overkill for nvim-web-devicons. The point of that though was to get use to the syntax and the folders and where everything resides and how things work.
After that, we see opts section, which we can get from the repo’s readme.
Then we have an init section, which is a lua function. the init section can be used for any repo, only the parts inside the opts are specific to the plugin and stated in the repo. This specific init function is documented, and states what its doing…its showing a blank statusline until this plugin loads. If its the starter page, it doesn’t show the lualine statusline at all. Neat!
This should start to look a little different.
Regarding the “theme” option. This is more for a color base, imho. As you can change the location of any of those items at anytime in your own custom config block relatively easy. I would even recommend doing that based on your workflow. Look into each of those “themes” at the code level, or even the examples, and for the most part its just color options mixed with some separators. A few cool functions to look into as well.
Bufferline
When learning about Vim and NVim, the two things that I missed the most were the Status line and the Buffer Line. Changing the appearance of the statusline with Lualine drew attention to the mode you were in, and other options (like file name and status) that you are so used to seeing in other editors. Bufferline will change the appearance of the line of buffers. Or in noob speak, the tabs across the top for files that are open. After adjusting the Bufferline, things will start to look like a a very familiar IDE.
-- This is what powers LazyVim's fancy-looking
-- tabs, which include filetype icons and close buttons.
return {
"akinsho/bufferline.nvim",
event = "VeryLazy",
version = "*",
enabled = true,
dependencies = {
"nvim-tree/nvim-web-devicons"
},
keys = {
{ "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", desc = "Toggle pin" },
{ "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", desc = "Delete non-pinned buffers" },
{ "<leader>bo", "<Cmd>BufferLineCloseOthers<CR>", desc = "Delete other buffers" },
{ "<leader>br", "<Cmd>BufferLineCloseRight<CR>", desc = "Delete buffers to the right" },
{ "<leader>bl", "<Cmd>BufferLineCloseLeft<CR>", desc = "Delete buffers to the left" },
{ "<S-h>", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev buffer" },
{ "<S-l>", "<cmd>BufferLineCycleNext<cr>", desc = "Next buffer" },
{ "[b", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev buffer" },
{ "]b", "<cmd>BufferLineCycleNext<cr>", desc = "Next buffer" },
},
opts = {
options = {
-- stylua: ignore
close_command = function(n) require("mini.bufremove").delete(n, false) end,
-- stylua: ignore
right_mouse_command = function(n) require("mini.bufremove").delete(n, false) end,
diagnostics = "nvim_lsp",
always_show_bufferline = false,
diagnostics_indicator = function(_, _, diag)
local icons = require("lazyvim.config").icons.diagnostics
local ret = (diag.error and icons.Error .. diag.error .. " " or "")
.. (diag.warning and icons.Warn .. diag.warning or "")
return vim.trim(ret)
end,
offsets = {
{
filetype = "neo-tree",
text = "Neo-tree",
highlight = "Directory",
text_align = "left",
},
},
},
},
config = function(_, opts)
require("bufferline").setup(opts)
-- Fix bufferline when restoring a session
vim.api.nvim_create_autocmd("BufAdd", {
callback = function()
vim.schedule(function()
pcall(nvim_bufferline)
end)
end,
})
end,
}
This is where the key mapping could get really ugly.
I do like to have other keymappings for something like this. I do use the tree / explorer, and you will see more of those mappings coming up.
Something that you will notice the functions for when the buffer for requiring “mini.bufremove”, which is another plugin. Its not a visual thing, but a functional thing. What these will do is allow you to interact with the buffer “tabs” and close them when you click on the “X” there.
mini.bufremove
alpha-nvim dashboard these are both really great, however I rarely, if ever see that “home screen” as some would call it. That initial screen when opening NVim that is not a directory or a file. If I am opening any IDE, I am getting right to work and not marveling at some ascii art and looking at options. I do want to marvel at ascii art, but not at the moment. Though I do recommend everyone decide for themselves and see what they want and marvel at the ascii art that people have created.
nui.nvim dressing.nvim nvim-notify
These you won’t see right away, but they will help with so much. This an alert or popup for various functions.
indent-blankline this is isimilar to the mini-indentscope, escept that it shows the indent for all indents. This is great when you have a long function or loop or even some json with a large structure and you want to see the indents. Its also very useful for those pesky python indentations. Use this in conjunction with mini-indentscope and you will see all the tab spacing.
mini-indentscope
I like to see the lines, for indentation. I know not everyone does, but I find this is very useful when navigating through a large file and trying to match up what is where. Especially if you have something like a Python file that uses the indents as a mechanism to determine which scope those lines are in. This will highlight the line tab line the cursor is on, making it easy to scope where you are.
mini-animate This is a cool ui thing, no image to show, but this will show an animation to the cursor position from a previous prosition when certain things happen.
theme!!! Onedarkpro.nvim
treesitter / nvim-treesitter syntax hylighting
which-key awesome helper
edgy
coding X mini.pairs X mini.surround nvim-ts-context-commentstring ??? X mini.comment
coding assistance mini.ai X codeium copilot tabnine nvim-cmp - autocomplete help
cut/copy/paste mode - yank/put
yanky
native_snippets
LuaSnip - snippets
editor
x neo-tree
nvim-spectre
telescope
flash - enhance search function
vim-illuminate - highlightes other instances of the word under cursor
mini.bufremove
trouble - diagnostics
todo-comments
aerial
leap
mini-files
navic
symbols-outline
nvim-window-picker
formatting conform none-ls mason
lint nvim-lint
util
vim-startuptime
persistence
plenary
nvim-dap
lsp nvim-lspconfig mason
RESEARCH
- airline vs lualine