How To Create An UI Menu In Neovim
Tags: vim, neovim, editor, lua
Published: 2023-06-02 02:26:44

---
title: How To Create An UI Menu In Neovim
published: true
description: Let's Create a UI Menu In Neovim 
tags: vim,neovim,editor,lua
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-06-02 01:34 +0000
---

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99fa4lz1vfyji8e76ham.jpg)

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
```lua
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
```
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
```lua
vim.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 UI
```
function CloseMenu()
  vim.api.nvim_win_close(Win_id, true)
end
```
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

```lua
function MyMenu() 
  local opts = {}
  local cb = function(_, sel)
    print("it works")
  end
  ShowMenu(opts, cb)
end
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpca7iq56mnncqrh2i0a.jpg)

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
```lua
function 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 now

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nmjxc60top0k0rrghsth.jpg)

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.
```lua
local cb = function(_, sel)
  vim.cmd("cd " .. sel)
end
```
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
```
now we can read this file and add to the options like this
```lua
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
```
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>')
```

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