Vimのバッファ上のURLを全てMarkdownのリンクにする


にわかVimmer始めました。
`rubydo`コマンドでバッファの各行にRubyを実行できることを知って使ってみたくなった。
URLをMarkdownのリンクにするコマンドを書いてみた。(実用性不明)

```rb:コマンド
:rubydo require 'uri'; require 'open-uri'; $_.gsub!(URI.regexp(%w|http https|)){|u; t|open(u){|f| t = f.read.match(%r|<title>(.*?)</title>|)[1]} rescue puts "開けないよ。: #{u}"; t ? "[#{t}](#{u})": u }
```

```text:実行前
やふー→http://www.yahoo.co.jp/←
ぐーぐる→http://www.google.co.jp/←
あっぷる→https://www.apple.com/jp/←
```

```text:実行後
やふー→[Yahoo! JAPAN](http://www.yahoo.co.jp/)←
ぐーぐる→[Google](http://www.google.co.jp/)←
あっぷる→[Apple](https://www.apple.com/jp/)←   
```

`rubydo`は一行しか実行できないので、無理やり一行にした。
こんなのいちいち入力してられないので、コマンドを定義する。(雑)

```
:command MDLink rubydo require 'uri'; require 'open-uri'; $_.gsub!(URI.regexp(%w|http https|)){|u; t|open(u){|f| t = f.read.match(%r|<title>(.*?)</title>|)[1]} rescue puts "開けないよ。: #{u}"; t ? "[#{t}](#{u})": u }
```

これで`:MDLink`と打つだけで実行できるようになる。
実行を繰り返すとおかしいことになるけど「u」押せば無問題。
複数行に渡る複雑なスクリプトは`:ruby <<`でやったほうがいいと思われる。

以下説明。

# 参考

- [Vim documentation: if_ruby](http://vim-jp.org/vimdoc-ja/if_ruby.html)
- [Vimスクリプト基礎文法最速マスター - 永遠に未完成](http://d.hatena.ne.jp/thinca/20100201/1265009821)
- [コマンドを定義する — 名無しのvim使い](http://nanasi.jp/articles/code/command/command.html)
- [vim-jp » Hack #158: ユーザコマンドを定義する](http://vim-jp.org/vim-users-jp/2010/06/29/Hack-158.html)

# rubydoコマンド
`rubydo`はVimのバッファの各行にRubyを実行できるコマンド。
1行は`$_`という変数に格納され、その変更も反映される。

`バッファ.each_line{|$_| rubydoの処理 }`みたいな感じ。
each_lineは変更を反映しないけど。

例:

```text:コマンド
:rubydo $_.upcase!
```

```text:実行前
abcd
efgh
ijkl
```

```text:実行後
ABCD
EFGH
IJKL
```

(上の処理は大文字にしてるだけなので、ノーマルモードで「gggUG」と叩いても可能)

# Rubyかんたんに説明

## URI.regexp
URI.regexpで、URIにマッチする正規表現を得られる。

```rb:URI.regexp
require 'uri'

URI.regexp %w|http https|
```

```text:結果
/(?=(?-mix:http|https):)
        ([a-zA-Z][\-+.a-zA-Z\d]*):                           (?# 1: scheme)
        (?:
           ((?:[\-_.!~*'()a-zA-Z\d;?:@&=+$,]|%[a-fA-F\d]{2})(?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*)                    (?# 2: opaque)
        |
           (?:(?:
             \/\/(?:
                 (?:(?:((?:[\-_.!~*'()a-zA-Z\d;:&=+$,]|%[a-fA-F\d]{2})*)@)?        (?# 3: userinfo)
                   (?:((?:(?:[a-zA-Z0-9\-.]|%\h\h)+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:(?:[a-fA-F\d]{1,4}:)*[a-fA-F\d]{1,4})?::(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))?)\]))(?::(\d*))?))? (?# 4: host, 5: port)
               |
                 ((?:[\-_.!~*'()a-zA-Z\d$,;:@&=+]|%[a-fA-F\d]{2})+)                 (?# 6: registry)
               )
             |
             (?!\/\/))                           (?# XXX: '\/\/' is the mark for hostport)
             (\/(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*(?:;(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*)*(?:\/(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*(?:;(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*)*)*)?                    (?# 7: path)
           )(?:\?((?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*))?                 (?# 8: query)
        )
        (?:\#((?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*))?                  (?# 9: fragment)
      /x
```

## String#gsub
URI.regexpで得た正規表現を使ってURLを「●」に置き換えてみる。

```rb:String#gsub
sample = <<EOS
やふー→http://www.yahoo.co.jp/←
ぐーぐる→http://www.google.co.jp/←
あっぷる→https://www.apple.com/jp/←
EOS

sample.gsub(URI.regexp(%w|http https|), '●')
```

```text:結果
やふー→●←
ぐーぐる→●←
あっぷる→●←
```

## open-uri
open-uriでソースをダウンロードしてタイトルを抜き出してみる。

```rb:open-uri
require 'open-uri'

url = 'http://www.yahoo.co.jp/'

open(url){|f| f.read.match(%r|<title>(.*?)</title>|)[1] }
```

```text:結果
Yahoo! JAPAN
```

## 終わり
上の3つを組み合わせる。

```rb:置換
sample = <<EOS
やふー→http://www.yahoo.co.jp/←
ぐーぐる→http://www.google.co.jp/←
あっぷる→https://www.apple.com/jp/←
EOS

require 'uri'
require 'open-uri'

sample.gsub! URI.regexp(%w|http https|) do |url; title|
  open(url) do |f|
    title = f.read.match(%r|<title>(.*?)</title>|)[1]
  end rescue puts "#{url}を開けませんでした。"

  title.nil? ? url : "[#{title}](#{url})"
end

puts sample
```

```text:結果
やふー→[Yahoo! JAPAN](http://www.yahoo.co.jp/)←
ぐーぐる→[Google](http://www.google.co.jp/)←
あっぷる→[Apple](https://www.apple.com/jp/)←
```

で、このソースを加工してrubydo用にしたのがこの記事の最初にあるコマンド。

ちなみに`ruby`や`rubydo`などのRubyを利用するコマンドは、自分で使う.vimrc等に使うならいいけどVimのプラグインとして配布するときとかには使わないほうがいいらしいです。
相手の環境にRubyがない可能性があるため。