Zshでデキるプロンプト

14,781 views

Published on

Japanese version only

0 Comments
40 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
14,781
On SlideShare
0
From Embeds
0
Number of Embeds
150
Actions
Shares
0
Downloads
27
Comments
0
Likes
40
Embeds 0
No embeds

No notes for slide

Zshでデキるプロンプト

  1. 1. Zshでデキるプロンプトまるやま2013/05/101 / 25
  2. 2. プロンプトをいじりたい人生、色々あるよね仕事に疲れた…育児に疲れた…贔屓のチームが負けた…そもそも人生に疲れた…そんな時は、デスクトップの見た目をいじりたくなるよねみんなそうだよね!(Yes!)ターミナルのプロンプトを変更したくなる時もあるよねみんなそうだよね!(Yes!)じゃあ、思い切りいじろうじゃないか!(Yeah!!)2 / 25
  3. 3. Zshのプロンプトをいじるよみんな、シェルは Zsh だよねそうじゃない人は、これを見て Zsh に変更するもよしapt-get install zsh && chsh で /bin/zsh に!Zsh は意外とステキだよ補完が何かとすごい履歴も何かとすごいプロンプトもいじり甲斐があるのさ改行を入れて複数行のプロンプトが可能右プロンプトがあるZsh の設定項目はいっぱいあって正直とっつきにくいけど、今回はプロンプトの設定だけに絞って紹介するよ!Zsh のバージョンによって対応してなかったりとかあるけど、最新バージョン(2013/05/10 現在、4.3.17)を前提とするよ3 / 25
  4. 4. プロンプトに何を出そうかプロンプトに出せる情報は、意外といっぱいあるman zshmisc の”SIMPLE PROMPT ESCAPES” を参照プロンプトのイメージ[現在のディレクトリ]ユーザー名@マシン名 マーク (ここに入力...)ポイント複数行が出来るから、1行目にディレクトリ名を表示ディレクトリ名は青色太文字でディレクトリ名を1行目に追いやったので、肝心のプロンプト部はユーザー名&マシン名でスッキリ4 / 25
  5. 5. プロンプトその1~/.zshrcautoload colorscolorslocal p cdir="%B%F{blue}[%~]%f%b"$’n’local p info="%n@%m"PROMPT=" $p cdir$p info > "5 / 25
  6. 6. プロンプトその1の解説autoload colors と colors 色を出力できるようにする%B…%b %B と%b の間の文字を太字にする%F{color}…%f %F と%f の間の文字を color 色にする%˜ カレントディレクトリ(ホームは “˜”)を出力$’n’ 改行%n ユーザー名%m ホスト名local 普通に変数を定義すると環境変数として見えてしまうが、local をつければ見えないPROMPT この変数に値を設定すれば、プロンプトとして表示される詳しい内容その他は、man zshmisc を参照のこと6 / 25
  7. 7. ユーザーIDでマークを変更マークは太字にしよう通常のユーザーの場合は、マークとして “>” を使いたいroot の場合は、きちんと区別するため “#” を使いたい~/.zshrclocal p cdir="%B%F{blue}[%~]%f%b"$’n’local p info="%n@%m"local p mark="%B%(!,#,>)%b"PROMPT=" $p cdir$p info $p mark "colors は(以降も)省略%( , , ) は if...then...else...!は(ここでは)特権ユーザーの判定詳しくはやはりman zshmisc で7 / 25
  8. 8. コマンドの返り値で色を変化直前のコマンドが成功している場合はマークを緑にコマンドがエラーの場合は、マークを赤に~/.zshrclocal p cdir="%B%F{blue}[%~]%f%b"$’n’local p info="%n@%m"local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"PROMPT=" $p cdir$p info $p mark "?は(この場合は)直前のコマンドの返り値%( , , ) を使って、色の指定を変えているだけ8 / 25
  9. 9. スクリーン番号を(あれば)表示screen コマンドなどで仮想ターミナルを使っている場合は、ウィンドウ番号を(“[ ]” の中に)表示したい使っていない場合は、何も表示したくない~/.zshrclocal p cdir="%B%F{blue}[%~]%f%b"$’n’local p info="%n@%m${WINDOW:+"[$WINDOW]"}"local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"PROMPT=" $p cdir$p info $p mark "${HOGE:+text} は、変数 HOGE が定義されていて値がある場合のみ、変数 HOGE の値を text に置換する詳しくは man zshexpn$WINDOW は、仮想ターミナルのウィンドウ番号が(あれば)格納される変数9 / 25
  10. 10. スクリーン番号を(あれば)表示下にスクリーン番号とウィンドウ名の一覧が出ているのは、screen の設定10 / 25
  11. 11. リモートホスト名の表示ssh などで他のマシンに入っている場合は、混乱するといけないので、元のマシン名を表示したい元のマシン名は FQDN でなく(%m のように)簡単なのがいいAstec-X などの X サーバを使っている場合は、(意外と重要なので)ディスプレイ番号を表示したい…さぁ、いよいよ難しくなってきたオラ、ワクワクしてきたぞ(変態)11 / 25
  12. 12. リモートホスト名の表示(続き)~/.zshrclocal p rhst=""if [[ -n "${REMOTEHOST}${SSH CONNECTION}" ]]; thenlocal rhost=‘who am i|sed ’s/.*((.*)).*/1/’‘rhost=${rhost#localhost:}rhost=${rhost%%.*}p rhst="%B%F{yellow}($rhost)%f%b"filocal p cdir="%B%F{blue}[%~]%f%b"$’n’local p info="%n@%m${WINDOW:+"[$WINDOW]"}"local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"PROMPT=" $p cdir$p rhst$p info $p mark "12 / 25
  13. 13. リモートホスト名の表示(解説)rsh の場合は$REMOTEHOST にリモートホスト名が入ってるssh の場合は$SSH CONNECTION に接続先&元の IP アドレスとポート番号が入っている連結して-n で中身を調べることで、両方に対応その点、who am i は接続元をカッコの中に表示してくれるそれを sed で抜き出す(sed の説明は省略!)X サーバの場合は、ここに “localhost:10.0” のような情報が入っているので、“localhost:” を(あれば)削除${HOGE#text} は、変数 HOGE の先頭から文字列 text を最短マッチで探して削除逆に${HOGE%%text} は、お尻から最長マッチで削除ここらへんは man zshexpn変な数字が表示されちゃう場合は、/etc/hosts をチェック13 / 25
  14. 14. リモートホスト名の表示Astec-X で接続した後に、色んな所に ssh で入った結果14 / 25
  15. 15. PROMPT以外のプロンプト以上で、PROMPT は満足(したとしよう)でも、PROMPT 以外にも Zsh のプロンプトはあるよ~/.zshrc(PROMPT2, SPROMPT)PROMPT2="(% ) %(!,#,>) "SPROMPT="correct: %R -> %r ? [n,y,a,e]: "PROMPT2 if, for などで複数行に渡る場合のプロンプトSPROMNT 入力したコマンドが存在しなく、「本当はこれ?」と聞く場合のプロンプトま、これらは(私は)ほとんど使わないので、あまりこだわらないことにする15 / 25
  16. 16. 右プロンプト重要なことを忘れていた右プロンプト!Zsh の白眉なんで、これを使わないと末代までの恥でも、何を表示しよう…バージョン管理の状態を表示しよう!16 / 25
  17. 17. vcs infoでgit情報を表示偉い人はいるもので、git なら簡単に出来てしまう~/.zshrc(git 情報を右プロンプトに)autoload -Uz vcs infozstyle ’:vcs info:*’ enable gitzstyle ’:vcs info:git:*’ check-for-changes truefunction update vcs info msg() {psvar=()LANG=en US.UTF-8 vcs info[[ -n "$vcs info msg 0 " ]] && psvar[1]="$vcs info msg 0 "}autoload -Uz add-zsh-hookadd-zsh-hook precmd update vcs info msgRPROMPT="%1(v|%1v|)"17 / 25
  18. 18. vcs infoでgit情報を表示(解説)vcs info パッケージをロードvcs info での情報取得に git を許可git の状態チェックを許可psvar=() で、psvar 変数(の配列)を初期化psvar 変数配列は、%1v とか使えるので、とても便利vcs info 関数を呼んで、情報取得vcs info 関数は、$vcs info msg ? という変数に文字列をセットするので、(デフォルトでは1個しか文字列が定義されていないので)もしもそれがあったら、psvar[1] にセットadd-zsh-hook パッケージをロードプロンプトの表示前に update vcs info msg 関数を呼び出すもしもセットされていたら、それを右プロンプトに表示%1(v|hoge|moge) は、if %1v then hoge else moge%1v で、実際の psvar[1] の値詳しくは、man zshcontrib18 / 25
  19. 19. しかし…cvs最高!vcs info パッケージは、実質 git しか対応してないhg や svn, bzr にも一部は対応してるが…情報がいっぱい取れるのは git だけ個人でソースを管理するには、cvs で十分!簡単なこと、この上なしgit なんか使わないよ∼でも vcs info は cvs の状態なんか全然表示してくれないじゃあ、自分でやる!!git なんかより、いっぱい情報出して、すんごく便利にしてやるんだから!19 / 25
  20. 20. 表示したいcvsの情報と実装方針普通に表示したい情報VCS の情報(“cvs”)と、レポジトリ名「注意」として黄色で表示したい情報変更がローカルに反映されてない(“U”)ファイルの数ローカルの変更がコミットされていない(“M”)ファイルの数append されただけ(“A”)のファイルの数remove されただけ(“R”)のファイルの数レポジトリに何の情報もない(“?”)ファイルの数「警告」として赤で表示したい情報コンフリクトを起こしている(“C”)ファイルの数実装方針結局、最大3色で表示するので、本来ならば max-exports を設定して、hook com で各変数(staged, unstaged)を変更すべきここらへんは「mollifier さんの Qiita ブログ」が非常に分かりやす過ぎるので、説明省略しかし、cvs だと全然上手くいかない(差別か?!)仕方ないので、psvar 変数に直接アクセスする20 / 25
  21. 21. 右プロンプトにcvs状態表示・1~/.zshrc(cvs 情報を右プロンプトに・1)autoload -Uz vcs infozstyle ’:vcs info:*’ enable git cvszstyle ’:vcs info:git:*’ check-for-changes truezstyle ’:vcs info:cvs:*’ formats ’(%s)-[%r]’zstyle ’:vcs info:cvs+set-messages:*’ hooks cvs-hookfunction update vcs info msg() {psvar=()LANG=en US.UTF-8 vcs info[[ -n "$vcs info msg 0 " ]] && psvar[1]="$vcs info msg 0 "}autoload -Uz add-zsh-hookadd-zsh-hook precmd update vcs info msgRPROMPT="%1(v|%1v|)%2(v| %B%F{yellow}%2v%f%b|)""%3(v| %B%F{red}%3v%f%b|)"21 / 25
  22. 22. 右プロンプトにcvs状態表示・1(解説)cvs も vcs info で有効にメッセージの表示フォーマットを変更%s, %r の意味などは、man zshcontrib上記メッセージを作成する際に呼び出されるフック関数(cvs-hook) を設定psvar[2], psvar[3] が、もしもあれば、各々黄色と赤で右プロンプトに表示…ということで、このフック関数でどのように psvar[2],psvar[3] の値を設定するかがミソになる22 / 25
  23. 23. 右プロンプトにcvs状態表示・2~/.zshrc(cvs 情報を右プロンプトに・2)function +vi-cvs-hook() {local cvsup=$(cvs -n update|egrep ’ˆ. ’|cut -c1|sort|uniq -c|xargs|tr -d ’ ’|sed ’s/([0-9]+)([ˆ0-9])/21/g’)[[ ! -n $cvsup ]] && return 0local cvsinfo=$(echo ${cvsup}|sed ’s/C[0-9]+//’)[[ -n $cvsinfo ]] && psvar[2]="$cvsinfo"local cvswarn=$(echo ${cvsup}|sed ’s/.*(C[0-9]+).*/1/’)[[ "$cvswarn" != "$cvsup" ]] && psvar[3]="$cvswarn"}cvs+set-messages に登録した関数名は “cvs-hook” だが、ここから呼び出される関数は “+vi-cvs-hook”今は formats に文字列を1個しか登録していないが、formatsに文字列を複数登録しておけば、その個数だけ set-messagesの hook 関数群が呼び出されるその場合、対応するメッセージ($vcs info msg ? )の番号(?の値)が、関数の第1引数($1)として渡される23 / 25
  24. 24. 右プロンプトにcvs状態表示・2(解説)+vi-cvs-hook() 関数の1行目cvs -n update で、変更を反映せずに cvs の状態をチェックegrep ’ˆ. ’ で、マークの行だけを抜き出すcut -c1 で、その1文字目だけを抜き出すsort|uniq -c で、ソートして同じ文字数をカウントxargs で、横一列に並べるtr -d ’ ’ で、空白を削除uniq -c では「文字の数」「文字」(例えば “12A”)という表示なので、sed でそれを入れ替える(“A12” のように)2行目:何も変更がなかったら終わり3行目:cvsup から “C” の部分を切り取り、cvsinfo へ4行目:cvsinfo があったら、psvar[2] に格納5行目:cvsup から “C” の部分だけを抜き出し、cvswarn へ6行目:cvsup に “C” がない場合は全く同じ文字列なので、そうじゃない場合は cvswarn を psvar[3] に格納24 / 25
  25. 25. 右プロンプトにcvs状態表示できた!これにて、満足満足25 / 25

×