Logo

dev-resources.site

for different kinds of informations.

How I Developed My First Neovim Plugin: A Step-by-Step Guide

Published at
9/19/2024
Categories
neovim
development
vim
extensions
Author
iamgoncaloalves
Categories
4 categories in total
neovim
open
development
open
vim
open
extensions
open
Author
15 person written this
iamgoncaloalves
open
How I Developed My First Neovim Plugin: A Step-by-Step Guide

Are you a Neovim enthusiast looking to extend its functionality? Ever wondered how to create your own plugin and publish it up on Github? Look no further! In this post, I'll walk you through my journey of developing a simple "Hello World" plugin for Neovim.

For those who want to see the finished product or follow along with the complete source code, you can check out the full repository here:

neovim-plugin-hello-world GitHub Repository

Feel free to star the repository if you find it helpful!

Btw, I'm building a real useful Neovim plugin and I will share how I built this plugin here, so make sure you follow me if you don't wanna miss that.

Ā 

Introduction

Neovim, a hyper-extensible Vim-based text editor, allows users to create custom plugins to enhance their editing experience. In this tutorial, we'll create a simple plugin that adds a :HelloWorld command and a keymapping to Neovim, which prints "Hello from Neovim!" when executed.

Ā 

Setting Up the Development Environment

Before we dive into coding, let's set up our development environment:

  1. Ensure you have Neovim installed (version 0.5 or later recommended).
  2. Choose a directory for your plugin development. I used ~/development/neovim/neovim-plugins/.

Ā 

Creating the Plugin Structure

Before we dive into coding our specific plugin, it's important to understand the typical structure of a Neovim plugin. This structure follows conventions that determine how and when different parts of the plugin are loaded.

The Anatomy of a Neovim Plugin

A generic Neovim plugin usually has the following structure:

.
ā”œā”€ā”€ LICENSE
ā”œā”€ā”€ README.md
ā”œā”€ā”€ plugin/
ā”‚   ā””ā”€ā”€ plugin-file.lua
ā””ā”€ā”€ lua/
    ā””ā”€ā”€ plugin-name.lua
Enter fullscreen mode Exit fullscreen mode

Let's break down each component:

  1. Root Directory:

    • LICENSE: The license file for your plugin.
    • README.md: Documentation and usage instructions for your plugin.
  2. plugin/ Directory:

    • Files in this directory are automatically executed when Neovim starts.
    • This is useful for setting up global commands, autocommands, or keymaps that should be available immediately.
    • Example: plugin/plugin-file.lua
  3. lua/ Directory:

    • This is where the main plugin code resides.
    • Code here is only executed when explicitly required by the user or other parts of the plugin.
    • There are two common ways to structure the main file: a. Single file: lua/plugin-name.lua b. Directory with init file: lua/plugin-name/init.lua

Key Points About Plugin Structure

  1. The plugin/ directory is for code that needs to run immediately when Neovim starts, regardless of whether the user explicitly requires the plugin.

  2. The lua/ directory contains the main plugin code, which is only executed when required. This is where most of your plugin's functionality should be implemented.

  3. Naming is important. The main file in the lua/ directory should typically match your plugin's name (e.g., hello-world.lua for a plugin named "hello-world").

  4. For simple plugins, a single file in the lua/ directory is often sufficient. For more complex plugins, you might use a directory with an init.lua file.

  5. The main entry point of your plugin (in the lua/ directory) is what users will require to use your plugin. For example, users would use require('hello-world') to load a plugin with the file lua/hello-world.lua.

This structure allows for efficient loading of plugin code, with immediate execution of necessary setup code (in plugin/) and on-demand loading of the main functionality (in lua/).

Structure for Our Hello World Plugin

For our simple "Hello World" plugin, we'll use the following structure:

neovim-plugin-hello-world/
ā”œā”€ā”€ LICENSE
ā”œā”€ā”€ README.md
ā””ā”€ā”€ lua/
    ā””ā”€ā”€ neovim-plugin-hello-world.lua
Enter fullscreen mode Exit fullscreen mode

Since our plugin doesn't need any immediate setup, we'll omit the plugin/ directory and focus on the main functionality in the lua/ directory.

Let's create this structure in your chosen development directory:

  1. Create a new directory for your plugin:
   mkdir -p neovim-plugin-hello-world/lua
Enter fullscreen mode Exit fullscreen mode
  1. Navigate to the plugin directory:
   cd neovim-plugin-hello-world
Enter fullscreen mode Exit fullscreen mode
  1. Create the main Lua file:
   touch lua/neovim-plugin-hello-world.lua
Enter fullscreen mode Exit fullscreen mode
  1. Create a README.md file:
   touch README.md
Enter fullscreen mode Exit fullscreen mode
  1. Add a LICENSE file (choose an appropriate license for your project).

Now that we have our plugin structure set up, we're ready to start writing the actual plugin code.

Ā 

Writing the Plugin Code

Let's create the main plugin file. Open lua/neovim-plugin-hello-world.lua in your favorite text editor and add the following code:

-- Main module for the Hello World plugin
local M = {}

-- Function to print the hello message
function M.say_hello()
  print("Hello from Neovim!")
end

-- Function to set up the plugin (Most package managers expect the plugin to have a setup function)
function M.setup(opts)
  -- Merge user options with defaults
  opts = opts or {}

  -- Create the user command
  vim.api.nvim_create_user_command("HelloWorld", M.say_hello, {})

  -- Set up a key mapping
  -- Use opts.keymap if provided, otherwise default to '<leader>hw'
  local keymap = opts.keymap or '<leader>hw'

  -- Create the keymap
  vim.keymap.set('n', keymap, M.say_hello, { 
    desc = "Say hello from our plugin",
    silent = true  -- Prevents the command from being echoed in the command line
  })
end

-- Return the module
return M
Enter fullscreen mode Exit fullscreen mode

Let's break down this code:

  1. We define a module M that will contain all our plugin's functionality.
  2. The say_hello() function is the core of our plugin. It simply prints a greeting message.
  3. The setup() function is used to initialize our plugin with user-provided options:
    • It creates a user command :HelloWorld that calls our say_hello() function.
    • It sets up a keymapping (default <leader>hw) that also calls say_hello().
  4. We return the module at the end, making its functions available to users of our plugin.

Ā 

Debugging Your Plugin

To debug your plugin locally using lazy.nvim with the dir option:

  1. Ensure you have lazy.nvim installed in your Neovim configuration.

  2. Modify your Neovim configuration to load your plugin locally. Add the following to your init.lua or wherever you configure your plugins:

require("lazy").setup({
  {
    "neovim-plugin-hello-world",
    dir = "~/development/neovim/neovim-plugins/neovim-plugin-hello-world",
    config = function()
      require("neovim-plugin-hello-world").setup({
        keymap = "<leader>hello"  -- optional: override the default keymap
      })
    end,
  },
  -- ... your other plugins ...
})
Enter fullscreen mode Exit fullscreen mode
  1. Restart Neovim or run :Lazy sync to load your plugin.

  2. Test your plugin:

    • Try running the command :HelloWorld
    • Use the keymapping (default <leader>hw or your custom mapping) in normal mode

You should see "Hello from Neovim!" printed in the command line for both methods.

Iterative Development

With this setup, you can easily iterate on your plugin:

  1. Make changes to your plugin code.
  2. Save the files.
  3. In Neovim, run :Lazy reload neovim-plugin-hello-world to reload your plugin.
  4. Test the changes by running :HelloWorld or using the keymapping.

This workflow allows for rapid development and testing without constantly restarting Neovim or manually sourcing files.

Ā 

Installing the Plugin Remotely

When you're ready to share your plugin with the world, you'll need to push it to a GitHub repository. Here's how to make it installable via lazy.nvim:

  1. Create a GitHub repository for your plugin.
  2. Push your plugin code to the repository.
  3. Update your README.md file with installation and usage instructions.

Here's a sample README.md:

# neovim-plugin-hello-world

A simple Neovim plugin that adds a `:HelloWorld` command and keymapping.

&nbsp;
## Installation

Using [lazy.nvim](https://github.com/folke/lazy.nvim):

{
  "yourusername/neovim-plugin-hello-world",
  opts = {
      keymap = "<leader>hello"  -- optional: override the default keymap
    }
}

&nbsp;
## Usage

After installation:
1. Run `:HelloWorld` command in Neovim
2. Or use the keymapping (default `<leader>hw` or your custom mapping) in normal mode

Both will print "Hello from Neovim!" in the command line.
Enter fullscreen mode Exit fullscreen mode

(Don't forget to replace yourusername with your actual GitHub username.)

Ā 

Conclusion

Congratulations! You've just created your first Neovim plugin. This simple example demonstrates the basics of plugin development, including structuring your code, creating user commands, setting up keymappings, and making your plugin installable.

As you become more comfortable with plugin development, you can explore more advanced features like autocommands, integrating with Neovim's API, and creating more complex functionality. The possibilities are endless!

Remember, the key to successful plugin development is iterative improvement and testing. With the setup we've created, you can quickly make changes, reload your plugin, and see the results in real-time.

Happy coding, and may your Neovim experience be ever more customized and efficient!

Ā 

Connect with me

If you reached this far and liked this article be sure to leave a comment. That will make my day!

If you want to connect with me you can send me a message on Twitter/X.

If you want to read other stuff by me you can check out my personal blog.

You can also check other stuff that I have going on here

neovim Article's
30 articles in total
Favicon
How to Enable Undercurl in Neovim: Terminal and Tmux Setup Guide
Favicon
Hassle free flutter Development in Hyprland with Neovim
Favicon
How to setup VueJs in Neovim (January 2025)
Favicon
Setting Up NeoVim + LazyVim on My New Mac Mini M4 šŸ’»āœØ
Favicon
Zed IDE vs. NeoVim and Other IDEs: The Future of Modern Coding Environments
Favicon
Enhancing Elixir Development in LazyVim: Quick Documentation Access by Telescope
Favicon
Lazyvim version 14.x in WSL
Favicon
From Vi to NeoVim: A Journey into the Heart of Text Editing
Favicon
As a beginner I use Arch, Neovim and code in assembly btw
Favicon
How to Setup Vim for Kotlin Development
Favicon
This developer created a 2K star repo from his phone
Favicon
Atomic Note-Taking Guide
Favicon
obsidian neovim markdown
Favicon
What I've Learned About My Editing Skills
Favicon
Vim Regex Tricks - Capitalize Every First Letter
Favicon
Lite šŸš€ ApolloNvim Distro 2024
Favicon
[SOLVED] Vue 3 + TypeScript + Inlay Hint support in NeoVim
Favicon
Migrating from VSCode to Neovim: A Journey of Learning, Confusion, and Triumph! šŸš€
Favicon
Managing LSPs in Neovim: Enable/Disable for the Entire Session
Favicon
Create a New Note for Your Obsidian Vault from the Terminal
Favicon
Faking the tmux experience on Windows using AutoHotkey
Favicon
How to resume neovim session
Favicon
Can't believe I've created 20 vim plugins since 2016
Favicon
Top 5 Neovim Repositories in this Week
Favicon
Compile Neovim in Debian/Ubuntu Linux
Favicon
Neovim for beginners
Favicon
Make environment to develop commonlisp with NeoVim
Favicon
Setting up neovim for web development in Golang
Favicon
Github copilot setup on Austronvim
Favicon
How I Developed My First Neovim Plugin: A Step-by-Step Guide

Featured ones: