◆ Simplenote はけっこう便利だけどスニペット向けじゃないところが扱いづらい
◆ Snipit はウェブのみ
◆ massCode はローカルのみ

ツール探し

これまでスニペット管理ツールを使おうとしては使ってませんでした
理想はショートカットキーでウィンドウが出て テキストを入れるとフィルタされて結果から選択するとクリップボードにコピーされるものです

ですが そういうのって特に無いのですよね
以前よさそうなのがあったのですが有料でしたし

結局 IME に登録したり AHK のホットワードに設定したり クリップボードツールに設定したりになりました
それでもほとんど使わず思いついたときに登録だけしたのが数個くらいです

慣れていなければ 数行ならその場で書いたほうが速いし 長いならググったほうが速いになってしまってます
ただそれも面倒になってきたので良いツールがないかなと久々に探してみることにしました

Gist 系

普段使ってる Gist も一応スニペット管理ツールです
今回意図してるスニペットとは「よく使い回す短いテンプレコード」なのですが Gist に普段置いてるのはそういうのとはちょっと違います

ブログに書いた内容のコードだけを置いたり package.json を配置しておけば npm でインストールできるので npm 用のものを置いたり
色々ありますが 基本的に後から使うことはあんまりないものの物置き的な扱いです

それらと一緒に置くこともできますが 検索しづらくなりますし 分けておきたい気持ちが強いです
なので Gist 系統は使わないことにします

メモツール

普通のメモツールを使うことも考えました

OneNote, GoogleKeep, Evernote, Notable, Joplin, Trilium, Simplenote などです
普通のメモとしてはそこまででもスニペット管理ツールとしては良いものがあるかもしれません

OneNote や GoogleKeep はコードブロックが書けません
Evernote はコードブロックは書けますがコードハイライトはありませんし エディタ機能に難ありです

Notable や Joplin は悪くはないのですが そこまでピンと来ません
他にないなら候補がないなら使えなくはないです

Trilium は機能が多すぎてよくわかりません
画面もごちゃごちゃしていて扱いづらめです

スニペットだけでいいのでシンプルなものでいいのですよね

Simplenote

https://simplenote.com/

そう思ってたら Simplenote が結構いい感じでした
メモツールとして見たときは WYSIWYG もなく画像等の添付もできないしで不満が多かったのですが 短いコード専用ならいい感じです
markdown で書いたコードはハイライトされますし オンラインで同期機能もあります
さらに編集履歴まで管理されています

ローカルアプリがあるのでそのショートカットにショートカットキーを設定しておけば 他のアプリで作業中でも Simplenote のウィンドウをアクティブにできます

これで問題ないじゃんということでしばらく使っていました
しかし 使っていると不便な点もありました

シンプルな分 設定も少なすぎるため フォントもデフォルトです
コードブロックは font-family が monospace なので汚いですし 編集中は等幅フォントでもないのでコードには不向きです

markdown モードにしてコードブロックを書かないといけないという手間もあります
また markdown のプレビューではタブも半角スペースに変換されます

あとコピーボタンがないのでコードブロックの範囲を全選択して Ctrl-C をする手間もあります
これはスニペット管理ツールとは違うので仕方ないですけど

ローカルアプリは Electron で devtools を開けるので スタイルを変えてコピーボタンを用意することもできますけど そこまでするのもなぁという気がします

スニペット管理ツール

やっぱりスニペット管理の専用ツールのほうがいいかなと思ってその方針で調べてみました
以前探したときも思ったのですが このジャンルは有料サービスが多い気がします

無料で良さそうなのはとりあえずこの 3 つでした

  • 3Cols
  • Snipit
  • massCode

3Cols

3Cols は紹介だと良さそうにも見えたのですが いざつかってみようとしたらまともに使えませんでした
サイトがすごく重い感じで全然つながらなかったり 画像はロード失敗したアイコンですし public から検索しても何も反応がありません
ログイン・登録のリンクも押してみましたがずっとロード中です

一時的なものだとしてもウェブ上にデータがあってこういうのがあるようだと必要なときに使えないこともあるので選択肢からは外しました

massCode

https://masscode.io/

ローカルアプリでオフライン専用です
他の端末と同期する機能はないです
同期するならオンラインストレージを使ってという方針のようです

スニペット管理ツールらしく テキストのみで画像を使うなどのノートアプリにある機能はないようです
それでも markdown に対応しているので⇩のように書いたらプレビューでローカルの画像を表示できました

![alt text](/Users/user10/Desktop/icon32.png)

エディタ部分は monaco editor なのでコードを書くのに向いています

UI の感じを見るに mac の Quiver クローンぽさを感じます
使ったこと無いので使い勝手的な意味ではわかりません

機能的にはシンプルながらも完成してるように見えますが 右クリックが使えないとか不便なところもありました

またエクスポート機能は実装されてないようです
バックアップという機能はありますが あくまで指定したフォルダに db ファイルをそのままコピーするだけでした

db ファイルは sqlite かと思ったらテキストファイルで json の行が並んでるというものでした
やろうとすれば自分でパースして取り出し可能です

snippets.db ファイルの中身はこういう感じです

{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":""}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876304044},"_id":"GNuQsoKFlXXazmiv"}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"a"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876304066},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"ab"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876316388},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abc"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876318446},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcd"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876318733},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876318860},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\n"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876319150},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nx"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876320304},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxy"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876321500},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876321732},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz\r\n"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876321973},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz\r\n1"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876322478},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz\r\n12"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876323152},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz\r\n123"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876323238},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}
{"name":"Untitled snippet","folderId":null,"content":[{"label":"Fragment 1","value":"abcde\r\nxyz\r\n1234"}],"tags":[],"isFavorites":false,"isDeleted":false,"createdAt":{"$$date":1585876304044},"updatedAt":{"$$date":1585876323359},"_id":"GNuQsoKFlXXazmiv","tagsPopulated":[]}

中身を見ると文字を打つたびに全部履歴として保存しているようなデータです
上のデータは 1 つのスニペットに対して適当にテキストを打った時のデータです
1 文字増えるごとに 1 行が保存されています

1 文字入力単位でバージョン管理されてるなら 以前のバージョンに戻す機能もあるのかなと思ったのにそれらしい機能はありませんでした
将来的に追加されるのかもしれません

あと 説明をみるとトレイに格納できるらしいです
スニペット管理ツールなら常駐してほしいですし 良さそうなツールだなと思った理由だったのですが Windows は非対応でした
ドキュメントを見ると mac のみ対応らしいです

Snipit

https://snipit.io/

Snipit は massCode とは反対でウェブ専用です
ローカルアプリは存在しません

また全てがパブリックとなり公開されます
非公開のプライベートにもできますが有料の pro のライセンスが必要です

自分のアカウント情報などを含んだコードを乗せれないデメリットはあります
しかし スニペットなんてほとんどは見られて困るものでもないのでこれはこれでいいかもしれません
パブリックのほうが一々ログインしなくても どの端末でも見れるメリットがあって楽です
Gist もプライベートはほぼ使ってませんし

ウェブになるのでアカウントが必要ですが Github 連携ができてユーザ名など何一つ登録せずに使えました
面倒な登録無しで使えるのは良いところです

エディタなどは特に問題もなく普通に使えます

ブラウザ拡張機能が用意されているので 拡張機能から検索してコピーしたりできるのかなと思って入れてみたのですが 検索機能はありませんでした
公式サイトへ移動してそこで検索するしかありません
拡張機能ができることは公式サイトへの移動と 選択したテキストをスニペットに保存するだけです
Stackoverflow などを見てるときに即保存するのが目的みたいです
保存のほうが公式サイト開いてやれば良いことだと思うのですけどね
どこでもポップアップを表示して検索できてほしかったです

ただ Snipit には API があります
VSCode 拡張機能があって VSCode からスニペット検索が可能です
VSCode で検索するために内部で Snipit の API を呼び出しています
そこで使うためのトークンがユーザページに表示されています

VSCode 拡張機能は Github で公開されているので 呼び出し方はここを参考にすればわかります
https://github.com/snipit-io/vscode-extension/blob/master/src/api/index.ts

Node.js だとこういう風にリクエストすれば自分のスニペットから検索できます

const fetch = require("node-fetch")

const token = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
const query = "html"

Promise.resolve().then(async () => {
const res = await fetch("https://snipit.io/api/snippets/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
"token": token,
},
body: JSON.stringify({
q: query,
}),
})

console.log(res.status)
console.log(await res.json())
})
{
status: 'ok',
snippets: [
{
id: 99999,
title: 'foo bar',
alias: 'foo-bar',
url: null,
code: '<!doctype html>\n' +
'\n' +
'<meta charset="utf-8" />\n' +
'\n' +
'<h1>hello</h1>\n',
is_favorite: null,
visibility: 'public',
date_added: '2020-01-01T00:00:00.000Z',
date_modified: null,
hash: null,
bookmark_for: null,
clone_for: null,
user_id: 99999,
category_id: null,
language_id: 99,
Language: [Object],
Tags: [Array],
Category: null,
search_score: 1111111
}
]
}

レスポンスの ID などは適当に置き換えています

これを使えば 自分でポップアップを表示して検索するブラウザ拡張機能を作れます
Chrome で拡張機能にグローバルショートカットキーを割り当てれば他のアプリ中でも即表示可能です

ただよく考えると 公式ページを開くショートカットキーを登録でもそこまで手間は変わらないかもしれません
公式サイトを開く系ってログインしないといけないのが面倒なのですが Snipit の場合 Github 連携でログインして Snipit のサイトではパスワード入力はしないので手間はほとんどありません

まとめ

Snipit と massCode は別方向なのでどっちも良さがあって決めるのが難しいです
Simplenote もこれらにないメリットもあります
とりあえずこの 3 択にはなったのですが 決めかねているところです

Simplenote

  • [+] バージョン管理
  • [+] ローカルアプリ+ウェブ (同期)
  • [+] エクスポート可能
  • [-] スニペット向きじゃない (非等幅フォント/コピーしづらい/タブがスペースになる/markdown モード必須)

Snipit

  • [+] ウェブ (同期)
  • [+] パブリックにできる (ログインしなくても見える)
  • [+] スニペット向き
  • [-] ローカルアプリなし (VSCode から検索はできる)
  • [-] ウェブ (サーバ落ちると使えない)
  • [-] エクスポートできない (ウェブなのでスクレイピングすれば)

massCode

  • [+] ローカルアプリ
  • [+] スニペット向き
  • [-] 同期なし
  • [-] エクスポートできない (一応 db ファイルから取り出せる)