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が 一巡してる時には、上手く指定できない事も。
そういう事態はあまり発生しないので、現状はこの実装で運用してます。何か良い解決策無いかな。

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


参考