0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Qiitaでバッチファイルのシンタクスハイライトが謎な件

Last updated at Posted at 2023-08-18

下記 Qiita の公式情報によると,シンタクスハイライトには Rouge を使っているとのこと。

対応言語は下記サイトを参照とのこと。

このリストを見る限り Windows のバッチファイルは対応していないようだが,実際に Qiita のコードブロックで試してみると何故かバッチファイル (bat, batch, batchfile)が候補に出てくるし,実際に指定すると確かにそれっぽく色がつく。だがしかし,よく見ると気持ち悪い・・・色付けがデタラメに見える。正しくハイライトがつけられているのはコメント行(rem文)だけのような気がする。

以下は自作のバッチファイル build.cmd で試した例。

build.cmd
@echo off
setlocal
rem ----------------------------------------------------------------------------
rem csc.exe にパスが通っているかどうかの確認
rem ----------------------------------------------------------------------------
set DOTNETPATH=
for %%I in ( csc.exe ) do set DOTNETPATH=%%~$PATH:I
if defined DOTNETPATH goto LETS_COMPILE

rem ----------------------------------------------------------------------------
rem .NET Framework のインストールパスを探す
rem ----------------------------------------------------------------------------
for /F "usebackq tokens=1,2,*" %%I in ( `reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v InstallPath` ) do (
  if "%%I"=="InstallPath" set "DOTNETPATH=%%K"
)
if defined DOTNETPATH goto APPEND_PATH

echo ^[[91m.NET Framework のインストールパスが見つかりません!
pause
exit /b

:APPEND_PATH
echo パスに %DOTNETPATH% を追加します。
set "PATH=%PATH%;%DOTNETPATH%"

:LETS_COMPILE
rem ----------------------------------------------------------------------------
rem コンパイル
rem ----------------------------------------------------------------------------
echo evalbar.cs をコンパイルします。
if exist evalbar.exe del evalbar.exe
csc -o -w:4 -win32icon:shogi.ico evalbar.cs

if exist evalbar.exe goto SUCCESS
echo ^[[91mevalbar のコンパイルに失敗しました!
pause
exit /b

:SUCCESS
echo evalbar のコンパイルに成功しました。
pause
exit /b

んんん?よく見るとバッチファイルにも対応しているのかな?

中身を見る限り(よく分からないけど)キーワードを定義して,それなりに頑張っていることは分かる。

batchfile.rb の内容
batchfile.rb
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
  module Lexers
    class Batchfile < RegexLexer
      title "Batchfile"
      desc "Windows Batch File"

      tag 'batchfile'
      aliases 'bat', 'batch', 'dosbatch', 'winbatch'
      filenames '*.bat', '*.cmd'

      mimetypes 'application/bat', 'application/x-bat', 'application/x-msdos-program'

      def self.keywords
        @keywords ||= %w(
          if else for in do goto call exit
        )
      end

      def self.operator_words
        @operator_words ||= %w(
          exist defined errorlevel cmdextversion not equ neq lss leq gtr geq
        )
      end

      def self.devices
        @devices ||= %w(
          con prn aux nul com1 com2 com3 com4 com5 com6 com7 com8 com9 lpt1 lpt2
          lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9
        )
      end

      def self.builtin_commands
        @builtin_commands ||= %w(
          assoc attrib break bcdedit cacls cd chcp chdir chkdsk chkntfs choice
          cls cmd color comp compact convert copy date del dir diskpart doskey
          dpath driverquery echo endlocal erase fc find findstr format fsutil
          ftype gpresult graftabl help icacls label md mkdir mklink mode more
          move openfiles path pause popd print prompt pushd rd recover ren
          rename replace rmdir robocopy setlocal sc schtasks shift shutdown sort
          start subst systeminfo takeown tasklist taskkill time timeout title
          tree type ver verify vol xcopy waitfor wmic
        )
      end

      def self.other_commands
        @other_commands ||= %w(
          addusers admodcmd ansicon arp at bcdboot bitsadmin browstat certreq
          certutil change cidiag cipher cleanmgr clip cmdkey compress convertcp
          coreinfo csccmd csvde cscript curl debug defrag delprof deltree devcon
          diamond dirquota diruse diskshadow diskuse dism dnscmd dsacls dsadd
          dsget dsquery dsmod dsmove dsrm dsmgmt dsregcmd edlin eventcreate
          expand extract fdisk fltmc forfiles freedisk ftp getmac gpupdate
          hostname ifmember inuse ipconfig kill lgpo lodctr logman logoff
          logtime makecab mapisend mbsacli mem mountvol moveuser msg mshta
          msiexec msinfo32 mstsc nbtstat net net1 netdom netsh netstat nlsinfo
          nltest now nslookup ntbackup ntdsutil ntoskrnl ntrights nvspbind
          pathping perms ping portqry powercfg pngout pnputil printbrm prncnfg
          prnmngr procdump psexec psfile psgetsid psinfo pskill pslist
          psloggedon psloglist pspasswd psping psservice psshutdown pssuspend
          qbasic qgrep qprocess query quser qwinsta rasdial reg reg1 regdump
          regedt32 regsvr32 regini reset restore rundll32 rmtshare route rpcping
          run runas scandisk setspn setx sfc share shellrunas shortcut sigcheck
          sleep slmgr strings subinacl sysmon telnet tftp tlist touch tracerpt
          tracert tscon tsdiscon tskill tttracer typeperf tzutil undelete
          unformat verifier vmconnect vssadmin w32tm wbadmin wecutil wevtutil
          wget where whoami windiff winrm winrs wpeutil wpr wusa wuauclt wscript
        )
      end

      def self.attributes
        @attributes ||= %w(
          on off disable enableextensions enabledelayedexpansion
        )
      end

      state :basic do
        # Comments
        rule %r/@?\brem\b.*$/i, Comment

        # Empty Labels
        rule %r/^::.*$/, Comment

        # Labels
        rule %r/:[a-z]+/i, Name::Label

        rule %r/([a-z]\w*)(\.exe|com|bat|cmd|msi)?/i do |m|
          if self.class.devices.include? m[1]
            groups Keyword::Reserved, Error
          elsif self.class.keywords.include? m[1]
            groups Keyword, Error
          elsif self.class.operator_words.include? m[1]
            groups Operator::Word, Error
          elsif self.class.builtin_commands.include? m[1]
            token Name::Builtin
          elsif self.class.other_commands.include? m[1]
            token Name::Builtin
          elsif self.class.attributes.include? m[1]
            groups Name::Attribute, Error
          elsif "set".casecmp m[1]
            groups Keyword::Declaration, Error
          else
            token Text
          end
        end

        rule %r/((?:[\/\+]|--?)[a-z]+)\s*/i, Name::Attribute

        mixin :expansions

        rule %r/[<>&|(){}\[\]\-+=;,~?*]/, Operator
      end

      state :escape do
        rule %r/\^./m, Str::Escape
      end

      state :expansions do
        # Normal and Delayed expansion
        rule %r/[%!]+([a-z_$@#]+)[%!]+/i, Name::Variable
        # For Variables
        rule %r/(\%+~?[a-z]+\d?)/i, Name::Variable::Magic
      end

      state :double_quotes do
        mixin :escape
        rule %r/["]/, Str::Double, :pop!
        mixin :expansions
        rule %r/[^\^"%!]+/, Str::Double
      end

      state :single_quotes do
        mixin :escape
        rule %r/[']/, Str::Single, :pop!
        mixin :expansions
        rule %r/[^\^'%!]+/, Str::Single
      end

      state :backtick do
        mixin :escape
        rule %r/[`]/, Str::Backtick, :pop!
        mixin :expansions
        rule %r/[^\^`%!]+/, Str::Backtick
      end

      state :data do
        rule %r/\s+/, Text
        rule %r/0x[0-9a-f]+/i, Literal::Number::Hex
        rule %r/[0-9]/, Literal::Number
        rule %r/["]/, Str::Double, :double_quotes
        rule %r/[']/, Str::Single, :single_quotes
        rule %r/[`]/, Str::Backtick, :backtick
        rule %r/[^\s&|()\[\]{}\^=;!%+\-,"'`~?*]+/, Text
        mixin :escape
      end

      state :root do
        mixin :basic
        mixin :data
      end
    end
  end
end

参考のために比較すると,Visual Studio Code だとこんな感じになる。
build.bat

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?