Back to articles

How To Create An UI Menu In Neovim

One of the great things about neovim is the ability to easilty create plugins using lua, lua is a very simple language and the way that it's integrated with neovim is really straight foward, when neovim is initiated it reads a file called init.lua in one of the paths configured, you can check the path by opening neovim and typing :h rtp for run time path you should see something like this the first path is the one that matters for us, it means that neovim will search for the file inside ~/nvim we can then go ahead the create a file there or use the file that you already have to create a function, just to test thingswe can create a function to open a pop up menu using plenary.popup like this, you need to install neovim plenary if you don't already have it https://github.com/nvim-lua/plenary.nvimlocal popup = require("plenary.popup")local Win_idfunction ShowMenu(opts, cb) local height = 20 local width = 30 local borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" } Win_id = popup.create(opts, { title = "MyProjects", highlight = "MyProjectWindow", line = math.floor(((vim.o.lines - height) / 2) - 1), col = math.floor((vim.o.columns - width) / 2), minwidth = width, minheight = height, borderchars = borderchars, callback = cb, }) local bufnr = vim.api.nvim_win_get_buf(Win_id) vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "<cmd>lua CloseMenu()<CR>", { silent=false })endthe code is pretty self explanatory the only part that is a little confusing is the cb parameter, this parameter is the function that you gonna call when someone intereact with the popup menu, also we create a keymap for the popup buffer to close the popup when you hit qvim.api.nvim_buf_set_keymap(bufnr, "n", "q", "<cmd>lua CloseMenu()<CR>", { silent=false })this part can also be a little confusing.and the following is the code to close the UIfunction CloseMenu() vim.api.nvim_win_close(Win_id, true)endthis is the function that we gonna call when we hit q when the pop up menu is openenedNow let's create another function to call the function that shows the menufunction MyMenu() local opts = {} local cb = function(_, sel) print("it works") end ShowMenu(opts, cb)endWe not gonna do anything here for now just open the menu with nothing inside and then you can close the menu by hitting qafter writing this data to ~/nvim/init.lua you can load the file by running :so then you can run :lua MyMenu() to call the function and show the menu, you should see something like thisthere's cool but not useful, how do we add data inside the menu? we can add data there the same way that we do in any buffer, just by setting lines of text, the plugin that we gonna build is just a list of projects that we can chose from and the cd in to the project from vim.we can add the lines of text by filling out opts the variable that we pass to the menu like thisfunction MyMenu() local opts = { "/home/me/myproject1", "/home/me/myproject2", "/home/me/myproject3", }........this is just a list of things to show in the menu if you do that you should be able to see a list of those things nowAwesome!We're almost there, now we just need to do something when someone choses one of the thing in the list, we can do that in the cb that we pass to the function.local cb = function(_, sel) vim.cmd("cd " .. sel)endif you hit enter on top of one of the lines, that line will be passed to this function and then we'll change neovim current directory to that path, in our example the paths aren't real but you get the idea, you just need to put a real path there, and that should do it, one upgrade that we can do is to load a file with paths instead of hardcoding the paths in the function, that way you don't need to open this lua file everytime you want to add a project to your list of projects, we can do that just by reading a simple file with a list of projects, same a list of project in ~/projects/home/me/myproject1/home/me/myproject2/home/me/myproject3now we can read this file and add to the options like thislocal file = io.open("~/projects", "r") -- Open the file in read modelocal opts = {}if file then for line in file:lines() do table.insert(opts, line) endend--- pass the opts to the file laterthe last thing we need to do is map this function to a shortcut that way we can hit the short cut and show the menu where we can chose our projectvim.keymap.set("n", "<leader>o", '<cmd>lua MyMenu()<CR>')and that's pretty much it, after you have a way of creating a menu you can thing about a lot of interesint things todo the idea presented here is just to show a easy way of creating a menu in neovim, you can use lua to do anything that you want
#lua
02 June 2023
vote
comment0