In a previous article I described how to create a CSS syntax highlighting definition file for use with the open source DigitalRune Text Editor Control.

Today I was testing events in one of our myriad of prototypes, which triggered an sample TextEditorControl to apply the BAT syntax definition found in BAT-Mode.xshd.

While it validated the particular piece of code I was working on rather nicely, I was less then enamoured with the highlighting. The image below shows an example of this.

My eyes! The original (and illegible) BAT syntax highlighting
My eyes! The original (and illegible) BAT syntax highlighting

Pretty ugly isn't it? However, I was actually doing a vaguely real-world test as I did want to see some simple batch file syntax highlighting. Perfect timing for a distraction to go look at another problem.

The following screenshot shows my new and improved syntax highlighting file, based on my experiences creating the CSS version. I couldn't do everything I tried/wanted, and I suspect this will be limitations of the TextEditorControl, but fixing that is "rainy day" stuff. Otherwise, simple as this was, it was a nice distraction with immediate benefits!

New and improved Joker products! Or, at least new and improved syntax highlighting
New and improved Joker products! Or, at least new and improved syntax highlighting

The XML Definition

The definition is very straightforward, as it's basically just keyword tokens and a single highlighting span for environment variables.

I was trying for something similar to how Notepad++ highlights batch files, in which if the first "word" on a line isn't a command, it's assumed to be a program and highlighted accordingly, but I couldn't get that working correctly so it's commented out in the definition - if you know of a trick or code patch to make it work, please let me know!

xml
<?xml version="1.0" encoding="utf-8"?>

<!-- Batch File syntax highlighting for DigitalRune TextEditor. Created by Cyotek (http://cyotek.com/) -->

<SyntaxDefinition name="Batch" extensions="*.bat;*.cmd">

  <Environment>
    <Default color="#000000" bgcolor="#ffffff" />
  </Environment>

  <RuleSets>

    <RuleSet ignorecase="true">

      <!-- Adding @ as a delimiter means the "ECHO" in "@ECHO OFF" will be highlighted. -->
      <Delimiters>@:</Delimiters> 

      <!-- REM comment -->
      <Span name="LineComment" bold="false" italic="false" color="#008000" stopateol="true">
        <Begin>REM</Begin>
      </Span>

      <!-- :: style comment -->
      <Span name="LineComment2" bold="false" italic="false" color="#008000" stopateol="true">
        <Begin>::</Begin>
      </Span>

      <!-- label -->
      <Span name="Label" bold="false" italic="false" color="#FF0000" bgcolor="#FFFF80" stopateol="true">
        <Begin startofline="true">:</Begin>
      </Span>

      <!-- Environment Variable -->
      <Span name="Variable" bold="false" italic="false" color="#FF8000" bgcolor="#FCFFF0" stopateol="true">
        <Begin>%</Begin>
        <End>%</End>
      </Span>

      <!-- Programs -->
      <!-- The idea here is the first word on a line that isn't a keyword is a program. 
           Doesn't work with the default TextEditorControl though. -->
      <!--<Span name="Program" bold="false" italic="true" color="Red" bgcolor="#FCFFF0" stopateol="true">
        <Begin startofline="true" singleword="true"></Begin>
        <End> </End>
      </Span>-->

      <!-- Operators -->
      <KeyWords name="Punctuation" bold="false" italic="false" color="#FF0000">
        <Key word="+" />
        <Key word="-" />
        <Key word="*" />
        <Key word="&amp;lt;" />
        <Key word="&amp;gt;" />
        <Key word="=" />
        <Key word="@" />
      </KeyWords>

      <!-- Standard command.com keywords -->
      <!-- http://en.wikipedia.org/wiki/COMMAND.COM -->

      <KeyWords name="command.com-internalcommands" bold="true" italic="false" color="#0000FF">
        <Key word="break" />
        <Key word="chcp" />
        <Key word="chdir" />
        <Key word="cd" />
        <Key word="cls" />
        <Key word="copy" />
        <Key word="ctty" />
        <Key word="date" />
        <Key word="del" />
        <Key word="erase" />
        <Key word="dir" />
        <Key word="echo" />
        <Key word="exit" />
        <Key word="lfnfor" />
        <Key word="loadhigh" />
        <Key word="lh" />
        <Key word="lock" />
        <Key word="move" />
        <Key word="mkdir" />
        <Key word="md" />
        <Key word="path" />
        <Key word="prompt" />
        <Key word="ren" />
        <Key word="rename" />
        <Key word="rmdir" />
        <Key word="rd" />
        <Key word="set" />
        <Key word="time" />
        <Key word="truename" />
        <Key word="type" />
        <Key word="unlock" />
        <Key word="ver" />
        <Key word="verify" />
        <Key word="vol" />
        <!-- http://ss64.com/nt/ -->
        <Key word="color" />
        <Key word="endlocal" />
        <Key word="ftype" />
        <Key word="mklink" />
        <Key word="popd" />
        <Key word="pushd" />
        <Key word="setlocal" />
        <Key word="start" />
        <Key word="title" />
      </KeyWords>

      <KeyWords name="command.com-commands" bold="true" italic="false" color="#0000FF">
        <Key word="call" />
        <Key word="for" />
        <Key word="goto" />
        <Key word="if" />
        <Key word="in" />
        <Key word="do" />
        <Key word="pause" />
        <Key word="rem" />
        <Key word="shift" />
      </KeyWords>

      <!-- Redirects -->
      <KeyWords name="command.com-redirects" bold="true" italic="false" color="#0000FF">
        <Key word="nul" />
        <Key word="con" />
        <Key word="prn" />
        <Key word="aux" />
        <Key word="clock$" />
        <Key word="com0" />
        <Key word="com1" />
        <Key word="com2" />
        <Key word="com3" />
        <Key word="com4" />
        <Key word="com5" />
        <Key word="com6" />
        <Key word="com7" />
        <Key word="com8" />
        <Key word="com9" />
        <Key word="lpt0" />
        <Key word="lpt1" />
        <Key word="lpt2" />
        <Key word="lpt3" />
        <Key word="lpt4" />
        <Key word="lpt5" />
        <Key word="lpt6" />
        <Key word="lpt7" />
        <Key word="lpt8" />
        <Key word="lpt9" />
      </KeyWords>

    </RuleSet>

  </RuleSets>
</SyntaxDefinition>

A sample project

I've attached a basic sample project, which shows how to dynamic load in the definition file. And yes, that is a (stripped down) version of one of the build scripts used by Spriter. I'm still an old school guy at heart, and so I use msbuild to compile a solution, but for anything else I still tend to turn to batch scripts and custom console apps first rather than MSBuild tasks or PowerShell cmdlets.

Although the example project loads in the definition from an external file, I would recommend that you build it into the TextEditorControl assembly itself to make deployment easier. I covered this in the Compiling the definition into the assembly section of the previous article so I won't replicate that here.

Update History

  • 2014-06-23 - First published
  • 2020-11-21 - Updated formatting

Like what you're reading? Perhaps you like to buy us a coffee?

Donate via Buy Me a Coffee

Donate via PayPal


Files


Comments