neovim: clipboard magic
Sérgio Araújo

Sérgio Araújo @voyeg3r

About: I am a Free Software enthusiast and a (neo)?vim addicted, I also like shell script, sed, awk, and as you can see I love Regular Expressions.

Location:
Brazil
Joined:
Sep 23, 2017

neovim: clipboard magic

Publish Date: Jun 4
0 0

Intro

In this article I will share some of my daily life solutions to make my neovim workflow smoother.

Since posting this article my repository was updated with more elaborate code. here

If I want copy a text and open in neovim (zsh)

I do ...

# Edit content of clipboard on vim
function _edit_clipboard(){
  # pbpaste | nvim
  termux-clipboard-get | nvim -c 'setlocal bt=nofile bh=wipe nobl noswapfile nu'
}
zle -N edit-clipboard _edit_clipboard
bindkey '^x^v' edit-clipboard
Enter fullscreen mode Exit fullscreen mode

I also have an autoloaded "nvimscratch" do deal with arguments and pipes:

nvscratch() {
  local content

  if [[ -p /dev/stdin ]]; then
    content=$(cat -)  # reads from pipes
  else
    content="$("$@")"  # runs with arguments
fi
## now we open the content in a scratch buffer
nvim -c "enew | setlocal buftype=nofile bufhidden=wipe noswapfile" +"0read !echo \"$content\""
}
Enter fullscreen mode Exit fullscreen mode

In termux my pbpaste and pbcopy come from

# for zsh
(( $+commands[termux-clipboard-get] )) && {
  alias pbpaste='termux-clipboard-get'
  alias pbcopy='termux-clipboard-set'
}
Enter fullscreen mode Exit fullscreen mode

in regular linux use xclip instead of termux-clipboatd. Then I cand run

some_command | pbcopy
Enter fullscreen mode Exit fullscreen mode

or

pbpaste | nvscratch
Enter fullscreen mode Exit fullscreen mode

Blockwise mode made easy

We frequently see articles and videos about visual block mode but sometines
people forget about pressing ctrl-v, and I have found a perfect solution for this:

NOTE: I usually cite the sources but in this case I have to say sorrow,
but the code bellow will make every insert "I", "A", and "gI", become
blockwise. (see my map function bellow)

-- Better block-wise operations on selected area
local blockwise_force = function(key)
    local c_v = vim.api.nvim_replace_termcodes('<C-v>', true, false, true)
    local keyseq = {
        I = { v = '<C-v>I', V = '<C-v>^o^I', [c_v] = 'I' },
        A = { v = '<C-v>A', V = '<C-v>0o$A', [c_v] = 'A' },
        gI = { v = '<C-v>0I', V = '<C-v>0o$I', [c_v] = '0I' },
    }
    return function() return keyseq[key][vim.fn.mode()] end
end
map('x', 'I', blockwise_force('I'), { expr = true, noremap = true, desc = 'Blockwise Insert' })
map('x', 'gI', blockwise_force('gI'), { expr = true, noremap = true, desc = 'Blockwise Insert' })
map('x', 'A', blockwise_force('A'), { expr = true, noremap = true, desc = 'Blockwise Append' })
Enter fullscreen mode Exit fullscreen mode

In my utils.lua I have a map function just to make easy creating new mappings (you can use vim.keymap.set instead):

NOTE: For newbies. We have a convetion: lua modules start with local M = {} and we finish them with return M. In the code below I am just showing some functions. Those who start whit M. are inside a module.

-- https://blog.devgenius.io/create-custom-keymaps-in-neovim-with-lua-d1167de0f2c2
-- https://oroques.dev/notes/neovim-init/
M.map = function(mode, lhs, rhs, opts)
    local options = { noremap = true, silent = true }
    if opts then options = vim.tbl_extend('force', options, opts) end
    vim.keymap.set(mode, lhs, rhs, options)
end
Enter fullscreen mode Exit fullscreen mode

Paste the clipboard right away blockwise:

It was been a while I needed this solution, because I am using nvim in termux and the 'termux-clipboard (get and set)' does not allows me to convert the clipboard to blockwise, linewise or characterewise. The idea is:

Using an internal vim register to receive the clipboard content, make it blockwise, paste at cursor position and restore the temporary register content, because in somewere else the temporary register I am using for this process could mess things up.

So, first we creare a function to use a temporary register and run a callback function we will use in our mapping:

-- paste into your utils.lua (as an example)

M.with_temp_register = function(reg, callback)
    local content = vim.fn.getreg(reg)
    local regtype = vim.fn.getreginfo(reg).regtype

    callback()

    vim.fn.setreg(reg, content, regtype)
end
Enter fullscreen mode Exit fullscreen mode

Now we are going to use our function in a Alt-2 mapping (just because I have a huge amount of mappings)

local UTILS = require('core.utils')

map("n", "<M-2>", function()
    ---@type string
    local reg_clip_raw = vim.fn.getreg('+')

    ---@type string[]
    local reg_clip = vim.split(reg_clip_raw, "\n", { plain = true })

    UTILS.with_temp_register("z", function()
        vim.fn.setreg("z", reg_clip, "b")
        vim.cmd('normal! "zp')
    end)

    print("Clipboard colado como blockwise")
end, { desc = "Colar clipboard como blockwise" })
Enter fullscreen mode Exit fullscreen mode

Using only lua api to paste @+ blockwise:

M.paste_blockwise = function(lines)
  local row, col = unpack(vim.api.nvim_win_get_cursor(0))
  row = row - 1

  local buf = 0
  local existing_lines = vim.api.nvim_buf_get_lines(buf, row, row + #lines, false)

  for i, l in ipairs(lines) do
    local target = existing_lines[i] or ""
    if #target < col then
      target = target .. string.rep(" ", col - #target)
    end
    existing_lines[i] = target:sub(1, col) .. l .. target:sub(col + 1)
  end

  vim.api.nvim_buf_set_lines(buf, row, row + #lines, false, existing_lines)
end
Enter fullscreen mode Exit fullscreen mode

The keymap

-- Uso:
map("n", "<M-4>", function()
  local block = vim.split(vim.fn.getreg("+"), "\n", { plain = true })
  UTILS.paste_blockwise(block)
  print("Colado como bloco via API")
end)
Enter fullscreen mode Exit fullscreen mode

Final note: Probably I am going to add more content in this article. Please give us you opinion we appreciate it very much!

Comments 0 total

    Add comment