2019/12/21

tmux 3.0a の window 分割線を ascii character にする

2019/12/01 に tmux  の version 3.0a がリリースされました
いつも通りに分割線を multibyte character から ascii にする作業をします。
過去の作業ログは 2.9a や 2.8 や 2.7 など。そもそもの問題についてはこの記事にあります。


環境



インストール方法

  • $ brew install --HEAD atton/customs/tmux
でインストールできます。


今回の変更

tmux は window や pane を表示するための文字情報を tty-acs.c に持っています。
なので、毎度この定義を修正する事で対応しています。
2.9a の時等は tty-acs.c に変更が無かった為、過去の commit の cherry-pick のみで目的が達成できました。
が、今回は修正が入っているので cherry-pick をすると conflict します。
conflict を解消する形で対応しても良いのですが、今回は新しく修正用の commit を作ることにしました。

過去のパッチ を参考にすると、置換が必要な文字とその対応関係は
  • j,k,l,m,n,t,u,v,w が "+"
  • x が "|"
  • q が "-"
  • ~ が "*"
のようです。これらを元に tty-acs.c を修正。make すると今まで通り動きました。
もちろん後から何か踏む可能性はありますが、今の所問題は発生していません。
ということで tmux のソースコードの更新は以上。
あとは branch 名を homebrew の atton/customs 用に付けてあげればおしまいです。

formula の更新は本家 tmux の --HEAD 版の定義を借りて、branch 名を指定すればOK。

と、いうことで tmux 3.0a-border-ascii の更新ログでした。


おまけ

分割線の定義を間違えると、分割した瞬間に tmux が crash します。こわい。
きちんと定義できれば以下のように割りたい放題しても動きます。


2019/12/15

AquaSKK で Sticky Shift を使う

私は普段、mac で日本語入力をする時は AquaSKK を使っています。
AquaSKK は version 4.7.0 から Stickey Shift が実装されたようなので設定してみました。


環境

  • OS: macOS Mojave 10.14.6
  • Homebrew: 2.1.15-63-g090259b
  • Homebrew/homebrew-cask: (git revision ec6b9; last commit 2019-10-26)
  • AquaSKK: 4.7.0
  • neovim: 0.4.2
  • eskk.vim: 207d05cd


AquaSKK の install

homebrew-cask に formula があるので
  • $ brew cask install aquaskk
で Install できます。


SKK とは

日本語のかな漢字変換プログラムの一つです。
形態素解析を行なわず、漢字に変換、もしくは送り仮名付きの漢字の変換箇所をユーザが指定して入力します。
何を言っているのかさっぱりな感じもあるので、具体的な例を見ていきましょう。


漢字変換

例えば『漢字』と入力したい場合、「ことえり」や「Google 日本語入力」では
  • kanzi<space> または kanji<space>
と入力します。
そして SKK では、変換を開始する入力を大文字のアルファベットで指定します。よって
  • Kanzi<space> または Kanji<space>
と入力します。


送り仮名付き漢字変換

さて、次は『感じ』と入力したい場合を想定します。
「ことえり」や「Google 日本語入力」では変わらずに
  • kanzi<space> または kanji<space>
と入力します。また、その時の変換候補に『漢字』が出ることもあるでしょう。
SKK では送り仮名付きの漢字変換の時の変換箇所も大文字アルファベットで指定します。つまり
  • KanZi<space> または KanJi<space>
と入力します。そうすると、「感じ」「観じ」といった送り仮名付きの変換候補しか出ません。

さらに言えば、先程の『漢字』の入力について
  • Kanzi<space> または Kanji<space>
と入力した場合の変換候補は「漢字」「幹事」「監事」といった、送り仮名無しの候補しか出ません。
これが結構便利で、「送り仮名あり、送り仮名無し」の入力に関しては誤字が少なくなります。


横道: 形態素解析をしない、ということ

例に上げたように、漢字入力の際や送り仮名付きの漢字入力では SKK にはメリットがあります。
しかし、変換のポイントを自分で指定するため
  • これは漢字の入力のテストです
といった入力は一度にはできません。

「ことえり」や「Google 日本語入力」では全てのアルファベットを入力した後、先頭から少しずつ変換することができます。
なので、それぞれ得手不得手がある、と思った方が良いかと思われます。


Sticky Shift とは

さて、ここまで来ると Sticky Shift のお話ができます。
Sticky Shift とは、変換の指定ポイントを大文字のアルファベットでは無く、特定の文字で指定する方法です。

例えば、';' を設定した場合、先程の「漢字と感じ」は
  • ;kanji<space>to;kan;ji
と入力できます。
一見冗長ですが、慣れると便利です。

加えて、大文字入力が必要無いので Shift Key を使わずに入力を完結させることができます。
なお、eskk.vim では default で ';' Key が Sticky Shift 用の文字として実装されています


Sticky Shift の設定

ので設定してみましょう。大元の設定をコピーして追記します。

なお、コピー先の ~/Library/Application\ Support/AquaSKK については、AquaSKK を install した時に作られています。
なので
  • $ cp /Library/Input\ Methods/AquaSKK.app/Contents/Resources/keymap.conf ~/Library/Application\ Support/AquaSKK
を実行してコピー。

そして ~/Library/Application\ Support/AquaSKK/keymap.conf に
  • StickyKey ;

その後、AquaSKK のプロセスを殺すか、reboot 等で AquaSKK が再起動すれば、Sticky Shift が有効になっているはずです。
めでたしめでたし。


参考

2019/11/17

Disable Text Replacement on Safari in Mojave

iOS で文字入力をする際、入力が億劫な定型文とかを登録してみる。
  • General > Keyboard > Text Replacement 
で追加できます。

そこそこ快適になったと思ったら、iCloud 経由で自動的に Mac にも sync される様子。
基本的には無害なのですが、一度 GitHub の sha1 の末尾が置換対象と認識されて誤爆しかけた。ので無効化させる事に。
以下、 iOS では Text Replacement を有効にしつつ、Mac では無効化したログ。意外と大冒険だった。


環境

  • OS: macOS Mojave 10.14.6
  • Saferi: Version 13.0.3 (14608.3.10.10.1)
  • iOS: 12.3.2 and 13.2.2


結論から言うと

以下のコマンドを実行すると Mac の Text Replacement 設定を全て削除できます。
  • $ echo 'delete from ZTEXTREPLACEMENTENTRY;' | sqlite3 ~/Library/KeyboardServices/TextReplacements.db
  • $ defaults delete -g NSUserDictionaryReplacementItems
これで macOS では Text Replacement が発生しなくなります。
あくまで delete なので、iOS 側で設定を追加すると、同期された設定を再度削除する必要があります。


設定が存在しないか探す

iCloud の設定等、怪しい部分を探すも、それらしきものを発見できず。


$ defaults write -g WebAutomaticTextReplacementEnabled -bool false

ググると同じ考えの人はいて、
  • $ defaults write -g WebAutomaticTextReplacementEnabled -bool false
すると良い、とのことで実行。しかし変化無し。

きちんと設定されているか分からないのでまずは設定を表示させる。
man defaults すると read があるので実行してみる。
  • $ defaults read -g WebAutomaticTextReplacementEnabled
    • => 0
0なので一応 false になってる、という事なのだろうか。
delete もあるので実行する。
  • $ defaults delete -g WebAutomaticTextReplacementEnabled
  • $ defaults read -g WebAutomaticTextReplacementEnabled
    • => The domain/default pair of (kCFPreferencesAnyApplication, WebAutomaticTextReplacementEnabled) does not exist
delete した場合は 0 すら返らないので、設定できていたことになる。
しかし効果は表れなかったので、この方法では無理そう。


$ defaults find TextReplacement

defaults には find 機能もあるようだったので、
  • $ defaults find TextReplacement
とすると大量の設定が返ってくる。

defaults は多分 NSUserDefauts を macOS 側からいじる用のコマンドだと思われる。
Application 毎に設定があるし、Application 側で値を変更したら defaults で見られる情報に変化があった。
具体的には 'com.apple.iWork.Keynote' の 'TSWPAutomaticTextReplacement' の値とか。
Keynote で Text Replacement を disable にすると 'TSWPAutomaticTextReplacement' の値が 0 になる。

ちなみに -g は global option らしい。
Safari だけに効くよう、以下のように domain を指定して設定してみる。
  • $ defaults write com.apple.Safari TSWPAutomaticTextReplacement -bool false
しかし無効化できず。うーん。


$ defaults write -g WebAutomaticTextReplacementEnabled -bool true

逆に 0 でなく 1 を設定してみる。そうすると 
  • Menu bar(Safari) > Edit > Substitutions
が select できるようになる。
その中の 'Text Replacement' を disable にすると置換が止まった。
後はこれを defaults のどこに書くのか調べると良さそう。

と、思ったがそうは問屋が卸さなかった。defaults を使っても設定が見付けられない。
その上、 Saferi で 新規 Window を開くと 'Text Replacement' が Enabled な Window が増える。
あと、mac を reboot したら Text Replacement がまた有効になる。
どこかに設定があるからそれに辿りつけば良いんだけれど、対症療法ではどうも分が悪そう。


$ defaults write -g NSUserDictionaryReplacementItems <dictionary>

設定の場所を特定するためにわざと 'hoge' とかを TextReplacement に追加する。
そして
  • $ defaults find hoge
で調べると、NSUserDictionaryReplacementItems という Dictionary に格納されている。

NSUserDictionaryReplacementItems をググると少ないが記事はある
それを辿ると ~/Library/Preferences/.GlobalPreferences.plist というファイルの存在が示唆されている。
  • $ ls ~/Library/Preferences/.GlobalPreferences.plist
すると一応存在している。
  • $ open -a XCode.app ~/Library/Preferences/.GlobalPreferences.plist
内容は defaults read -g と同じっぽい。のでこれをいじっても defaults とやっている事は変わらない筈。

またググって引っかかった記事によれば
  • NSUserReplacementItems は 10.8 より前のバージョンで使われている
  • NSUserDictionaryReplacementItems は 10.9 で使われてる
とのことで。NSUserDictionaryReplacementItems をいじることにする。

元の値を一度取り出して
  • $ defaults read -g NSUserDictionaryReplacementItems 
    • => '( { on = 1; replace = hoge; with = "hogefugapiyo"; } )'
on を 0 にして、書き込む
  • $ defaults write -g NSUserDictionaryReplacementItems '( { on = 0; replace = hoge; with = "hogefugapiyo"; } )'
しかし Text Replacement は発生してしまう。
が、 Safari を起動すると、Text Replacement が発生しなくなった。ということでコレで良さそうだ。
その後、 macOS を再起動しても on flag は 0 のままだった。これで解決かな。


復活する NSUserDictionaryReplacementItems

解決かと思ったがそうでも無かった。しばらくすると on flag が 1 になっていた。
iCloud から sync した時に 1 になるなら理解できるが、特に編集せずとも 1 になる時がある。

ググると DB に格納されている、という記事が。
  • $ ls /Library/Dictionaries/CoreDataUbiquitySupport/atton~*/UserDictionary/local/store/UserDictionary.db
確かにある。sqlite3 で中身を覗いてみるとデータが無い。
というか ls -l したら 0B だった。のでここでは無い。


ちなみに、 on flag が 1 になる再現条件の一つは
  • System Preferences > Keyboard > Text を見る
でした。とりあえず確認に使えるので再現方法が1つ見付かっただけありがたい。


echo 'delete from ZTEXTREPLACEMENTENTRY;' | sqlite3 ~/Library/KeyboardServices/TextReplacements.db

Dictionary の save 先が無いかなー、とかググっていると ~/Library/Spelling に text edit の auto correction の情報がある、という記事にぶつかる。

~/Library をいろいろ見ると
  • $ ls ~/Library/KeyboardServices/TextReplacements.db
という怪しい物体を発見。早速中を見る。
  • $  file KeyboardServices/TextReplacements.db
    • => KeyboardServices/TextReplacements.db: SQLite 3.x database, last written using SQLite version 3016000
  • $ sqlite3 ~/Library/KeyboardServices/TextReplacements.db
    • sqlite> .schema
      • CREATE TABLE ZTEXTREPLACEMENTENTRY
      • CREATE TABLE ZTRCLOUDKITSYNCSTATE 
      • CREATE INDEX ...
      • CREATE TABLE Z_PRIMARYKEY
      • CREATE TABLE Z_METADATA
      • CREATE TABLE Z_MODELCACHE
    • sqlite> select * from ZTEXTREPLACEMENTENTRY limit 1;
      • 4|1|1|0|0|582166527.750349|三度寝|さんどね|C561DE44-D3D9-4F37-95E6-5916FF62C390|bplist00=>X$versionX$objectsY$archiverT$top
システム設定が参照しているかはともかく、コイツが Text Replacement のデータを保存しているのは間違いなさそう。

とりあえずバックアップを取って消してみる。
  • sqlite> delete from ZTEXTREPLACEMENTENTRY;
  • sqlite> select * from ZTEXTREPLACEMENTENTRY;
    • 消えてるので record は無い
System Preferences > Keyboard > Text を開くと見事に消えている。
ので NSUserDictionaryReplacementItems が復活する事も無さそう。
ということで defaults で NSUserDictionaryReplacementItems を消す。
  • $ defaults delete -g NSUserDictionaryReplacementItems
これにて一段落。これらを調べた結果が最初に書いた例の2行です。



余談: WebKit の shallow clone とか

ソース読むかー、ということで WebKit を落とそうとするも時間がかかりすぎる。
  • $ git clone --depth 1 git://git.webkit.org/WebKit.git WebKit
何かないかと git grep -i replacementした結果
  • NSUserDictionaryReplacementItems
  • ContextMenuItemTagTextReplacement
  • WebMenuItemTagTextReplacement
  • kWKContextMenuItemTagTextReplacement
等があって更に混乱した。それと対応してなのか
  • ContextMenuItemTagSmartCopyPaste
  • WebMenuItemTagSmartCopyPaste
  • kWKContextMenuItemTagSmartCopyPaste
等もあり迷宮じみてる感じ。ちなみに depth 1 でも 4.5GB というトンデモサイズです。


参考

2019/11/10

zle を使って特定の条件下のコマンドを実行する際、自動で丸括弧でくくる

前回の記事では peep コマンドを使ってプロセスの終了時に通知を行ないました。
また、peep-mac-tmux というコマンドを作って pid の指定を省略しました。

ですが、 peep-mac-tmux を使う際、上手く動いてくれないパターンがいくつか出てきました。
具体的には以下のようなパターンです。

  • '&&' で繋がれたコマンド
    • peep するのは実行中のコマンドなので、途中のコマンドが終了すると通知してしまう
  • `xargs -L1` のように何度も子プロセスを生成するコマンド
    • 1つの子プロセスが終わった時に通知してしまう

そこで、zsh の機能である zle を使い、これらのパターンの時に括弧で括って実行するようにしました。
丸括弧で括ってあると subshell 内部でコマンドが実行されます。
なので、peep は subshell の pid を peep する事で適切に動作させる狙いです。


環境

  • OS: macOS Mojave 10.14.6
  • Homebrew: 2.1.16-38-ge2c76cc
  • Homebrew/homebrew-core: (git revision 0f36; last commit 2019-11-09)
  • zsh: 5.7.1 (x86_64-apple-darwin18.2.0)


zle とは

zsh command line editor という機能で、man zshzle すると詳細が見られます。

今回の場合、'&&' が含まれる or '|' が含まれる、という時に括弧を追加することにします。
そうして作成したのが以下の call-subshell です。


安直に、egrep で特定の pattern がある時、 BUFFER という vairable を編集する事で追加します。
これで peep-mac-tmux の指定もやりやすくなりました。


無限に増える括弧

さて、peep-mac-tmux しやすくなりました、万歳、とはいかないようです。
この定義ではパターンが含まれるコマンドに、() を追加するので、後のコマンドにもパターンが含まれる。
なので、履歴からコマンドを呼び出すと括弧が増え続けます。これは困る。

そこで括弧が重複しないようにしたのが以下の call-subshell です。


一応、前後に空白があった場合にも対応しています。
これで良し。


まとめ

zle を使うとコマンドを編集できて便利、というお話でした。

ちなみにオチとしては、
  • peep が上手くいくメリット < () がある事で誤爆したりするデメリット
と感じたので、作成して2ヶ月くらいで消してしまいました


参考

2019/11/02

peep を使って、プロセス終了時に Notification Center へ音付きで通知をする

peep というコマンドがあります。pid を指定することで、そのプロセスが終了した際に通知等が行なえます。
この記事は peep コマンドを macOS 上で使ったり、自前 function を作ったりしたログです。


環境

  • OS: macOS Mojave 10.14.6
  • Homebrew: 2.1.15-63-g090259b
  • Homebrew/homebrew-core (git revision 51ba; last commit 2019-10-25)
  • peep: 0.1.2 (rev: f770419/go1.11.4)
  • terminal-notifier: 2.0.0
  • tmux: 2.9a(border-ascii)


peep の install

Homebrew を使ってインストールしてみます。作成者の Songmu さんの記事 の通り
  • $ brew install Songmu/tap/peep
で install できます。


peep-mac: peep + terminal-notifier

peep を install すると peep-notify というコマンドも一緒に install されます。
peep-notify コマンドは Slack に通知したり、macOS の notification center に通知したりできます。

ただ、notification center への通知は音が鳴らずにメッセージだけ表示されます。
軽く読んでみたところ、peep-notify は内部で gosx-notifier を使っていてTitle と Messge のみ設定されています。

peep 自体は pid を監視するコマンドなので、通知に必ずしも peep-notify を使う必要はありません。
そこで、 macOS で音付きで通知できるものは無いかと探す事にしました。
いくつか試したのですが、 terminal-notifier が良さそうです。

terminal-notifier は homebrew に取り込まれているので
  • $ brew install terminal-notifier
で Install できます。

peep + terminal-notifier を使って peep-mac function を作ってみました。 zsh で動きます。
  • $ peep-mac <PID>
とすると、その pid のコマンド名を表示。
その後、プロセス終了時に terminal-notifier で通知が生成されて "Glass" が鳴ります。便利。


peep-mac-tmux: peep + terminal-notifier + tmux

さて、peep-mac を作ったことで、長いプロセスの実行時、音が鳴るまで別の事ができるようになりました。
しかし、 peep-mac を使っていて思ったのです。「pid 調べるのが面倒」と。

そこで作成したのが peep-mac-tmux function です。
tmux 環境下 + 使い方次第では pid の指定をせずに peep-mac が動きます。

具体的には
  • 長いプロセスが実行中の window に pane を追加。
  • 追加した pane 上で peep-mac-tmux を実行。
すると良いです。ここまで来ると完全に自分専用感もありますね。

peep-mac-tmux の実装に関しては
  • pane は 2 つであること
    • 長い process を実行している pane と
    • それをこれから監視しようとする pane
  • active な pane を tmux list-panes から特定する
  • そこで実行されている zsh の pid を取得
  • ps -o <ZSH_PID> で zsh が parent になっている process 一覧を取得
  • pid を sort -r して、一番上のものを peep-mac に投げる
みたいな感じです。大体良い感じに peep してくれます。

ただ、sort -r で監視対象の pid 取得をするので、pidが 一巡してる時には、上手く指定できない事も。
そういう事態はあまり発生しないので、現状はこの実装で運用してます。何か良い解決策無いかな。

と、いうことで、『実行時間長いから終わったら呼んで』みたいな事ができるので便利、みたいなお話でした。


参考

2019/10/20

DefaultKeyBinding.dict を編集して ^; を入力しても beep が鳴らないようにする

私が作業する時は Terminal.app + tmux + neovim の時が多いです。
beep 音はあまり鳴って欲しくないので neovim と Terminal の beep setting は全て off 。
それでも稀に beep 音が鳴ってしまう。しかし、稀すぎて再現できず。
が、最近再現できたので、それに対処したログを残しておきます。


環境

  • OS: macOS Mojave 10.14.6


beep が鳴る原因

『^;(control + ';')』を入力した際に beep が鳴ることを見付けました。
Terminal.app に限らず Safari といった他の Application でも鳴るので、macOS 側の設定のようです。


対応: DefaultKeybinding.dict

OSX 時代から DefaultKeybinding.dict という物があって、それで keymap を設定できるようです。
参考のリンクで一番古いのは2010年とか。そのくらい前から存在しているらしい。
最終的には ~/Library/KeyBindings/DefaultKeyBinding.dict に

だけ記述。
一度 Application を落として ^; を入力しても何も鳴らない。よし。


寄り道

  • 'noop:' を設定してはダメなのか
    • 設定してみたこともあります。が、どうも『noop: だから beep が鳴る』みたいです。
    • DefaultKeyBinding.dict 自体始めて触るので、まず map ができているか怪しかった。
    • 一度「特定の文字を insert する」ように map して、DefaultKeyBinding.dict が有効な事を確認。
    • それから「空の文字列を insert する」ことで beep を抑えている状態です。
  • 他の組み合せでは beep は鳴らないのか
    • 'noop:' の物は基本鳴ります。
    • なので control + 記号 とかは beep 祭りです。
    • 全組み合せを設定しても良いのですが、特に鳴りまくる物を見付けたら設定していこうかと。
    • Keyboard 側の Setting でそもそも beep が鳴らないようにするのがベストな気がします。
      • が、Input Method "ASCII" には 設定項目が存在せず、 AquaSKK にも無い。
    • ので keymap でアドホックに回避してる状態です。
  • macOS 側の KeyBinding と衝突した場合はどうなるのか
    • macOS 側の設定が優先されました。
  • system-wide の key binding とか参考にならなかったのか
    • /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict ですね。
    • Property List Editor で開けると記述されているが、そんな Application は存在せず。
    • .plist を開ける XCode で開こうと試す。
    • 追加コンポーネントをダウンロードし始めたので、開けるかも、と期待。
    • で、ダウンロードしても開けず。えー。
  • 最終的に私自身の dot_files に入れることにしました。
    • .config/nvim/init.vim といったファイルは symlink で設定を配置しています。
    • が、DefaultKeyBinding.dict は symlink を follow してくれない。
    • ので cp することで対応しています。


参考

2019/10/12

.dockerignore を記述して Docker の image build を高速化する

docker image の build が作業をする毎に重くなる時があります。
今回のケースはカレントディレクトリのサイズが作業ごとに大きくなっていく場合。
その場合は .dockerignore を記述することで解決できます。


環境

  • OS: macOS Mojave 10.14.6
  • Docker: version 19.03.2, build 6a30dfc


具体例

例えば、以下のように image の build を実行したとします。
  • $ docker build -t hoge .
その際、`Sending build context to Docker daemon ...` と長く表示されることがあります。

Docker は image の build 時、指定された directory (今回は ".") のファイルを serialize して daemon に送ります。
このコマンドだと . のサイズが大きいと送信に時間がかかってしまいます。

確かこの時の curerent directory のサイズは2GB程度で、ビルド時間は 100 秒ほどでした。


.dockerignore を記述する

.gitignore のように .dockerignore を directory に配置します。
そして build に関係無いファイルを .dockerignore に記述すると、daemon に送る context から外すことが可能です。
例えば .git など、 docker image に含めることは無さそうなファイルやディレクトリを記述します。
また、git clean などで不要なファイルを消してしまうのも選択肢に入ります。

私の例では.dokerignore を記述した結果 context のサイズが 100MB 以下になり、ビルド時間も20秒以下になりました。
めでたしめでたし。



参考

2019/10/06

q を使って CSV ファイルに SQL を発行する

"q" という、CSV や TSV に SQL をに発行できるコマンドがあります。
便利なのですが、名前がググりづらいことこの上無い感じですね。


環境

  • OS: macOS Mojave 10.14.6
  • Homebrew: 2.1.12-8-gfd9a09e
    • homebrew-core: (git revision 5b99; last commit 2019-10-05)
  • q: 1.7.4


インストール方法

  • $ brew install q
でインストールできます。


実行例

例えば、以下のような "servant.csv" があったとして


以下のように SQL が発行できます。
  • select
    • $ q -d, -H 'select * from servant.csv ;'
      • 1,Altria Pendragon,saver,5
      • 2,Altria Pendragon (alter),saver,4
      • 3,Altria Pendragon,archer,5
      • 4,Altria Pendragon,lancer,5
      • 5,Altria Pendragon (alter),lancer,4
  • count
    • $ q -d, -H 'select count(*) from servant.csv ;'
      • 5
  • limit
    • $ q -d, -H 'select * from servant.csv limit 2;'
      •  1,Altria Pendragon,saver,5
      •  2,Altria Pendragon (alter),saver,4
  • distinct
    • $ q -d, -H 'select distinct(name) from servant.csv ;'
      •  Altria Pendragon
      •  Altria Pendragon (alter)
  • where
    •  $ q -d, -H 'select id,name,class from servant.csv where rarity = 5;'
      •  1,Altria Pendragon,saver
      •  3,Altria Pendragon,archer
      •  4,Altria Pendragon,lancer
  • order 
    • $ q -d, -H 'select * from servant.csv order by rarity;'
      •  2,Altria Pendragon (alter),saver,4
      •  5,Altria Pendragon (alter),lancer,4
      •  1,Altria Pendragon,saver,5
      •  3,Altria Pendragon,archer,5
      •  4,Altria Pendragon,lancer,5
  • distinct + count
    •  $ q -d, -H 'select count(distinct(name)) from servant.csv ;'
      •  2
なお、付けているオプションは
  • -d (--delimiter) 今回は csv なので  ','  が delimiter です。
  • -H (--skip-header) 今回は一行目に header があるので、それは値としてみなしません。
    • と、いうことは header が無い場合も想定していると思われます(やったこと無し)。
です。--help は貴重な情報源。


まとめ

と、いう感じで、"q" を使うと CSV を色々いじったりできて便利です。
ちなみに、 Office で開くと重かったり止まったりするサイズの csv でも捌いてくれます。つよい。


参考

2019/09/21

git clean を使って untracked なファイルを削除する

Mercurial には hg purge というコマンドがあって、 hg で control していないファイルを一括削除できます。
具体的には add してないファイルとか、.c から作った .o とか、間違って作った Rails の migration とか。
それを Git でもできないかなー、と調べたメモ。


環境

  • OS: macOS Mojave 10.14.6
  • Git: 2.23.0


git clean

hg purge のようなコマンドは Git にも default でも存在していて、git clean だそうです。

untracked なファイルを消す際は
  • $ git clean -fd
とかすると add してないファイルが消えます。

あとは、すぐに消すのではなく、消す対象が何かを教えてくれる -n (--dry-run) option が便利です。
  • $ git clean -fdn
で削除対象一覧を出してくれます。ちなみに
  • git clean -f -d -n
と書いても良いみたいです。

他には 
  • -X option: .gitignore で指定されたファイルのみを消す
    • .o とかが消えてくれる。
    • あと untracked なファイルは消えない
    • 新規にファイルを作った上で rebuild したい時に便利だよ、とのこと
  • -x option: .gitignore で指定されたファイルも削除対象 + untracked のファイルも削除対象
    • かなり危険なので事前に dry-run を付けた方が良いです
    • git clean -fdx とかすると clone 直後くらい綺麗な状態になります
とかですかね。
さらに詳細を知りたい場合は man git-clean を読んで頂ければ。


参考

2019/09/16

Terminal.app を使って mac を sleep させる

Terminal から mac を sleep させる方法無いかなー、と思ったのでそのメモ。


経緯

私は普段 MacBookPro + Display + Keyboard で作業をしています。
この状態からそのまま MBP を閉じると clamshell mode になってしまいます。
なので MBP を sleep -> MBP を閉める という流れで全体を sleep させています。
MBP を sleep させるには Shift + Control + 電源ボタン の shortcut を使うことが多いです。

しかし、たまに MBP を sleep させずに閉じてしまう時があります。
外付け keyboard には電源ボタンが無い。ので  sleep させられない。
そのせいで一旦閉じた MBP を再度開いて sleep させて閉じる、とかやっていたのですがちょっと面倒。

ということで、外付け Keyboard だけで clamshell mode の MBP を sleep させる方法た無いかな、と思って調べました。


環境

  • OS: macOS mojave 10.14.6 Version (18G95)


コマンド

  • $ pmset sleepnow
sleep させることができます。思ったより楽だった。


2019/09/01

neovim で plugin を利用せずに sudo を使う

root 権限が必要なファイルを neovim や vim で編集する事があると思います。
その際、 sudoers で許可されているユーザならば
  • :write ! sudo tee % > /dev/null
で sudo を使って root として書き込むことができます。

ですが、 neovim では
  • :write ! sudo tee % > /dev/null
    • sudo: no tty present and no askpass program specified
    • shell returned 1
と言われて sudo が使えません。


解決策

以下のようなコマンドを定義することで対応できます。 このコマンドは vim と neovim の両方で利用できます。

vim で利用する場合は ~/.vimrc に追記します。
neovim で利用する場合は ~/.cofig/nvim/init.vim に追記します。


使い方

  • $ nvim /etc/hosts
    • root 権限が必要なファイルを開いて編集します。保存の際は
  • :SudoWriteCurrentBuffer
    • を実行します。
    • パスワードを入力すれば root で書き込む事ができます。


動作確認をした環境

大元の環境(vim と neovim で動作確認済)
  • OS: macOS Mojave 10.14.6 (18G95)
  • Homebrew: 2.1.11
    • Homebrew/homebrew-core: (git revision 883ee; last commit 2019-09-01)
  • neovim: v0.3.8
  • vim: 8.0.1365
  • sudo: version 1.8.17p1
    • Sudoers policy plugin version 1.8.17p1
    • Sudoers file grammar version 45
    • Sudoers I/O plugin version 1.8.17p1
  • docker: 19.03.1, build 74b1e89

    docker を使っていくつかの distribution でも動作を確認
    • Alpine linux: 3.10.2
      • neovim: v0.3.7
      • vim: 8.1.1365
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27
    • CentOS: release 7.6.1810 (Core)
      • vim: 7.4.1099
      • sudo: version 1.8.23
        • Sudoers policy plugin version 1.8.23
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.23
    • Fedora: release 30
      • vim: 8.1.1912
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27
    • Ubuntu: 18.04.3
      • vim: 8.0.1453
      • sudo: version 1.8.21p2
        • Sudoers policy plugin version 1.8.21p2
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.21p2
    • Debian: 10.0 (buster-20190812)
      • vim: 8.1.1401
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27


    何故 neovim では sudo が使えないのか

    ここから先は先程の Vimscript を作るに至った経緯を書きます。
    興味のある方はご覧ください。

    まず sudo の error message
    • sudo: no tty present and no askpass program specified
    を見ると、 tty と askpass が無いと言っています。


    tty と askpass

    実際、vim では
    • : ! tty
      • /dev/ttys004 
    などが得られますが、 neovim では
    • : ! tty
      • not a tty
      • shell returned 1
    と言われてしまいます。

    askpass は使ったことが無いのですが、fedora の container で dnf search すると
    の様に、いくつかの askpass が確認できます。のでちょっと試してみます。
    • x11-ssh-askpass
    • openssh-askpass
    • ksshaskpass
    という感じで全然起動してくれません。
    ですがエラーの内容的に display を開こうとしているのが分かります。
    なので、おそらく GUI で password を聞くような物だと思われます。


    askpass を作る

    askpass について調べていると、どうやら
    • password を stdout に出力するもの
    であることが分かりました

    よって
    • neovim 内で password を取得
    • password を stdout に出力する
    • password の履歴はどこにも残さない
    ようなものを作れば解決できそうです。

    それで完成したのが /tmp/askpass を作るこの Vimscript です。

    本当はファイル名は固定でなく tempfile 的な物で対応するなど、改善点はいくつも存在するかと思います。
    ですが私は Vimscript に明るくないので、"3つの条件を満たして動けばOK" という条件で作成しました。
    他により良い対応方法があればご指摘頂けると幸いです。


    その他の解決策

    調べた結果、 suda.vim というプラグインがあるようです。
    また、他にも sudo.vim など、似たようなプラグインはいくつかあるらしいです。

    これを使わなかった理由としては
    • docker のコンテナ内で作業をする事が多々ある
    • init.vim を配置するスクリプトは既にある
    • plugin を install するスクリプトはまだ無い
    • 全コンテナに plugin を入れるのも面倒だし結構サイズがある
      • $ du -sh ~/.config/nvim/repos
        • 100M    /Users/atton/.config/nvim/repos
    などがあります。

    また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
    • 前述した理由の後半3つ
    • 複数人数のユーザが使う環境だと、 /root 配下に自分専用の設定を置くことになる
    のでこちらも無しで。

    他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
    が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。

    ということでこの Vimscript を書くに至った、という訳なのです。


    おまけ: 環境変数の unlet

    スクリプト内部では askpass の場所を示す SUDO_ASKPASS を設定している部分があります。
    具体的には
    • let $SUDO_ASKPASS  = s:askpass_path
    ですね。

    この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
    一応、 :SudoWriteCurrentBuffer の実行後にはなるべく元の環境に戻すために
    • unlet $SUDO_ASKPASS
    を書いていた時もありました。

    ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
    また 、-A を指定しなければ sudo の動作は変わらないので 、残っていても無害と判断して unlet しない形になりました。


    おまけ: shebang を指定しないとどうなるのか

    ちなみに askpass の shebang を消すと
    • sudo: unable to run /tmp/askpass: Exec format error
    • sudo: no password was provided
    と言われる為、きちんと書いておく必要があります。


    おまけ: x flag を付けないとどうなるのか

    setfperm(s:askpass_path, "rwxr-xr-x")  をせずに 644 のままだと
    • sudo: unable to run /tmp/askpass: Permission denied
      • sudo: no password was provided
      と言われるので、こちらもきちんと指定しておく必要があります。


      参考

      2019/08/29

      tmux 2.9a の window 分割線を ascii character にする

      2019/05/01 に tmux 2.9a がリリースされていました
      残念ながら 2.9 は見逃がしてしまいました。
      ということで恒例の分割線を EastAsianAmbiguous から ascii の線に変更するバージョンを作成。
      2.8の時とか2.7 の時とかの作業履歴とかもまとめてあります。
      そもそもどういう問題なのかはこの記事で。


      環境

      • OS: macOS mojave 10.14.6 (18G95)
      • tmux: 2.9a-border-ascii ( f976aed943f322a3652f51846b0fe472534ab6d6 )
      • Homebrew: 2.1.11
      • Homebrew/homebrew-core: (git revision 269c; last commit 2019-08-29)
      • Font: Ricty: 3.2.2(no option)


      作業

      今回も割とあっさりできました。cherry-pick して tag 更新して終わり。
      • $ git pull upstream
      • $ git checkout 2.9a
      • $ git cherry-pick border-ascii
      • $ git checkout -b 2.9a-border-ascii
      make できるかの確認は
      • $ sh autogen.sh
      • $ ./configure 
      • $ make
      で。

      ちなみに brew edit tmux して本家のビルド手順を参考にしてます。
      あと、 dependencies から utf8proc が消えて ncurses が追加。

      make すると current directory に tmux command ができるので、動作確認も可能。
      • $ ./tmux -V
        • tmux 2.9a
      • $ ./tmux
        • border-ascii 版の tmux が起動します。
      あとは自分用の tap に反映しておしまい。


      インストール方法

      1からインストールする場合のコマンドは
      • $ brew install --HEAD atton/customs/tmux
      でいけます。
      必要あらば自動で atton/cusoms を tap してくれるようになってました。便利。

      2019/08/20

      hub コマンドの user 設定を変更する

      hub というコマンドがあります。
      GitHub に関連したコマンドが追加された git の wrapper です。
      例えば
      • $ hub clone neovim/neovim
      とすると
      • $ git clone git@github.com:neovim/neovim.git
      相当の事をしてくれます。
      git の wrapper になってるので、 hub だけで全てを済ませる派の人がいるかもしれません。


      環境

      • OS: macOS Mojave 10.14.6
      • Homebrew: 2.1.10
      • Homebrew/homebrew-core:  (git revision ea34; last commit 2019-08-20)
      • hub: version 2.12.3
      • git: version 2.23.0


      設定を変更するきっかけ

      • $ hub browse tmux/tmux
        • とすると tmux/tmux をブラウザで開いてくれます。
      • $ hub browse hoge
      • $ git config --list
        • で git の設定を確認しても 'atton-' は存在しない。
        • むしろ github.user=atton になってるくらい。
        • hub が git の wrapper になってる事のデメリットがちょっとあって
      • $ hub config --list
        • としても git config --list の時と同じ内容が出てくる。
        • つまり hub 経由で config を update しても git の config が変更されそう。
      ということで 'atton-' を設定している部分を探してみる。


      設定箇所探し + 設定

      • $ hub --help
        • hub と git の help が出る
        • hub 部分に config とか setting とかの項目は無い
      • $ man hub
        • config で search するとありました。 
        • どうやら $HOME/.config/hub に書かれているようです。
        • 編集すると 'user: atton-' になっていたので 'user: atton' に修正。
      • $ hub browse dot_files


      おまけ

      ちなみに私が良く使うコマンドは
      • $ hub browse
      です。
      current directory の repository の github ページがブラウザで開きます。
      あとは hub clone くらい……?

      実際 hub をあまり使わないのは
      • hub が無い環境で作業することもある
      • wrapper が隠してくれているオプションとかに「気付かずに助けられている」のは勘弁
      とかの理由があります。

      なので、個人的にはなるべく git を使うようにしています。
      もちろん hub の方が便利な時は hub を使います。

      2019/08/13

      nodenv を使って複数のバージョンの Node.js を管理する

      プロジェクト毎に指定の Node.js のバージョンがあったり、常に最新の Node.js を使いたかったりすると、Homebrew だけで管理するのは面倒になってきます。

      今回は nodenv を使って Node.js の環境を作ろうと思います。
      ちなみに私は Ruby では rvm より rbenv 派。
      なので nvm よりは nodenv かな、と。

      環境

      • OS: macOS Mojave 10.14.6
      • zsh: 5.7.1
      • Homebrew: 2.1.9
      • Homebrew/homebrew-core (git revision 2548c; last commit 2019-08-11)
      • nodenv: 1.3.0
      • node-build: 4.6.3


      インストール

      • $ brew install nodenv
      • $ nodenv init
        • eval "$(nodenv init -)"
        • を .zshrc に追加せよ、と言ってきますので追記
      • $ nodenv install 12.8.0
        • とかで好きなバージョンを指定
      • $ nodenv global 12.8.0
        • とかで通常使用するバージョンを指定できます。
      • $ nodenv local 12.7.0
        • とかで特定ディレクトリの下で使用するバージョンを指定します。
        • 具体的には .node-version というファイルが作られて、そこにバージョンが書かれる。


      nodenv init をちょっと追ってみる

      ちなみに zsh 上で
      • $ nodenv init -
      とすると


      のような設定がされることが分かります。つまり、
      • executables がある PATH を追加する
      • NODENV_SHELL の設定
      • 補完スクリプトを source
      • nodenv rehash (executables の再配置)
      • nodenv の wrapper
        • rehash と shell の両コマンドは特別扱い(eval する感じ)みたいですね
        • 興味がある人はさらに読んでみても良いかと思います。

      nodenv init と shell 指定

      rbenv を設定していた時に見つけたのですが、特定の shell であることを指定することもできます。
      具体的には $SHELL が zsh の状態でも
      • $ nodenv init - bash
      とすると

      のような、bash 向けの設定が生成されます。
      nodenv init - zsh と具体的に違うのは NODENV_SHELL と補完スクリプトの場所くらい。
      zsh で bash の設定を読み込むなんてことはほぼ無いと思うので、 nodenv init - で問題無いと思います。


      nodenv rehash

      ちなみに zshrc に nodenv init - が記述される訳ですから、シェルを立ち上げる度に nodenv init - が実行されます。
      気持ち程度の問題だとは思いますが、 rehash を省略するオプションがあって
      • $ nodenv init - --no-rehash zsh
      とすると nodenv rehash が実行されません。

      とはいえ普通はこのオプションのある無しで実行時間はほとんど変わらないです。
      大量に package を入れたバージョンから新バージョンに上がった直後とかなら rehash にコストがかかるかも? 程度

      とりあえず、私は .zprofile には rehash 無しの init script を書いてます。
      それで、npm install -g とかしたら手で nodenv rehash を打つ、という運用をしています。

      2019/06/03

      utf8proc が 2.3 から East Asian Ambiguous の文字幅を 2 と判定するようになった

      Homebrew でインストールできる tmux は文字幅判定の方法をいくつか持っています。
      その中に utf8proc というソフトウェアに任せる、という方法があります。
      しかし、その utf8proc は East Asian Ambiguous の幅を固定で 1 にするよう実装していました。
      なので、自分用に patch を当てた formula を作ったりして対応していました。

      ですが、utf8proc 2.3 から East Asian Ambiguous を 2 と判定する用になりました。
      とりあえず自分が使っている patched 2.8 な tmux では問題無さそうなので公式の utf8proc を使うようにします。

      蛇足
      本当は LC_CTYPE を見て動的に判定する、という実装が理想っぽいですが流石にそこまではしてもらえないようです。

      2019/02/20

      zsh で c flag を指定すると .zshrc が読み込まれない

      .zshrc に定義している function f を zsh -c 'f' 等で実行したいが、 f が無いとエラーが発生する。
      なお、Terminal.app から起動した zsh では f は実行可能。


      結論

      function を .zshrc ではなく .zprofile に書いて zsh -l -c 'f' とする。(もしくは zsh -lc 'f')


      zsh の -l option について

      -l option は LOGIN option (man zshoptions)で、login shell として zsh を起動する。
      何も指定しない場合と異なり、設定ファイルをいくつか読み込む。その中に .zprofile が含まれている。


      .zprofile と .zshrc の読み込まれるタイミング

      • .zprofile: login 時に読み込まれる
      • .zshrc: terminal session が発生した時に読み込まれる
      との事。つまり、 zsh -c では .zprofile も .zshrc も読み込まれない。
      そこに -l を追加して .zprofile が読み込まれるようにする。そこに function を書けば良い。


      環境

      • OS: macOS Sierra 10.12.6
      • zsh: 5.7.1 (x86_64-apple-darwin16.7.0)

      2019/01/23

      EastAsianAmbiguous の幅を2に固定した utf8proc のバージョンを 2.2.0 に上げた

      さて、今私が使っている tmux は

      ようにしています。
      が、 utf8proc 側の更新は何気に初ですね。


      How to version up

      brew で tap 済みなら
      • $ brew upgrade
      で終わりです。丁寧に再インストールするのなら
      • $ brew uninstall utf8proc
      • $ brew install atton/customs/utf8proc
      でしょうか。便利。


      脱線: 楽をするための苦労の話

      brew で install できるようにするまでで一番面倒だったのが環境構築。
      なのですが、関連ファイルの生成は結構面倒。
      www.unicode.org から Unicode の定義ファイルを落としてきてスクリプトで処理とかしているので。
      スクリプトには ruby とか julia とか使われてるので微妙に mac の上に作るのはダルい。
      今回は docker で fedora 28 の上に使い捨ての環境を作って解決。

      fedora 29 だと julia が新しすぎてダメとか、CentOS7 にはデフォルトで julia が無かったりとか、寄り道はいろいろ。
      最終的には fedora 28 の上に call-by-need で環境を作って patch を cherry-pick して make update をかけて終了。
      brew の formula 回りは tmux で何度も触ってるので特筆すべきことは発生せず。
      途中であった謎現象としては www.unicode.org 自体が落っこちていて make update が上手くくいかない事がありました。
      何度も make してスパム判定されたとかなのかもしれない。