Giter Site home page Giter Site logo

hovercraft.nvim's Introduction

hovercraft.nvim

hovercraft.nvim is a plug and play framework for writing custom hover provider. It brings a few providers out of the box, such as a LSP, as well as a Dictionary.

It allows for basic customizations of the hover window (such as defining custom borders, set the max width and so on).

This plugin is heavily inspired by hover.nvim! Many kudos to lewis6991 for providing inspiration.

Setup

via lazy.nvim:

{
  'patrickpichler/hovercraft.nvim',

  dependencies = {
    { 'nvim-lua/plenary.nvim' },
  },

  -- this is the default config and can be skipped
  opts = function()
    return {
      providers = {
        providers = {
          {
            'LSP',
            require('hovercraft.provider.lsp.hover').new(),
          },
          {
            'Man',
            require('hovercraft.provider.man').new(),
          },
          {
            'Dictionary',
            require('hovercraft.provider.dictionary').new(),
          },
        }
      },

      window = {
        border = 'single',
      },

      keys = {
        { '<C-u>',   function() require('hovercraft').scroll({ delta = -4 }) end },
        { '<C-d>',   function() require('hovercraft').scroll({ delta = 4 }) end },
        { '<TAB>',   function() require('hovercraft').hover_next() end },
        { '<S-TAB>', function() require('hovercraft').hover_next({ step = -1 }) end },
      }
    }
  end,

  keys = {
    { "K", function()
      local hovercraft = require("hovercraft")

      if hovercraft.is_visible() then
        hovercraft.enter_popup()
      else
        hovercraft.hover()
      end
    end },
  },
}

Configuration

Show hover dialog

There are various ways of displaying the hover popup. The simplest is the hover method. It takes an option table, that allows you to specify what provider should be shown.

Example:

require('hovercraft').hover({ current_provider = "LSP" })

If you want to cycle through all available providers, hovercraft offers a hover_next function. It takes options to specify how many steps it should move forward from the current shown provider. This also allows for negative steps, to cycle backwards. You can disable the cycling by setting cycle = false.

Example:

require('hovercraft').hover_next({ step = -1, cycle = false })

Last, but not least, you can also let hovercraft open the vim selection dialog, so that you can choose which provider to show. This is archieved by the hover_select method.

Example:

require('hovercraft').hover_select()

Keys

The keys you specify in the keys section of the config, are automatically mounted, as soon as a hovercraft popup is shown. Once the popup is hidden again, the previous keymappings will be re-installed. This allows you to overload certain keys.

Tab order

The order of tabs is controlled by the priority you can pass in either via the config table, or the register function When you omit it, hovercraft.nvim will automatically handle it for you.

For the config table, the priority will be based the index of the provider. The exact formula is 90000 + (i * 10). This means that the first provider in the provider map will have a priority of 90000 + (1 * 10) = 90010.

If you register a provider via the register function and you omit the priority, hovercraft.nvim will take the highest know priority (it starts with 1000 though) and adds 10. This might be subject to change, since I need to see if this works as nicely as hoped.

Local instances

hovercraft.nvim features both a global instance, as well as local instances. This means, that if you want to configure a special hovercraft for e.g. a certain set of buffer, you can do this. Simply call require('hovercraft.instance').new(<opts>) to create a new instance. It behaves the same as the global instance, only that of course all methods must be called on it.

Example:

local my_hovercraft = require('hovercraft.instance').new({
    providers = {
        providers = {
            {'Dictionary', require('hovercraft.provider.dictionary').new()}
        }
    }
})

vim.keymap.set('n', '<leader>k', function() my_hovercraft:hover() end)

Enter focus popup when already displayed

hovercraft.nvim doesn't provide an out of the box way of focusing an already visible popup, but it can be easily achieved with some custom code. Simply bind the following function to whatever key you like:

function()
  local hovercraft = require('hovercraft')

  if hovercraft.is_visible() then
    hovercraft.enter_popup()
  else
    hovercraft.hover()
  end
end

Here is the full example how to use it with lazy.nvim:

{
  'patrickpichler/hovercraft.nvim',

  keys = {
    { 'K', function()
      local hovercraft = require('hovercraft')

      if hovercraft.is_visible() then
        hovercraft.enter_popup()
      else
        hovercraft.hover()
      end
    end },
  },
}

Providers

LSP

require('hovercraft.provider.lsp.hover')

Builtin LSP

Dictionary

require('hovercraft.provider.dictionary')

Shows definitions for valid words, by querying dictionaryapi.dev

ManPage

require('hovercraft.provider.man')

Shows man page definitions of word under cursor for C, sh, zsh, tcl, fish and make.

Github Issue

require('hovercraft.provider.github.issue')

Shows details about the issue under the cursor. It gets enabled for either #(\d+), which will try to get the issue details by figuring out the current github repo, or (\w+)/(\w+)#(\d+), which specifies the repo of the issue.

The logic for detecting the current Github project is based the remotes of the local git project. We fetch the current remote url by running git ls-remote --get-url. Then we try to extract the Github repo name. If the repo has no issues enabled, we try getting it from the parent repository.

Github Repo

require('hovercraft.provider.github.repo')

Fetches details about the repo from Github and diplays them. You can disable fetching the repo readme by passing in fetch_readme = false when calling the new method on the provider.

Examples for when this provider activates:

Github User

require('hovercraft.provider.github.user')

Fetches details about the user from Github and display them. The regex for it to trigger is something along the line of (?:TODO|FIX|FIXME)\(@?([\w_-]*)\). It also works for organizations.

Here are some examples:

  • https://github.com/neovim
  • -- TODO(@patrichpichler): this is a test

Git Blame

require('hovercraft.provider.git.blame')

Shows details from Git blame about the current line.

You can disble it to also display the commit message, by passing in show_commit_message=false when constructing the provider.

Diagnostics

require('hovercraft.provider.git.blame')

Shows details about reported diagnostics for the current position.

Creating a custom hover provider

There are multiple ways of registering a custom hover provider. The simplest is by passing in a function as the second argument in the providers array. hovercraft.nvim expects the following function signature:

---@alias Hovercraft.Provider.Function fun(opts: Hovercraft.Provider.ExecuteOptions, done: fun(result:Hovercraft.Provider.ExecuteResult))

--- @class Hovercraft.Provider.ExecuteOptions
--- @field bufnr integer
--- @field pos {[1]: integer, [2]: integer} tuple of [row, col]
--
--- @class Hovercraft.Provider.ExecuteResult
--- @field lines? string[]
--- @field filetype? string

The done callback is required to communicate back results, as the function will be called asynchronous.

Besides a function, you can also pass it a table that implements the provider interface. Here is the interface definition:

---@alias Hovercraft.Provider.ExecuteFunction fun(self: Hovercraft.Provider, opts?: Hovercraft.Provider.ExecuteOptions, done: fun(result: Hovercraft.Provider.ExecuteResult))

---@class Hovercraft.Provider
---@field is_enabled fun(self: Hovercraft.Provider, bufnr: integer): boolean
---@field execute Hovercraft.Provider.ExecuteFunction

The most notable difference is, that with a table provider, you have the possibility to enable it based on the is_enabled function returning true.

Here is an example:

dummy_text.lua

local M = {}

local Provider = {}
Provider.__index = Provider

function Provider:is_enabled()
  return true
end

function Provider:execute(_, done)
  done({ lines = self.lines, filetype = self.filetype })
end

function M.new(lines, filetype)
  filetype = filetype or 'markdown'

  return setmetatable({
    lines = lines,
    filetype = filetype
  }, Provider)
end

return M
{
  'patrickpichler/hovercraft.nvim',

  dependencies = {
    { 'nvim-lua/plenary.nvim' },
  },

  -- this is the default config and can be skipped
  opts = function()
    return {
      providers = {
        providers = {
          {
            'Dummy',
            function(opts, done)
              done({ lines = { 'This', 'is *great*' }, filetype = 'markdown' })
            end,
          },
          {
            'Dummy1',
            require('dummy').new({ 'Hello' })
          },
        }
      },
    }
  end,
}

Why

A few weeks ago I discovered hover.nvim and thought the idea is amazing! Sadly it didn't fully fit my workflow. Since I wanted to get more into neovim plugin development, I thought this is it. Hence I created hovercraft.nvim.

hovercraft.nvim's People

Contributors

patrickpichler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hovercraft.nvim's Issues

Sometimes I get an error when hovering over things that might not return anything

Here I attempted to hover over a comment (lmao don't ask why)

Error executing vim.schedule lua callback: ...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:18: The coroutine failed with this message: ...lar/neovim/0.9.5/share/nvim/runtime/lua/vim/lsp/util.lua:1682: 'width' key must be a positive Integer
stack traceback:
	[C]: in function 'error'
	...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:18: in function 'callback_or_next'
	...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:45: in function 'done'
	...zy/hovercraft.nvim/lua/hovercraft/provider/lsp/hover.lua:43: in function 'handler'
	...azy/hovercraft.nvim/lua/hovercraft/provider/lsp/util.lua:74: in function 'handler'
	...w/Cellar/neovim/0.9.5/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
	vim/_editor.lua: in function <vim/_editor.lua:0>

Multiple errors when setting up the hovercraft

Hi, I configured hovercraft following the examples of the repository, but when i try to use any of this functions i have similar errors, this is my config:

{
    "patrickpichler/hovercraft.nvim",
    lazy = true,
    event = "BufRead",
    dependencies = {
      { "nvim-lua/plenary.nvim" },
    },
    opts = function()
      local opts = {}
      -- local hc = require "hovercraft"
      local wk = require "which-key"
      opts.providers = {
        providers = {
          {
            "LSP",
            require("hovercraft.provider.lsp.hover").new(),
          },
          {
            "Man",
            require("hovercraft.provider.man").new(),
          },
          {
            "Dictionary",
            require("hovercraft.provider.dictionary").new(),
          },
        },
      }
      opts.window = {
        border = "single",
      }
      -- opts.keys = {}

      wk.register {
        ["<C-p>"] = { function() require("hovercraft").scroll { delta = -4 } end, "Scroll up" },
        ["<C-i>"] = { function() require("hovercraft").scroll { delta = 4 } end, "Scroll down" },
        ["<TAB>"] = { function() require("hovercraft").hover_next() end, "Next hover" },
        ["<S-TAB>"] = {
          function() require("hovercraft").hover_next { step = -1 } end,
          "Previous hover",
        },
      }

      return opts
    end,
  },

i have this error whit every function:

E5108: Error executing lua: ...local/share/nvim/lazy/hovercraft.nvim/lua/hovercraft.lua:32: attempt to call field 'unpa
ck' (a nil value)
stack traceback:
        ...local/share/nvim/lazy/hovercraft.nvim/lua/hovercraft.lua:32: in function 'hover_next'
        /home/gus/.config/nvim/lua/plugins/hovercraft.lua:38: in function </home/gus/.config/nvim/lua/plugins/hovercraf
t.lua:38>

image

Error When Customizing `providers` Section in `hovercraft.nvim` Configuration

Issue Description:
When using the default configuration for the hovercraft.nvim plugin, everything works as expected. However, customizing the providers section in the configuration leads to an error upon restarting Neovim.

Configuration Causing the Issue:

{
    'patrickpichler/hovercraft.nvim',
    dependencies = { { 'nvim-lua/plenary.nvim' } },
    opts = {
        providers = {
            providers = {
                { 'LSP', require('hovercraft.provider.lsp').new() },
                { 'Man', require('hovercraft.provider.man').new() },
                { 'Dictionary', require('hovercraft.provider.dictionary').new() },
            }
        },
    },
}

Error Message:

Error detected while processing /Users/andreaventi/.config/nvim/init.lua:
Failed to load `user.plugins.user`

~/.config/nvim/lua/user/plugins/user.lua:332: module 'hovercraft.provider.lsp' not found:
^Ino field package.preload['hovercraft.provider.lsp']
cache_loader: module hovercraft.provider.lsp not found
cache_loader_lib: module hovercraft.provider.lsp not found
^Ino file './hovercraft/provider/lsp.lua'
^Ino file '/opt/homebrew/share/luajit-2.1/hovercraft/provider/lsp.lua'
^Ino file '/usr/local/share/lua/5.1/hovercraft/provider/lsp.lua'
^Ino file '/usr/local/share/lua/5.1/hovercraft/provider/lsp/init.lua'
^Ino file '/opt/homebrew/share/lua/5.1/hovercraft/provider/lsp.lua'
^Ino file '/opt/homebrew/share/lua/5.1/hovercraft/provider/lsp/init.lua'
^Ino file './hovercraft/provider/lsp.so'
^Ino file '/usr/local/lib/lua/5.1/hovercraft/provider/lsp.so'
^Ino file '/opt/homebrew/lib/lua/5.1/hovercraft/provider/lsp.so'
^Ino file '/usr/local/lib/lua/5.1/loadall.so'
^Ino file './hovercraft.so'
^Ino file '/usr/local/lib/lua/5.1/hovercraft.so'
^Ino file '/opt/homebrew/lib/lua/5.1/hovercraft.so'
^Ino file '/usr/local/lib/lua/5.1/loadall.so'

# stacktrace:
  - plugins/user.lua:332
  - ~/.config/nvim/lua/astronvim/lazy.lua:43
  - ~/.config/nvim/init.lua:10
Press ENTER or type command to continue

Additional Observations:

  • The plugin does not break when configuring keys = {} and window = {} configurations within opts.
  • Setting opts = { providers = { providers = {} }, }, does not break the plugin, but triggers an error No active providers for line! when using the keymap for hovercraft.
  • The goal is to add more providers as mentioned in the README, but this leads to the stated issue.

Request for Help:
I'm unsure why configuring opts = { providers = { providers = {} }, }, with additional providers causes these errors. Any guidance or suggestions to resolve this would be greatly appreciated.

NOTE: I am using AstroNvim Neovim distribution. I also tried different ways to configure the plugin, one under it's own .lua file and another under user.lua.

Current Working Configuration:

    {
        "patrickpichler/hovercraft.nvim",
        dependencies = {
            { "nvim-lua/plenary.nvim" },
        },
        event = "User AstroFile",
        opts = {
            keys = {
                { "<C-u>", function() require("hovercraft").scroll { delta = -4 } end },
                { "<C-d>", function() require("hovercraft").scroll { delta = 4 } end },
                { "<TAB>", function() require("hovercraft").hover_next() end },
                { "<S-TAB>", function() require("hovercraft").hover_next { step = -1 } end },
            },
        },
    },

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.