タグ "Hack" が付けられた記事

LintとFormatをGitのコミット時に自動でかける方法

  1. 1. 使うもの
    1. 1.1. Husky
    2. 1.2. lint-staged
  2. 2. インストール
  3. 3. 設定
    1. 3.1. まずhuskyの設定
    2. 3.2. lint-stagedの設定
  4. 4. おまけとまとめ

前回、LintとFormatをかけるのはもちろんなんだけど、なんでGitHookのタイミングにしたかって話を書いた。今回はそれの具体的な方法を書いていこうと思う。

ちなみに前回書いたやつ。

使うもの

まず使うNPMのライブラリを使うので、Node.jsを用意してください。これmacならbrewでyarnを入れてもいいし、僕はanyenvを経由してndenvを使ってる。いろんなやり方があるし、それぞれ利点が違うので自分にあった入れ方を推奨。

それで使うライブラリなんだけど

  • husky
  • lint-staged

の2つ。以下で簡単に紹介しよう。

Husky

huskyはGitHookをプロジェクト単位で設定できるようにするツール。
GitHookの設定は通常だと{project root}/.git/hooks/配下にある。.git以下は通常ではリポジトリに含まれないので共有されない、つまりhookを共有したり強制したりできない。

だから、husky経由で共有できるところで設定できるようにする、というのがhuskyの役割。どうやらhuskyを入れたときにGit hookをhusky経由で動くように入れかえてるっぽい。

lint-staged

lint-stagedはgit addした対象に対して特定のコマンドを走らせるもの。READMEにもあるとおりhuskyと合わせて使うのがオススメとされている。ちなみに以前はhusky以外にもpre-commitをやり方やいろいろあった。あと、名前はlint-stagedだけどやることはstagingされたコミット前のものに対して何かをするのでlint以外にも使える。

ちなみに昨年前半あたりまでずーっとハンク(git add -p)したファイルの対応する方法に関してissueで議論されていたが、昨年中頃にlint-stagedがアルファ版を経て正式に対応した。個人的にハンクはかなり使うのでずっと動向を追っていたし、これが解消されたからプロジェクトに導入したし、紹介するに相なりました。

インストール

npmに慣れてる人には言うまでもないだろうけど

$ yarn add -D husky lint-staged
# or npm install -D husky lint-staged

でOK。

設定

package.jsonに設定を書いていく。ちなみに別ファイルに分けることもできるけど、そう複雑で長い設定でもなく、huskyとlint-staged両方とも連続した設定になるし、package.jsonのscriptともかかわることもあるので個人的にはpackage.jsonだけでやっちゃうのが良いと思ってる。

まずhuskyの設定

以下を追加

package.json
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},

要はhuskyの設定を、hooksのpre-commitにlint-stagedコマンドをするよ、という設定。
ここではpre-commitだけだけどもちろん他のhookも同様に書くことができる。詳しくはhuskyのREADME参照。

lint-stagedの設定

同様にlint-stagedの設定もpackage.jsonに書く。ここはどのようなファイルにどのようなlintをするかので一例として

package.json
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix",
"git add"
]
},

みたいに設定する。
lint-staged直下の設定で対象のファイルのglobパターンを書く。例えば上の例だったらGitのStageにある拡張子がjs,ts,vueのものにeslint --fixがかかる。これで自動で修正された結果のファイルが再度addされて、問題なければcommitされる。

もちろん、lintの結果エラーが返ったときはcommitされない。意図的にpre-commitフックを避けない、という前提のもとであればコミットされたものは全てプロジェクトで設定されたLintのルールにパスしていることが担保される。

で、もちろんファイル名の条件にしたがってコマンドを走らせるだけなので、

package.json
"lint-staged": {
"*.{js,vue,ts}": [
"eslint --fix",
"git add"
],
"(*.rb|*.rabl|Gemfile)": [
"bundle exec rubocop --auto-correct --fail-level E",
"git add"
]
},

みたいにやればこの例で言えばJS系だけでなくRubyのファイルにRubocop(Ruby用のLinter兼Formatter)をかけるようにもできる。

ちなみにJS系のformatterとしてprettierがあるけど、eslintのルールとバッティングするところもあるので、eslintにpluginを噛ませてeslintの中でprettierによるformatするのがお勧め。

おまけとまとめ

あとは以前に紹介したcommitizenもNPMなので一緒に使うのも簡単で、そうするとコミットメッセージも綺麗、コミット内容もキレイ、という素敵なコミットができる。

と書いてきたけど、やってることはいろんなところで紹介されてるしそんな難しいことじゃない。
でもNPMがフロントエンド特化傾向にあるため、Node.js系をふだん使ってない人には有用であればうれしいなぁ。特にRailsはWebpackerやらYarnを採用したこともあって相性は悪くないと思う。

途中でもちょっと触れたけどこのGitのハンクに対応したこともあって、この仕組みを業務でも使ってみたけど上手くいってますのでけっこうオススメしますよ。

LintとFormatをGitHook時にかけてる理由

  1. 1. いつかけるか
    1. 1.1. Save時
    2. 1.2. GitHookにひっかける
    3. 1.3. Pull Request時にCIで回す
  2. 2. もうひとつの目的
  3. 3. 実践

LinterとFormatterをかけないコーディングはツラくて個人的にはちょっと悲しくなるんだけど、問題はどのタイミングでやるかってこと。個人的にやっていたものを昨年なかごろから業務にも取り入れてみてそこそこ上手く回っているので書き残しておきたい。

いつかけるか

LinterとFormatterをかけるとしたらいつがいいのかいろいろ考えて、結論から先に言えばGit commit時にしている。なんでそう結論づけたかっていう話の比較を交えてご紹介したい。

Save時

一番頻繁にかかる一例としてファイルの保存時。例えばVSCodeなんかではFixOnSaveとかって設定があるようにわりとメジャーだと思う。

Saveするときにかかるので一番頻繁だし、適当に書いてもガっとキレイにFormatは効くし、変なコードはすぐに警告が出る。良い。

でも残念ながらできるかどうかははエディタ頼みになってしまう。独りで開発しているときは十分かもしれないけど、みんな違うエディタだったり対応できないエディタの使用者がいたら?

例えもし開発者それぞれが使うエディタで全部対応できたとしても、エディタごとに設定もプラグインとかも違ってくるのでどうしてもノウハウが属人化してしまう。

一番大事なのは自分以外も加わるとしたら強制できないのであまり有効でないところ。ルールを適用するならそれは守られなければ意味がない。

GitHookにひっかける

GitにはGitHookという機能があって、commit時やpush時に設定したスクリプトを回すことができる。最初に言ったようにこのフックにひっかけてpre-commit時にLinterとFormatterをかける運用にしている。

理由はcommitをしないことには開発は進められないし、エディタがなんであろうと強制できる。そしてローカル上でエラーが出るのでそのcommitする開発者が自分でエラー箇所を修正することになる。また最悪どうしようもないときは--no-verifyオプションをつけることで一時的にGit Hookを飛ばすこともできる。

ちなみにpre-pushも検討してみたけど、push時に弾かれたり修正が入ることでコミットログがエラーやコーディングスタイルの修正だけになったりして、それは別コミットにすべきじゃないと思ったのでpre-commitにした。

Pull Request時にCIで回す

他の候補としてPull Request時にCI等の外部サービス経由で回すことももちろん検討した。これも結局はpre-pushと同じようにコミットをキチンと整理したいこと、その後のマージ戦略まで影響するのがちょっと面倒で見送った。

ただし方法としては一番、開発環境に依存しない方法だし悪くはないと思う。pre-commitにしろpre-pushにしろ、CIにしろ、ポイントとしては

  1. Lintに通ってないコードを採用しない(できない)。
  2. Formatterのルールにのっとってないコードを紛れこまさない
  3. 1と2を共同開発者全員で共有する

というのが前提として守りたいルールだった。

もうひとつの目的

なし崩し的にチームリーダー的なポジションになって後輩を抱えるにことになったけど、なにもイチから教えることはなくて「こういうコードがいいよね」っていうのはLinterやFormatterに助けてもらうことにした。

なにより僕がレビューコメントや口頭で「こういうコードがいいよ」っていうより、ルールの説明のドキュメントのほうがよっぽど説得力がある。

まずチームにJoinすることになったときにルールを確認してもらって、できればその時になんでそういうルールを設定してあるかもコメント等で共有する。そしてそのルールに納得してもらうようにした。反論は出なかったものの今でも合わないルールがあったら変えるからいつでも相談して欲しいとは伝えてある。

そうすることで例えばLinterではうっかり使用されない変数、到達しえない分岐、デバッグ用のコードなど紛れこんだままだったり、同じ結果だとしてもよりリーダーブルな書き方だったり、そういったことがPull Requestに紛れこまないことによってレビューの時間コストも抑えれるし、エラーが出たら自身でちゃんとルールを参照して修正してもらうようにしてる。そうすることで自身で徐々により良いコードを書けるようになってもらう作戦。

またFormatをキチっとやるのことも僕は大事だと思っていてインデントが不揃いだったり、なんか感覚的に気持ち悪いっていうことだけじゃなく、コーディングスタイルを統一することで読みやすくして、本質じゃないノイズを極力カットすることで本質にフォーカスしやすくするのが狙い。

この目的にあたって注意したのは「ルールは聖域、無視しちゃダメ」ということ。もちろんキビしすぎるルールは時に枷となって開発スピードを鈍化させたりもするんだけど、そういう場合もキチっと直すことを意識した。なんども苦労するようであればそれはルール自体を変更したり緩めたりすることで対応する。

これはLinterのルールは割れ窓理論的に悪化しやすいと思っていて「ああ、このルールはまあ無視してもいいよ」みたいにしてしまうと次第にどんどん広がっていき、最終的にはルールは守られず、無いもの同然になってしまう。その経験が僕にはある。だから「ルールは聖域、無視したいのであればルールの変更を提案しよう」として運用して、事実上手くいってる。

実践

じゃあpre-commit時にLinterとFormatterをかけるための具体的な方法なんだけど、それはちょっと次回に回したいと思います。使ってる言語と環境にも寄るんだけど、僕の主戦場がRubyとJS(TS)なのでそれら限定になってしまう。とはいえフックさせて回すのはNPMライブラリだけでやってるので他の言語のプロジェクトでもNPMを同時に使えば実現できそう。

そんなhuskylint-stagedを使った具体的な設定はまた次回。

追記
書きました。

Firestoreを使うためにVuexFireを使ってちょっぴり悩んだ話

  1. 1. 入れかた
  2. 2. VuexFireのRootのMutationのみ対応
  3. 3. ライフサイクルフックはCreatedで

ちょっと業務でFirestore使ってみようかーみたいな話がでたもんで、おっじゃあちょっと使ってみようと思いまして。で実際使ってみたらアイデアが湧いてきたのでFirestoreを使った趣味Webアプリを作ってみてます。

その過程でVuexFireというライブラリを使ってみてちょっと苦戦したけど無事できた顛末

入れかた

まずVuexFire。

ここで注意したいのはVuexFireという名前だけど、場所はGitHubのvuejs/vuefireにあること。
もともとはVuexFireだったのがVueファミリーに組みこまれたのかな?

それで、注意すべきは入れかたは

npm install vuexfire@next --save
# or yarn add -D vuexfire@next

普通に入れるんじゃなくて@nextが必要なこと。

今の環境に対応するにはalpha版の@nextで入れないと使えないことに注意。
まずこれをちゃんと読まずに入れたら上手く動かずにウンウン唸ったあげく1時間ぐらい飛ばした。無念
。いつもどおりだなーとわかったふりじゃなくてちゃんとREADME読め案件ですね。

VuexFireのRootのMutationのみ対応

そもそもVuexFireはどんなライブラリかっていうとVuexのMutationでデータの変更先をFirestoreにて、Firestore経由でVuexのStoreを扱えするやつ。従来Action経由でMutationをコミットしてStoreを変更するのがMutation部分がまるっとVuexFireになるので、Actionから変更するようなイメージに近くなる。

で、Vuexの細かい話は割愛するけども、Vuexがそこそこの大きさになるとnamespaceで分割していくと思う。でもVuexFireではMutation直で読み込むため、Rootで設定しないとちゃんと動かないみたい。
良くみるとちゃんのREADMEにも書いてある。

VueFire Usage

良く探してみたらこの件についてちゃんと言及してるQiita記事があったので詳細はそこに譲りたいと思います。言及先でもあるようにちゃんとREADME読め案件ですね、読んだつもりじゃなくてちゃんと読むの重要。

ライフサイクルフックはCreatedで

Vue.jsで読み込み時に最初にデータをロードしたい場合、beforeCreateとかで読みこんだりするのが定石だと思う。特にaxiosなんかで外部から持ってくる場合はみんなそうやってると思う。

Nuxtなんかだと、fetchとかasyncDataが備わってるからあたりまえのようにやってるんじゃないかと思う。だからこう、いつもの癖で

export default class extends Vue {
fetch({params}) {
const ref = params //雑な例
this.$store.dispatch('setUsersRef', ref)
}
}

やっちゃってた。

これでウーンおかしいなぁ、データがロードされないぞーウーンウーン、あーでもない、こーでもないってやってたわけで、慣れてないのもあって試行錯誤してみたんだけど、全然そうじゃなくてちゃんとIssueに質問として挙がってた。

というわけで

export default class extends Vue {
async created() {
const ref = params //雑な例
await this.$store.dispatch('setUsersRef', ref)
}
}

createdでフックしなきゃいけないっぽいです。これに気づかずに2時間ぐらいは飛ばした。

ただ、最近のIssueを見てみるともっと早いタイミングでbindする方法も模索してるみたいで、ちょっと期待。とにかく今はcreatedでやるしかない。

なので、絶対にデータがある前提でもcreatedフックでbindしても実際のデータがロードされるのは表示領域が発生してからということもあると思うのでそこでエラーにならないように実装する必要もある。

これで使えるようになったけど、じゃあ実際にアプリを動かしてみるとVuexFireをメインで使っていくのがいいのかはまだちょっと不明。とくにロードのパフォーマンスというかドキュメントの取得回数的に。そのへんのことはまたそのうち書くと思うけど、firestore面白いけど、反面Productionレベルでの知見がまだまだ出てきてない(そりゃBetaだから当たり前かもだけど)。

使ってみた、はたくさんあるけど、デプロイ以降運用やパフォーマンス、設計のベストプラクティス、金銭的に効率の良い使い方とかプロジェクトの扱うドキュメントの数にもよるけど考えることは無数にある感じ。なので「使ってみた」に留まらずちゃんと人が使えるレベルまで落としこんで知見をどんどん身につけていきたい所存。

そろそろ本気でちゃんとブログを書こうと思った

  1. 1. 毎週ブログを書くSlackに参加した
  2. 2. ハードモードでスタートです
  3. 3. 共闘感
    1. 3.1. slackのおかげ?
  4. 4. 手助けできたこと
  5. 5. 気後れしますがやっていこう!

また随分と最後の更新から日があいたようで。
最近いろいろ思うところあって、アレでアレな現実をソバットで一蹴する生存戦略的な考えもあってアウトプットをいよいよ本腰いれて加速していこうと思いまして。
たまたまみかけたブログで紹介されてたのでとあるSlackに参加してみた顛末。

毎週ブログを書くSlackに参加した

「write-blog-every-week」というものなんだけど、まぁその名のとおり毎週ブログを書くことをやっていこうというやつ。

仕組みとしては

  • 書かない日がしばらく続くとたまにSlackBotから通知が来る
  • 書かない週が一定期間続くと強制的に退会になる
  • 他の人のアップしたブログ記事がFeedとして流れてくる

というわりと単純なもの。

そうやってリマインドがありつつ、Slackなので通知以外にもコミュニティ的に他のみなさんと話したり
ネタをシェアしてみたり、何か質問をしてみたりとして周ってるご様子。

一番のポイントはというと一定期間、つまり4週間更新がなく5週目になったら強制的に退会させられるということ。
新参者なので僕は知らないが、今までに退会した人はいるのだろうか……

ハードモードでスタートです

おそらく僕が見たブログ記事がバズったからだと思うんだけど、僕がこうして参加したのと同じにように、どうやら同時期に一気に人が増えたらしい。

当初は参加承認は自動でやっていたようだけど、急激な人数の増加と人数の増加によるフィードが多すぎたり、リマインドの緊張感の薄れなどを懸念されたようで、現在は一旦参加を締めきってしまった様子。

ちなみに参加だけされて結局自分のブログを登録されなかった人も幾人かいらっしゃったらしく、退会となっていったようです。このまま人数が落ちつけば再度募集もあるらしいです。

そして、さらにはそれまで強制退会までの猶予週間が4週間から2週間に改訂されるとのこと。

こいつはのっけからハードだぜ……

共闘感

で、実際参加してみて一番感じたのは共闘感。

これまでブログを書くっていう作業は完全に一人の作業で、どっちかってっとちょっとしんどい。書いても別にすごくバズるわけでもなく、どこかでフィードバックが貰えるわけでもなく。それでもなんかアウトプットにしないと自分からじんわり無くなっていくようなジレンマというか。

それが他にも同じような仲間と知りあって、ちゃっとしたり、反応しあったりしてる空間というのはそれだけで気が楽になるんだなぁ、と思った。

常時そんなバシバシチャットが交わされるわけではないんだけど、誰かが新しく記事を書いたり、こういうネタが、とかあったりして良い感じで刺激がある。

slackのおかげ?

もしかしたらそれもSlackのおかげで、Slackだと絵文字アイコンのリアクションがとりやすくって
だれかが反応したら自分も同じく反応できやすい。

自分の発言として流れるわけではなく、あくまでも誰かのリアクションに賛同みたいなライトな感じがとても居心地がよくて。乗っかれる気軽さってすごい。

いつも業務では某ChatWorkなんだけど、同じようで実は大きな差異なんだなぁと思い知った。
あとはMarkdownに準拠した記法とか。なんか独自タグみたいなのじゃないのってすごく楽。
弊社、某ChatなんとかとかいうのからSlackに乗り替えてくれないかなぁ……

Slack今まで軽くは使っていたけど今回初めてちゃんと使ってこうも良いものかと知れたのは大きい。
常々僕自身、コミュニケーションをポジティブに回すためにシステムで手助けできることはある、と思っていたのを今回あらためて実感できて良かった。

手助けできたこと

先日、たまたま家の都合で休みをとって自宅で趣味開発してたときに、
「Twitterで自分の記事がシェアされたときに補足するのはどうしてる?」
という話題があがっていて、僕はTwitter検索でurl:blog.solunita.netみたいにしてますよーという返信をした。

しかしながらどうも件の方のブログのURLだと検出されないようでなんでだろうと思っていろいろ検証した結果、どうもurl:で検出したい対象を指定するとき、指定対象(URL)に-が入ってると上手くいかないようだった。例えばURLがwww.example-jp.comのような場合。

検証の結果、url:"www.example\-jp.com"みたいにクォートで囲んでやるとバックスラッシュでエスケープが効くようになるということをつきとめて解決できた。

Twitterの検索は公式でもあまり多くを言及してない印象だけど、それでもそこそこ高機能で、それ以外にも基本的には後方一致だったりもする。なのでサブドメインをまたいだ検索とかも結構楽。

あと、-from:AquiTCDでAquiTCDさんからのツイート以外(つまり自分発信じゃないものだけ)、みたいなのもできるし-rtでRTを弾くこともできたり。

ちなみに言えば僕はTweetDeck派なので、自分のブログのほか、自分が趣味でつくったアプリとか
chrome拡張とかを全部ORでつなげたごった煮な検索式でカラムを作ってウォッチしてるだけで事足りてるが、話題に上ったのはIFTTで通知をする方法とか。

Twitterの検索結果をIFTTに通知するのはすごく簡単なので、僕は天気予報とかで雨の時だけLINEに飛ばしてたりする。

気後れしますがやっていこう!

僕なんかでも参加してすぐに他の人の役にたてたり、まわりでも奮闘してる仲間がいて嬉しい反面、そればかりではなく。

このブログは技術以外の内容も書く雑記ブログなので「技術的なアウトプットをしようよ」みたいなところで全然関係ない話をアップしていいものかと躊躇する。

躊躇するものの、筋トレと同じく「まずは体裁はどうであれ、習慣化することに主眼を置くべし」と思って、これから本腰入れてがんばっていこうと思います。

AtomからVSCodeに乗り換えたので使ってる拡張パッケージを対応表にしてみた

  1. 1. 使用感比較
    1. 1.1. UI
    2. 1.2. 見た目のカスタマイズ
    3. 1.3. パフォーマンス
  2. 2. 選択系、変換、入力補助(エディタ操作)
  3. 3. ファイル、タブ、ペイン操作系
  4. 4. HyperClick系
  5. 5. ミニマップ
  6. 6. その他、機能拡張
  7. 7. Linter系(Atomのみ)
  8. 8. 各言語とか用途とか別
    1. 8.1. Git
    2. 8.2. Markdown
    3. 8.3. JSON
    4. 8.4. Ruby
    5. 8.5. JavaScript系(Node.jsやメタ言語、フレームワーク含む)
    6. 8.6. HTML系(メタ言語含む)
    7. 8.7. CSS系(メタ言語含む)
    8. 8.8. PUML
    9. 8.9. その他の言語系
  9. 9. おしまいに

年末年始にAtomの使ってるプラグインを列挙して棚卸しをしたけども、ちょっと前のMSのGitHubの買収を機に食わず嫌いしてたVSCodeを使ってみた。

ただし使うにあたってはAtomで使ってる環境と同程度のことができてくれないとダメなので調べてみた。

結果から言って今はVSCodeに乗り換えてしまった。せっかくなので使ってるAtomとVSCodeの拡張パッケージをそれぞれ対応する表にしてみた。ちなみに元々「俺のAtomは環境だ」と笑い話的に言っていたのでややAtom寄りの表になってるのはご容赦いただきたい。

使用感比較

拡張パッケージ表に行くまえに使用感を比較した所感。100%満足はしてないもののパフォーマンスの恩恵が大きく、なんとかAtomでできたことを損なうことなくVSCodeでも許容できるレベルにもっていけたのが乗り換えの決め手。

UI

ほとんどどちらも同じような感じで差異は大きくない。ただ、プロジェクト内から文字列検索した時の結果表示がAtomのほうがエディタ部に表示されるのでわかりやすい。VSCodeだとエクスプローラー部分に表示されるのが小さくてみづらい。

またキーバインドの設定はAtomイベントが発火したのか表示できるけど、VSCodeは表示する機構がないで、コンフリクトしてるキーバインドのデバッグが非常にしづらい。

見た目のカスタマイズ

見ためのカスタマイズは完全にAtomのほうが柔軟。これはDevToolsを開ける上、設定のLESSファイルを自由に編集できる。ということは変更したい箇所のセレクタにCSSを書いてあげることで如何様にもなる。

一方VSCodeは全てではないものの主要箇所はできて、まあ必要十分かな、という感じではある。個人的にはツリービュー(エクスプローラー)の文字サイズや行の高さなどはカスタムしたいけどできないのがもどかしい。

パフォーマンス

よくAtomは遅いと言われるけど、うん、まあ否定できない。それでも一応速くはなったんだけど。あとログファイルみたいに大きなファイルを開くとビーチボールがぐるぐるしてどうしようもなくなることがある。

VSCodeは最初の表示は速い。ウインドウの起動はちょっとかかるけどAtomに比べたら軽い。またファイル表示はキビキビ開く。ただし、これはどうもLinterやシンタックスハイライトなんかは開いた後でやってるような感じ。まず表示を優先する、みたいな挙動っぽい。大きなファイルは大きすぎた時はまず警告出してくれるので助かる。


さて、以下に拡張機能を列挙していくんだけど、自分で探す場合の注意としてはVSCodeのパッケージは検索すると同名のものが出てきたりする。同名のものをフォークして上げただけ、みたいな感じっぽいけどインストールの際はちょっと注意したい。

また、見つからなかったものは[-]とかって書いてあるけど、単に検索力が足りなかったり別のパッケージの一部にその代替機能が含まれてたりする可能性はあるのでご注意されたし。

選択系、変換、入力補助(エディタ操作)

概要 詳細 Atom Package VSCode Package
矩形選択 SublimeText的な矩形選択。見たままの四角の範囲を選択可能。 Sublime-Style-Column-Selection -
選択範囲を段階ごとに広げる 選択範囲を文字、単語、クォートや括弧で囲んだ要素、と順々に大きくできる。 expand-region expand-region
キャレット列のハイライト - highlight-column -
キャレット行のハイライト - highlight-line ビルトイン
選択した文字列のハイライト 選択してるものと同じ文字列をハイライト。 highlight-selected -
ブラケットハイライト 対応するブラケットをハイライト ビルトイン -
ブラケットカラーハイライト 対応するブラケットごとに色をかえてわかりやすく表示 bracket-colorizer Bracket Pair Colorizer
文字ケースの相互変換 キャメルケースとスネークケースだけでなく、ケバブケースもドット記法なども幅広く対応してるのでうれしい。 change-case change-case
クォーテーションマークを相互に変換 シングルクォートとダブルクォートのトグルだけでなく、設定でバッククォートも対応できる。 toggle-quotes Toggle Quotes
二元的要素のトグル変換 true/falseなどをトグルで変換。設定で対応文字列をカスタマイズ可能。 toggler toggler
タブ-スペース変換 インデントのタブorスペースをトグル変換。 tabs-to-spaces ビルトイン
セミコロンやカンマ付与 今キャレットがどの列にあろうとも現在の行末にセミコロンとカンマをつける。キーバインドで設定すると捗る。 trailing-semicolon toggle semicolon
行末スペース制御 行末のスペースを目立たせたり自動で削除したり。Atomはスタイルをカスタムすると良い感じ trailing-spaces Trailing Spaces
全角スペース制御 全角スペースを強調表示。Atomはスタイルをカスタムすると良い感じ。 show-ideographic-space EvilInspector
制御文字の制御 BackSpaceなど制御文字を削除するフォーマッタ。不意に紛れこむと思わぬバグを起こすのでありがたい。 - Remove backspace control character
連番の数字を挿入 複数行にわたって一括で連番生成。 sequential-number vscode-input-sequence
選択した複数行をソート 選択した範囲に含まれる複数行をアルファベット順や逆順などでソート lines Sort lines
カラーコードの部分だけカラー表示 カラーコードになってる文字列の背景色をその色で表示。CSSとか書くときに便利。StylusやSassの変数も対応してるので重宝する。 pigments Color Highlight
正規表現補助 正規表現をビジュアルで表示してくれる。 regex-railroad-diagram Regex Railroad Diagrams
Path入力補完 Path入力補完、でもたまに邪魔なときがある気がする。 autocomplete-paths Path Intellisense
列のフォーマッタ オブジェクトの定義とか、連続して変数に値を入れるとき、=:をセパレータとして左右のインデントが揃うようにしてくれるフォーマッタ。言語別のものもある。 aligner Better Align
インデントフォーマット ネストした要素のインデントをうまいこと整形してくれるフォーマッタ。JSONとかも良い感じにやってくれたり。けっこういろいろ対応してる。 atom-beautify Beautify
高機能マルチカーソル デフォルトより高機能なマルチカーソル。キーバインドがバッティングしやすいので要カスタム。 multi-cursor-plus -
キャレットの行移動補助 設定した行数文だけキャレットを一気に移動する。Emacsのページ送り的な送り用途として使える。 line-jumper line-jumper

ファイル、タブ、ペイン操作系

概要 詳細 Atom Package VSCode Package
ペイン自動最大化 複数Paneで分割してる時にアクティブなペインを自動的にほぼ最大化する。フォーカスしたペインを自動的に最大化したりもできる。 hey-pane -
ツリービューのフィルタ ツリービューで表示しているファイルをインクリメンタルに絞り込む。 tree-view-filter -
タブの規制 最大タブ数の設定制御。設定数を越えると古いタブから自動的に閉じて入れ変わる挙動になる。設定でピン止めしたファイルや、未コミットファイル除外したりもできる。たくさんファイル開きすぎてわかんなくなっちゃうので。 zentabs -
メソッド定義などのツリー表示 定義されたメソッド、変数などをサイドドロワーにツリー表示 symbols-tree-view ビルトイン
TODOコメントの抽出 プロジェクト内に存在するTODOやNOTEなどのコメントを抽出して表示。 todo-show Todo Tree
GHQ連携 CLIリポジトリ管理ツールghqの管理下にあるプロジェクトのショートカット。全てのプロジェクトがGit管理されていれば、プロジェクトマネージャーはこれだけで十分だと思う。 douglas vscode-ghq
変更ファイルの強調 ツリービュー(エクスプローラー)上でGitステータス▽による色分け表示する。追加ファイルや変更したファイルとかが視覚的にわかりやすいし、未コミットのファイルもみつけやすい。 tree-view-git-status ビルトイン
ファイルエンコーディング判別 エンコーディングの自動判別。 auto-encoding ビルトイン
ファイルエンコーディング変換 マルチバイトのファイルをutf-8に変換。 convert-to-utf8 -
FuzzyGrepファイル検索 プロジェクト内をag的なfuzzyGrepしてファイル表示。 atom-fuzzy-grep -
ディレクトリごとのファイル操作 ディレクトリごとに絞り込みでファイルを開ける、フルキーボードで階層ごとに掘っていく場合に便利。 advanced-open-file -
Expose風タブ操作 開いてるタブをmacのexpose的に表示、切り替えできるやつ。 expose -

HyperClick系

概要 詳細 Atom Package VSCode Package
HyperClick コード中のいろんな要素がクリッカブルになる。キーバインドにも対応していて対象の文字列にキャレットがあるときはキー操作でも動作する。**-hyperclick系のアドオンとかで拡張可能。言語特化のアドオンは後述の言語別のところで。 hyperclick -
HyperClickのURL対応 URLをクリッカブルにしてデフォルトブラウザで開けるようになる。 hyperlink-hyperclick ビルトイン

ミニマップ

概要 詳細 Atom Package VSCode Package
Minimap サイドドロワーにコード全体をざっと単純化して見わたせるようなやつを表示。他のパッケージで拡張可能。 minimap ビルトイン
Minimap選択文字列ハイライト Minimap内で選択した文字を全てハイライト。 minimap-highlight-selected select highlight in minimap
Minimapを自動で隠す ミニマップをスクロールしてないとき以外は自動的に非表示 minimap-autohider -
Mimimap内検索文字列ハイライト ミニマップ内で検索文字列を全てハイライト。 minimap-find-and-replace ビルトイン
Minimapカラーコード表示 ミニマップ内でカラーコード部分をカラー表示。 minimap-pigments -

その他、機能拡張

概要 詳細 Atom Package VSCode Package
多人数同時編集 他の人とつなげて同時にシェアしながらコーディングできる。モブプロ、ペアプロなどでものすごい活躍する。 teletype VS Live Share
Atomキーマップコンフィグ Atomでデフォルトのキーマップに一括で変更する ビルトイン Atom Keymap
コーディングフォーマットの統一 EditorConfigの対応。プロジェクトルートに.editorconfigという設定ファイルを置いて制御。 editorconfig EditorConfig for VS Code
設定の共有、同期 GitHubGist経由でエディタの設定、インストールしているアドオン情報を複数端末で同期する。 sync-settings Settings Sync
ノートテイキング 検索しやすいノートシステムをエディタに組み込み、メモやスニペットなどの一元管理を自分のカスタマイズしたエディタで編集できるのは強み。Atom版はnotational-velocityライクでかなり使いやすい。 atom-notes VSNotes
ブラウザ連携 同名のGoogleChrome拡張をブラウザに入れることで、ブラウザで開いてるページのテキストエリアを同期的にエディタで編集できるようになる。例えばPull RequestなどMarkdown対応のテキストエリアをエディタで編集できるのはかなり便利。 atomic-chrome GhostText
ターミナル エディタ内でターミナルを動作させる platformio-ide-terminal ビルトイン
CSVエディタ エディタからCSVを表計算アプリケーションのように表示、編集できる tablr Excel Viewer
拡張パッケージ管理 パッケージにアップデートがあったら自動でアップデートする。ちょいちょい自分で確認しなくていいので楽。 auto-update-packages ビルトイン
ファイルアイコン ツリービュー(エクスプローラー)やタブにファイルのアイコンを表示して視認性を上げる。VSCodeでは各種テーマでさらにカスタム可能。 file-icons ビルトイン
ファイルタイプの判別補助 自動で判別されるファイルタイプのルールをカスタマイズを楽にする。 file-types -
差分表示、補助 Paneで分割してDiff表示、見やすい。しかも保存してない状態でもDiffとれるので、長大な文字列とか大きめなオブジェクトを一時的に比較するときも重宝する。 split-diff Partial Diff
コードプリプロセス プリプロセッサ言語から元言語へ変換。 preview -
ステータスアイコン ステータスバーに状況表示アイコンをプラス。確かAtom用のLinterと一緒に入ってくるはず。 busy-signal -
ウィンドウタイトルのカスタマイズ Atomのウィンドウに表示されるタイトルのルールを変更できるようになる。上手く好きなようにファイル名の表示とかにカスタマイズすると地味に便利。 custom-title -
定義元にジャンプ メソッドの定義元にジャンプできるようになる。 goto-definition -
ステータスバーにファイル名表示 現在開いているファイル名とファイルパスをステータスバーに表示 ビルトイン Active File In StatusBar

Linter系(Atomのみ)

概要 詳細 Atom Package VSCode Package
Linter Linter機能。各言語用のPackageを別途追加が必要。各言語用のLintは後述。 linter -
Linter表示 Linter表示用UI。たぶんLinter入れると入ってくるはず。 linter-ui-default -

各言語とか用途とか別

Git

概要 詳細 Atom Package VSCode Package
Git総合サポート Git周りのこといろいろ - GitLens — Git supercharged
Git履歴表示 Git logビューア git-log Git History
Git変更内容アイコン AtomにビルトインのステータスバーにGitのファイル変更状況アイコンを表示する - Git Indicators
gitignoreサポート gitignore用のシンタックスハイライト - gitignore
Gist GitHubのGistを編集したりアップロードしたり、挿入したり。Gist系はいくつかあったけどこれが一番使いやすかった。 gist -
Git Blame表示 行ごとにGitで変更した人を表示する。 git-blame GitLens — Git supercharged
Git操作ショートカット よく使うGit操作をAtomから直でできる、Atomのコマンド補完が効くので便利、基本的なgit操作はこれだけでいける。ビルトインのものでも十分だがあると便利 git-plus -
コンフリクトのサポート Gitでmergeしようとしてコンフリクトしたときの編集サポート。 merge-conflicts ビルトイン
ホスティングサービス対応 GitHubなどのホスティングサービスを開いたり、プルリクエストページを開いたりできる。GitHubだけでなくBitbucketなど他のサービスにも対応しててうれしい - Open in GitHub, Bitbucket, Gitlab, VisualStudio.com

Markdown

概要 詳細 Atom Package VSCode Package
Markdown表示の拡張 デフォルトのMarkdownプレビューより高機能なプレビュー、TOCやプレゼンモードもあったりする。目次機能もあったり、いろいろと便利。 markdown-preview-enhanced Markdown Preview Enhanced
入力補助 Markdownの全般的な入力補助。とりあえず入れてる。 markdown-writer Markdown All in One
目次自動生成 編集中のMarkdownの目次を自動生成 Markdown TOC Markdown All in One
テーブル記法補助 Markdownのテーブル記法編集補助、うまいこと縦のカラム表示を整えてくれる。 markdown-table-editor Markdown All in One
テーブル記法補助2 別のMarkdownのテーブル記法編集補助 Markdown Table Formatter Markdown All in One
Markdown目次機能 ドロワーやエクスプローラーに編集中のMarkdownの目次をページ内リンク付きで表示。 document-outline ビルトイン
タスク記法のトグル Markdownのチェックボックス記法のチェック状態のトグル変換。そんなに使わないけどいちいちキャレットを移動するのが面倒なので。 toggle-markdown-task Markdown Checkboxes
フォーマッタ 番号付きリスト記法の番号振りなおしなど、フォーマッタ。 tidy-markdown -
シンタックスハイライト Atomデフォルトのものより高機能なハイライタ。 language-markdown -
TextLint 特に日本語に強い自然言語用のLinter、textlintをAtomで使えるように。Markdown以外でも効く。 linter-textlint vscode-textlint

JSON

概要 詳細 Atom Package VSCode Package
シンタックスハイライト(階層) JSONファイルを階層によってカラーリングを変えて視認性を上げる。 atom-json-color -
フォーマッタ JSONファイルの整形フォーマッタ。 pretty-json JSON Tools
Linter JSON用のLinterアドオン。 linter-jsonlint -
ソート JSONオブジェクトをアルファベット順などでソートできる。 - Sort JSON objects

Ruby

概要 詳細 Atom Package VSCode Package
総合サポート - Ruby Ruby
Hamlサポート haml用の言語ファイル。 language-haml Ruby Haml
Slimサポート Slim用の言語ファイル。 language-slim Slim
Rspecサポート Rspec(Rubyのテストフレームワーク)用の言語ファイル。 language-rspec rspec-snippets
Rablサポート Rabl(RubyOnRails用のJSONやxmlに特化したテンプレートサポートGem)用の言語ファイル。 language-rabl -
Linter(RuboCop) Rubocop用のLinterアドオン。 linter-rubocop ruby-rubocop
Linter(erb) erb用Linter linter-erb -
Linter(Haml) Haml用Linter linter-haml -
Linter(Slim) Slim用Linter linter-slim -
入力補完 Ruby用の入力補完。別途Solagraph Gemのインストールが必要。 autocomplete-ruby Ruby Solargraph
自動修正 Rubocopルールに従って自動修正。 rubocop-auto-correct -
フォーマッタ Ruby用フォーマッタのrufoをエディタから実行。JSのprettier用のプラグインのほうが主流になりそうな感じ。 rufo-atom rufo (Ruby formatter)
Railsサポート - - Ruby on Rails
Railsパーシャルビューサポート Railsのパーシャルビューの自動補完 autocomplete-rails-partial -
Rspecファイルを開く 現在開いてるファイルに対応したRspecのファイルを開く。 rails-open-rspec -
Rspecの実行 エディタからRspecをrun。 rspec Rails Run Specs
ブロック文法の補助 do,if,begenendなどの対になるブロック要素をハイライト。 ruby-block -
i18nサポート Railsのi18n用のAutocompleteとHyperClickアドオンのセット rails-i18n-plus -
Rails補助 Rails用のスニペット集。 rails-snippets Ruby on Rails
Rails補助(ファイル) Model,View,Controllerなど対応するファイル同士を素早く開けるようにする。 rails-transporter -

JavaScript系(Node.jsやメタ言語、フレームワーク含む)

ちなみにPrettier系入れずにプロジェクトにESlintと統合するeslint-plugin-pretteirを使って統合している。

概要 詳細 Atom Package VSCode Package
TypeScriptサポート TypeScriptの言語ファイルか補完や便利機能まで、IDE的サポート。 atom-typescript ビルトイン
Vue.jsサポート Vue.js用の言語ファイル。 language-vue Vetur
Vuc.js入力補完 Vue.js用Autocompleteアドオン。 vue2-autocomplete Vetur
ESlint JavaScript用のLinterであるEslintサポート、prettierと連携も可。 linter-eslint ESLint
JS用HyperClick JavaScript用のHyperClickアドオン。 js-hyperclick -
Vue.js用HyperClickアドオン Vue.js用HyperClickアドオン。 vue-hyperclick -
Jestサポート JS用テストフレームワークJestのサポート - Jest

HTML系(メタ言語含む)

概要 詳細 Atom Package VSCode Package
Pugサポート - language-pug Pug (Jade) snippets
HTML用Linter HTML用Linterアドオン。 linter-htmlhint -
Pug用Linter Pug用Linterアドオン。 linter-pug -
HTMLタグ補完 HTMLの閉じタグのショートカットと補完。Pugで書けばいらないんだけどね。 tag Auto Close Tag
Emmetサポート html,css(プリプロセッサ含む)の強力なスニペット集。 emmet ビルトイン
インデント記法サポート Jade(pug)やStylus,Sassのインデントベース記法の環境で、現在のキャレットの位置がどの要素のネスト中なのかツールチップで表示。 indent-tooltip -

CSS系(メタ言語含む)

概要 詳細 Atom Package VSCode Package
Stylusサポート Stylus用の言語ファイルとスニペット集。 Stylus language-stylus
Stylus自動補完 Stylus用のAutocompleteアドオン。 autocomplete-css-with-stylus-support -
Stylusフォーマッタ Stylus用フォーマッタSupremacyサポート、かなり柔軟な設定が可能。 - Manta’s Stylus Supremacy
Stylus用Linter Stylus用のLinterアドオン。 linter-stylint Stylint
CSS用Linter CSS用のLinterアドオン。 linter-stylelint stylelint
Sass用Linter SCSS(SASS含む)のLinterアドオン。 linter-scss-lint Sass Lint

PUML

UMLをテキストから表現したもの。
細かいレイアウトは難しいもののテキストならGit管理もできるし素早くかけるので覚えてよかった。

概要 詳細 Atom Package VSCode Package
PlantUMLサポート PlantUMLの言語ファイル language-plantuml PlantUML
PlantUMLビューア PlantUML用のUMLを表示 plantuml-viewer PlantUML

その他の言語系

概要 詳細 Atom Package VSCode Package
Apache Apacheのコンフィグ用 language-apache Apache Conf
nginx nginxのコンフィグ用 language-nginx nginx.conf
Lisp Lispサポート language-lisp Lisp
envファイル 環境変数を設定するenvファイルのシンタックスハイライト DotENV -

おしまいに

VSCodeに乗り換えたものの、今もAtomは好きだし、なんとなくVSCodeは好きになれない。もしかしたらあるイベントで好きでAtom使ってるところにかなり無理にVSCodeを勧められた経験からかもしれない。(やれ補完がどうとか。それはVSCodeの機能ではなくLanguage Serverだ)

Web上でもVSCode推しみたいのを良く見る。しかもAtomを貶めてまで。エディタは宗派で戦争になるためそういう推し方は好きじゃないんだよなぁ。あ、あれだインド行った時、自分の旅の一部としてとても楽しかったけど、インド推ししてる日本人の方々をどうも好きになれなかった感じと似ている。

なんにせよどんなエディタを使おうにもこういう拡張が充実してきてみんなが平和に好きなエディタを心地良く使う世の中がいいよね。

ちゃんとしたGitコミットメッセージをCommitzenを日本語で使って楽に書く

  1. 1. 決定打は’Commitzen’
  2. 2. タイプ、スコープの効能
  3. 3. 日本語でどうしましょ?
  4. 4. Commitzenを少しだけ日本人に優しくしました
    1. 4.1. 使い方
  5. 5. もうちょっと拡張するには
    1. 5.1. 使い方

Gitを使うようになって以来、使えば使うほどこれは良いバージョン管理だなぁと関心する。その反面、コミットに対しての悩みはつきない。コミットメッセージ、粒度。そのへんをどうしたら良いのか決定打が無いまま、ちゃんとしてるっぽいようにできてはいるけど今イチ自信がないままだった。

そう思いつつもいろいろと思考錯誤してようやく最近ではこれで行こう! と自信もって上手くできてる感がでてきたのでそのへんのことを共有していこう。

決定打は’Commitzen’

Commitzenは一言で言えば対話的にコミットメッセージを作るやつ。NPMで配布されていて、Angularで使われているコミットメッセージのルールが元になってるそうな。

簡単に言えば

Type(Scope): Title

Body

というメッセージルールで書く。ScopeBodyに関してはオプショナルでなくても可。
タイプは例えば、feat, fix, style とか。大項目みたいな。
スコープは言わずもがな。変更範囲。タイトルは普通のコミットメッセージみたいなコミットの要約で、Bodyはさらに細かい説明、これはよくある1行空けて詳細を説明、みたいなのと一緒。
これを対話的に

  1. このコミットのタイプは? (選択式)
  2. スコープは?(enterでスキップ)
  3. コミットの要約
  4. さらに細かい説明(オプショナル)
  5. 破壊的変更について
  6. 関連するissueについて

みたいな感じで質問に答えるように入力する。こうすることによって「うーん、コミットメッセージ、どう書こう」みたいなのをちょっと楽にしてくれる。さらには、タイプを選択式にすることによってメッセージの統一性を強制し、スコープをちゃんと考える契機にもなる。

タイプ、スコープの効能

実はメッセージを入力するのが楽になるだけじゃなくて「メッセージと内容の整合性」をちゃんと意識してる場合、変更内容の粒度や区切りもある程度しっかりしてくる。

バグ修正のコミットに機能追加を含めてはいけない。後からアレコレしたい場合に無理が生じてくる。Gitの良いところは履歴であり戻れることなので、戻りやすく、選択できるレベルにしておくのが良い。だけど例えばバグ修正と機能追加が1つのコミットにある場合、バグ修正は取り込みたいけど、機能追加は問題があって取りこみたくない、という場合に死ぬ。

さらにconventional-changelogというのがcommitzenプロジェクトの一環にある。これはこのタイプを自動で判別してCHANGELOG.mdを自動生成したり、セマンティックバージョニングをコントロールする方法。簡単に言えばfixが含まれていれば0.0.1(patch)上がってfeatが含まれていれば0.1.0(minor)上がる。

日本語でどうしましょ?

僕は個人的に言えばプライベートなものかつ、日本人のみのチームで作業されるものは日本語コミットメッセージで良いと思ってる。コミットメッセージを書くためにうんうん悩んで時間を浪費したりするのは本質じゃないし、読むときもいちいち機械翻訳にかけて理解するのももったいない。

ただし、被検索性は高くもっていたいのでそれなりなルールは必要で、コミットメッセージに日本語か嫌われるのはこのへんが大きいとにらんでる。問題は文法と表記のあいまいさ。

英語だとSVC文法で、さらに本質から先に出てくる。日本語は逆でSCVというか、大切なことほど後にでてくる(ごめんなさい、このへんの言語的な細かいことは正確に解説できる知識がないです)

fix SomeClass work properly

というメッセージと

SomeClassが正しく動作するように修正

というメッセージ、どっちが見やすい? 英語のほうが理解しやすいように思う。後からコミットメッセージをもとに探す場合、もう何でさがしたらいいかわからない。バグフィクスって書く? 修正って書く? っていう表記揺れだったり、「修正」が最後に来るので目で追う場合もズレる。文字数が多くなって自動でBodyに送られた場合はさらにキツい。

で、じゃあ表記揺れをルールで縛ってある程度書き方も一文じゃなくて配慮したルールにしてみたとしよう(これは以前僕が日本語コミットを書くなら、と独自に考えてみたもの)

修正: SomeClassが正しく動作するように

もしくは「修正」を外に出したので説明を追加すると

修正: SomeClassが正しく動作するようにsome-functionを追加

とか。これならまず本質が「修正」であることがわかるし、メッセージの最初が主語なのでSomeClassに対する修正だな、とわかりやすいと思う。そしてこれをAngularルールで書いてさらに日本語を混ぜると

fix(SomeClass): add some-function for working properly

fix(SomeClass): 正しく動作するようにsome-functionを追加

日本語話者にとってもタイプとスコープ程度は英語でも誰も困らないし、ちゃんと明記されてるし、その後の説明は日本語でも何をしたのかわかるし。まずタイプとスコープを最初に固定することでそのあとメッセージがもうちょっと変更内容をちゃんと説明しやすく書ける。

これだと日本語コミットでもわかりやすいし、バランスも良いと思う。もちろんパブリックなリポジトリや日本語話者のみで構成されていなければ英語で書くべきなのは言うまでもないけど。

Commitzenを少しだけ日本人に優しくしました

そんなわけで、日本語で書こうが英語で書こうがCommitzenが役に立つのはわかってもらえたはず。で、日本語で書くような場合、対話型で設定できたとしてもまだちょっとやりづらい。英語にそこまで不自由を感じないようになった僕でも日本語を読むほうが圧倒的に速い(漢字は文字あたりの情報量が圧縮されているということ抜きにしても)。

で、commitzen(cz-cli)は何もしないと対話的CLIのところにcz-conventional-changelogが使われている。ここを~/.czrcとかで別のものに指定ができるような作りなのでcz-conventional-changelog-jaというもの作った。作ったと言ってもオリジナルをフォークして日本語訳しただけなのですがね。

これを適用すると対話の質問やタイプ選択の説明が日本語になる。自分でも使ってみたけど、英語でコミットするにしてもこっちのほうが使いやすい。

使い方

グローバルに設定してプロジェクト問わず使うとしたら

$ yarn global add cz-cli cz-conventional-changelog-ja
# or npm i -g cz-cli cz-conventional-changelog-ja

とインストールしたら、ユーザー直下に

~/.czrc
{
"path": "cz-conventional-changelog-ja"
}

としてやる。そうすると

$ git cz

とやったときにデフォルトのcz-conventional-changelogではなくcz-conventional-changelog-jaを参照するので、日本語で表示されるようになるはず。

もうちょっと拡張するには

それで使ってたんだけどどうも僕がメッセージ書いててタイプの種類が少なかったり合わなかったり感じてた。コミットメッセージを書きやすくするためのツールなのにこの場合のタイプはうーんどうしよう、みたいに詰まるのは本末転倒だなぁ、と。

もちろんこのTypesを制御する方法ああるんだけど、これってプロジェクトやチームによっても変わるのでもっと柔軟なほうが良さそう。その都度別バージョンのcz-conventional-changelogをフォークしたりするのも違うよなぁって思いもあってcz-customizable経由でやることにした。

cz-customizableは、質問やタイプ情報の設定を外部から読み込めるようにして、カスタムできるようにしたもの。なので日本語で使う場合も.cz-config.jsを書いて参照するようにしたらいい。

参考までに僕の設定を載せておきます。

使い方

運用としては、上の-jaのようにグローバルに設定してプロジェクト問わず使うとしたら

$ yarn global add cz-cli cz-customizable
# or npm i -g cz-cli cz-customizable

とインストールしたら、ユーザー直下に

~/.czrc
{
"path": "cz-customizable"
}

cz-cliが参照するのをcz-customizableにする。で、cz-customizableはデフォルトでは.cz-config.jsを参照するので、下記のようにファイルを作って置く、と。

~/.cz-config.js
'use strict';
module.exports = {
types: [
{
value: 'feat',
name: 'feat: 新機能',
title: 'Features'
},
{
value: 'fix',
name: 'fix: バグ修正',
title: 'Bug Fixes'
},
{
value: 'HOTFIX',
name: 'HOTFIX: 致命的で緊急なバグ修正',
title: 'Critical hotfix'
},
{
value: 'UI',
name: 'UI: UIやスタイルの更新',
title: 'UI'
},
{
value: 'docs',
name: 'docs: ドキュメントのみの変更',
title: 'Documentation'
},
{
value: 'style',
name: 'style: フォーマットの変更\n (コードの動作に影響しないスペース、フォーマット、セミコロンなどの変更)',
title: 'Styles'
},
{
value: 'texts',
name: 'texts: 文字や文章の更新',
title: 'Text and literals'
},
{
value: 'i18n',
name: 'i18n: 国際化',
title: 'Internationalization'
},
{
value: 'typo',
name: 'typo: タイプミスの修正',
title: 'Typos'
},
{
value: 'refactor',
name: 'refactor: リファクタリングのための変更\n (機能追加やバグ修正を含まない変更)',
title: 'Code Refactoring'
},
{
value: 'perf',
name: 'perf: パフォーマンスの改善のための変更',
title: 'Performance Improvements'
},
{
value: 'ux',
name: 'ux: ユーザーエクスペリエンス/ユーザビリティの改善',
title: 'UX'
},
{
value: 'test',
name: 'test: 不足テストの追加や既存テストの修正',
title: 'Tests'
},
{
value: 'config',
name: 'config: 設定の追加や変更',
title: 'Configuration'
},
{
value: 'build',
name: 'build: ビルドシステムや外部依存に関する変更\n (スコープ例: gulp, broccoli, npm)',
title: 'Builds'
},
{
value: 'ci',
name: 'ci: CI用の設定やスクリプトに関する変更\n (スコープ例:Travis, Circle, BrowserStack, SauceLabs)',
title: 'CI'
},
{
value: 'chore',
name: 'chore: その他の変更\n (補助ツール、ドキュメント生成などのソースやテストの変更を含まない変更)',
title: 'Chores'
},
{
value: 'WIP',
name: 'WIP: 作業中',
title: 'WIP'
}
],
scopes: [
// { name: '*' },
// { name: 'admin' },
// { name: 'exampleScope' },
// { name: 'changeMe' }
],
// it needs to match the value for field type. Eg.: 'fix'
/*
scopeOverrides: {
fix: [
{name: 'merge'},
{name: 'style'},
{name: 'e2eTest'},
{name: 'unitTest'}
]
},
*/
// override the messages, defaults are as follows
messages: {
type: 'コミットする変更タイプを選択:\n',
scope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n',
// used if allowCustomScopes is true
customScope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n',
subject: '変更内容を要約した本質的説明:\n',
body: '変更内容の詳細("|"で改行)(optional):\n',
breaking: '破壊的変更についての記述(optional):\n',
footer: '関連issueを追記 (例:"fix #123", "re #123")(optional):\n',
confirmCommit: 'このコミット内容でよろしいですか?'
},
allowCustomScopes: true,
allowBreakingChanges: ['feat', 'fix']
};

もし参考にしていただけたら幸いです。

これがないと捗らない、僕のKarabiner設定(late 2017)

  1. 1. Karabiner-elements
    1. 1.1. GUI設定 Overview
      1. 1.1.1. Simple Modifications
      2. 1.1.2. Function Keys
      3. 1.1.3. Complex Modification
        1. 1.1.3.1. Change Space to R-Shift (if alone)
        2. 1.1.3.2. Change Delete to R-Ctrl (if alone)
        3. 1.1.3.3. Change L-Cmd + R-Opt to L-Cmd + Space
        4. 1.1.3.4. Change L-Opt + R-Opt to L-Opt + Space
        5. 1.1.3.5. Change L-Opt to TAB (if alone)
        6. 1.1.3.6. Change R-Opt to ESC (if alone)
        7. 1.1.3.7. コマンドキーを単体で押したときに、英数・かなキーを送信する。
        8. 1.1.3.8. Change FN1 to (, Shift + FN1 to <
        9. 1.1.3.9. Change FN2 to ), Shift + FN2 to >
    2. 1.2. JSON設定ファイル

昨年末から続いてる極まりつつある入力環境シリーズ、Karabiner編。
macOSユーザの大半が使ってるであろう、Karabiner(-elements)というキーボードセッティングユーティリティの設定のお話。ここの設定はもはや無いと使えないレベル。

Karabiner-elements

macOS Sierra以前にKarabinerというツールがあって(それ以前はKeyRemap4macbookという名称だった)。Sierraで内部的に大きく変更があって、簡易的な代替としてKarabiner-elementsが生まれた背景がある。その後アップデートを繰り返し今では以前のKarabinerにひけを取らない、もしくは以前よりも柔軟な設定ができるユーティリティとして生まれ変わっている。

で、もちろんGUIから設定もある程度できるんだけど、内部的にはJSONで設定ファイルが書かれている。さらに柔軟な設定となるとJSONを直接編集する方法になる。なので今回はGUI部分はさっと紹介に留めてJSONをメインで。というより、設定JSONさえ入れればすぐにその設定を使えるので良い。(Karabiner時代は独自のxmlだったので以前よりやりやすくなったと思う)

僕の場合、外付けキーボードを使っていて、そちらでファームウェアレベルでキーリマップはできるものの、外してノートのキーを直接叩く機会もあるので、共通する設定はKa rabiner-elements側で行なっている。また、僕の設定はかなりErgoDox特化の設定でもあるのでご注意を。

GUI設定 Overview

Simple Modifications

Caps LockCtrlにしているだけ。Caps Lockが無いと大変な人って多数派なんだろうか疑問である。システム環境設定側でもできるけど、いろいろ絡めるとこちらで設定するのが良い。

Function Keys

基本的に叩かないのでわりとどうでもいい。デフォルト。すごい偏見だけどWindows使ってた人ってFunctionキー好きだよね。

Complex Modification

Change Space to R-Shift (if alone)

SandS用。SandSとはSpaceShiftキーを両立させるキーで、単体で押したらSpace、他と組み合わせるとShiftになるようなキーのこと。ちなみに僕の使うErgodoxではDoubleFunctionとして設定できるけど、挙動はKarabinerでやるほうが好みの感じになるのでこちらでやってる。

Change Delete to R-Ctrl (if alone)

これは完全に僕の好み。しかもErgoDox特化。黄金の小指を捨てて鋼鉄の親指にするためのもの。要は親指位置にCtrlキーを持ってきていて、それが単体押しだとDeleteとして動作したらいいよね、って感じ。ちなみにノートのキーボードを直で叩く時は小指が黄金化せざるを得ない。

Change L-Cmd + R-Opt to L-Cmd + Space

Cmd+SpaceでAlfred呼び出しにしてるものをErgoDox使用時とキーボード直の時の差を吸収する設定。直の場合、左親指でCmd、右親指でShiftを叩いてAlfredを呼び出している。が、ErgoDoxのときは左側にSpaceキーがないのでOptキーと組み合わせることで同じ動作をするように。

Change L-Opt + R-Opt to L-Opt + Space

これも上と同様で、Opt+SpaceでOmniFocusのクイックエントリに設定しているから。

Change L-Opt to TAB (if alone)

左のOptを単体で押したらTABとして動作。僕の小指はそんなに長くないし。そしてErgoDox系が素晴しいのは親指の有効活用を目指しているからである。

Change R-Opt to ESC (if alone)

上記同様。

コマンドキーを単体で押したときに、英数・かなキーを送信する。

これは最初からプリセットされているものを読み込んで設定できる。US配列好きの日本ユーザーに割と常識になってる英数、かなキーのエミュレーション。僕の場合、AquaSKKでの設定を使うのであまり出番がないけど一応。

Change FN1 to (, Shift + FN1 to <

ErgoDoxにはb,gキーの右側に特殊キーがある。そこを括弧系の入力に割り当ててる。ErgoDox側でFN1を割り合てて、Karabiner側で実際に入力されるキーを指定。これは本来ならErgoDox側のハードウェア的にやるほうが望ましいけど、ErgoDox側でのShiftを絡めたキー指定が難しいため。

Change FN2 to ), Shift + FN2 to >

上記の逆。h,nの左にも同様のキーがあるので逆の閉じる側の括弧を。余談だけど、その上に配置されたキーは、[]{}を割り当てている。

余談だけどUSキーボード好きのJISキーボード使いずらい派は、括弧のキー配列が横並びじゃなくて縦並びになってるが嫌って人が多いと思ってる。あれはとても直感的じゃない。

JSON設定ファイル

上記までの設定が全部かかれたJSONファイル。ちなみに生成されるのファイルのインデントは4スペースだけど、個人的に見辛いので2スペースにしている。で、つまるところJSONなので、これをGitとかGitHub Gistで管理したりDropboxとSymlinkで同期させたりすると複数端末でも使い勝手が良いよね。

karabiner.json
{
"global": {
"check_for_updates_on_startup": true,
"show_in_menu_bar": true,
"show_profile_name_in_menu_bar": false
},
"profiles": [{
"complex_modifications": {
"parameters": {
"basic.to_delayed_action_delay_milliseconds": 500,
"basic.to_if_alone_timeout_milliseconds": 1000,
"basic.to_if_held_down_threshold_milliseconds": 500
},
"rules": [{
"description": "Change ␣ to R⇧ (if alone)",
"manipulators": [{
"from": {
"key_code": "spacebar",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "right_shift"
}],
"to_if_alone": [{
"key_code": "spacebar"
}],
"type": "basic"
}]
},
{
"description": "Change ⌦ to R⌃(if alone)",
"manipulators": [{
"from": {
"key_code": "delete_forward",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "right_control"
}],
"to_if_alone": [{
"key_code": "delete_forward"
}],
"type": "basic"
}]
},
{
"description": "Change L⌘ + R⌥ to L⌘ + ␣",
"manipulators": [{
"from": {
"key_code": "right_option",
"modifiers": {
"mandatory": [
"left_command"
],
"optional": [
"any"
]
}
},
"to": [{
"key_code": "spacebar",
"modifiers": [
"left_command"
]
}],
"type": "basic"
}]
},
{
"description": "Change L⌥ + R⌥ to L⌥ + ␣",
"manipulators": [{
"from": {
"key_code": "right_option",
"modifiers": {
"mandatory": [
"left_option"
],
"optional": [
"any"
]
}
},
"to": [{
"key_code": "spacebar",
"modifiers": [
"left_option"
]
}],
"type": "basic"
}]
},
{
"description": "Change L⌥ to ⇥(if alone)",
"manipulators": [{
"from": {
"key_code": "left_option",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "left_option"
}],
"to_if_alone": [{
"key_code": "tab"
}],
"type": "basic"
}]
},
{
"description": "Change R⌥ to ⎋(if alone)",
"manipulators": [{
"from": {
"key_code": "right_option",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "right_option"
}],
"to_if_alone": [{
"key_code": "escape"
}],
"type": "basic"
}]
},
{
"description": "コマンドキーを単体で押したときに、英数・かなキーを送信する。(左コマンドキーは英数、右コマンドキーはかな)",
"manipulators": [{
"from": {
"key_code": "left_command",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "left_command"
}],
"to_if_alone": [{
"key_code": "japanese_eisuu"
}],
"type": "basic"
},
{
"from": {
"key_code": "right_command",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "right_command"
}],
"to_if_alone": [{
"key_code": "japanese_kana"
}],
"type": "basic"
}
]
},
{
"description": "Change FN1 to (, ⇧ + FN1 to <",
"manipulators": [{
"from": {
"key_code": "international3",
"modifiers": {
"mandatory": [
"left_shift"
],
"optional": [
"shift"
]
}
},
"to": [{
"key_code": "comma",
"modifiers": [
"left_shift"
]
}],
"type": "basic"
},
{
"from": {
"key_code": "international3",
"modifiers": {
"mandatory": [
"right_shift"
],
"optional": [
"shift"
]
}
},
"to": [{
"key_code": "comma",
"modifiers": [
"right_shift"
]
}],
"type": "basic"
},
{
"from": {
"key_code": "international3",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "9",
"modifiers": [
"right_shift"
]
}],
"type": "basic"
}
]
},
{
"description": "Change FN2 to ), ⇧ + FN2 to >",
"manipulators": [{
"from": {
"key_code": "international1",
"modifiers": {
"mandatory": [
"left_shift"
],
"optional": [
"any"
]
}
},
"to": [{
"key_code": "period",
"modifiers": [
"left_shift"
]
}],
"type": "basic"
},
{
"from": {
"key_code": "international1",
"modifiers": {
"mandatory": [
"right_shift"
],
"optional": [
"any"
]
}
},
"to": [{
"key_code": "period",
"modifiers": [
"right_shift"
]
}],
"type": "basic"
},
{
"from": {
"key_code": "international1",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [{
"key_code": "0",
"modifiers": [
"right_shift"
]
}],
"type": "basic"
}
]
}
]
},
"devices": [{
"disable_built_in_keyboard_if_exists": true,
"fn_function_keys": [],
"identifiers": {
"is_keyboard": true,
"is_pointing_device": false,
"product_id": 4871,
"vendor_id": 65261
},
"ignore": false,
"manipulate_caps_lock_led": false,
"simple_modifications": []
},
{
"disable_built_in_keyboard_if_exists": false,
"fn_function_keys": [],
"identifiers": {
"is_keyboard": true,
"is_pointing_device": false,
"product_id": 630,
"vendor_id": 1452
},
"ignore": false,
"manipulate_caps_lock_led": true,
"simple_modifications": []
},
{
"disable_built_in_keyboard_if_exists": false,
"fn_function_keys": [],
"identifiers": {
"is_keyboard": true,
"is_pointing_device": false,
"product_id": 628,
"vendor_id": 1452
},
"ignore": false,
"manipulate_caps_lock_led": true,
"simple_modifications": []
}
],
"fn_function_keys": [{
"from": {
"key_code": "f1"
},
"to": {
"key_code": "display_brightness_decrement"
}
},
{
"from": {
"key_code": "f2"
},
"to": {
"key_code": "display_brightness_increment"
}
},
{
"from": {
"key_code": "f3"
},
"to": {
"key_code": "mission_control"
}
},
{
"from": {
"key_code": "f4"
},
"to": {
"key_code": "launchpad"
}
},
{
"from": {
"key_code": "f5"
},
"to": {
"key_code": "illumination_decrement"
}
},
{
"from": {
"key_code": "f6"
},
"to": {
"key_code": "illumination_increment"
}
},
{
"from": {
"key_code": "f7"
},
"to": {
"key_code": "rewind"
}
},
{
"from": {
"key_code": "f8"
},
"to": {
"key_code": "play_or_pause"
}
},
{
"from": {
"key_code": "f9"
},
"to": {
"key_code": "fastforward"
}
},
{
"from": {
"key_code": "f10"
},
"to": {
"key_code": "mute"
}
},
{
"from": {
"key_code": "f11"
},
"to": {
"key_code": "volume_decrement"
}
},
{
"from": {
"key_code": "f12"
},
"to": {
"key_code": "volume_increment"
}
}
],
"name": "Default profile",
"selected": true,
"simple_modifications": [{
"from": {
"key_code": "caps_lock"
},
"to": {
"key_code": "left_control"
}
}],
"virtual_hid_keyboard": {
"caps_lock_delay_milliseconds": 0,
"keyboard_type": "ansi"
}
}]
}

そんなこんなで年も明けてだいぶたつけど、去年末にもあとめた一連の入力環境カスタマイズシリーズはおしまい。
整理するにあたって確認しなおしたのでこれからはあんまり変わることはなさそう。

とはいえ、キーバインドあたりはまだまだ何とかしたい感ある。
装飾キーの押し分けによってスコープを変えたい、例えばCmd単体ならアクティブなウインドウの操作、Cmd+Ctlrならアクティブなアプリの操作、Cmd+Ctlr+Altでグローバルな操作、とか。

そうやりたいのはやまやまなんだけど、デフォルトで設定されてるキーバインドも大事にしたくて、その両方の落としどころが上手く見つからない感じ。

モンスターハンターワールド 弱点早見表

攻略サイトがたくさんあるし、同様の弱点早見表もあったり、またTwitterで誰かが作ったやつが拡散されてたりするけど、個人的にはどれも見づらい(し、間違ってたりする)ので自分のために自分で作った。

ちなみにデータはゲーム内の図鑑を参照してるので間違えないはず。
逆に言えばもっと細かいデータとかもあるんだろうけどそこには触れない。TA勢でもない限りはこれで十分だと思う。
一部表記(脚→後脚、胴など)変えたりしてるけど、普通にわかる範囲内で。
背中側と腹側とか厳密に分かれてるモンスターもいるけど、胴、でわかるはず。背中が堅いやつとか明らかにわかるので。

色のイメージと明度でわけて見やすくしてるつもりだけど、項目が多いのでまだゴチャゴチャした印象。もうちょっと淡い色が上手くつかえたらいいんだけど。
とはいえパっと見で「こいつにはコレが効く!ここが弱点!」ってのはわかりやすいかと。
使う場面は相手モンスターはわかってるので、何属性を持っていくか、自分の武器ならどこを狙えばいいか、をすぐわかるようにすることにフォーカスしたつもり。

まあ僕の主武装であるタメ砲撃メインガンスには弱点部位とか属性とか関係ないんですけどね。

それにしても夢中でやってると手に汗かいてくるので、コントローラスキンを買おうか迷ってる。以前使ってたのはかなり良かったものの貼るタイプで少し吸水性があったので汗のオイニーが気になったので一度捨てた。
赤いコントローラーとか好きなんだけど、純正マグマレッドが使いすぎで潰れたので今はもともとの黒。これにスキンでグリップ力つけて色も変えれば楽しいかなーと。値段も高くないので意外にオススメです。

これがないと捗らない、僕のErgoDoxファームウェア(late 2017)

  1. 1. ErgoDox
    1. 1.1. ErgoDoxEZ
      1. 1.1.1. Kinesisとの使用感比較
      2. 1.1.2. ErgoDoxのキーカスタム
        1. 1.1.2.1. 基本
        2. 1.1.2.2. 親指まわり
        3. 1.1.2.3. 周りのキー
        4. 1.1.2.4. レイヤー系
  2. 2. Karabiner-element Required

昨年末から続いてる極まりつつある入力環境シリーズ、今回はソフト的な設定ではなく外付けキーボードのハードウェア的な設定の話。普段家でも職場でもMacBookProを使っていて持ち運ばない時はErgoDoxEZという外付けキーボードを使っている。これがいろいろ柔軟に設定できるのでその話。

ErgoDox

ErgoDoxという風変りなキーボードを知っているだろうか?以前エンジニア界隈で話題になったけど、左右セパレート型かつ親指周りに多めにキーを配置したのが基本形のキーボードがある。昔からある最強にして変態キーボードと名高いKinesisと似てる使用感がありつつ、左右セパレートを実現している。そして、ファームウェア(押したキーに対する挙動の設定)をキーボード側に書き替えれるので自分の好みの配置にできるのが素晴しい。

ErgoDoxEZ

ErgoDoxとは半自作キーボードであり、通常はキットで自分ではんだ付けして組み立てる。が、組み立て済みのセットとして、ErgoDoxEZというのもある。こちらはフルセットかつ作りもしっかりしていて、保証もある。逆にキットで自作するほうが色とか本当に自分好みにできる。

そんなわけで僕はEZのほうを使ってるけど、一度トラブルがあったもののすぐに、本当にすぐに交換対応してくれたので保証があって良かったなぁ、と思う。そして備え付けの角度調節用の足も良い感じ。EZでもCherry MX軸の中のいくつかから軸は選べる(僕は赤軸使用。欲を言えばピンク軸が欲しかった。)し、キーキャップはEZの販売サイト以外でも手に入る。

もちろんキットで自作するよりは高く付くものの、保証や出来を考えるとEZも値段的バリューは悪くないと思う。特に台湾から発送なので送料はキットよりも安い(キットはヨーロッパから)。ドル立てとユーロ立ての為替も関係してくるけど。

Kinesisとの使用感比較

ErgoDox以前はKinesisユーザだったので、簡単に思い出せる範囲内で使用感を比較してみよう。

打鍵感は、今のErgoDoxのほうが良いかな。でもKinesisの時はデフォルトの茶軸、今のErgoDoxは好みに合った赤軸を使ってるからな気がする。正直、Kinesisの赤軸と比較しないとなんとも。あとはキーキャップ替えたりO-ring噛ませたりでタッチは変わってくる。

キーキャップはKinesisは専用で選択の余地がないけど、エルゴノミクスデザインが素晴らしい。手の自然な形状に合うような気がする。ErgoDoxはキーキャップの選択の余地があるものの、一つ一つが専用の傾斜があるわけではない。ただし、足などでキーボード全体の傾斜を整えれば結構肉薄できてると思う。

パームレストはErgoDoxは必須だと思う。専用がもちろん良いけど、下で紹介してるような安価な物でも十分。Kinesisは本体がパームレストも兼ねてるし、固いなら付属のパッドをくっつければ十分だと思う。

大きさと置き場所的には断然ErgoDoxのほうが上。セパレート型は慣れると素晴しい。左右の手の間隔を自分で決められるのは思ってる以上にデカい。その証拠に僕の自宅のイスの写真を載せておこう。もはやキーボードは机に置く必要すらない。Kinesisだとこうは行かず机に置かざるを得ない。しかも単体の大きさがそれなりにあるのでいろいろ物理的制約が出てくる。ErgoDoxだとセパレートなので左右の間にMacBookProを挟んで(僕の職場仕様はこのスタイル)も全く問題ない。

キーカスタマイズはErgoDoxのほうがやや上かな。ファームウェアを自分でビルドして書き替えなきゃいけないものの、ビルドはDockerで、書き替えは専用ソフトでやっちゃえば良いので一度やれば変更はそんなに大変じゃない。最初はちょっと戸惑うけど。ただそのぶん、柔軟性は随一。Kinesisのキー設定も必要十分でキーの入れ替えはもちろんマクロ登録もできる。加えてレイヤーにも分けれるのでErgoDoxにもひけを取らない。

ErgoDoxのキーカスタム

ここでようやく本題。とりあえずソースを。

// Netable differences vs. the default firmware for the ErgoDox EZ:
// 1. The Cmd key is now on the right side, making Cmd+Space easier.
// 2. The media keys work on OSX (But not on Windows).
// make clean && make keyboard=ergodox subproject=ez keymap=my-keymap
#include "ergodox_ez.h"
#include "debug.h"
#include "action_layer.h"

#define BASE 0 // default layer
#define MOVE 1 // Cursol keys and Mouse Keys
#define CALC 2 // Keys like a calculator
/* period of tapping(ms) */
#ifndef TAPPING_TERM
/* #define TAPPING_TERM 200 */
#define TAPPING_TERM 75
#endif

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Keymap 0: Basic layer
*
* ,-----------------------------------------------------. ,-----------------------------------------------------.
* | ESC | 1 | 2 | 3 | 4 | 5 | `~ | | '" | 6 | 7 | 8 | 9 | 0 | \| |
* |--------+------+------+------+---------+-------------| |------+------+---------+------+------+------+--------|
* | TAB | Q | W | E | R | T | [ | | ] | Y | U | I | O | P | '" |
* |--------+------+------+------+---------+------| { | | } |------+---------+------+------+------+--------|
* | LCtrl | A | S | D | F | G |------| |------| H | J | K | L | ;: | -_ |
* |--------+------+------+------+---------+------| |------+---------+------+------+------+--------|
* | LShift | Z | X | C | V | B | ( | | ) | N | M | , | /? | += |
* `--------+------+------+------+---------+-------------' `-------------+---------+------+------+------+--------'
* | ~L2 | ~L1 | Left | Right|LGui/Eisu| |RGui/Kana| Up | Down | ~L1 | ~L2 |
* `-------------------------------------' `-------------------------------------'
* ,-----------------. ,-----------------.
* |LCtrl | LAlt | | RAlt | RCtrl |
* ,------|--------|--------| |--------+--------+------.
* | | | Tab | | Tab | | |
* | Space| Del |--------| |--------| BKspc |Enter |
* |LShift| LCtrl |LAlt/TAB| |RAlt/ESC| | |
* `------------------------' `------------------------'
*/
// If it accepts an argument (i.e, is a function), it doesn't need KC_.
// Otherwise, it needs KC_*
[BASE] = KEYMAP( // layer 0 : default
// left hand
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_GRV,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LBRC,
KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_JYEN,
// MO(CALC), MO(MOVE), KC_LEFT, KC_RGHT, MT(MOD_LGUI, KC_LANG2),
MO(CALC), KC_LALT, KC_LEFT, KC_RGHT, KC_LGUI,
KC_LCTL, KC_LALT,
KC_TAB,
// MT(MOD_LSFT, KC_SPC), MT(MOD_LCTL, KC_DEL), MT(MOD_LALT, KC_TAB),
KC_SPC, KC_DEL, KC_LALT,
// right hand
KC_QUOTE, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSLS,
KC_RBRC, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_QUOT,
KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_MINS,
KC_RO, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_EQL,
// MT(MOD_RGUI, KC_LANG1), KC_UP, KC_DOWN, MO(MOVE), MO(CALC),
KC_RGUI, KC_UP, KC_DOWN, KC_RALT, MO(MOVE),
KC_RALT, KC_RCTL,
KC_TAB,
// MT(MOD_RALT, KC_ESC), KC_BSPC, KC_ENT
KC_RALT, KC_BSPC, KC_ENT
),
/* Keymap 1: Media and mouse keys
*
* ,--------------------------------------------------------. ,--------------------------------------------------.
* | TRANS | F1 | F2 | F3 | F4 | F5 | | | Power| F6 | F7 | F8 | F9 | F10 | F11 |
* |--------+------+--------+--------+--------+-------------| |------+------+------+------+------+------+--------|
* | TRANS | | | MsUp | | | WhUp | | WhUp | | | UP | | | F12 |
* |--------+------+--------+--------+--------+------| | | |------+------+------+------+------+--------|
* | TRANS |WhLeft| MsLeft | MsDown | MsRght |WhRght|------| |------| | Left | Down | Right| | VolU |
* |--------+------+--------+--------+--------+------|WhDown| |WhDown|------+------+------+------+------+--------|
* | TRANS | | | | | | | | | | | | | | VolD |
* `--------+------+--------+--------+--------+-------------' `-------------+------+------+------+------+--------'
* | TRANS| TRANS| TRANS | TRANS | TRANS | | TRANS| TRANS|TRANS | TRANS| TRANS |
* `----------------------------------------' `------------------------------------'
* ,-------------. ,-------------.
* | TRANS| TRANS| | TRANS| TRANS|
* ,------|------|------| |------+------+------.
* | | | TRANS| | TRANS| | |
* | Lclk | Rclk |------| |------|MsAcl2|MsAcl1|
* | | | WhClk| |MsAcl0| | |
* `--------------------' `--------------------'
*/
// Cursor Keys and Mouse Keys
[MOVE] = KEYMAP(
KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_MUTE,
KC_TRNS, KC_NO, KC_NO, KC_MS_U, KC_NO, KC_NO, KC_WH_D,
KC_TRNS, KC_WH_L, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_R,
KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_WH_U,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS,
KC_TRNS,
KC_BTN1, KC_BTN2, KC_BTN3,
// right hand
KC_PWR, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
KC_WH_D, KC_NO, KC_NO, KC_UP, KC_NO, KC_NO, KC_F12,
KC_NO, KC_LEFT, KC_DOWN, KC_RGHT, KC_NO, KC_VOLU,
KC_WH_U, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_VOLD,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS,
KC_TRNS,
KC_ACL0, KC_ACL2, KC_ACL1
),


/* Keymap 2: Keys like a Culculator
*
* ,---------------------------------------------------. ,--------------------------------------------------.
* | TRANS | | | | | | | | | | 7 | 8 | 9 | | |
* |---------+------+------+------+------+------+------| |------+------+------+------+------+------+--------|
* | TRANS | | | UP | | |WhDown| |WhDown| | 4 | 5 | 6 | * | / |
* |---------+------+------+------+------+------| | | |------+------+------+------+------+--------|
* | TRANS |WhLEFT| LEFT | DOWN | RIGHT|WhRght|------| |------| | 1 | 2 | 3 | + | - |
* |---------+------+------+------+------+------|WhUp | |WhUp |------+------+------+------+------+--------|
* | TRANS | | | | | | | | | | 0 | 0 | . | + | = |
* `---------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
* | TRANS | TRANS| TRANS| TRANS| TRANS| | TRANS| TRANS| TRANS| TRANS| TRANS |
* `-----------------------------------' `------------------------------------'
* ,-------------. ,-------------.
* | TRANS| TRANS| | TRANS| TRANS|
* ,------|------|------| |------+------+------.
* | | | TRANS| | TRANS| | |
* | TRANS|TRANS |------| |------| TRANS| TRANS|
* | | | TRANS| | TRANS| | |
* `--------------------' `--------------------'
*/
// act like ten keys
[CALC] = KEYMAP(
// left hand
KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_TRNS, KC_NO, KC_NO, KC_UP, KC_NO, KC_NO, KC_WH_D,
KC_TRNS, KC_WH_L, KC_LEFT, KC_DOWN, KC_RIGHT,KC_WH_R,
KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_WH_U,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS,
KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS,
// right hand
KC_TRNS, KC_NO, KC_P7, KC_P8, KC_P9, KC_NO, KC_NO,
KC_WH_D, KC_NO, KC_P4, KC_P5, KC_P6, KC_PAST, KC_PSLS,
KC_NO, KC_P1, KC_P2, KC_P3, KC_PLUS, KC_PMNS,
KC_WH_U, KC_NO, KC_P0, KC_PDOT, KC_PEQL, KC_PLUS, KC_PEQL,
KC_TRNS,KC_P0, KC_PDOT, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS,
KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS
),


};
enum function_id {
LEFT_BRACE, RIGHT_BRACE
};
const uint16_t PROGMEM fn_actions[] = {
// [13] = ACTION_KEY(KC_LPRN), // FN13 - (
// [14] = ACTION_KEY(KC_RPRN) // FN14 - ) >
};
// #define MY_FN13 KC_LPRN
// #define MY_FN14 KC_RPRN
// #define S(MY_FN13) KC_LABK
// #define S(MY_FN14) KC_RABK
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
{
// MACRODOWN only works in this function
switch(id) {
case 0:
if (record->event.pressed) {
register_code(KC_RSFT);
} else {
unregister_code(KC_RSFT);
}
break;
}
return MACRO_NONE;
};

// Runs just one time when the keyboard initializes.
void matrix_init_user(void) {

};
// Runs constantly in the background, in a loop.
void matrix_scan_user(void) {

uint8_t layer = biton32(layer_state);

ergodox_board_led_off();
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
switch (layer) {
// TODO: Make this relevant to the ErgoDox EZ.
case 1:
ergodox_right_led_1_on();
break;
case 2:
ergodox_right_led_2_on();
break;
default:
// none
break;
}

};

基本

基本はQWERTY配列。外出時などMacBookPro側のキーを叩くこともあるし、自分のじゃないキーボードを触る時に戸惑うのでQWERTYからなるべく外れないように指の互換性をキープ。

親指まわり

ErgoDoxの特徴的な配置の親指周りのキー。ここはKarabiner設定でも紹介するけど、SandS(単体押しがSpace、他のキーと組み合わせるとShift)が大活躍。一番使うところ左にSandSキー、その隣はDelete(Forwerd) OR Ctrl。右はEnterとBackSpace。あとはOptionやTABやESCなど。

ちなみに単体押しと同時押しで違う挙動をさせるのはファームウェアでも設定できるけど僕の場合はKarabinerでやってる。実は厳密な挙動が少し違う。

例えば、単体だとAキー、他のキーと押すとBキーとして動作させたいとする。
ErgoDox DoubleFunctionだと、キーを押しつづけると一定時間後にBキーになる。これだとほぼ同時押しに近いような場合、Bキーとして動作しない。単体の時も一定時間以上の場合はBキーだけが入力される。要はKey-Downの時間が一定以上でKey-Up時に入力されるキーが変わる仕様。もっとわかりやすく言えば、普通に押す時と長押しで変わる、という感じ。

Karabinerの場合、まずBキーとして認識され、一定時間以内に他のキーの入力なく離した場合だけAキーとして認識される。この挙動の場合、同時押ししてもBキーになるし、キーを押したまま組み合わせるキーを迷っていてもBキーのまま。単体で入力する時のKey-downからKey-upの時間はわりと一定に収束するので、その時にだけAキーとして入力されるほうが都合が良い。

すごく細かい話だけど、やってみるとかなり使い勝手が変わってくるので重要。本来ならErgoDox側で設定できるならそちらでやるほうが設定と動くものの整合性というかレイヤー的に理に叶ってるんだけど、この違いはデカいのでしょうがない感。

周りのキー

外側一列と内側一列にあるキー達。左手外側には普通のUSキーボードと同じような感じで特殊キーを配置。右手外側も同じ感じで記号キーを配置。左手内側にはカッコ郡を配置。

具体的に、左手内側上は[,{、右手内側上に],}、左手内側下には独自キー用にFN1を指定、逆にはFN2。そしてこれをKarabinerで(,、),>に割り当てる。これはErgoDoxのファームウェア側だと単押しがすでにShiftと組み合わせる入力の場合、さらにShiftを追加する入力が上手く設定できなかったため。FNキーに設定して一旦逃がしてから、FN1単押しでShift+9Shift+FN1ではShift+,が入力されるように設定して実現させている。

レイヤー系

レイヤーはメイン以外に2つ設定していて、1つは上下左右への矢印キーを直感的にしたものと、マウス操作。もうひとつはテンキー操作。これはKinesisにもあったのでなかなか良い。

ちなみに内側の特殊キーにマウスホイールのエミュレート(つまりスクロール)を割り当ててるけどこれもなかなか良い。

必要ないところはぜんぶ割り当てない設定にしてる。

Karabiner-element Required

シリーズ内別記事でKarabinerカスタマイズを紹介する(してる)けど、上記に書いてあるようにかなり頼ってる部分というか密結合してる。本当はあまりよろしくないとは思いつつも他に手段がない上、使い勝手には替えられないのでしかたなし。

小気味良いSandS入力なしにSKKと親指多用のErgoDoxは実現しえない。

これがないと捗らない、僕のAquaSKKカスタマイズ(late 2017)

  1. 1. AquaSKK
    1. 1.1. そもそもAquaSKKって?
    2. 1.2. AquaSKKの設定について
    3. 1.3. keymap.conf
    4. 1.4. カスタムルール
  2. 2. ついでに

昨年(2017年末)僕がメインで使ってるテキストエディタAtomのカスタマイズ記事を書いたんだけど、付随してAquaSKKの設定も書いておこうと思ってたら年が明けちゃった。
表題は(early 2018)とすべきかもしれないけど、変わってないので関連製を持たせるために(late 2017)で。

AquaSKK

そもそもAquaSKKって?

mac OS用のSKKIME。
これについてはだいぶ前に書いた記事「僕が日本語 IM「SKK」に憑かれた訳」を参照していただければ。

AquaSKKの設定について

AquaSKKはただ単にSKK入力を実現するだけじゃなくて、キーバインドや入力ルールもカスタマイズできる。そのへんを弄くる話。

keymap.conf

キー割り当てのセッティング。これをAtomでのキーバインドと相互に寄せてることで入力に関して割と近い統一性を保つようにしてる。

設定の方法についてはkeymap.confの文法を参照のこと。

今の設定はこんな感じ

###
### keymap.conf
### https://ja.osdn.net/projects/aquaskk/wiki/keymap.conf%E3%81%AE%E6%96%87%E6%B3%95

# ======================================================================
# event section
# ======================================================================

SKK_JMODE ctrl::j||keycode::0x68
SKK_ENTER group::hex::0x03,0x0a,0x0d||ctrl::m
SKK_CANCEL ctrl::g||hex::0x1b
SKK_BACKSPACE hex::0x08||ctrl::h
SKK_DELETE hex::0x7f||ctrl::d
SKK_TAB ctrl::n
# SKK_PASTE ctrl::v
SKK_PING ctrl::l
SKK_UNDO ctrl::/

# ======================================================================
# attribute section(for SKK_CHAR)
# ======================================================================

ToggleKana q
# ToggleJisx0201Kana ctrl::q
SwitchToAscii l||hex::0x1b
# SwitchToJisx0208Latin L

EnterAbbrev /
EnterJapanese Q
NextCompletion hex::0x09
PrevCompletion ctrl::p
NextCandidate hex::0x20||ctrl::f
PrevCandidate x||ctrl::b
RemoveTrigger X

UpperCases group::A-K,M-P,R-Z
Direct group::keycode::0x41,0x43,0x45,0x4b,0x4e,0x51-0x59,0x5b,0x5c,0x5f
InputChars group::hex::0x20-0x7e

CompConversion shift::hex::0x0D||shift::hex::0x20

# ======================================================================
# handle option
# ======================================================================

AlwaysHandled group::keycode::0x66,0x68
PseudoHandled ctrl::0||hex::0x1b

ちょっと解説すると、ベースはAquaSKKのデフォルトを踏襲しつつ、自動補完に関してはEmacsのCtrl+p,nによる上下で送り、戻りをできるようにしつつ、Shift+Enterで補完して変換決定をしてる。これはAtomでやってるAutocompleteとほぼ同様になるように寄せている。

変換候補の送り、戻りもCtrl+b,fで対応するようにしてるけど大概の場合はSpaceを何度か叩くことで問題ないのであまり使ってない。

余談だけどSKKになれると日本語/直接入力の切り変えはSKK側のショートカットで行えるので、USキーボードのようにかなキー、英数キーが無くても全く問題ない。(一応僕はKarabiner-elementsで設定してるけどほとんど使ってない)

カスタムルール

AquaSKKでは日本語入力時の入力に対する出力をカスタムできる設定がある。
設定方法についてはかな変換のカスタマイズをご参照あれ。

簡単に言えば、入力,ひらがな時の出力,カタカナ入力時の出力,半角カナ時の出力を書けば、それぞれ適宜出力されるようになる。これによって、使わない全角入力文字の排除と日本語入力時にも半角英数(記号)の直接入力の両方が実現できる。さらに慣例的にz+何かでよく使われる記号を入力することもできる。これもなかなかありがたい。

ファイルで分割すればチェックボックスでオン/オフが設定できるけど、そもそもオン/オフしたい時がないので1つのファイルに自分用は全部書いて適用してる。注意すべきは文字コードをEUC-JPで保存しなければいけない点。

###
### custom-symbols.rule -- 日本語入力時の記号入力
###

### 日本語で良く使うもの
!,!,!,!
?,?,?,?
~,〜,〜,~
(,(,(,(
),),),)

### FEPベース全角記号
z1,○,○,z1
z!,●,●,z!
z2,▽,▽,z2
z@,▼,▼,z@
z3,△,△,z3
z#,▲,▲,z#
z4,□,□,z4
z$,■,■,z$
z5,◇,◇,z5
z%,◆,◆,z%
z6,☆,☆,z6
z^,★,★,z^
z7,◎,◎,z7
z8,∞,∞,z8
z*,×,×,z*
z+,±,±,z+
z~,≠,≠,z~
z=,≒,≒,z=
z`,※,※,z`
z|,|,|,z|
z\,¥,¥,z\
z{,【,【,z{
z},】,】,z}

### HTML escapes
z&,&,&,z&
zc,©,©,zc
z",",",z"
z',',',z'
z,>,>,z>

### PNBF emacs arrows
zp,↑,↑,zp
zn,↓,↓,zn
zb,←,←,zb
zf,→,→,zf

### コロン/セミコロン
;,;,;,;
:,:,:,:
z;,;,;,z;
z:,:,:,z:

簡単に解説すると、

  • !,?,〜,()についてはちゃんと全角で入力できるようにしてる。
  • Windows用SKK「FEP」で設定されている記号入力をベースにしつつ自分用にカスタマイズしたもの
  • HTMLで使われる記号用エスケープの入力ショートカット
  • Emacsの操作に基づく矢印キー入力(ちなみにHJKLはデフォルトで対応してる)
  • コロン/セミコロンは半角を入力するようにし、zをつけたときだけ全角で入力できるようにする

ついでに

ほとんど関係ない余談だけど、僕はキーボードは変態用として名高いKinesisを経て、今はErgoDox EZを使ってる。US配列なので英数キー、かなキーがないけどAquaSKK使いなので困ったことがない。