Home

Awesome

nvim-neoclip.lua

This is a story about Bob 👷.

Bob loves vim ❤ī¸.

Bob likes to yank Šī¸.

Bob knows about registers but sometimes forgets them ÂŽī¸.

This is what happens to Bob everyday 🚧:

Don't be like Bob, use neoclip! 🎉

neoclip is a clipboard manager for neovim inspired by for example clipmenu. It records everything that gets yanked in your vim session (up to a limit which is by default 1000 entries but can be configured). You can then select an entry in the history using telescope or fzf-lua which then gets populated in a register of your choice.

If you're on latest nightly (works if :echo exists('##RecordingLeave') returns 1) neoclip will also keep track of any recorded macro (opt-out) which you can search for using telescope, put back in a register or simply replay.

That's it!

Oh, some more things, you can define an optional filter if you don't want some things to be saved and custom actions to take.

Hold on, neoclip optionally also supports persistent history between sessions powered by sqlite.lua.

neoclip

Installation

<details> <summary>Using <a href="https://github.com/folke/lazy.nvim">Lazy.nvim</a></summary>
require {
  "AckslD/nvim-neoclip.lua",
  dependencies = {
    -- you'll need at least one of these
    -- {'nvim-telescope/telescope.nvim'},
    -- {'ibhagwan/fzf-lua'},
  },
  config = function()
    require('neoclip').setup()
  end,
}
</details> <details> <summary>Using <a href="https://github.com/wbthomason/packer.nvim">Packer</a></summary>
use {
  "AckslD/nvim-neoclip.lua",
  requires = {
    -- you'll need at least one of these
    -- {'nvim-telescope/telescope.nvim'},
    -- {'ibhagwan/fzf-lua'},
  },
  config = function()
    require('neoclip').setup()
  end,
}
</details> <br>

When require('neoclip').setup() is called, only the autocommand (for TextYankPost event) is setup to save yanked things. This means that telescope is not required at this point if you lazy load it. Depending on your setup you might need to load the telescope extension before using it though, see the troubleshooting-section below.

If you want to use persistent history between sessions you also need sqlite.lua installed, for example by:

<details> <summary>Using <a href="https://github.com/folke/lazy.nvim">Lazy.nvim</a></summary>
require {
  "AckslD/nvim-neoclip.lua",
  dependencies = {
    {'kkharji/sqlite.lua', module = 'sqlite'},
    -- you'll need at least one of these
    -- {'nvim-telescope/telescope.nvim'},
    -- {'ibhagwan/fzf-lua'},
  },
  config = function()
    require('neoclip').setup()
  end,
}
</details> <details> <summary>Using <a href="https://github.com/wbthomason/packer.nvim">Packer</a></summary>
use {
  "AckslD/nvim-neoclip.lua",
  requires = {
    {'kkharji/sqlite.lua', module = 'sqlite'},
    -- you'll need at least one of these
    -- {'nvim-telescope/telescope.nvim'},
    -- {'ibhagwan/fzf-lua'},
  },
  config = function()
    require('neoclip').setup()
  end,
}
</details>

Configuration

You can configure neoclip by passing a table to setup (all are optional). The following are the defaults and the keys are explained below:

require('neoclip').setup({
  history = 1000,
  enable_persistent_history = false,
  length_limit = 1048576,
  continuous_sync = false,
  db_path = vim.fn.stdpath("data") .. "/databases/neoclip.sqlite3",
  filter = nil,
  preview = true,
  prompt = nil,
  default_register = '"',
  default_register_macros = 'q',
  enable_macro_history = true,
  content_spec_column = false,
  disable_keycodes_parsing = false,
  on_select = {
	move_to_front = false,
	close_telescope = true,
  },
  on_paste = {
	set_reg = false,
	move_to_front = false,
	close_telescope = true,
  },
  on_replay = {
	set_reg = false,
	move_to_front = false,
	close_telescope = true,
  },
  on_custom_action = {
	close_telescope = true,
  },
  keys = {
	telescope = {
	  i = {
		select = '<cr>',
		paste = '<c-p>',
		paste_behind = '<c-k>',
		replay = '<c-q>',  -- replay a macro
		delete = '<c-d>',  -- delete an entry
		edit = '<c-e>',  -- edit an entry
		custom = {},
	  },
	  n = {
		select = '<cr>',
		paste = 'p',
		--- It is possible to map to more than one key.
		-- paste = { 'p', '<c-p>' },
		paste_behind = 'P',
		replay = 'q',
		delete = 'd',
		edit = 'e',
		custom = {},
	  },
	},
	fzf = {
	  select = 'default',
	  paste = 'ctrl-p',
	  paste_behind = 'ctrl-k',
	  custom = {},
	},
  },
})

See screenshot section below for how the settings above might affect the looks.

Custom actions

You can specify custom actions in the keys entry in the settings. For example you can do:

require('neoclip').setup({
  ...
  keys = {
    ...
    n = {
      ...
      custom = {
        ['<space>'] = function(opts)
          print(vim.inspect(opts))
        end,
      },
    },
  },
})

which when pressing <space> in normal mode will print something like:

{
  register_names = { '"' },
  typ = "yanks" -- Will be "macros" if selected from :Telescope macroscope
  entry = {
    contents = { "which when pressing `<space>` in normal mode will print something like:" },
    filetype = "markdown",
    regtype = "l"
  }
}

to do your custom action and also populate a register and/or paste you can call neoclips built-in handlers, such as:

require('neoclip').setup({
  ...
  keys = {
    ...
    n = {
      ...
      custom = {
        ['<space>'] = function(opts)
          -- do your stuff
          -- ...
          local handlers = require('neoclip.handlers')
          -- optionally set the registers with the entry
          -- handlers.set_registers(opts.register_names, opts.entry)
          -- optionally paste entry
          -- handlers.paste(opts.entry, 'p')
          -- optionally paste entry behind
          -- handlers.paste(opts.entry, 'P')
        end,
      },
    },
  },
})

Usage

Yanks

Yank all you want and then do:

:Telescope neoclip

if using telescope or

:lua require('neoclip.fzf')()

if using fzf-lua, which will show you a history of the yanks that happened in the current session. If you pick (default <cr>) one this will then replace the current " (unnamed) register.

If you instead want to directly paste it you can press by default <c-p> in insert mode and p in normal. Paste behind is by default <c-k> and P respectively.

If you want to replace another register with an entry from the history you can do for example:

:Telescope neoclip a

if using telescope or

:lua require('neoclip.fzf')('a')

if using fzf-lua, which will replace register a. The register [0-9a-z] and default (") are supported.

The following special registers are supported:

and Telescope neoclip (and Telescope neoclip default) will use what you set default_register in the setup.

You can also specify more registers to populate in a single command with the extra keyword argument which supports registers separated by comma, for example:

:Telescope neoclip a extra=star,plus,b

if using telescope or

:lua require('neoclip.fzf')({'a', 'star', 'plus', 'b'})

if using fzf-lua.

Macros

If enable_macro_history is set to true (default) in the setup then any recorded macro will be stored and can later be accessed using:

:Telescope macroscope

or equivalently (which is probably the better way if you're lazy loading telescope):

:lua require('telescope').extensions.macroscope.default()

The same arguments are supported as for the neoclip extension.

NOTE: This feature requires latest nightly and in particular this PR. You can check that your neovim supports this by checking that :echo exists('##RecordingLeave') returns 1. If not then everything will work normally except that no macro will be saved in the history of neoclip.

Start/stop

If you temporarily don't want neoclip to record anything you can use the following calls:

Sync database

If you don't want to use the setting continuous_sync, but still keep two instances of neovim synchronized in their neoclip history you can use the functions:

Remove entries

You can remove entries manually using the keybinds for delete. You can also delete the whole history with :lua require('neoclip').clear_history().

Edit entries

You can edit the contents of an entry using the keybinds for edit. It'll open the contents of the entry in a separate floating buffer. When you leave the buffer (:q), it'll update the contents of the entry with what's in the buffer.

Tips

Troubleshooting

Thanks

Screenshots

preview = true and content_spec_column = false

preview

preview = false and content_spec_column = true

content_spec_column

preview = false and content_spec_column = false

clean