A bit more lua in your vim

November 13, 2019

Following up on the previous entry about lua in vim, in this one I document other ways in which I used lua to improve my setup.

Anyone using Neovim should know that it has support for floating windows: real windows that can float around. You can do all kinds of cool stuff with it. Here it is in action:

So this is how the story begins: one day my friend, and teammate, Miguel was showing me something on his computer, when I saw him doing something like this:

asciicast

He was opening fzf inside a floating window! I immediately ran to my desk and copied the code that does this from his dotfiles. The relevant parts are here and here. He got it somewhere from the Github.

I was in love with this for a while!… Until I realized that it didn’t work great when I was using Vim in smaller tmux splits. I need something more “intelligent” that took into account the editor’s size. Since my VimScript skills are non-existent, I replaced his implementation with Lua.

Here’s what I want:

  • if the editor is small (when I’m in a split with 1/4 of the screen’s size) it uses a full window instead of a floating one.
  • the floating window’s width is 90% of the editor’s width, but if the editor’s width is small, it uses full width minus 4 columns from each side.
  • a floating window’s height is 3/4 of the editor’s height to a max of 30 lines.

The code, with comments, so it’s easier to understand:

function NavigationFloatingWin()
  -- get the editor's max width and height
  local width = vim.api.nvim_get_option("columns")
  local height = vim.api.nvim_get_option("lines")

  -- create a new, scratch buffer, for fzf
  local buf = vim.api.nvim_create_buf(false, true)
  vim.api.nvim_buf_set_option(buf, 'buftype', 'nofile')

  -- if the editor is big enough
  if (width > 150 or height > 35) then
    -- fzf's window height is 3/4 of the max height, but not more than 30
    local win_height = math.min(math.ceil(height * 3 / 4), 30)
    local win_width

    -- if the width is small
    if (width < 150) then
      -- just subtract 8 from the editor's width
      win_width = math.ceil(width - 8)
    else
      -- use 90% of the editor's width
      win_width = math.ceil(width * 0.9)
    end

    -- settings for the fzf window
    local opts = {
      relative = "editor",
      width = win_width,
      height = win_height,
      row = math.ceil((height - win_height) / 2),
      col = math.ceil((width - win_width) / 2)
    }

    -- create a new floating window, centered in the editor
    local win = vim.api.nvim_open_win(buf, true, opts)
  end
end

To make it work, place the code in a file such as ~/.config/nvim/lua/navigation/init.lua, and in your vim configuration put something like this:

" load lua functions for navigation
lua require("navigation")
let g:fzf_layout = { 'window': 'lua NavigationFloatingWin()' }

Once again, I know that you can do this with VimScript, but I can’t. And, because I know there are more like me out there, I hope this helps you, and my future self as well.

Do have a comment or a question? I'm on twitter: @gabrielgpoca..