Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Batch highlightining #60

Draft
wants to merge 15 commits into
base: feature/lang-dockerfile
Choose a base branch
from
19 changes: 19 additions & 0 deletions Config/metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@
'standalone' => true,
'injectable' => false,
],
[
'Kadet\\Highlighter\\Language\\Batch',
'name' => [
'bat',
'batch',
'dos',
],
'mime' => [
'application/bat',
'application/x-bat',
'application/x-msdos-program',
],
'extension' => [
'*.bat',
'*.cmd',
],
'standalone' => true,
'injectable' => false,
],
[
'Kadet\\Highlighter\\Language\\C',
'name' => [
Expand Down
1 change: 1 addition & 0 deletions Docs/A-languages.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Class | Name | MIME | Extension
------|------|------|----------
`Kadet\Highlighter\Language\Apache` | `apache` | none | `.htaccess`
`Kadet\Highlighter\Language\Assembler` | `asm`, `assembler` | `text/x-asm` | `*.asm`
`Kadet\Highlighter\Language\Batch` | `bat`, `batch`, `dos` | `application/bat`, `application/x-bat`, `application/x-msdos-program` | `*.bat`, `*.cmd`
`Kadet\Highlighter\Language\C` | `c` | `text/x-csrc`, `text/x-chdr` | `*.c`, `*.h`, `*.idc`
`Kadet\Highlighter\Language\CSharp` | `CSharp`, `C#` | `text/x-csharp` | `*.cs`
`Kadet\Highlighter\Language\Cobol` | `cobol` | `text/x-cobol` | `*.cbl`
Expand Down
88 changes: 88 additions & 0 deletions Language/Batch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

/**
* Highlighter
*
* Copyright (C) 2016, Some right reserved.
*
* @author Kacper "Kadet" Donat <[email protected]>
*
* Contact with author:
* Xmpp: [email protected]
* E-mail: [email protected]
*
* From Kadet with love.
*/

namespace Kadet\Highlighter\Language;

use Kadet\Highlighter\Matcher\CommentMatcher;
use Kadet\Highlighter\Matcher\RegexMatcher;
use Kadet\Highlighter\Matcher\WordMatcher;
use Kadet\Highlighter\Parser\Rule;

class Batch extends GreedyLanguage
{
public function setupRules()
{
$this->rules->addMany([
'comment' => [
new Rule(new RegexMatcher('/^\s*(rem)[\t\n\r]+/mi')),
new Rule(new RegexMatcher('/^\s*(rem\s+.+)/mi')),
new Rule(new CommentMatcher(['::'])),
],

'string' => new Rule(new RegexMatcher('/^\s*@?echo[ \t]+(.+)\s/mi'), ['priority' => 2]),

'keyword' => [
new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 3]),
new Rule(new WordMatcher([
'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS',
'CLS', 'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY', 'DATE', 'DEL', 'DIR', 'DISKCOMP',
'DISKCOPY', 'DISKPART', 'DOSKEY', 'DRIVERQUERY', 'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC',
'FIND', 'FINDSTR', 'FOR', 'FORMAT', 'FSUTIL', 'FTYPE', 'GPRESULT', 'GRAFTABL', 'HELP', 'ICACLS',
'IF', 'LABEL', 'MD', 'MKDIR', 'MKLINK', 'MODE', 'MORE', 'MOVE', 'OPENFILES', 'PATH', 'PAUSE',
'POPD', 'PRINT', 'PROMPT', 'PUSHD', 'RD', 'RECOVER', 'REN', 'RENAME', 'REPLACE', 'RMDIR',
'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START',
'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER',
'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT',
'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', 'goto',
]), ['priority' => 3]),
],

'variable' => [
'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')),
new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none', '*string'], 'priority' => 4]),
new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none', '*string'], 'priority' => 4]),
],

'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/', ['context' => '!comment'])),

'symbol.parameter' => new Rule(new RegexMatcher('/(\/[a-z])\b/i'), [
'priority' => 0,
'context' => ['!comment'],
]),
]);
}

/**
* Unique language identifier, for example 'php'
*
* @return string
*/
public function getIdentifier()
{
return 'batch';
}

public static function getMetadata()
{
return [
'name' => ['bat', 'batch', 'dos'],
'mime' => ['application/bat', 'application/x-bat', 'application/x-msdos-program'],
'extension' => ['*.bat', '*.cmd']
];
}
}
73 changes: 73 additions & 0 deletions Tests/Expected/Test/batch/big.bat.tkn
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token}
rem backbat.bat -- Backup batch files (Windows NT/2000 version)
{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token}
rem usage: backbat backupdir
{comment:Kadet\Highlighter\Parser\Token\Token}rem where: backupdir is the directory to copy batch files{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem all batch files in the current directory will{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem be backed up{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token}

rem Make sure that there is at least one argument

{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}"=="" {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} argsok

{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}usage: {variable:Kadet\Highlighter\Parser\Token\Token}%0{/variable:Kadet\Highlighter\Parser\Token\Token} backupdir{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}where: backupdir is the directory to copy batch files{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}all batch files in the current directory will{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}be backed up{/string:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end


:argsok


{keyword:Kadet\Highlighter\Parser\Token\Token}setlocal{/keyword:Kadet\Highlighter\Parser\Token\Token}


{comment:Kadet\Highlighter\Parser\Token\Token}rem Save the backup directory{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable.assign:Kadet\Highlighter\Parser\Token\Token}backupdir{/variable.assign:Kadet\Highlighter\Parser\Token\Token}={variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}


{comment:Kadet\Highlighter\Parser\Token\Token}rem Check to make sure that the backupdir exists and isn't a file{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} notfile

{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} is a file
{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end


:notfile

{comment:Kadet\Highlighter\Parser\Token\Token}rem If the directory does not exist, create it.{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\nul {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} skipdir

{keyword:Kadet\Highlighter\Parser\Token\Token}md{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="0" {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} skipdir

{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Error creating backup directory{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end


:skipdir

{comment:Kadet\Highlighter\Parser\Token\Token}rem Copy each batch file one at a time.{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem Note: the for loop variable (%%b) must be contain only one letter.{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}for{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} in ( *.bat ) {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}copy{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} > nul


{comment:Kadet\Highlighter\Parser\Token\Token}rem Use the for loop again to check if each file was copied (since it is{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem difficult to run multiple commands in a for loop).{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}for{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} in ( *.bat ) {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\%{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} was {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} copied

:end

{comment:Kadet\Highlighter\Parser\Token\Token}rem Clean up{/comment:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}endlocal{/keyword:Kadet\Highlighter\Parser\Token\Token}
{/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}
15 changes: 15 additions & 0 deletions Tests/Expected/Test/batch/small.bat.tkn
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token}

{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Wartość dwóch parametrów przekazanych do skryptu{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%2{/variable:Kadet\Highlighter\Parser\Token\Token}

{comment:Kadet\Highlighter\Parser\Token\Token}rem To jest komentarz i nie ma wpływu na działanie programu{/comment:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} {symbol.parameter:Kadet\Highlighter\Parser\Token\Token}/p{/symbol.parameter:Kadet\Highlighter\Parser\Token\Token} {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię?

{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token}
{comment:Kadet\Highlighter\Parser\Token\Token}:: Wyświetl odpowiedź użytkownika{/comment:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Witaj, {variable:Kadet\Highlighter\Parser\Token\Token}{variable:Kadet\Highlighter\Parser\Token\Token}%imie{/variable:Kadet\Highlighter\Parser\Token\Token}%{/variable:Kadet\Highlighter\Parser\Token\Token}.{/string:Kadet\Highlighter\Parser\Token\Token}
{keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token}
{/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}
72 changes: 72 additions & 0 deletions Tests/Samples/batch/big.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@echo off
rem
rem backbat.bat -- Backup batch files (Windows NT/2000 version)
rem
rem usage: backbat backupdir
rem where: backupdir is the directory to copy batch files
rem all batch files in the current directory will
rem be backed up
rem

rem Make sure that there is at least one argument

if not "%1"=="" goto argsok

echo usage: %0 backupdir
echo where: backupdir is the directory to copy batch files
echo all batch files in the current directory will
echo be backed up

goto end


:argsok


setlocal


rem Save the backup directory

set backupdir=%1


rem Check to make sure that the backupdir exists and isn't a file

if not exist %backupdir% goto notfile

echo %backupdir% is a file
goto end


:notfile

rem If the directory does not exist, create it.

if exist %backupdir%\nul goto skipdir

md %backupdir%
if "%errorlevel%"=="0" goto skipdir

echo Error creating backup directory
goto end


:skipdir

rem Copy each batch file one at a time.
rem Note: the for loop variable (%%b) must be contain only one letter.

for %%b in ( *.bat ) do copy %%b %backupdir% > nul


rem Use the for loop again to check if each file was copied (since it is
rem difficult to run multiple commands in a for loop).

for %%b in ( *.bat ) do if not exist %backupdir%\%%b echo %%b was not copied

:end

rem Clean up

endlocal
14 changes: 14 additions & 0 deletions Tests/Samples/batch/small.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@echo off

echo Wartość dwóch parametrów przekazanych do skryptu
echo %1
echo %2

rem To jest komentarz i nie ma wpływu na działanie programu
rem
set /p imie=Jak masz na imię?

echo
:: Wyświetl odpowiedź użytkownika
echo Witaj, %imie%.
pause
Loading