はじめに
筆者は Windows でバッチファイルを愛用しているが,そのバッチファイルを Qiita の記事内で取り上げるときにシンタクスハイライトが気持ち悪いので下記の記事で取り上げたことがある。
Qiitaでバッチファイルのシンタクスハイライトが謎な件 - Qiita
具体的には下記のような感じである。なおシンタクスハイライト自体はバージョンアップによって変更される可能性があるため,この記事を書き始めた時点(2024年11月現在)における色付けを保存したものを以下に示す。
違和感を感じる部分を以下列挙する。
- 実行ファイル名
csc.exe
,evalbar.exe
の.exe
部分がエラー判定となること。 - FOR 変数
%%~$PATH:I
もエラー判定となること。 - キーワード属性
#ebd247
の対象が謎。echo
やpause
が外されてif
,goto
,exit
,for
,do
,in
などの制御構文が入るのは分かるが,それ以外にもecho
文の単なる出力文字列やgoto
文のラベルにまでマッチングしているのがおかしい。 - 環境変数の設定
set
文がキーワード属性#ebd247
になっているのは分かるが,環境変数まで対象になっているのは止めたい。 - オプションスイッチがアトリビュート属性
#8bdf4c
になっているのは分かる。-w:4
の部分は分かるが,-win32icon:shogi.ico
の色付けは無理やり感がある。
開発環境の立ち上げ
この記事を書いている現在,Qiita のシンタクスハイライトは Ruby の rouge によって実現されているので,まず ruby のインストールから始める。
次に gem を使って rouge をインストールする。
デバッグ用コード
改造のベースとするために batchfile.rb
を開発用フォルダにコピーする。筆者の環境の場合,もともとのファイルは下記のパスにあった。
C:\Ruby32-x64\lib\ruby\gems\3.2.0\gems\rouge-4.5.0\lib\rouge\lexers\batchfile.rb
コピーする際にファイル名を MyBatchfile.rb
に変え,クラス名も MyBatchfile
に変える。
module Rouge
module Lexers
class MyBatchfile < RegexLexer
# 以下略
デバッグモード用のスクリプトを以下に示す。先ほどコピーした MyBatchfile.rb
と同じフォルダに置く。なお,入力するファイル(バッチファイル)の文字コードを UTF-8
にする必要がある。
require "rouge"
require_relative "MyBatchfile"
if ARGV.size == 0 then
puts "usage: debug(.rb) [filename(.cmd/bat)]"
exit
end
filename = ARGV[0]
if !File.exist?(filename) then
puts "#{filename} is not found."
exit
end
input = File.open(filename, "rt:BOM|utf-8")
source = input.read
Rouge::Lexer.enable_debug!
lexer = Rouge::Lexers::MyBatchfile.new({'debug'=>'1'})
null = Rouge::Formatters::Null.new
null.format(lexer.lex(source))
exit
デバッグモードの実行例を以下に示すが,なんといきなり echo
コマンドがビルトインコマンドとして判定されておらず,単なるテキストとして誤判定されているではないか!ちなみにビルトインコマンドとして判定されていない理由は先頭に @
の文字が付いているせいである。
※@
を外せばビルトインコマンド判定になる。
c:\qiita\rouge>debug build.cmd
lexer: batchfile
stack: [:root]
stream: "@echo off\nsetlocal\nr"
entering: mixin :basic
trying: #<Rule /@?\brem\b.*$/i>
trying: #<Rule /^::.*$/>
trying: #<Rule /:[a-z]+/i>
trying: #<Rule /([a-z]\w*)(\.exe|com|bat|cmd|msi)?/i>
trying: #<Rule /((?:[\/\+]|--?)[a-z]+)\s*/i>
entering: mixin :expansions
trying: #<Rule /[%!]+([a-z_$@#]+)[%!]+/i>
trying: #<Rule /(\%+~?[a-z]+\d?)/i>
exiting: mixin :expansions
trying: #<Rule /[<>&|(){}\[\]\-+=;,~?*]/>
exiting: mixin :basic
entering: mixin :data
trying: #<Rule /\s+/>
trying: #<Rule /0x[0-9a-f]+/i>
trying: #<Rule /[0-9]/>
trying: #<Rule /["]/>
trying: #<Rule /[']/>
trying: #<Rule /[`]/>
trying: #<Rule /[^\s&|()\[\]{}\^=;!%+\-,"'`~?*]+/>
got: "@echo"
yielding: Text, "@echo"
~以下略~
長くなったので次回に続く。
次回,Qiitaでバッチファイルの謎なシンタクスハイライトを直したい2(予定)