WordPress

【PHP】highlight.phpに行番号を表示する方法

更新日:2023/09/11

以前Webページ上のプログラムコードをハイライト表示するhighlight.phpを紹介しましたが、このライブラリは行番号を表示する機能がありませんでした。
そこで、独自に行番号を表示する方法を紹介します。

 

highlight.phpの元コード

以前、次のようなhighlight.phpの記事を書きました。

ここで、次のようなコードを紹介しています。

$input = 'function(){ /* 何らかのコード */ }';

$highlighter = new Highlighter();
$input = html_entity_decode($input,ENT_QUOTES | ENT_HTML5);
$highlighter->setAutodetectLanguages([  // 言語の自動判別候補をセット
              'html',
              'php',
              'css',
              'shell',
              'javascript',
              'perl'
]);

$result = $highlighter->highlightAuto($input);
$output = $result->value;  // 結果
$class = $result->language; // 言語
echo '<div class="hljs '.$class.'"><pre>'.$output.'</pre></div>';

最後のタグ出力行は、少し変更してあります。
divタグの中にpreタグが入れ子になっています。

今回は、このコードに行番号を表示する仕組みを追加していきます。

 

行番号表示の仕組み

行番号を表示する方法は幾つか考えられますが、今回は行頭にspanタグを挿入します。
そしてcssで行番号を表示します。

まずは、spanタグの挿入です。

次のように、preg_replace()で置換します。

$input = preg_replace( '#^(\r\n|\n|\r)#','',$input,1); // 改行で開始なら削除
$result = $highlighter->highlightAuto($input);
$output = $result->value;  // 結果

  // 行頭にspanタグを挿入
$output = preg_replace( '#(^.*$)#m' , '<span class="hljs_number"></span>$1',$output);

$class = $result->language; // 言語
echo '<div class="hljs '.$class.'"><pre>'.$output.'</pre></div>';

最初の行は、コードが改行で開始している場合、その改行を削除しています。
preタグの後に改行を入れることが多いですが、この改行が一行と判断されるのを防いでいます。

spanタグを挿入する正規表現は、mオプションがポイントですね。
これがないと、改行までを一行と認識してくれません。

次に、cssです。

.hljs{
  counter-reset: hljs_number_counter;
  position:relative;
}
.hljs pre{
  padding-left:calc(2.5em + 20px); /* 調整 */
  position:static; /* 行番号を div.hljs基準で設置するため */
  background: inherit;
}
.hljs .hljs_number{
  counter-increment: hljs_number_counter;
  background: inherit;
  vertical-align: top;
}
.hljs .hljs_number:before{
  content:counter(hljs_number_counter);
  position:absolute;
  left:0;
  display:inline-block;
  width:2.5em; /* 調整 */
  text-align:right;
  background: inherit; /* 背景を親要素と同じにする */
}
/* 追記:2023/9 */
.hljs .hljs-comment,.hljs .hljs-function,.hljs .hljs-params{
  background: inherit;
}

いろいろやっていますが、横スクロールをしたとき行番号を固定するように設定しています。

行番号欄の幅は、コメントに調整と記述してある属性値で設定しています。
この部分は実際に表示して調整してください。

追記分はhighlight.phpが挿入したタグが .hljs .hljs_number の親要素となってしまうことで、追記の上の .hljs .hljs_number:before の background: inherit が上手く機能しない現象を対策しています。

 

行数で行番号欄の幅を変化させる

行番号の桁数が一定でない場合、行番号欄の幅を決定するのが難しいかもしれません。
例えば3桁に合わせると、1桁のとき隙間が大きく感じます。

そこで、桁数に応じて幅を変更するようにコードを変更してみます。

$input = preg_replace( '#^(\r\n|\n|\r)#','',$input,1); // 改行で開始なら削除
$result = $highlighter->highlightAuto($input);
$output = $result->value;  // 結果

  // 行頭にspanタグを挿入
$output = preg_replace( '#(^.*$)#m' , '<span class="hljs_number"></span>$1',$output , -1, $replace_count);
  // 桁数からクラスを決定
$number_width = $replace_count > 999 ? 'hljs_number_width3' : 'hljs_number_width' . strlen($replace_count);

$class = $result->language; // 言語
echo '<div class="hljs '.$class.' '.$number_width.'"><pre>'.$output.'</pre></div>';

preg_replace()で挿入した回数を行数と判断して、行番号の幅を決定するクラスをセットしています。

今回は3桁以下のときのみ、対応しています。
4桁以上の可能性があるときは、上手く修正してください。

そして次のcssを追加します。

.hljs.hljs_number_width1 pre{ /* 1桁用 コード左余白 */
  padding-left:calc(1.5em + 20px);
}
.hljs.hljs_number_width2 pre{ /* 2桁用 コード左余白 */
  padding-left:calc(2.5em + 20px);
}
.hljs.hljs_number_width3 pre{ /* 3桁用 コード左余白 */
  padding-left:calc(3.5em + 20px);
}

.hljs.hljs_number_width1 .hljs_number:before{
  width:1.5em; /* 1桁用 行番号幅 */
}
.hljs.hljs_number_width2 .hljs_number:before{
  width:2.5em; /* 2桁用 行番号幅 */
}
.hljs.hljs_number_width3 .hljs_number:before{
  width:3.5em; /* 3桁用 行番号幅 */
}

こちらも、実際に表示して位置合わせしてください。

更新日:2023/09/11

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。