less
でシンタックスハイライトする方法があると聞いたので、GNU source-highlight を使った方法を試してみました。
より詳しい記事として以下のような記事もあるので参考のこと。
- Ubuntuでlessを使って構文をカラー表示する方法
- ソースを綺麗に整形表示するGNU source-highlight - それマグで!
- lessコマンドを少し便利にしておく - Qiita
- 漢(オトコ)のコンピュータ道: lessでソースコードに色をつける
これらの記事では環境変数を弄っているのに対して、本記事では alias
を使用する方法を紹介します。
GNU source-highlight のインストール
ほとんどの環境で less
は最初から使用できるはずなのでインストールはスキップします。とは言うものの、もしかしたらバージョン違いで同じように設定できない恐れもあるので、その辺りは確認しておきます。
# cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)
# less --version
less 458 (POSIX regular expressions)
Copyright (C) 1984-2012 Mark Nudelman
less comes with NO WARRANTY, to the extent permitted by law.
For information about the terms of redistribution,
see the file named README in the less distribution.
Homepage: http://www.greenwoodsoftware.com/less
ではインストールします。root でない人は sudo
してください。
# yum install source-highlight
略
インストールが完了したら大雑把な構成を把握します。
# rpm -q source-highlight
source-highlight-3.1.6-6.el7.x86_64
# rpm -ql source-highlight
/etc/bash_completion.d
/etc/bash_completion.d/source-highlight
/usr/bin/check-regexp
/usr/bin/cpp2html
/usr/bin/java2html
/usr/bin/source-highlight
/usr/bin/source-highlight-settings
/usr/bin/src-hilite-lesspipe.sh
/usr/lib64/libsource-highlight.so.4
/usr/lib64/libsource-highlight.so.4.0.0
/usr/share/doc/source-highlight-3.1.6
略(マニュアルっぽいhtmlファイルがいっぱい)
/usr/share/info/source-highlight-lib.info.gz
/usr/share/info/source-highlight.info.gz
/usr/share/man/man1/check-regexp.1.gz
/usr/share/man/man1/source-highlight-settings.1.gz
/usr/share/man/man1/source-highlight.1.gz
/usr/share/source-highlight
/usr/share/source-highlight/Hello.css
略(共通設定と思われるファイルがいっぱい)
バージョンは 3.1.6
がインストールされたようです。
/etc/
の下は bash
関連のようなので一旦無視でいいでしょう。実行ファイルは /usr/bin/
に入ったようです。その他はマニュアル類と、共通設定ファイルと思われるファイルがインストールされます。
使い方
先ほどインストールされた /usr/bin/src-hilite-lesspipe.sh
を使います。ソースコードをこのスクリプトに与えると、カラーシーケンスが付与されたテキストが出力されます。色の定義は拡張子に依存するようです(後述)。これを -R
オプション付きの less
にパイプします。
やってみます。まずコマンドが長くなるので alias
を設定します。
# which hilite
/usr/bin/which: no hilite in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)
#
# alias hilite='/usr/bin/src-hilite-lesspipe.sh'
# alias less='less -R'
# alias | grep less
alias hilite='/usr/bin/src-hilite-lesspipe.sh'
alias less='less -R'
動作確認は以下のように。
# hilite hoge.sh | less
カラースキームの調整
デフォルトのカラースキームに不満がある場合は、/usr/share/source-highlight/
配下のファイルを弄ります。
ごちゃごちゃしていますが、拡張子ごとに見ると以下のようなファイル構成です。
# ls /usr/share/source-highlight/ | sed -e 's/.*\.//' | sort | uniq -c
46 css
1 defaults
100 lang
2 map
21 outlang
6 style
lang
は言語の構文定義ファイルのようです。outlang
は出力方式を定義するファイルのようです。map
は拡張子と構文定義ファイルの紐づけを行っている lang.map
と、出力フォーマット名と outlnag
ファイルを紐づけているらしい outlang.map
の 2 つです。実際のカラースキームを定義しているのは、css
か style
のようです。style.defaults
は style
ファイル全体のデフォルト値だと思われます。
詳細はちょっとわからないので、hilite
コマンドの中で何が行われているのか確認してみます。
# cat /usr/bin/src-hilite-lesspipe.sh
#! /bin/sh
for source in "$@"; do
case $source in
*ChangeLog|*changelog)
source-highlight --failsafe -f esc --lang-def=changelog.lang --style-file=esc.style -i "$source" ;;
*Makefile|*makefile)
source-highlight --failsafe -f esc --lang-def=makefile.lang --style-file=esc.style -i "$source" ;;
*) source-highlight --failsafe --infer-lang -f esc --style-file=esc.style -i "$source" ;;
esac
done
思ったよりシンプルでした。--style-file=esc.style
が怪しいですね。見てみましょう。
# cat /usr/share/source-highlight/esc.style
keyword blue b ;
type, classname darkgreen ;
string red ;
regexp orange ;
specialchar pink ;
comment cyan i ;
number purple ;
preproc darkblue b ;
symbol darkred ;
function black b;
cbracket red;
variable darkgreen ;
// line numbers
linenum yellow;
// other elements for ChangeLog and Log files
date blue ;
time darkblue ;
ip darkgreen ;
file darkblue ;
name darkgreen ;
// Internet related
url blue u;
// for diffs
oldfile orange;
newfile darkgreen;
difflines blue;
// for css
selector purple;
property blue;
value darkgreen i;
はい。お気づきでしょうか、この中に function black b;
という項目があります。これは関数名を黒のボールドで表示せよという指定になるのですが、通常の端末は背景が黒であるため異様に見づらいです(というか見えませんでした)。
変えました。
# diff /usr/share/source-highlight/esc.style /usr/share/source-highlight/esc.style.20160625
10c10
< function yellow b;
---
> function black b;
おわりに
各記事では LESS
や LESSOPEN
といった環境変数を変更しているのですが、この記事では環境変数に手を加えない方向でシンタックスハイライトできるようにしてみました。
なぜそのようなことをしたかというと、LESSOPEN
には既に値が設定されていたからです(LESS
は空でしたが)。
$ echo $LESSOPEN
|/usr/bin/lesspipe.sh %s
LESSOPEN
に指定される値は入力プリプロセスと呼ばれるもので、less
が実行される前に実行されるコマンドだそうです。
では、/usr/bin/lesspipe.sh
は一体何をしているのかというと、
$ cat /usr/bin/lesspipe.sh
#!/bin/sh
#
# To use this filter with less, define LESSOPEN:
# export LESSOPEN="|/usr/bin/lesspipe.sh %s"
#
# The script should return zero if the output was valid and non-zero
# otherwise, so less could detect even a valid empty output
# (for example while uncompressing gzipped empty file).
# For backward-compatibility, this is not required by default. To turn
# this functionality there should be another vertical bar (|) straight
# after the first one in the LESSOPEN environment variable:
# export LESSOPEN="||/usr/bin/lesspipe.sh %s"
if [ ! -e "$1" ] ; then
exit 1
fi
if [ -d "$1" ] ; then
ls -alF -- "$1"
exit $?
fi
exec 2>/dev/null
# Allow for user defined filters
if [ -x ~/.lessfilter ]; then
~/.lessfilter "$1"
if [ $? -eq 0 ]; then
exit 0
fi
fi
case "$1" in
*.[1-9n].bz2|*.[1-9]x.bz2|*.man.bz2|*.[1-9n].[gx]z|*.[1-9]x.[gx]z|*.man.[gx]z|*.[1-9n].lzma|*.[1-9]x.lzma|*.man.lzma)
case "$1" in
*.gz) DECOMPRESSOR="gzip -dc" ;;
*.bz2) DECOMPRESSOR="bzip2 -dc" ;;
*.xz|*.lzma) DECOMPRESSOR="xz -dc" ;;
esac
if [ -n "$DECOMPRESSOR" ] && $DECOMPRESSOR -- "$1" | file - | grep -q troff; then
$DECOMPRESSOR -- "$1" | groff -Tascii -mandoc -
exit $?
fi ;;&
*.[1-9n]|*.[1-9]x|*.man)
if file "$1" | grep -q troff; then
man -l "$1" | cat -s
exit $?
fi ;;&
*.tar) tar tvvf "$1" ;;
*.tgz|*.tar.gz|*.tar.[zZ]) tar tzvvf "$1" ;;
*.tar.xz) tar Jtvvf "$1" ;;
*.xz|*.lzma) xz -dc -- "$1" ;;
*.tar.bz2|*.tbz2) bzip2 -dc -- "$1" | tar tvvf - ;;
*.[zZ]|*.gz) gzip -dc -- "$1" ;;
*.bz2) bzip2 -dc -- "$1" ;;
*.zip|*.jar|*.nbm) zipinfo -- "$1" ;;
*.rpm) rpm -qpivl --changelog -- "$1" ;;
*.cpi|*.cpio) cpio -itv < "$1" ;;
*.gpg) gpg -d "$1" ;;
*.gif|*.jpeg|*.jpg|*.pcd|*.png|*.tga|*.tiff|*.tif)
if [ -x /usr/bin/identify ]; then
identify "$1"
elif [ -x /usr/bin/gm ]; then
gm identify "$1"
else
echo "No identify available"
echo "Install ImageMagick or GraphicsMagick to browse images"
exit 1
fi ;;
*)
if [ -x /usr/bin/file ] && [ -x /usr/bin/iconv ] && [ -x /usr/bin/cut ]; then
case `file -b "$1"` in
*UTF-16*) conv='UTF-16' ;;
*UTF-32*) conv='UTF-32' ;;
esac
if [ -n "$conv" ]; then
env=`echo $LANG | cut -d. -f2`
if [ -n "$env" -a "$conv" != "$env" ]; then
iconv -f $conv -t $env "$1"
exit $?
fi
fi
fi
exit 1
esac
exit $?
拡張子によって実行するコマンドを振り分けています。つまりどういうことかというと、less
は各種バイナリファイルを開く(ファイルのサマリを表示する)のにも使えてしまうということです。
折角の便利機能なので、使えなくしてしまうことは避けたいと思った結果、上記のような方法を選択しました。
というわけで我が家の less
でもシンタックスハイライトができるようになりました。