VimperatorからAppleScriptを実行して、WebページへのリンクをHTMLのデータとしてクリップボードに保存する

つまり

```
<a href="http://qiita.com/">ホーム - Qiita</a>
```

のようなテキストのリンクをクリップボードに保存するではなく、GmailやEvernoteなどに貼り付けた時に

<a href="http://qiita.com/">ホーム - Qiita</a>

となるようにしたい。

結論を言うと、[Vimperator](https://addons.mozilla.org/ja/firefox/addon/vimperator/)のコマンドラインで

```
:js io.system('hex="$(echo -E \'<meta charset="utf-8"><a href="' + content.document.location.href.replace(/'/g, "'\\''") + '">' + content.document.title.replace(/'/g, "'\\''") + '</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to «data HTML${hex}»"')
```

を実行すればおｋ。

例えば以下のようにvimperatorrcにマップを設定しておくと便利。

```
nnoremap <Leader>yh :js io.system('hex="$(echo -E \'<meta charset="utf-8"><a href="' + content.document.location.href.replace(/'/g, "'\\''") + '">' + content.document.title.replace(/'/g, "'\\''") + '</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to «data HTML${hex}»"')<CR>
```

`<Leader>yh`（`<Leader>`を変更していない場合は`<Leader>`は\（バックスラッシュ））をタイプするとクリップボードにリンクのHTMLデータが保存される。


## 解説

[osx - Apple Script : How can I copy html content to the clipboard? - Stack Overflow](http://stackoverflow.com/questions/11085654/apple-script-how-can-i-copy-html-content-to-the-clipboard)を参考にターミナルで

```bash
$ hex="$(echo -E '<meta charset="utf-8"><a href="http://qiita.com/">ホーム - Qiita</a>' | hexdump -ve '1/1 "%.2x"')"; osascript -e "set the clipboard to «data HTML${hex}»"
```

を実行するとクリップボードにHTMLのデータとして保存される。

ここでechoの-Eのオプションはバックスラッシュエスケープを無視する設定（\nとかを解釈しなくなる）。bashの場合はデフォルトだがzshは解釈するのでつける。

Stack Overflowでは-nのオプションを付けて、出力の最後で改行しないようにしているが、改行しないとメモで貼り付けをしたときに、スタイルが貼り付け以降の文字列でも引き継がれてしまうのでつける。
ただしこの場合はメモで貼り付けた場合に最後に半角スペースが入る。

meta charsetでutf-8を指定して、非ASCII文字を使っても文字化けしないようにしている。

これをVimperatorの`js io.system()`で実行する。

```
:js io.system('hex="$(echo -E \'<meta charset="utf-8"><a href="http://qiita.com/">ホーム - Qiita</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to «data HTML${hex}»"')
```

全体をシングルクォートで囲み、中のシングルクォートをバックスラッシュでエスケープする。

さらにURL・タイトルをJavaScriptで取得するように変更する。

```
:js io.system('hex="$(echo -E \'<meta charset="utf-8"><a href="' + content.document.location.href + '">' + content.document.title + '</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to «data HTML${hex}»"')
```

しかし、このままだと、URLやタイトルにシングルクォートが入っている場合、シェルの実行時に例えば以下のようになって、

```bash
$ hex="$(echo -E '<meta charset="utf-8"><a href="http://qiita.com/'">ホ'ーム - Qiita</a>' | hexdump -ve '1/1 "%.2x"')"; osascript -e "set the clipboard to «data HTML${hex}»"
```

echoの文字列が途中で切れてしまうので、シングルクォートを`'\''`のように変換してやる必要がある。これは`'`で一旦文字列を切って`\'`でシングルクォートそのもの、`'`で文字列を開始することを意味している。
replaceを使って、シングルクォートを変換する処理を加えてやると、


```
:js io.system('hex="$(echo -E \'<meta charset="utf-8"><a href="' + content.document.location.href.replace(/'/g, "'\\''") + '">' + content.document.title.replace(/'/g, "'\\''") + '</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to «data HTML${hex}»"')<CR>
```

ここで`'\''`をダブルクォートで囲んで文字列でしているが、バックスラッシュそのものを表すためにバックスラッシュを加えて`"'\\''"`になっている。

## 補足1 ブラウザでリンクをドラッグしたときとの違い

ブラウザでリンクをドラッグしてコピーした場合、Gmailなどに貼り付ければリンクが、テキストエディタに貼り付けば文字列が貼り付けられるが、今回の場合はテキストエディタには貼り付けられない。その違いはなんだろうか。

<a href="http://qiita.com/">ホーム - Qiita</a>をコピーする。コピーした内容は以下のようにして見れる。

```bash
$ osascript -e "the clipboard as record"
«class HTML»:«data HTML3C68746D6C3E3C686561643E3C6D65746120687474702D65717569763D22636F6E74656E742D747970652220636F6E74656E743D22746578742F68746D6C3B20636861727365743D7574662D38223E3C2F686561643E3C626F64793E3C6120687265663D22687474703A2F2F71696974612E636F6D2F223EE3839BE383BCE383A0202D2051696974613C2F613E3C2F626F64793E3C2F68746D6C3E», «class utf8»:ホーム - Qiita, «class ut16»:ホーム - Qiita, string:ホーム - Qiita, Unicode text:ホーム - Qiita
```

一方今回作ったコマンドを使った場合は

```bash
$ osascript -e "the clipboard as record"
«class HTML»:«data HTML3C6D65746120636861727365743D227574662D38223E3C6120687265663D22687474703A2F2F71696974612E636F6D2F223EE3839BE383BCE383A0202D2051696974613C2F613E»
```

となっており、文字列の情報がなにもない。

[applescript - Setting a clipboard kind without setting "styled Clipboard text" - Ask Different](http://apple.stackexchange.com/questions/193129/setting-a-clipboard-kind-without-setting-styled-clipboard-text)を参考に、テキスト情報を追加してみる。

```
:js io.system('hex="$(echo -nE \'<meta charset="utf-8"><a href="' + content.document.location.href.replace(/'/g, "'\\''") + '">' + content.document.title.replace(/'/g, "'\\''") + '</a>\' | hexdump -ve \'1/1 "%.2x"\')"; osascript -e "set the clipboard to {«class HTML»:«data HTML${hex}», Unicode text:\\"' + content.document.title.replace(/"/g, '\\\\\\"') + '\\"}"')
```

するとコピーされた内容は

```bash
$ osascript -e "the clipboard as record"
«class HTML»:«data HTML3C6D65746120636861727365743D227574662D38223E3C6120687265663D22687474703A2F2F71696974612E636F6D2F223EE3839BE383BCE383A0202D2051696974613C2F613E», Unicode text:ホーム - Qiita, string:ホーム - Qiita, styled Clipboard text:«data styl01000000000010000E00004000000C00000000000000», «class utf8»:ホーム - Qiita, «class ut16»:ホーム - Qiita
```

となる。これでテキストとして貼り付けられるようになったが、今度はメモに貼り付けるとリンクがなくなってしまう。リンクをドラッグしてコピーした場合との違いはstyled Clipboard textの項目があること。上に張ったリンク先にあるPython scriptで直接書き込めばこの問題は解決するらしい。

## 補足2 textutil

textutilを使う手もある

```bash
$ echo '<meta charset="utf-8"><a href="http://qiita.com/">ホーム - Qiita</a>' | textutil -stdin -stdout -format html -convert rtf | pbcopy
```

textutilでHTMLのテキストをリッチテキスト形式(rtf)に変更して、pbcopyでコピーしている。但しこの場合はフォント情報が乗っかる。rtfを見てみると以下の感じ。

```
$ echo '<a href="http://qiita.com/">ホーム - Qiita</a>' | textutil -stdin -stdout -format html -convert rtf
{\rtf1\ansi\ansicpg932\cocoartf1404\cocoasubrtf470
{\fonttbl\f0\froman\fcharset0 Times-Roman;}
{\colortbl;\red255\green255\blue255;\red0\green0\blue233;\red0\green0\blue0;}
\deftab720
\pard\pardeftab720\sl280\partightenfactor0
{\field{\*\fldinst{HYPERLINK "http://qiita.com/"}}{\fldrslt
\f0\fs24 \cf2 \expnd0\expndtw0\kerning0
\ul \ulc2 \outl0\strokewidth0 \strokec2 \'e3\'83\'9b\'e3\'83\'bc\'e3\'83\'a0 - Qiita}}
\f0\fs24 \cf3 \expnd0\expndtw0\kerning0
\outl0\strokewidth0 \strokec3  }
```
Times-Romanが設定されてしまうのでAppleScriptを使った方法がよいかと。

## 補足3 copy.js

タイトル・URLなどを、markdown形式などテキストでコピーしたい場合はcopy.jsを使うとよい。

使い方は[vimpr/vimperator-plugins: for Vimperator plugins](https://github.com/vimpr/vimperator-plugins)を`git clone`して、vimperatorrcに

```vim
let g:plugin_loader_roots = "/path/to/vimperator-plugins"

" _liblyと使いたいプラグインをカンマ区切りで記述
let g:plugin_loader_plugins = "_libly,copy,feedSomeKeys_3,prevent-pseudo-domain"

" copy.jsの設定例
javascript <<EOM
liberator.globalVariables.copy_templates = [
    { label: 'title',     value: '%TITLE%'},
    { label: 'markdown',  value: '[%TITLE%](%URL%)'},
    { label: 'n',         value: '%TITLE%\n%URL%'},
    { label: 'image',     value: '![](%URL%)'},
    { label: 'decoded_URI', value: 'copy decoded URI',
        custom: function () {
            return decodeURI(content.document.location);
        }
    },
    { label: 'github_repository', value: 'copy repository name of Github',
        custom: function () {
            return content.document.location.pathname.replace('/','');
        }
    },
    { label: 'line',      value: '%TITLE% - %URL%'},
    { label: 'textile',   value: '%TITLE%:%URL%'},
    { label: 'anchor',    value: '<a href="%URL%">%TITLE%</a>'},
    { label: 'selanchor', value: '<a href="%URL%" title="%TITLE%">%SEL%</a>' },
];
EOM

" mapを上で設定すると不安定なので、ここで設定
nnoremap <Leader>yd :copy decoded_URI<CR>
nnoremap <Leader>yt :copy title<CR>
nnoremap <Leader>ym :copy markdown<CR>
nnoremap <Leader>yn :copy n<CR>
nnoremap <Leader>yi :copy image<CR>
nnoremap <Leader>yg :copy github_repository<CR>
nnoremap <Leader>yl :copy line<CR>
nnoremap <Leader>yT :copy textile<CR>
```

などと書けばよい。