🚉

Zshをカスタマイズしよう

2023/07/06に公開

AGENDA

  • zsh使ってますか?
  • zshellをカスタマイズすると…
  • zshのカスタマイズ方法
  • 私と一緒に開発しませんか? (zshianの紹介)

伝えたいこと

  • 自作コマンドは気持ちいい
  • 自作TUIは気持ちいい

zsh使っていますか?

  • Z shell is 何?
    • The Z shell (Zsh) is a Unix shell that can be used as an interactive login shell and as a command interpreter for shell scripting. Zsh is an extended Bourne shell with many improvements, including some features of Bash, ksh, and tcsh.
    • 要するに対話的なログインシェルでShell Scriptのコマンドインタープリタ
    • Wikipedia: https://en.wikipedia.org/wiki/Z_shell
    • last edit: 4 May 2023
  • Macの皆さんはご存知かもしれませんが…

Zshをカスタマイズしませんか?

  • Zshをカスタムする理由
    • 建前: 打ち込む文字数の削減, 便利機能を使いたい
    • 本音: かっこいいから

Z shellをカスタマイズすると…

  • 私のZ shellの画面

  • gitのcommitにメッセージと絵文字を入れれます

  • デフォルトの画面はwikiのように色の設定があまりされてない (白黒)
  • また, terminalの入力受付状態のときに表示される文字(prompt)に情報が少ない
  • Gitの情報とか時間とかを知りたい!
  • 実際aliasと補完があると打ち込み回数が減り開発が楽になる

どうやって使いやすくするか

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
  • 自力
    • 「素晴らしいプラグインはあるけど完璧に自分好みの設定のプラグインなんてないよね」
    • 「ないなら作っちゃえばいいじゃん」
    • 「そうか、作ればいいのか」
    • 「作りたくなりましたよね...??????」

Z shellのカスタマイズの仕方

~/.zshrc に書き込み, sourceで有効化する. 簡単!

cd $HOME
touch .zshrc
echo "alias helloworld='echo Hello World'" > .zshrc
source .zshrc
helloworld // print Hello World
  • aliasはshort cutのようなもので設定するとterminalが解釈・変換してくれる
  • optionの設定
setopt RM_STAR_SILENT       # do not confirm when run `rm *`
setopt nonomatch            # enable to use ? and & in curl as literal
setopt no_beep              # disable beep sound
setopt nolistbeep           # disable beep sound after completion
setopt auto_cd              # if command not found consider using cd
setopt share_history        # share history between all zsh
setopt hist_ignore_dups     # do NOT add command to history if command is same to prev command
setopt extended_glob        # enable wild pattern when using glob
  • pathの設定
# PATH SETTING #
# * add path path to home brew
# typeset -Ug : deal with path as set of PATH
# N-/         : add path if not exist
typeset -gU path PATH
path=(
  /opt/homebrew/bin(N-/)
  /opt/homebrew/sbin(N-/)
  /usr/bin
  /usr/sbin
  /bin
  /sbin
  /usr/local/bin(N-/)
  /usr/local/sbin(N-/)
  /Library/Apple/usr/bin
)
  • homebrewの設定
    • promptはgitと連携したいのでここで設定している
# HOMEBREW SETTING
# * if brew has already installed, below lines will be run when reading this file
# if type brew          : check wheather brew command exist
# &>                    : redirect both of standard output and error to /dev/null
# zsh-git-prompt/zshrc  : to use for showing git branch in command prompt
# autoload -Uz          : prevent from being over written by user alias. use zsh format
if type brew &>/dev/null; then
  FPATH=$(brew --prefix)/share/zsh-completions:$FPATH
  source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh
  source $(brew --prefix)/opt/zsh-git-prompt/zshrc.sh
  autoload -Uz compinit && compinit
  autoload -Uz colors && colors
  autoload -Uz add-zsh-hook
fi
# Delete the empty character immediately before the completion entered in zsh-completion
ZLE_REMOVE_SUFFIX_CHARS=$'' # add space after completion

# PROMPT SETTING #
# alias python="python3"  : add alias for git_super_status
#                         : if Mac OS version < 12 Monterey, you can comment out this line
# %F{color} ... %f        : change color
# %n                      : user name
# ($(arch))               : system architecture
# %D                      : YYYY-mm-dd
# %T                      : hh:mm
# $(git_super_status)     : git status
# %#                      : show "#" if you are root, else show %
# if brew list | grep ~   : if ~ exists, return true
# add-zsh-hook precmd     : if
alias python="python3"

git_prompt() {
  # if .git exists show it
  if [ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" = true ]; then
    PROMPT="%F{green}🖱️ : %n%f 🔧: %F{cyan}($(arch))%f ⏰: %F{yellow}%D %T%f
📍: %F{blue}%~%f  🌿: $(git_super_status)
%F{green}>> %f %# "
  else
    PROMPT="%F{green}🖱️ : %n%f 🔧: %F{cyan}($(arch))%f ⏰: %F{yellow}%D %T%f
📍: %F{blue}%~%f
%F{green} >> %f %# "
  fi
}

if brew list | grep zsh-git-prompt &> /dev/null; then
  add-zsh-hook precmd git_prompt
fi
  • 「複数ファイルに分割したい!」
    • .zsh ファイルを作り, それぞれを source する処理を.zshrcに書く
    • 私は $HOME/.zsh の下に設定対象ごとのdir, fileを作っています
# Load seperated config files
for conf in "$HOME/.zsh/"*/*.zsh; do
  source "${conf}"
done
unset conf

そんなにコマンド作って覚えていられるの?

  • commandやaliasは基本的に覚えない
    • 覚えるという発想が間違っている(過激派)

具体例

  • gitのalias
  • show_git_alias で出現するようにしている

grepとone liner perlを使って文字列整形します. 対象のファイルはaliasを設定しているファイルです.

ソースコード

# Add all changes in working directory to the staging area
alias gad='git add .'

# Amend the most recent commit
alias gamd='git commit --amend'

# List all local branches
alias gbr='git branch'

# List all remote branches
alias gbrr='git branch -r'

# Create a new branch and switch to it
alias gcb='git checkout -b '

# Remove files from the index (staging area)
alias gcr='git rm -r --cached'

# Fetch from and integrate with another repository or a local branch (short for 'git pull origin')
alias gpull='git pull origin'

# Update remote refs along with associated objects (short for 'git push origin')
alias gpush='git push origin'

# Reset current HEAD to the specified state
alias greset='git reset'

# Show the working tree status
alias gst='git status'

# Switch to another branch
alias gsw='git switch '

ソースコードからcsvを作るShell Script

#!/bin/bash

# Remove lines starting with '#'
grep -v '^#' .zsh/git/alias.zsh | \
# Remove 'alias ' at the start of each line
perl -pe 's/^alias //' | \
# Replace '=' with ','
perl -pe "s/='/,/" | \
# Remove trailing quote
perl -pe "s/'$//" | \
# Remove blank lines
grep -v '^$' > .zsh/doc/git_alias.csv

出力用のコマンド show_git_aliasの実装

# Note: line 7; doc dir is upper dir of this file
# Note: line 7; we use absolute path for git_alias
function show_git_alias() {
    echo -e "Alias\tCommand\n----\t-------"
    while IFS=',' read -r alias command
    do
        echo -e "${alias}\t${command}"
    done < $HOME/.zsh/doc/git_alias.csv | column -t
}

具体例2

- gitのcommitにメッセージと絵文字を入れるとき
- `gcm what_you_did “message”` ⇒ `git commit -m ":emoji: [what_you_did] ===> message` のalias(function) を貼って実装している
- what_you_didの部分は正規表現で検索できるようにしている

gcmgcm_search_command . gcm_search_commandはgcmのコマンド引数をgrepで検索する

gcm () {
  # input validation
  if [ $# -ne 2 ];then
    echo "Error: the number of arguments must be 2. if you do not command name, please run 'gcm_searc_command' you can read file on command"
    return 1
  fi
  case "$1" in
    "add_a_dependency" ) icon=":heavy_plus_sign: [add a dependency] =>" ;;
    "add_analytics" ) icon=":chart_with_upwards_trend: [add analytics] => " ;;
    "add_animation" ) icon=":dizzy: [add animation] => " ;;
		...
    "work_in_progress" ) icon=":construction: [work in progress] =>" ;;
    "work_on_responsive_design" ) icon=":iphone: [work on responsive design] => " ;;
    "write_code_drunkely" ) icon=":beer: [write code drunkly] => " ;;
    "h" ) vim ~/zsh_config/data/gcm_command_commit
  esac
  commit_message="$icon $2"
  git commit -m $commit_message
}

gcm_search_command (){
  if [ $# -ne 1 ];then
    echo "ERROR: the number of input must be 1"
    exit 1
  fi
  cat ~/.zsh/doc/gcm_command_name.txt | grep $1
}

私と一緒に開発しませんか?

今日紹介したものは全てOSSで公開しています. 開発に興味のあるかたは是非repositoryを訪れてみてください!

https://github.com/shunsock/zshian

Discussion