DEV Community

Cover image for neovim: Wrap selection into clipboard
Sérgio Araújo
Sérgio Araújo

Posted on • Edited on

neovim: Wrap selection into clipboard

Intro

NOTE: The proposed solutions here have evolved a little bit, my utils.lua was modularized becomming a folder. If you want to see the differences follow this link.

Sharing code using markdown is way common these days. What about having those backticks and the language of the code (our fenced code) wrapped around the selection and placed into the clipboard at the distance of a keyboard map?

First we define a lua function to get the visual selection

get_clipboard_selection

--- @return string # selected text
M.get_visual_selection = function()
  local mode = vim.fn.mode()
  if not vim.tbl_contains({ 'v', 'V', '\22' }, mode) then return '' end

  -- visual selection margins
  local s_pos = vim.fn.getpos('v')
  local e_pos = vim.fn.getpos('.') -- cursor atual

  local s_row, s_col = s_pos[2], s_pos[3]
  local e_row, e_col = e_pos[2], e_pos[3]

  -- if selection is backwards
  if s_row > e_row or (s_row == e_row and s_col > e_col) then
    s_row, e_row = e_row, s_row
    s_col, e_col = e_col, s_col
  end

  local lines = vim.api.nvim_buf_get_lines(0, s_row - 1, e_row, false)
  if #lines == 0 then return '' end

  lines[1] = string.sub(lines[1], s_col)
  if #lines == 1 then
    lines[1] = string.sub(lines[1], 1, e_col - s_col + 1)
  else
    lines[#lines] = string.sub(lines[#lines], 1, e_col)
  end

  return table.concat(lines, '\n')
end
Enter fullscreen mode Exit fullscreen mode

Wrap visual selected text with fenced code

Now a helper wrapper function that adds backtics and the language name around the selected text

function M.wrap_in_markdown_codeblock(text, lang)
  if not text or text == '' then return '' end
  lang = lang or ''
  return string.format('```%s\n%s\n```', lang, text)
end
Enter fullscreen mode Exit fullscreen mode

The keymap

The functions of sections above are in text_manipulation.lua module.

local text_utils = require('core.utils.text_manipulation')

map('v', '<M-s>', function()
  local wrap_in_markdown_codeblock = text_utils.wrap_in_markdown_codeblock
  local ft = vim.bo.filetype
  local text = text_utils.get_visual_selection()

  if text == '' then
    vim.notify('No selection found', vim.log.levels.WARN)
    return
  end

  local wrapped = wrap_in_markdown_codeblock(text, ft)
  vim.fn.setreg('+', wrapped)
  vim.notify('markdown block copied into reg +', vim.log.levels.INFO)
end, { desc = 'Copy selection as markdown fenced code' })
Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.