Oh-my-zshのテーマをカスタマイズ
今回は、Oh-my-zshをインストールしthemaをカスタマイズしました。
早くて簡単です。
.oh-my-zshが新しく作成されます。
Themes
これらのテーマを使うのもいいのですがやはり自分専用の
プロンプトがほしくなると思います。ということで作りました。
今回はプロンプトに表示したかったものとして
・Gitのリポジトリの情報
・バックグランドのプロセスの数
です。
Gitの情報の取得の関数はすでに.oh-my-zsh/lib/git.zshにあります。
しかし、すでにある関数では主にファイルの変更、削除やリモートとのコミットの差分のチェックは
存在の有無であったため自分は数まで把握したいなと思いカスタマイズしました。
Gitのリポジトリの情報としてほしかったのが
・ローカルリポジトリの状態
・リモートリポジトリとの差分
以下がコードです。(ほとんど.oh-my-zsh/lib/git.zshと同じかつ汚いコードになりました)
まずGitの状態を取得するためにgit status --porcelainを使っています。
これは以下のようにステータス情報を簡単に表示してくれます。
存在する行数をカウントして表示するという 簡単なメソッドです。
おもにコミットのハッシュを表示してくれるコマンドでした。
さらにここで使用しているオプション --verifyは指定されたオブジェクトがGitのオブジェクトかどうかチェックしています。
what-does-git-rev-parse-do
でもなぜ refs/stash と思いませんか?
どこを指定しているのだろうと。
調べたら.git/refs/stash(ファイル)を指していました。
Gitの内側-Gitの参照 ← 詳しくはこちらでお願いします。
さらにrefs/stashはstashが存在する時のみに作成されるファイルです。
不思議なことにstashには最新のstash時のみコミットハッシュしか保存されていませんでした。
他のstashの情報はどこにあるのだろうかと思い調べたのですが分からなかったです><
すいません。
リモートとの差分といっても比較対象はgit fetchしてきたリポジトリの情報になります。
新しい順にコミットハッシュを並べてくれます。
これによりリモートとのコミットの差分が存在するのかチェックしてくれます。
「%j」で代用できることを知り開発をやめました。
バックグラウンドの種類まで表示しようとしましたが出来ませんでした。
完成形
通常
git
色々いじった状態 ??←unstaged [緑] ←インデックスの状態 [黄色]←作業ディレクトリの状態
感想
コードが汚い、きれいにする。バックグランドの種類までほしいので頑張る。
(周りにはそこまでしなくてもと言われたが)
カスタマイズはやっぱり面白い。Gitの知らないことが分かってよかった。
githubのコードです
curl -L https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh | shinstall.shでは特に難しいことやっていないため、手動で行っても良いかもしれません。
早くて簡単です。
.oh-my-zshが新しく作成されます。
.oh-my-zsh ├── MIT-LICENSE.txt ├── README.textile ├── custom ├── lib ├── log ├── oh-my-zsh.sh ├── plugins ├── templates ├── themes └── tools
今回注目するのは、themesです。
oh-my-zshには多くのプロンプトのテーマが存在します。Themes
これらのテーマを使うのもいいのですがやはり自分専用の
プロンプトがほしくなると思います。ということで作りました。
今回はプロンプトに表示したかったものとして
・Gitのリポジトリの情報
・バックグランドのプロセスの数
です。
Gitのリポジトリの情報
Gitの情報の取得の関数はすでに.oh-my-zsh/lib/git.zshにあります。
しかし、すでにある関数では主にファイルの変更、削除やリモートとのコミットの差分のチェックは
存在の有無であったため自分は数まで把握したいなと思いカスタマイズしました。
Gitのリポジトリの情報としてほしかったのが
・ローカルリポジトリの状態
・リモートリポジトリとの差分
ローカルリポジトリの状態
まず、ローカルのリポジトリの情報の取得です。以下がコードです。(ほとんど.oh-my-zsh/lib/git.zshと同じかつ汚いコードになりました)
custom_git_prompt_status() { #INDEX=$(command git status --porcelain -b 2> /dev/null) # for git version 1.7.1 INDEX=$(command git status --porcelain 2> /dev/null) STATUS="" if COUNT=$(echo "$INDEX" &> /dev/null | grep -E '^\?\? ' -c ) && [ $COUNT -gt 0 ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_UNTRACKED$COUNT" fi # Staged STAGED="" if COUNT=$(echo "$INDEX" &> /dev/null | grep '^A ' -c ) && [ $COUNT -gt 0 ]; then STAGED="$STAGED$ZSH_THEME_GIT_PROMPT_STAGED_ADDED$COUNT" fi if COUNT=$(echo "$INDEX" &> /dev/null | grep '^M ' -c ) && [ $COUNT -gt 0 ]; then STAGED="$STAGED$ZSH_THEME_GIT_PROMPT_STAGED_MODIFIED$COUNT" fi if COUNT=$(echo "$INDEX" &> /dev/null | grep '^R ' -c ) && [ $COUNT -gt 0 ]; then STAGED="$STAGED$ZSH_THEME_GIT_PROMPT_STAGED_RENAMED$COUNT" fi if COUNT=$(echo "$INDEX" &> /dev/null | grep '^D ' -c ) && [ $COUNT -gt 0 ]; then STAGED="$STAGED$ZSH_THEME_GIT_PROMPT_STAGED_DELETED$COUNT" fi if [ "$STAGED" != "" ];then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_STAGED_PREFIX$STAGED$ZSH_THEME_GIT_PROMPT_STAGED_SUFFIX" fi # Unstaged UNSTAGED="" if COUNT=$(echo "$INDEX" &> /dev/null | grep '^AM \|^ T \|^ M ' -c ) && [ $COUNT -gt 0 ]; then UNSTAGED="$UNSTAGED$ZSH_THEME_GIT_PROMPT_MODIFIED$COUNT" fi if COUNT=$(echo "$INDEX" &> /dev/null | grep '^AD ' -c ) && [ $COUNT -gt 0 ]; then UNSTAGED="$UNSTAGED$ZSH_THEME_GIT_PROMPT_DELETED$COUNT" fi if [ "$UNSTAGED" != "" ];then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_UNSTAGED_PREFIX$UNSTAGED$ZSH_THEME_GIT_PROMPT_UNSTAGED_SUFFIX" fi if $(command git rev-parse --verify refs/stash >/dev/null 2>&1); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_STASHED" fi if $(echo "$INDEX" | grep '^UU ' &> /dev/null); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_UNMERGED" fi if $(echo "$INDEX" | grep '^## .*ahead' &> /dev/null); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_AHEAD" fi if $(echo "$INDEX" | grep '^## .*behind' &> /dev/null); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_BEHIND" fi if $(echo "$INDEX" | grep '^## .*diverged' &> /dev/null); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_DIVERGED" fi echo $STATUS }
まずGitの状態を取得するためにgit status --porcelainを使っています。
これは以下のようにステータス情報を簡単に表示してくれます。
$git status --porcelain M zsh/theme/ooma.zsh-theme ?? testcustom_git_prompt_statusでは表示された内容をgrepで検索を行い、
存在する行数をカウントして表示するという 簡単なメソッドです。
$git status --porcelain | grep '^ M'
M zsh/theme/ooma.zsh-theme
$git status --porcelain | grep '^ M' -c
1
stashのチェックもここで行っています。if $(command git rev-parse --verify refs/stash >/dev/null 2>&1); then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_STASHED" fiコマンドが私が見たことの無いrev-parseを使っていました。
おもにコミットのハッシュを表示してくれるコマンドでした。
さらにここで使用しているオプション --verifyは指定されたオブジェクトがGitのオブジェクトかどうかチェックしています。
what-does-git-rev-parse-do
でもなぜ refs/stash と思いませんか?
どこを指定しているのだろうと。
調べたら.git/refs/stash(ファイル)を指していました。
Gitの内側-Gitの参照 ← 詳しくはこちらでお願いします。
$tree .git/refsrefs/stashにはpushされたときのHEADのコミットハッシュが書かれています。
.git/refs ├── heads │ ├── linux │ └── master ├── remotes │ └── origin │ ├── HEAD │ ├── linux │ └── master ├── stash └── tags
└── ver1.0
さらにrefs/stashはstashが存在する時のみに作成されるファイルです。
不思議なことにstashには最新のstash時のみコミットハッシュしか保存されていませんでした。
他のstashの情報はどこにあるのだろうかと思い調べたのですが分からなかったです><
すいません。
リモートリポジトリとの差分
次はリモートとの差分です。リモートとの差分といっても比較対象はgit fetchしてきたリポジトリの情報になります。
custom_git_remote_status() { remote=${$(command git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/} if -n ${remote} ; then ahead=$(command git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l) behind=$(command git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l) if [ $ahead -eq 0 ] && [ $behind -gt 0 ] then echo "$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" elif [ $ahead -gt 0 ] && [ $behind -eq 0 ] then echo "$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE" elif [ $ahead -gt 0 ] && [ $behind -gt 0 ] then echo "$ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE" fi fi }
ここでも出ました。rev-parse --verify です。
${hook_com[branch]}にはブランチ名が入ってきます。
--symbolic-full-nameはrev-parseで出力するときにGitのオブジェクトのパスを渡します。
通常の場合・・コミットハッシュのみ
--symbolic-full-nameの場合 (gitオブジェクトのパスが表示される)${hook_com[branch]}にはブランチ名が入ってきます。
--symbolic-full-nameはrev-parseで出力するときにGitのオブジェクトのパスを渡します。
通常の場合・・コミットハッシュのみ
$git rev-parse --verify master 30c1615daa638a7442c2ab043c9ba7021ba81c3f--symbolicの場合 ブランチ名(リモートの場合はリモート名も付く)
$git rev-parse --verify master --symbolic master
$git rev-parse --verify master --symbolic-full-name refs/heads/master
おおこれでローカルのgitのオブジェクトのパスが手に入りました。
でもほしいのはリモートです。そこで@{upstream}の出番です。git-rev-parse
@{upstream}は、指定されたブランチのupstreamのgitのオブジェクトのパスを取得してくれます。
(リモートのブランチのどれかに該当します)definition-of-downstream-and-upstream
git branch -vv(vが二つ)で見ることが出来ます。下の実行結果ですとmasterブランチの
upstreamは「origin/master」となります。
how-do-i-get-git-to-show-me-which-branches-are-tracking-what
rev-listについて git-rev-list
-- list commit object in reverse chronological orderでもほしいのはリモートです。そこで@{upstream}の出番です。git-rev-parse
@{upstream}は、指定されたブランチのupstreamのgitのオブジェクトのパスを取得してくれます。
$git rev-parse --verify master@{upstream} --symbolic-full-name refs/remotes/origin/masterupstreamとは該当するブランチの本家のリポジトリ?みたいな感じで言い方が悪いかもしれません。
(リモートのブランチのどれかに該当します)definition-of-downstream-and-upstream
git branch -vv(vが二つ)で見ることが出来ます。下の実行結果ですとmasterブランチの
upstreamは「origin/master」となります。
how-do-i-get-git-to-show-me-which-branches-are-tracking-what
$git branch -vv linux df0b61f remove tmp * master 59a593a [origin/master: ahead 1] delete space
rev-listについて git-rev-list
これによりリモートとのコミットの差分が存在するのかチェックしてくれます。
$git rev-list HEAD..refs/remotes/origin/master 471fff9b92650c5e4deaec584a3b6f62ad1543a6
あとはコミットハッシュの数をカウントすれば差分の数が分かります。
バックグラウンドのジョブ数確認
頑張ってコードを書いていました。ZSH_THEME_BACKGROUND_JOB_PREFIX="%{$C%}" ZSH_THEME_BACKGROUND_JOB_SUFFIX="%{$RE%}" background_jobs() { jobs=$(jobs 2>/dev/null) if [ $jobs ];then echo "$ZSH_THEME_BACKGROUND_JOB_PREFIX" for i in $jobs; do echo $i done echo "$ZSH_THEME_BACKGROUND_JOB_SUFFIX" fi }でも zsh-prompt-checking-if-there-are-any-background-jobsを見て
「%j」で代用できることを知り開発をやめました。
バックグラウンドの種類まで表示しようとしましたが出来ませんでした。
完成形
通常
git
色々いじった状態 ??←unstaged [緑] ←インデックスの状態 [黄色]←作業ディレクトリの状態
感想
コードが汚い、きれいにする。バックグランドの種類までほしいので頑張る。
(周りにはそこまでしなくてもと言われたが)
カスタマイズはやっぱり面白い。Gitの知らないことが分かってよかった。
githubのコードです