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

# はじめに

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

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

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

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

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

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

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

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

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

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

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

# 問題の概要

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

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

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

そして、 [tmux][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][TMUX] の再起動を行っても、 [tmux][TMUX] のステータスラインはデフォルトの状態で全く変化が無く、 [powerline][POWE] が正常に動作していないことが判りました。

# 問題の原因

本章では、[前章][CHAP01]で述べた、 [Github 上における HEAD 版の tmux][TMGP] において、 [powerline][POWE] を導入した際に、 [tmux][TMUX] を再起動しても [tmux][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][TMUX] において、 [powerline][POWE] を動作させる際には、 [powerline][POWE] の動作に関わるデーモンプロセスとなるコマンド ```powerline-daemon``` を起動した上で、 [powerline][POWE] を構成するコマンドの一つである ```powerline-config``` を起動していることが判ります。

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

```shell-session
  $ ~/.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][POWE] を構成するファイルの一つである ```${HOME}/.local/lib/python2.7/site-packages/powerline/bindings/tmux/__init__.py``` 内の関数である ```get_tmux_version``` において異常終了を起こしていることが判ります。

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

```python:${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][TMUX] のバージョンを表示させるために、 ```tmux``` コマンドに ```-V``` オプションを付与して実行すると、以下のバージョンを出力することが判ります。

```shell-session
  $ tmux -V
  tmux next-2.9
  $
```

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

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

# 問題の回避

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

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

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

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

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

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

## powerline の修正による問題回避

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

```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][POWE] の再インストールを行い、 [tmux][TMUX] を再起動して、正常に [powerline][POWE] が動作することを確認します。

## tmux の修正による問題回避

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

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

```sh:configure.ac
# configure.ac

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

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

```sh:configure.ac
# configure.ac

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

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

```shell-session
  $ sh ./autogen.sh
  $ ./configure
  $ make
  $ make install
```

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

```shell-session
  $ tmux -V
  tmux master
  $
```

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

## Linuxbrew を用いた問題回避

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

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

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

まず、 [powerline][POWE] の修正に基づいて、[前々章][CHAP01]の問題を回避するには、以下の通りにして [tmux][TMUX] と [powerline][POWE] を導入します。

```shell-session
  $ brew tap z80oolong/tmux
  $ brew install --HEAD z80oolong/tmux/tmux
  $ brew install z80oolong/tmux/powerline-status
```

そして、 [tmux][TMUX] の修正に基づいて、[前々章][CHAP01]の問題を回避するには、以下の通りにして [tmux][TMUX] と [powerline][POWE] を導入します。

```shell-session
  $ 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][TMGP] のバージョンを "master" に修正する為のオプションであり、また、 ```z80oolong/tmux/tmux``` の導入時に付与するオプション ```--without-fix-powerline``` は、 [powerline][POWE] のソースコードを修正しない為のオプションであることを示します。

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

# 結論

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

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

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

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

# 謝辞

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

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

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

最後に、 [Linuxbrew][BREW] と [tmux][TMUX] 及び [powerline][POWE] に関わる全ての皆様に心より感謝致します。

<!-- 各章及び各節へのリンク一覧 -->

[CHAP01]:#問題の概要
[CHAP02]:#問題の原因
[CHAP03]:#問題の回避
[CHAP04]:#結論
[SEC0301]:#powerline-の修正による問題回避
[SEC0302]:#tmux-の修正による問題回避
[SEC0303]:#linuxbrew-を用いた問題回避

<!-- 外部リンク一覧 -->

[POWE]:https://powerline.readthedocs.io/en/latest/index.html
[TMUX]:https://github.com/tmux/tmux/wiki
[VIM_]:http://www.vim.org/
[ZSH_]:http://www.zsh.org/
[PYTH]:https://www.python.org/
[TMGP]:https://github.com/tmux/tmux
[PO27]:https://github.com/powerline/powerline/archive/2.7.tar.gz
[BREW]:https://linuxbrew.sh/
[TAP1]:https://github.com/z80oolong/homebrew-tmux
[EAWA]:http://www.unicode.org/reports/tr11/#Ambiguous
[KIMS]:kim.silkebaekken+vim@gmail.com
[SHAU]:http://sjackman.ca/