GNU Screenのウィンドウタイトルを自動設定する際に日本語の文字化けを回避する

スポンサード リンク

GNU Screenで複数のウィンドウを開くと,どのウィンドウで何の作業をしているか分かりづらい。これを区別する手段がウィンドウタイトルであり,GNU screenのウィンドウタイトルを自動設定 - 貳佰伍拾陸夜日記 の設定に従うとウィンドウタイトルに実行中のコマンド名か,カレントディレクトリの名称を自動設定できる。

一方,(少なくともaptで入る version 4.06.02の) Screenではウィンドウタイトルに日本語を使えない。文字化けするとレイアウトが崩れてしまう。この問題はカレントディレクトリに日本語を含むときに特に問題になる。今回はScreenにパッチを当てるのではなく,日本語をローマ字に変換してからScreenにわたすことで文字化けを回避する。

インストール

この日本語のローマ字変換は kakasi プログラムで実現できる。そのインストールは通常通りにaptで可能だ。

sudo apt install -y kakasi

kakasiを使えば以下のように日本語をローマ字に変換できる。今回は -S_ -s オプションの付与で _ で区切ることにした。その他のオプションの詳細は man kakasi を参照いただきたい。

$ echo 'とても眠い' | kakasi -Ja -Ha -Ka -Ea -i utf-8 -o utf-8 -S_ -s
totemo_nemui

screenの設定

~/.screenrc に以下の1行を追加する。

setenv SCREENTITLE auto

zshの設定

まず ~/.zshrc に以下の内容を追加する。

# automatically set title
typeset -ga precmd_functions
typeset -ga preexec_functions

if [[ $ZSH_VERSION == (<5->|4.<4->|4.3.<10->)* ]]; then
  source ~/.zsh/term.zshrc
fi

次に ~/.zsh/term.zshrc として以下の内容を保存する。ポイントは which kakasi > /dev/null 2>&1 && title=$(echo ${1} | kakasi -Ja -Ha -Ka -Ea -i utf-8 -o utf-8 -S_ -s) の行であり,ここで日本語をローマ字に変換している。

# VCS
autoload -Uz vcs_info
zstyle ':vcs_info:(git|svn):*' formats '%R' '%S' '%b' '%s'
zstyle ':vcs_info:(git|svn):*' actionformats '%R' '%S' '%b|%a' '%s'
zstyle ':vcs_info:*' formats '%R' '%S' '%s:%b' '%s'
zstyle ':vcs_info:*' actionformats '%R' '%S' '%s:%b|%a' '%s'
function precmd_vcs_info () {
    psvar=()
    STY= LANG=en_US.UTF-8 vcs_info
    repos=`print -nD "$vcs_info_msg_0_"`
    if [[ -n "$vcs_info_msg_1_" ]]; then
        vcs="$vcs_info_msg_3_"
    else
        vcs=''
    fi
    [[ -n "$repos" ]] && psvar[2]="$repos"
    [[ -n "$vcs_info_msg_1_" ]] && psvar[3]="$vcs_info_msg_1_"
    [[ -n "$vcs_info_msg_2_" ]] && psvar[1]="$vcs_info_msg_2_"
}

# set window title of screen
function set_screen_title () {
  local title
  # convert Kanji to Rome-ji to avoid Mojibake
  which kakasi > /dev/null 2>&1 && title=$(echo ${1} | kakasi -Ja -Ha -Ka -Ea -i utf-8 -o utf-8 -S_ -s)
  echo -ne "\ek${title}\e\\"
}
function { # use current directory as a title
    function precmd_screen_window_title () {
        if [[ "$SCREENTITLE" = 'auto' ]]; then
            local dir
            dir=`pwd`
            dir=`print -nD "$dir"`
            if [[ ( -n "$vcs" ) && ( "$repos" != "$dir" ) ]]; then
                # name of repository and directory
                dir="${repos:t}:${dir:t}"
            else
                # name of directory
                dir=${dir:t}
            fi
            set_screen_title "$dir"
        fi
    }
}
typeset -A SCREEN_TITLE_CMD_ARG; SCREEN_TITLE_CMD_ARG=(ssh  -1 su -1 man -1)
typeset -A SCREEN_TITLE_CMD_IGNORE; SCREEN_TITLE_CMD_IGNORE=()
function { # use command name as a title
    function set_cmd_screen_title () {
        local -a cmd; cmd=(${(z)1})
        while [[ "$cmd[1]" =~ "[^\\]=" ]]; do shift cmd; done
        if [[ "$cmd[1]" == "env" ]]; then shift cmd; fi
        if [[ -n "$SCREEN_TITLE_CMD_IGNORE[$cmd[1]]" ]]; then
            return
        elif [[ -n "$SCREEN_TITLE_CMD_ARG[$cmd[1]]" ]]; then
            # argument of command
            cmd[1]=$cmd[$SCREEN_TITLE_CMD_ARG[$cmd[1]]]
        fi
        set_screen_title "$cmd[1]:t"
    }
    function preexec_screen_window_title () {
        local -a cmd; cmd=(${(z)2}) # command in a single line
        if [[ "$SCREENTITLE" = 'auto' ]]; then
            case $cmd[1] in
                fg)
                    if (( $#cmd == 1 )); then
                        cmd=(builtin jobs -l %+)
                    else
                        cmd=(builtin jobs -l $cmd[2])
                    fi
                    ;;
                %*)
                    cmd=(builtin jobs -l $cmd[1])
                    ;;
                *)
                    set_cmd_screen_title "$cmd"
                    return
                    ;;
            esac
            # resolve command in jobs
            local -A jt; jt=(${(kv)jobtexts})
            $cmd >>(read num rest
                cmd=(${(z)${(e):-\$jt$num}})
                set_cmd_screen_title "$cmd"
            ) 2>/dev/null
        fi
    }
}
function title() {
    if [[ -n "$SCREENTITLE" ]]; then
        if [[ -n "$1" ]]; then
            # set title explicitly
            export SCREENTITLE=explicit
            set_screen_title "$1"
        else
            # automatically set title
            export SCREENTITLE=auto
        fi
    fi
}

precmd_functions+=precmd_vcs_info
precmd_functions+=precmd_screen_window_title
preexec_functions+=preexec_screen_window_title

するとローマ字に変換された内容がウィンドウタイトルに自動設定されるようになる。

Comments !

social