💞

Vim script / Neovim luaで現在のファイルのパスと行数をコピーするコマンド

に公開

この記事はVim駅伝の2025-06-27の記事です。
前回の記事はs-showさんのNix を使って複数バージョンの Neovim をインストールする方法です。

Vim駅伝は常に参加者を募集しています。詳しくはこちらのページをご覧ください。


設定ファイルに入れて使っている、「現在のファイルのパスと行数をコピーするコマンド」を共有します。

同様の機能を提供しているプラグインもいろいろあると思いますが、このくらいなら自分の設定に入れておいても良いのではと思います。

定義

Vim script版

function! s:copy_path(target, range, line1, line2) abort
  " defaultはrelative path
  let expr = '%'
  if a:target == 'full path'
    let expr ..= ':p'
  elseif a:target == 'file name'
    let expr ..= ':t'
  endif

  let range_str = ''
  if a:range > 0
    if a:line1 == a:line2
      let range_str = '#L' .. a:line1
    else
      let range_str = '#L' .. a:line1 .. '-L' .. a:line2
    endif
  endif

  let result = expand(expr) .. range_str
  let @* = result
  echo 'Copy ' .. a:target .. ': ' .. result
endfunction
command! -range CopyFullPath     call s:copy_path('full path', <range>, <line1>, <line2>)
command! -range CopyFileName     call s:copy_path('file name', <range>, <line1>, <line2>)
command! -range CopyRelativePath call s:copy_path('relative path', <range>, <line1>, <line2>)

Neovim lua版

local function get_range_str(opts)
  if opts.range ~= 2 then
    return ''
  end
  if opts.line1 == opts.line2 then
    return '#L' .. opts.line1
  end
  return '#L' .. opts.line1 .. '-L' .. opts.line2
end
local function copy_path(opts, target)
  local expr = '%'
  if target == 'full path' then
    expr = '%:p'
  elseif target == 'file name' then
    expr = '%:t'
  end

  local path = vim.fn.expand(expr) .. get_range_str(opts)
  vim.fn.setreg('*', path)
  vim.notify('Copied ' .. target .. ': ' .. path)
end

vim.api.nvim_create_user_command('CopyFullPath', function(opts)
  copy_path(opts, 'full path')
end, { range = true, desc = 'Copy the full path of the current file to the clipboard' })

vim.api.nvim_create_user_command('CopyRelativePath', function(opts)
  copy_path(opts, 'relative path')
end, { range = true, desc = 'Copy the relative path of the current file to the clipboard' })

vim.api.nvim_create_user_command('CopyFileName', function(opts)
  copy_path(opts, 'file name')
end, { range = true, desc = 'Copy the file name of the current file to the clipboard' })

つかいかた

:CopyFileNameのように呼び出すと、vimrcのように、現在のファイル名をコピーします。
また、ビジュアルモードから:'<,'>CopyRelativePathのように使うこともできます。この場合は.config/nvim/init.lua#120のように行数がコピーされます。複数行を選択していた場合には.config/nvim/init.lua#120-L125のようになります。

なお、unnamed(*)レジスタを使っているので、ほかのレジスタが良い場合は書き換えてください。

Discussion