flagging starting and ending parens in batch files
-
In the following code the use of command continuation character ^ causes the paren highlighting feature to break. The do ( maps to the incorrect closing paren and the else ( that include or follow the ^ character do not map at all. Replacing (delete and re-enter) the paren in either else ( results in a temporary incorrect mapping to the next closing paren regardless of nesting. Can anyone point out where in the code this pairing occurs? I would like to try to code and submit a fix.
DO %%F IN (z y x) DO (
IF %%F==x (
ECHO ‘x’
) ELSE (
IF %%F==y (
ECHO ^
‘y’
) ELSE (
IF %%F==z (
ECHO ‘z’
)
)
)
) -
Batch syntax can be so crazy that I for one give Notepad++ (or any lexer) a total pass on it! :-)
-
You may be correct. However if anyone can identify where this pairing is done (I could not find a ‘(’ or ‘\(’ literal in LexBatch.cxx in scintilla) so I am guessing not there. If the source code that contains this function can be identified I am willing to attempt to provide a fix (patch) for consideration, assuming I can fix it.
-
I attempted to create a user defined batch file editor.
<UserLang name="bat" ext="bat cmd nt" udlVersion="2.1"> <Settings> <Global caseIgnored="yes" allowFoldOfComments="no" foldCompact="no" forcePureLC="1" decimalSeparator="0" /> <Prefix Keywords1="no" Keywords2="no" Keywords3="no" Keywords4="no" Keywords5="no" Keywords6="no" Keywords7="no" Keywords8="no" /> </Settings> <KeywordLists> <Keywords name="Comments">00rem 01 02 03 04</Keywords> <Keywords name="Numbers, prefix1">- + ~</Keywords> <Keywords name="Numbers, prefix2"></Keywords> <Keywords name="Numbers, extras1"></Keywords> <Keywords name="Numbers, extras2"></Keywords> <Keywords name="Numbers, suffix1"></Keywords> <Keywords name="Numbers, suffix2"></Keywords> <Keywords name="Numbers, range"></Keywords> <Keywords name="Operators1">! = : \ @ . , / -</Keywords> <Keywords name="Operators2">^</Keywords> <Keywords name="Folders in code1, open">(</Keywords> <Keywords name="Folders in code1, middle"></Keywords> <Keywords name="Folders in code1, close">)</Keywords> <Keywords name="Folders in code2, open"></Keywords> <Keywords name="Folders in code2, middle"></Keywords> <Keywords name="Folders in code2, close"></Keywords> <Keywords name="Folders in comment, open"></Keywords> <Keywords name="Folders in comment, middle"></Keywords> <Keywords name="Folders in comment, close"></Keywords> <Keywords name="Keywords1">assoc aux break call cd chcp chdir choice cls cmdextversion color con copy country ctty date defined del dir dpath echo endlocal erase errorlevel exit ftype goto loadfix loadhigh md mkdir mklink move path pause popd prn prompt pushd rd ren rename rmdir set setlocal shift start time title type ver verify vol</Keywords> <Keywords name="Keywords2">com com1 com2 com3 com4 do else exist for if in lpt lpt1 lpt2 lpt3 lpt4 not nul on</Keywords> <Keywords name="Keywords3"></Keywords> <Keywords name="Keywords4"></Keywords> <Keywords name="Keywords5"></Keywords> <Keywords name="Keywords6">*</Keywords> <Keywords name="Keywords7">%%a %%b %%c %%c %%d %%e %%f %%g %%h %%i %%j %%k %%l %%m %%n %%o %%p %%q %%r %%s %%t %%u %%v %%w %%x %%y %%z</Keywords> <Keywords name="Keywords8">%1 %2 %3 %4 %5 %6 %7 %8 %9 %~1 %~2 %~3 %~4 %~5 %~6 %~7 %/~8 %~9</Keywords> <Keywords name="Delimiters">00" 01 02" 03' 04 05' 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords> <!-- <Keywords name="Delimiters">00" 01 02" 03' 04 05' 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21% 22 23%</Keywords> --> </KeywordLists> <Styles> <WordsStyle name="DEFAULT" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="COMMENTS" fgColor="008000" bgColor="80FF80" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="LINE COMMENTS" fgColor="008000" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="NUMBERS" fgColor="FF80FF" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="KEYWORDS1" fgColor="0000FF" bgColor="A0FFFF" fontName="" fontStyle="7" nesting="0" /> <WordsStyle name="KEYWORDS2" fgColor="008000" bgColor="80FF80" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="KEYWORDS3" fgColor="0000FF" bgColor="A0FFFF" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="KEYWORDS4" fgColor="0000FF" bgColor="A0FFFF" fontName="" fontStyle="2" nesting="0" /> <WordsStyle name="KEYWORDS5" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="KEYWORDS6" fgColor="008000" bgColor="80FF80" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="KEYWORDS7" fgColor="FF8040" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="KEYWORDS8" fgColor="FF8040" bgColor="FFFFFF" fontName="" fontStyle="3" nesting="0" /> <WordsStyle name="OPERATORS" fgColor="0000FF" bgColor="FFC060" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="FOLDER IN CODE1" fgColor="000040" bgColor="FF8080" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="FOLDER IN CODE2" fgColor="0000FF" bgColor="A0FFFF" fontName="" fontStyle="3" nesting="0" /> <WordsStyle name="FOLDER IN COMMENT" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="DELIMITERS1" fgColor="008000" bgColor="FFFF00" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="DELIMITERS2" fgColor="008000" bgColor="FFFF80" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="DELIMITERS3" fgColor="008000" bgColor="FFFF80" fontName="" fontStyle="1" nesting="0" /> <WordsStyle name="DELIMITERS4" fgColor="E020E0" bgColor="E0C0E0" fontName="" fontStyle="0" nesting="67108864" /> ``` <WordsStyle name="DELIMITERS5" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="256" /> <WordsStyle name="DELIMITERS6" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="DELIMITERS7" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" nesting="0" /> <WordsStyle name="DELIMITERS8" fgColor="FF8040" bgColor="FFFFFF" fontName="" fontStyle="1" nesting="83886080" /> </Styles> </UserLang>
In the above keyword1 is a command list (incomplete)
keyword2 is an operand list (probably incomplete)
keyword6 is an operand the * in dir .
(there may be a better way to do this)
keyword7 is for FOR loop iteration variables
keyword8 is for command line arguments
The rest are fairly commonNext consider the following bat file
@ECHO ON REM LINKdir.bat REM REM %1 = A99LINK REM %2 = A99TARGET REM %3 = A99FILTER REM SET A99LINK=%~1 SET A99TARGET=%~2 SET A99FILTER=%~3 REM REM make directories and link files REM PUSHD %A99TARGET:~0,-1% REM REM make directories FOR %%F IN (DIR /ad /b) DO ( SET %A99FILE%=%%F IF %A99FILE:~0,1%!='.' ( MKDIR %A99LINK%%A99FILE% %A01TESTbatPATH%LINKdir.bat ^ %A99LINK%%A99FILE% ^ %A99TARGET%%A99FILE% ) ) REM REM link files REM FOR %%T IN (%A99FILTER%) DO ( FOR %%F IN (DIR /a-d /b *.%%T) DO ( SET %A99FILE%=%%F IF %A99FILE:~0,1%!='.' ( MKLINK /h %A99LINK%%A99FILE% ^ %A99TARGET%%A99FILE% ) ) ) POPD
Quirk 1 the POPD command requires a space or CR/LF to color as a keyword – adding the CRLF is an easy workaround
Desire 1 – to be able to use bold, italic and underline instead of background colors for most keywords. (This does not seem to work in the current portable version)
Desire 2 a program change that would permit %…% to be added to the delimiters as in the commented code. This requires a program change (maybe easier said than done) to eliminate the keywords (list 7 and 8) starting with %% or % from being considered as a %…% delimited named variable resulting from a set command or an environment variable. Allowing numbers and operands (not space delimited) to be nested in this delimited value would support the substring construct of :~nn,snn inside a delimited named variable. (%{named variable:~nn,snn%) As a result the length value can be determined to be a number which does not work now. This would also allow named variables to be styled like keywords 7 and 8 which is also what I would do.
Is there another way to do Desire 2 in UDL?
Thanks for considering this.
-
Desire 1 works when the stupid user (me) does not set the global overrides for BIU.
-
Hello @dshuman52, @alan-kilborn and All,
@dshuman52, Here is a method which could help you ! It works whatever the current language as it’s a recursive regular expression looking for well-balanced
( .... )
blocks, containing possible juxtaposed / nested other( .... )
blocks !SEARCH
\((?:[^()]++|(?0))*\)
( Select theRegular expression
search mode )Notes :
-
From current location of the caret, this regex selects, automatically, the next longest well balanced
( .... )
block -
If you prefer to get the ending parenthesis, only, simply change this regex as below :
SEARCH
\((?:[^()]++|(?0))*\K\)
To explain this regex, the best is to use the free-spacing mode, which allows comments in regexes :
(?x) # FREE-SPACING mode \( # STARTING parenthesis (?: # Start of the NON-CAPTURING group [^()]++ # Any NON-NULL ATOMIC range of ALLOWED characters | # OR (?0) # A RECURSION, using the WHOLE regex pattern ( group #0 ) )* # End of the NON-CAPTURING group, repeated 0 or MORE times # \K # DELETE the initial '#' character, of that line, to match the ENDING parenthesis, ONLY \) # ENDING parenthesis
Try this regex against your text, below :
@ECHO ON REM LINKdir.bat REM REM %1 = A99LINK REM %2 = A99TARGET REM %3 = A99FILTER REM SET A99LINK=%~1 SET A99TARGET=%~2 SET A99FILTER=%~3 REM REM make directories and link files REM PUSHD %A99TARGET:~0,-1% REM REM make directories FOR %%F IN (DIR /ad /b) DO ( SET %A99FILE%=%%F IF %A99FILE:~0,1%!='.' ( MKDIR %A99LINK%%A99FILE% %A01TESTbatPATH%LINKdir.bat ^ %A99LINK%%A99FILE% ^ %A99TARGET%%A99FILE% ) ) REM REM link files REM FOR %%T IN (%A99FILTER%) DO ( FOR %%F IN (DIR /a-d /b *.%%T) DO ( SET %A99FILE%=%%F IF %A99FILE:~0,1%!='.' ( MKLINK /h %A99LINK%%A99FILE% ^ %A99TARGET%%A99FILE% ) ) ) POPD
Notes :
-
Place the caret at different locations, of this batch file
-
Then do the search hitting, several times, the
F3
shortcut
Important :
-
Each time that a well-balanced
( .... )
block is selected :-
An hit on the
Left Arrow
key moves the caret right before the(
starting parenthesis -
An hit on the
Right Arrow
key moves the caret right after the)
ending parenthesis
-
-
The nice thing is that, when you hit the
shift + F3
shortcut, it gets the inner( ... )
block, closed to the end of the outer( ... )
block !
Try also, with your first sample text :
DO %%F IN (z y x) DO ( IF %%F==x ( ECHO ‘x’ ) ELSE ( IF %%F==y ( ECHO ^ ‘y’ ) ELSE ( IF %%F==z ( ECHO ‘z’ ) ) ) )
Best Regards,
guy038
P.S. :
In batch files , the
&
ampersand, the|
vertical line and the(
and)
parentheses are special chars. So, they must be preceded with the escape character^
or embedded inside double quotes.Thus, here’s a more elaborate version, where we suppose that the
^
symbol is the default escape character and any character, preceded with a^
symbol, is just considered as a literal chars, including the syntaxes^(
and^)
!(?x) # FREE-SPACING mode (?<!\\) # NEXT character is NOT PRECEDED with a '\' symbol ( LOOK-BEHIND condition ) \( # STARTING parenthesis (?: # Start of the 1st NON-CAPTURING group (?: # Start of the 2nd NON-CAPTURING group \^ [()] # STRINGS '^(' or '^)' are supposed to be ALLOWED characters | # OR [^()] # Any ALLOWED character, even EOL ones, DIFFERENT of the PARENTHESES '(' and ')' )++ # End of the 2nd NON-CAPTURING group ( NON-NULL ATOMIC range of ALLOWED characters ) | # OR (?0) # A RECURSION, using the WHOLE regex pattern ( group #0 ) )* # End of the 1st NON-CAPTURING group, repeated 0 or MORE times (?<!\\) # NEXT character is NOT PREDECED with a '\' symbol ( LOOK-BEHIND condition ) \) # ENDING parenthesis
Here is its shortest syntax :
SEARCH
(?x)(?<!\\)\((?:(?:\^[()]|[^()])|(?0))*(?<!\\)\)
Test it against this sample text :
DO %%F IN (z y x) DO ( IF %%F==x ( ECHO ‘x’ ^( ) ELSE ( IF %%F==y ( ECHO ^ ‘y’ ) ELSE ( IF %%F==z ( ECHO ‘z’ ) ) ^) ) )
-