Macのghci上でCtrl+yを入力するとsuspendされる

MacのアプリケーションではCtrl-Yはヤンクに割り当てられていることが多いが,Haskellの対話環境であるghciを使っているときに,Ctrl-Yがおかしな動作をすることに気づいた.

$ ghci
Configuring GHCi with the following packages:
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /private/var/folders/5q/q2ghsy6s29z88zqbtthn1x5w0000gn/T/ghci57891/ghci-script
Prelude> -- ここでCtrl-Yを押す
Prelude> zsh: suspended (signal)  stack ghci --
$

Ctrl-Yを押すと,zsh: suspend (signal) stack ghci --の文字列が出力されてghciがサスペンドしてしまう.

解決策

StackExchangeに書いてあった.Haskell: GHCi treats Ctrl-Y like Ctrl-Zによると,要するに

stty dsusp undef

.zshrcに設定すればOKのようだ.

dsuspが何かとか,なんでこれを設定すればOKなのかを少し調べてみる.

まず,stty -aで現在のterminalの設定を調べられるので,それを見てみる.

$ stty -a
speed 38400 baud; 40 rows; 158 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
	-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
	-extproc
iflags: -istrip icrnl -inlcr -igncr -ixon -ixoff ixany imaxbel iutf8
	-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
	-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
	eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
	min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
	stop = ^S; susp = ^Z; time = 0; werase = ^W;

dsusp = ^Y;とあるのでCtrl-Yにdsuspなるものが割り当てられているのがわかる.

ではdsuspは何かというと,ジョブコントロールのシグナルであるSIGTSTPをジョブに送出するようだ.
で,SIGTSTPがジョブに送出されるとジョブはsuspendする. ジョブをサスペンドするといえばメジャーなのはCtrl-Zを入力することだと思うけど,Ctrl-ZだとSIGSTOPシグナルを送出する.SIGTSTPSIGSTOPの違いは,SIGSTOPが信号をすぐに送出するのに対してSIGTSTPはプログラムが入力としてシグナルを読み込んだときに送出されるらしい.要するにSIGTSTPの場合だとちょっと待ってからサスペンドされる,ということか?

ghciはどうもそのdsuspの機能が有効になっているらしく,そのせいでCtrl-Yを押すとサスペンドされてしまったらしい.

よってdsuspをCtrl-Yに割り当てられている状態を解除することで,Ctrl-Yを入力してもシグナルが送出されなくなった.またアプリ側で上書きされていたヤンクの機能も使えるようになり大分使いやすくなった.

参考