2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

macOSで画像をコマンドラインからクリップボードにコピーする

2
Posted at

はじめに

コマンドラインから画像をクリップボードにコピーしたくなることがたまによくあります。
毎回Finderを開いてコピーするのがストレスなので、画像ファイルをクリップボードへコピーするfish関数を作成しました。
普段はエディタとしてNeovim、ファイラとしてnvim-treeを使っているので、nvim-tree上からも同じ処理を実行できるようにしました。

fish関数の作成

普段シェルとしてfishを使っているので、
fishの関数として、画像ファイルをクリップボードへコピーするcopyimageコマンドを作成しました

macOSには、JavaScriptからmacOSのAPIを操作できるJXAが用意されているのでこれを使って操作を宣言しています。
指定されたファイルをNSImageとして読み込み、クリップボードを表すNSPasteboard.generalPasteboardへ書き込んでいます。

function copyimage --description "Copy image file to clipboard"
    if test (count $argv) -ne 1
        echo "usage: copyimage <image-path>" >&2
        return 1
    end

    set -l path $argv[1]

    if not test -f "$path"
        echo "copyimage: file not found: $path" >&2
        return 1
    end

    osascript -l JavaScript -e '
      ObjC.import("AppKit")

      function run(argv) {
        const path = $.NSString
          .stringWithString(argv[0])
          .stringByStandardizingPath

        const image = $.NSImage.alloc.initWithContentsOfFile(path)

        if (!image) {
          throw new Error("failed to load image: " + argv[0])
        }

        const clipboard = $.NSPasteboard.generalPasteboard
        clipboard.clearContents

        const objects = $.NSArray.arrayWithObject(image)

        if (!clipboard.writeObjects(objects)) {
          throw new Error("failed to write image to clipboard")
        }
      }
    ' "$path"

    or return $status
end

次のように実行できます。

copyimage ./image.png

nvim-treeから実行できるようにする

nvim-tree上でカーソルが置かれているファイルをコピーできるようにします。

<Leader>yyへ次の処理を割り当てます。

  • 画像ファイルの場合は、copyimageを実行する
  • 画像以外の場合は、ファイルをテキストとして読み込んでクリップボードへコピーする
local function attach(bufnr)
  local api = require("nvim-tree.api")

  local function opts(desc)
    return {
      desc = "nvim-tree: " .. desc,
      buffer = bufnr,
      noremap = true,
      silent = true,
      nowait = true,
    }
  end

  local image_extensions = {
    png = true,
    jpg = true,
    jpeg = true,
    gif = true,
    tif = true,
    tiff = true,
    bmp = true,
    webp = true,
    heic = true,
  }

  local function is_image(path)
    local extension = path:lower():match("%.([^./]+)$")
    return extension ~= nil and image_extensions[extension] == true
  end

  api.config.mappings.default_on_attach(bufnr)

  vim.keymap.set("n", "<Leader>yy", function()
    local node = api.tree.get_node_under_cursor()

    if not node or node.type ~= "file" then
      vim.notify(
        "nvim-tree: cursor is not on a file",
        vim.log.levels.WARN
      )
      return
    end

    if is_image(node.absolute_path) then
      local result = vim.system({
        "fish",
        "-lc",
        'copyimage "$argv[1]"',
        "--",
        node.absolute_path,
      }):wait()

      if result.code ~= 0 then
        local message = result.stderr

        if not message or message == "" then
          message = "unknown error"
        end

        vim.notify(
          "nvim-tree: failed to copy image\n" .. message,
          vim.log.levels.ERROR
        )
        return
      end

      vim.notify("nvim-tree: copied image to clipboard")
      return
    end

    local ok, lines = pcall(vim.fn.readfile, node.absolute_path)

    if not ok then
      vim.notify(
        "nvim-tree: failed to read " .. node.absolute_path,
        vim.log.levels.ERROR
      )
      return
    end

    vim.fn.setreg("+", lines, "l")
    vim.notify("nvim-tree: copied file contents to clipboard")
  end, opts("Copy file contents"))
end

require("nvim-tree").setup({
  on_attach = attach,
})

おわりに

気づけばなくてはならないコマンドになっていました。
macOS、fish、Neovim、nvim-treeという限定的な構成ではありますが、同じような環境を使っている方の参考になれば幸いです。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?