Linux
tmux
powerline

HEAD 版の tmux において powerline を使用する際の問題とその回避手法

はじめに

powerline は、端末多重化ツールである tmux と、軽量テキストエディタである vim 及び zsh 等のコマンドシェルのステータスライン及びプロンプトの表示を、機能的に装飾するためのツールです。

powerline を用いることによって、 tmux のステータスライン等に、現在の日付と時刻及び端末の電池残量等といった、端末の各種状態等を機能的かつ明瞭に表示させることが出来ます。

しかし、 Github 上における HEAD 版の tmux 上において、 powerline を導入し、 powerline による端末の各種状態を表示させる設定を行うと、 tmux のステータスラインの機能的表示が全く行われず、 powerline が正常に動作しない問題が発生する場合があります。

この問題は、 powerline を構成するコマンドの一つである powerline-config が、端末上の tmux のバージョンを検出する際に、 tmux コマンドが異常なバージョンを返すために powerline-config が異常終了する事が原因であると考えられます。

そこで、 powerlinetmux に関する設定を行うコードにおいて、 tmux のバージョンを検出する関数を修正するか、若しくは Github 上における HEAD 版の tmux のバージョンを修正することにより、 Github 上における HEAD 版の tmux 上において、 powerline を正常に動作させることが可能となりました。

本稿では、 Github 上における HEAD 版の tmux において、 powerline を導入する際に tmux のステータスラインの表示に発生する問題の概要と原因及び問題の回避手法について述べます。

まず最初に、 "問題の概要" の章において、 Github 上における HEAD 版の tmux において、 powerline を導入する際に発生する tmux のステータスラインの表示に関する問題の概要について述べます。

次に、 "問題の原因" の章において、前章で述べた問題が発生する原因について述べます。

そして、 "問題の回避" の章において、前々章で述べた問題を回避するための実際の手法について述べます。

最後に、 "結論" の章において、本稿の結論について述べます。

なお、本稿においては、特段の断りのない限り、ホームディレクトリ $HOME/home/user に設定されており、 powerline は、 安定版の powerline-2.7 を用いて、これを Python 処理系におけるユーザ環境上に導入し、 Github 上の HEAD 版の tmux 向けに設定するものとします。

問題の概要

本章では、 Github 上における HEAD 版の tmux において powerline を導入した場合に、 tmux のステータスラインの表示に不具合が発生する問題の概要について述べます。

まず最初に、 powerline の公式ページを参考に、以下のようにして、 powerline をディレクトリ ${HOME}/.local 以下に導入します。

  $ tar -zxvf powerline-2.7.tar.gz
  $ pip install --user ./powerline-2.7

そして、 tmux の設定ファイルである ${HOME}/.tmux.conf に以下の設定を追記します。

${HOME}/.tmux.conf
...
run-shell "/home/user/.local/bin/powerline-daemon -q"
source "/home/user/.local/lib/python2.7/site-packages/powerline/bindings/tmux/powerline.conf"
...

以上の設定の後、 tmux の再起動を行いました。しかし、 tmux の再起動を行っても、 tmux のステータスラインはデフォルトの状態で全く変化が無く、 powerline が正常に動作していないことが判りました。

問題の原因

本章では、前章で述べた、 Github 上における HEAD 版の tmux において、 powerline を導入した際に、 tmux を再起動しても tmux のステータスラインがデフォルトの状態で変化しない問題の原因について述べます。

まず最初に、 tmux の設定ファイル ${HOME}/.tmux.conf に追記したファイル ${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/powerline.conf の内容は以下の通りになっています。

${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/powerline.conf
if-shell 'env "$POWERLINE_CONFIG_COMMAND" tmux setup' '' 'run-shell "powerline-config tmux setup"'
# vim: ft=tmux

上記の内容より、 tmux において、 powerline を動作させる際には、 powerline の動作に関わるデーモンプロセスとなるコマンド powerline-daemon を起動した上で、 powerline を構成するコマンドの一つである powerline-config を起動していることが判ります。

ここで、 powerline-daemon デーモンが起動している状態で、コマンド powerline-config を以下のように起動すると、以下のようなエラーメッセージを出力して停止することが判ります。

  $ ~/.local/bin/powerline-config tmux setup
Traceback (most recent call last):
  File "/home/user/.local/bin/powerline-config", line 22, in <module>
    args.function(pl, args)
  File "/home/user/.local/lib/python2.7/site-packages/powerline/commands/config.py", line 15, in __call__
    self.function(*args, **kwargs)
  File "/home/user/.local/lib/python2.7/site-packages/powerline/bindings/config.py", line 184, in tmux_setup
    tmux_version = get_tmux_version(pl)
  File "/home/user/.local/lib/python2.7/site-packages/powerline/bindings/tmux/__init__.py", line 84, in get_tmux_version
    return TmuxVersionInfo(int(major), int(minor), suffix)
ValueError: invalid literal for int() with base 10: 'next-2'
  $ 

上記のエラーメッセージの内容から、 powerline を構成するファイルの一つである ${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/__init__.py 内の関数である get_tmux_version において異常終了を起こしていることが判ります。

ここで、関数 get_tmux_version の内容は以下のようになっています。

${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/__init__.py
...
def get_tmux_version(pl):
        version_string = get_tmux_output(pl, '-V')
        _, version_string = version_string.split(' ')
        version_string = version_string.strip()
        if version_string == 'master':
            return TmuxVersionInfo(float('inf'), 0, version_string)
        major, minor = version_string.split('.')
        suffix = DIGITS.subn('', minor)[0] or None
        minor = NON_DIGITS.subn('', minor)[0]
        return TmuxVersionInfo(int(major), int(minor), suffix)

上記の関数 get_tmux_version の処理内容より、関数 get_tmux_version は、 tmux のバージョンを検出するための関数である事が判ります。

また、端末上の tmux のバージョンを表示させるために、 tmux コマンドに -V オプションを付与して実行すると、以下のバージョンを出力することが判ります。

  $ tmux -V
  tmux next-2.9
  $

上記の tmux のバージョンの出力結果と関数 get_tmux_version の処理内容とその処理結果による異常終了時のエラーメッセージより、 tmux のバージョンとして、 2.6 や 2.7 等の安定版のバージョン番号もしくは、 git のリポジトリからビルドされたことを示す "master" 以外の文字列が出力される場合は、関数 get_tmux_version は例外を発生し、 powerline-config コマンドが異常終了する事が判ります。

以上のことより、 tmux のバージョンが異常なバージョンを返すことにより、コマンド powerline-config が異常終了することが、 Github 上における HEAD 版の tmux 上において、 powerline が正常に動作しない原因であると考えられます。

問題の回避

本章では、 前々章において述べた、 Github 上における HEAD 版の tmux において、 powerline を導入した際に、 tmux を再起動しても tmux のステータスラインがデフォルトの状態で変化しない問題を実際に回避するための手法について述べます。

まず、前章において述べた原因を踏まえて、前々章において述べた Github 上における HEAD 版の tmux 上において、 powerline が正常に動作しない問題を回避するには、以下の2通りのいずれかの手法を用いれば良いことが判ります。

  • powerline を構成するファイル ${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/__init__.py 内の関数 get_tmux_version において、 tmux のバージョンが安定版のバージョンを返さない場合は、 Github 上の HEAD 版の tmux として扱うように、関数 get_tmux_version を修正する。
  • Github 上の HEAD 版の tmux のコマンド tmux にオプション -V を付与して起動すると、 tmux master を出力結果として返すように、 tmux のソースコードを修正する。

最初に、 "powerline の修正による問題回避" の節において、 powerline のソースコードを修正することによって、前々章の問題を回避する手法について述べます。

次に、 "tmux の修正による問題回避" の節において、 Github 上における HEAD 版の tmux のソースコードを修正することによって、前々章の問題を回避する手法について述べます。

最後に、 "Linuxbrew を用いた問題回避" の節において、前々節及び前節において述べた手法を Linuxbrew による tmux 及び powerline の導入に基づいて、前々章の問題を回避する手法について述べます。

powerline の修正による問題回避

まず、 powerline の修正に基づいて前述した問題を回避するには、 tmux のバージョンが安定版のバージョンを返さない場合は、 Github 上の HEAD 版の tmux として扱うように、関数 get_tmux_version を修正するための以下に示す差分ファイルを powerline のソースコードに適用すれば良い事が判ります。

powerline-status-2.7-fix.diff
diff --git a/powerline/bindings/tmux/__init__.py b/powerline/bindings/tmux/__init__.py
index 011cd689..26cc7dfd 100644
--- a/powerline/bindings/tmux/__init__.py
+++ b/powerline/bindings/tmux/__init__.py
@@ -78,7 +78,11 @@ def get_tmux_version(pl):
    version_string = version_string.strip()
    if version_string == 'master':
        return TmuxVersionInfo(float('inf'), 0, version_string)
-   major, minor = version_string.split('.')
-   suffix = DIGITS.subn('', minor)[0] or None
-   minor = NON_DIGITS.subn('', minor)[0]
-   return TmuxVersionInfo(int(major), int(minor), suffix)
+   try:
+       major, minor = version_string.split('.')
+       suffix = DIGITS.subn('', minor)[0] or None
+       minor = NON_DIGITS.subn('', minor)[0]
+       return TmuxVersionInfo(int(major), int(minor), suffix)
+   except:
+       # If version_string == "next-2.9", and etc., then version of tmux is 'master'.
+       return TmuxVersionInfo(float('inf'), 0, version_string)

上記の差分ファイルを適用した後、 powerline の再インストールを行い、 tmux を再起動して、正常に powerline が動作することを確認します。

tmux の修正による問題回避

まず、 powerline の修正に基づいて前述した問題を回避するには、 Github 上の HEAD 版の tmux のバージョンを修正する必要があります。

ここで、 Github 上の HEAD 版の tmux のバージョンは、以下に示す通り、 Github 上の HEAD 版の tmux のソースコードのファイル confifgure.acAC_INIT マクロに示されていることが判ります。

configure.ac
# configure.ac

AC_INIT([tmux], next-2.9)  # ここでは、バージョンが "next-2.9" に設定されている
AC_PREREQ([2.60])
...

そこで、以下の通りに、ファイル configure.acAC_INIT マクロが書かれている行を修正します。

configure.ac
# configure.ac

AC_INIT([tmux], master)  # next-2.9 → master に修正。
AC_PREREQ([2.60])
...

ファイル configure.ac を修正した後は、以下に示す手順で、 configure スクリプトを生成し、 ./configure スクリプトの実行と tmux のビルド及びインストールを行います。

  $ sh ./autogen.sh
  $ ./configure
  $ make
  $ make install

以上の tmux のインストールが完了した後は、以下のようにして、コマンド tmux -V を実行して出力結果を確認します。

  $ tmux -V
  tmux master
  $

上記の修正を行った後、 tmux の再起動を行い、正常に powerline が動作することを確認します。

Linuxbrew を用いた問題回避

本節では、前々節及び前節において述べた、 Github 上における HEAD 版の tmux において、 powerline を導入した際に、 tmux を再起動しても tmux のステータスラインがデフォルトの状態で変化しない問題を実際に回避するための手法にについて、 Linuxbrew による tmux 及び powerline の導入に基づいた手法について述べます。

前々章で述べた問題を回避する tmux 及び powerline を導入するための Formula を収めた Linuxbrew 向けの Tap リポジトリを z80oolong/tmux に置きました。

なお、この Tap リポジトリに収められた Formula である z80oolong/tmux/tmux を導入することにより、 "◎" や "★" 等の記号文字及び罫線文字等、 East_Asian_Width 特性の値が A (Ambiguous) となる文字が、日本語環境において全角の文字幅として表示できるように修正された tmux を導入することが出来ます。

まず、 powerline の修正に基づいて、前々章の問題を回避するには、以下の通りにして tmuxpowerline を導入します。

  $ brew tap z80oolong/tmux
  $ brew install --HEAD z80oolong/tmux/tmux
  $ brew install z80oolong/tmux/powerline-status

そして、 tmux の修正に基づいて、前々章の問題を回避するには、以下の通りにして tmuxpowerline を導入します。

  $ brew tap z80oolong/tmux
  $ brew install --HEAD z80oolong/tmux/tmux --with-version-master
  $ brew install z80oolong/tmux/powerline-status --without-fix-powerline

ここに、 z80oolong/tmux/tmux の導入時に付与するオプション --with-version-master は、 Github 上の HEAD 版の tmux のバージョンを "master" に修正する為のオプションであり、また、 z80oolong/tmux/tmux の導入時に付与するオプション --without-fix-powerline は、 powerline のソースコードを修正しない為のオプションであることを示します。

上記の tmux 及び powerline の導入を行った後、 tmux を起動し、正常に powerline が動作することを確認します。

結論

本稿では、 "問題の概要" の章において、 Github 上の HEAD 版の tmuxpowerline を導入した場合、 tmux を再起動しても、 tmux のステータスラインがデフォルトのままで変化せず、 powerline が正常に動作しない問題が発生することを示しました。

次に、前々章において、 Github 上の HEAD 版の tmux において、 powerline を導入する設定を行い、 tmux を再起動すると、 tmux が 2.6 や 2.7 等の安定版のバージョンもしくは、 git のリポジトリからビルドされたことを示す "master" 以外の文字列をバージョンの文字列として返す場合に、 powerline を構成するコマンドの一つである powerline-config 内の関数 get_tmux_version が例外を発生し、 powerline-config コマンドが異常終了する為に、 "問題の概要" で示した問題が発生する原因となることを示しました。

そして、前章において、前々章の原因を踏まえて、本稿で示した問題を回避する手法として、 powerline を構成する一部のコマンド powerline-config における関数 get_tmux_version を修正することによる手法と、 Github 上の HEAD 版の tmux が返すバージョンを "master" に修正する手法を示し、また、これらの手法を Linuxbrew による tmux 及び powerline の導入に基づいて問題を回避する手法についても併せて示しました。

以上の本稿で示した問題回避の手法により、 Github 上の HEAD 版の tmux が異常なバージョンを返した場合においても、 powerline を正常に動作させることが可能となることを示すことが出来ました。

謝辞

まず最初に、 tmux と、 vim 及び zsh 等のコマンドシェルのステータスライン及びプロンプトの表示を、機能的かつ明瞭に装飾し表示するためのツール powerline を開発した Kim Silkebækken 氏及び Fabrizio Schiavi 氏らを始めとする powerline の開発コミュニティの各氏に心より感謝致します。

そして、利便性の非常に高い端末多重化ツールである tmux を開発した、 [Nicholas Marriott 氏][NICM]を始めとした tmux の開発コミュニティの各氏にも心より感謝致します。

また、 powerlineLinuxbrew 向け Formula を記述するにあたっては、 Linuxbrew のコア Tap リポジトリ homebrew/core 内の各種 Python 処理系のライブラリを導入するための Formula を参考にしました。Linuxbrew の本体のリポジトリの開発を行っている Shaun Jackman 氏を始めとする Linuxbrew の開発コミュニティの各氏に心より感謝致します。

最後に、 Linuxbrewtmux 及び powerline に関わる全ての皆様に心より感謝致します。