DEV Community

Marcell Cruz
Marcell Cruz

Posted on • Updated on

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
Image description

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 and create a file there or use the file that you already have to create a function, just to test things out.

we can create a function to open a pop up menu using plenary.popup, you need to install neovim plenary if you don't already have it here's the link https://github.com/nvim-lua/plenary.nvim, here's the function to show a popup menu using neovim plenary

local popup = require("plenary.popup")

local Win_id

function 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 })
end
Enter fullscreen mode Exit fullscreen mode

The 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 q

vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "<cmd>lua CloseMenu()<CR>", { silent=false })
Enter fullscreen mode Exit fullscreen mode

This part can also be a little confusing.
and the following is the code to close the UI

function CloseMenu()
  vim.api.nvim_win_close(Win_id, true)
end
Enter fullscreen mode Exit fullscreen mode

this is the function that we gonna call when we hit q when the pop up menu is openened

Now let's create another function to call the function that shows the menu

function MyMenu() 
  local opts = {}
  local cb = function(_, sel)
    print("it works")
  end
  ShowMenu(opts, cb)
end
Enter fullscreen mode Exit fullscreen mode

We not gonna do anything here for now just open the menu with nothing inside it and then you can close the menu by hitting q

After 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 this

Image description

there'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 this

function MyMenu()
  local opts = {
    "/home/me/myproject1",
    "/home/me/myproject2",
    "/home/me/myproject3",
  }
........
Enter fullscreen mode Exit fullscreen mode

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 now

Image description

Awesome!

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)
end
Enter fullscreen mode Exit fullscreen mode

if 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/myproject3
Enter fullscreen mode Exit fullscreen mode

now we can read this file and add to the options like this

local file = io.open("~/projects", "r") -- Open the file in read mode
local opts = {}
if file then
  for line in file:lines() do
    table.insert(opts, line)
  end
end
--- pass the opts to the file later
Enter fullscreen mode Exit fullscreen mode

the 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 project

vim.keymap.set("n", "<leader>o", '<cmd>lua MyMenu()<CR>')
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)