ちくわ

ちくわにきゅうりを入れるとうまい

手元のテキストスニペットを alfred にもってきた話

snippet 便利ですよね。 長らく peco + zsh を使って CUI 上でスニペット運用をしておりました。 まさに、以下の仕組みです。

blog.glidenote.com

これはこれで非常に便利なのですが、本番サーバに入っている場合は都度ローカルターミナルを開いて(或いは移動して)、スニペットを出すコマンドを実行し、セレクトするため、ちょっとアクションが多いなという所感を持っていました。

そんな中、alfred version3 がリリースされました。

私の alfred への依存は強く、今回のバージョンアップで別途お布施が必要でしたが、ここは投資と思い支払いましたよ。ええ。
このアップデートで Snippet 周りも厚くなりましたので、これを機に移行できるといいなぁと思ったのですが、

% cat .snippets | grep -v '^$' | grep -v '^#' | wc -l
     162

162 回もポチポチ & コピペ登録するのは、つらい。あまりにツライ。これをするなら懸垂 162 回したほうがマシです。
そこで、なんとか .snippet ファイルの中身(テキストファイル)を、alfred へ一気に import 出来ないかチャンレンジしてみました。

テキストファイルの中身

こんな事もあろうかと、以下の法則で今まで snippet をしたためていました。

# <Group name>
<snippet>  ## <description>
<snippet>  ## <description>
<snippet>  ## <description>

# <Group name>
<snippet>  ## <description>
<snippet>  ## <description>
<snippet>  ## <description>

例えばこんな具合です ( desctiption はあったりなかったり)

# sar
sar -W -f /var/log/sa/sa13  ## 13日の Swap I/O 量を見る pswpin/s pswpout/s
sar -r                      ## メモリ見たい             kbmemfree kbmemused  %memused kbbuffers  kbcached kbswpfree kbswpused  %swpused
sar -b 1 0                  ## I/O みたい               tps      rtps      wtps   bread/s   bwrtn/s
sar -B 1 0                  ## ページングみたい         pgpgin/s pgpgout/s   fault/s  majflt/s

# mysql
mysql -e "show processlist"
mysql -e "show full processlist"
mysql -e "show slave status\G"

因みに、実際に clip board に入る時は ## より後ろは削っています。

alfred の snippets

Import 可能なスニペットの中身を見てみたところ、zip 圧縮され、且つ中身は json ファイルであることが分かりました。

% file Funny\ Quotes.alfredsnippets
Funny Quotes.alfredsnippets: Zip archive data, at least v2.0 to extract
% unzip Desktop/Funny\ Quotes.alfredsnippets
% cat Saturn\ \[9BD50C62-F721-40AF-B14E-40E1BE99FC4E\].json
{
  "alfredsnippet" : {
    "snippet" : "\"The scientific theory I like best is that the rings of Saturn are composed entirely of lost airline luggage.\" - Mark Russell",
    "dontautoexpand" : true,
    "uid" : "9BD50C62-F721-40AF-B14E-40E1BE99FC4E",
    "name" : "Saturn",
    "keyword" : "!saturn"
  }
}%
% ls *.json
I love deadlines [87868B4B-E45F-416A-801F-9BC26977FCC6].json        Some cause happiness [FC15A1C6-AC5C-453B-84FE-DCB94358D290].json
Invention my dear [300075D6-64BA-44BC-B643-B71AA6DB6142].json       This land [539C8F65-0233-4B3A-87EF-C8502D613A34].json
Review [4CDF63ED-A19F-4621-968B-95AB86AB6E78].json          Timey Wimey [7FA27F84-4BAC-4C28-B837-493DD9EBC0D9].json
Saturn [9BD50C62-F721-40AF-B14E-40E1BE99FC4E].json          To err is human [7A706F3E-5F2C-4008-95F3-7978968C1369].json

いい感じに変換すればいい感じに import 出来そうと見立てて、勉強も兼ねて ruby で変換スクリプトを書いてみました。

実際の変換

書いてみたスクリプトはこちらです。

f = open(ARGV[0])

f.each do |line|
  if line =~ /^#/
    @collection = line.gsub(/# (.+)/, '\1').gsub(/ /,'_').chomp
  elsif !(line =~ /^$/)
    line = line.gsub(/\\/) { '\\\\' }.gsub(/"/,'\"')
    snippet = line.gsub(/\s+##.*/,'').chomp
    name = line.gsub(/^(.*)\s+##(.*)/,'\2 # \1',).chomp
    uuid = `uuidgen`.chomp
    filename = "[" + uuid.to_s + "]" + '.json'
    output = <<-EOS
{
  "alfredsnippet" : {
    "snippet" : "#{snippet}",
    "dontautoexpand" : true,
    "uid" : "#{uuid}",
    "name" : "#{name}",
    "keyword" : ""
  }
}
    EOS
    File.write(filename, output)
  else
    command = "zip -m " + @collection.to_s + ".alfredsnippets *.json"
    p command
    system(command)
  end
end

実行の様子

% ruby alfredsnippets.rb ../.snippets
"zip -m misc.alfredsnippets *.json"
  adding: [052CB956-62CF-40D1-A6DE-2B0830D501CB].json (deflated 36%)
  adding: [057ECFAA-F4C0-43B5-A1A7-5121EE91B9A6].json (deflated 40%)
  adding: [0B366B6D-FDC8-4C71-A9C1-BB8BEC0B8550].json (deflated 33%)
  adding: [1164B1B4-82A3-403D-8769-C749A9E853C2].json (deflated 35%)
  adding: [1212D3DA-EAC8-4F1E-A065-C15DD144CE53].json (deflated 39%)
-- -- snip -- --

import 可能な状態でファイルが生まれました。

% ls
Vagrantfile.alfredsnippets
alfredsnippets.rb
apache.alfredsnippets
daemontools_+_dnscache.alfredsnippets
dstat.alfredsnippets
find.alfredsnippets
-- -- snip -- --

一つの impoort ファイルに纏めても良かったのですが、ここである程度の塊でグループ化(alfred のアプリでは collection という名前になっている)した方が便利っぽそうだったのでそうしています。
(alfred の snip を開くと collection 毎に区別されて表示することができる。)

ただし、複数ファイルを同時に import 出来なかったので、個々だけはツライ D&D 業がまっていました。ぐぬぬ。

とりあえずこれで import は出来ました。 こんな感じに使えています。

f:id:ginbear:20160614202926p:plain

今回仕様部分として悩ましたかったのが、折角残していったコメント部分が、どうしても途切れてしまうことです。 alfred から読みだした時に、長いコマンドやコメントのものは省略されて、全部読むことが出来ないのです。上記キャプチャ画面でも ... で省略されている事がわかります。 貼り付けする内容は全文出るのですが、そこにフックしてコメントアウト以降を外すといった事は出来無さそうでした。

ここでは、とりあえずコメント部分を最初に持ってきて、最初だけでも読めるようにしました。ここは未だに納得がいってない...

まずはこれで運用してみて、便利そうであれば本格的に alfred に snippet を移行しようと思います。だって高いお金払ったんだもの。

ruby スクリプトについて

勉強用に書いたので突っ込みどころはたくさんあると思います。お待ちしております。
後、正直まだちゃんと import できているかは未検証なので、まだ何か処理を加える必要があるかもしれません。
バリデーション部分はちょっとハマったところでした。(コメントアウト自体をコメントアウトする、ダブルクオーテーションもエスケープする)

メソッドチェーンがパイプの様に使えるので(語弊がある発言かも)、shell に慣れているとささっと書けて ruby 便利と思ったのでした。