How My ColdFusion Code Snippet Color Coding Works

Posted March 28, 2007 at 2:26 PM by Ben Nadel

Tags: ColdFusion

I have been through about 5 iterations of trying to get my color coding to work. It has been complicated because I output my code using unordered lists (UL) which I just feel is the right way to do it. It gives you excellent control over line spacing, wrapping, and just formatting in general... formatting other than color coding of course. Color coding is much tougher with this style as you cannot start a SPAN tag in one LI and then end it in another LI.

All of my previous attempts tried to strip out LIs, do crazy ass regular expressions, replace out and back in brackets and quotes and well frankly, it was a beast! This time around I decided to start from scratch and just totally simplify the process.

  1. Stepping back, I realized that color coding the code snippets was all about a few key elements:
  2. LI - both closing and opening played heavily into the SPAN creation.
  3. Comment tags - I didn't want to format anything inside a comment tag.
  4. CF/HTML tags - I only want to color attributes within tags.
  5. End Tags and Self Closing Tags - Do I need to do anything.

What I realized quickly is that color coding was a matter of State. When I hit a "token" in the code, what state am I in? How does this state affect how I alter the text that I am looking at? Awesomely enough, looking at it this way made the coding a 100% easier. What used to be a convoluted regex-heavy UDF is now this:

  • <cffunction
  • name="ColorCode"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="This takes code samples and color codes for display.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Code" type="string" required="true" />
  •  
  • <cfscript>
  •  
  • // Define the local scope.
  • var LOCAL = StructNew();
  •  
  • // Create a pattern for parts of the code display.
  • LOCAL.Pattern = CreateObject( "java", "java.util.regex.Pattern" ).Compile(
  • "(?i)(</?div[^>]*>)|(</?li[^>]*>)|(&lt;!--)|(--&gt;)|(&lt;/?[a-z]+)|(/?&gt;)|("")"
  • );
  •  
  • // Create a pattern matcher based on our input.
  • LOCAL.Matcher = LOCAL.Pattern.Matcher( ARGUMENTS.Code );
  •  
  • // Create a buffer to build our return text.
  • LOCAL.Buffer = CreateObject( "java", "java.lang.StringBuffer" ).Init();
  •  
  •  
  • // Create some state values so that we can determine which actions
  • // we are supposed to take for each group.
  • LOCAL.State = StructNew();
  • LOCAL.State.InCF = false;
  • LOCAL.State.InHTML = false;
  • LOCAL.State.InAttribute = false;
  • LOCAL.State.InComment = false;
  • LOCAL.State.InScript = false;
  •  
  •  
  • // Loop over the matcher.
  • while( LOCAL.Matcher.Find() ){
  •  
  • // Get the gurrent group value.
  • LOCAL.Value = LOCAL.Matcher.Group();
  •  
  •  
  • // Check to see if we in script. If we are, we need
  • // to do things very differently.
  • if (LOCAL.State.InScript){
  •  
  •  
  • // Check to see if found a cloase cfscript tag and that we
  • // NOT in a comment tag.
  • if (REFindNoCase( "^&lt;/cfscript", LOCAL.Value )){
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""cfmlcodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InCF = true;
  • LOCAL.State.InScript = false;
  •  
  • }
  •  
  •  
  • // Check to see if we found a close tag.
  • if (
  • REFindNoCase( "/?&gt;$", LOCAL.Value ) AND
  • LOCAL.State.InCF
  • ){
  •  
  • // Add the span.
  • LOCAL.Value = (LOCAL.Value & "</span>");
  •  
  • // Update the state.
  • LOCAL.State.InCF = false;
  •  
  • }
  •  
  •  
  • } else {
  •  
  •  
  • // Check to see if we found a close list item.
  • if (REFindNoCase( "^</li", LOCAL.Value )){
  •  
  • // Close all existing span tags. Check states
  • // to see what we have going on.
  • if (LOCAL.State.InComment){
  • LOCAL.Value = ("</span>" & LOCAL.Value);
  • }
  •  
  • if (LOCAL.State.InCF){
  • LOCAL.Value = ("</span>" & LOCAL.Value);
  • }
  •  
  • if (LOCAL.State.InHTML){
  • LOCAL.Value = ("</span>" & LOCAL.Value);
  • }
  •  
  • if (LOCAL.State.InAttribute){
  • LOCAL.Value = ("</span>" & LOCAL.Value);
  • }
  •  
  • }
  •  
  •  
  • // Check to see if we found an open list item.
  • // If this is the case, we have to re-start any tags
  • // that we closed in the previous close list item.
  • if (REFindNoCase( "^<li", LOCAL.Value )){
  •  
  • // Re-start any existing span tags. Check states
  • // to see what we have going on.
  • if (LOCAL.State.InComment){
  • LOCAL.Value = (LOCAL.Value & "<span class=""commentcodecolor"">");
  • }
  •  
  • if (LOCAL.State.InCF){
  • LOCAL.Value = (LOCAL.Value & "<span class=""cfmlcodecolor"">");
  • }
  •  
  • if (LOCAL.State.InHTML){
  • LOCAL.Value = (LOCAL.Value & "<span class=""htmlcodecolor"">");
  • }
  •  
  • if (LOCAL.State.InAttribute){
  • LOCAL.Value = (LOCAL.Value & "<span class=""attributecodecolor"">");
  • }
  •  
  • }
  •  
  •  
  • // Check to see if found a comment.
  • if (LOCAL.Value EQ "&lt;!--"){
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""commentcodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InComment = true;
  •  
  • }
  •  
  •  
  • // Check to see if found a close comment and that we
  • // are already in a comment.
  • if (
  • (LOCAL.Value EQ "--&gt;") AND
  • LOCAL.State.InComment
  • ){
  •  
  • // Add the span.
  • LOCAL.Value = (LOCAL.Value & "</span>");
  •  
  • // Update the state.
  • LOCAL.State.InComment = false;
  •  
  • }
  •  
  •  
  • // Check to see if found a cf tag and that we are NOT in
  • // a comment tag.
  • if (
  • REFindNoCase( "^&lt;cf", LOCAL.Value ) AND
  • (NOT LOCAL.State.InComment)
  • ){
  •  
  • // Check to see if we started a script tag.
  • if (REFindNoCase( "^&lt;cfscript", LOCAL.Value )){
  •  
  • // Update the state.
  • LOCAL.State.InScript = true;
  •  
  • }
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""cfmlcodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InCF = true;
  •  
  • }
  •  
  •  
  • // Check to see if found a cloase cf tag and that we
  • // NOT in a comment tag.
  • if (
  • REFindNoCase( "^&lt;/cf", LOCAL.Value ) AND
  • (NOT LOCAL.State.InComment)
  • ){
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""cfmlcodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InCF = true;
  •  
  • }
  •  
  •  
  • // Check to see if found an open HTML tag and that we
  • // are not in a comment.
  • if(
  • REFindNoCase( "^&lt;(?!cf)", LOCAL.Value ) AND
  • (NOT LOCAL.State.InComment)
  • ){
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""htmlcodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InHTML = true;
  •  
  • }
  •  
  •  
  • // Check to see if we found a close tag.
  • if (
  • REFindNoCase( "/?&gt;$", LOCAL.Value ) AND
  • (NOT LOCAL.State.InComment)
  • ){
  •  
  •  
  • // Check to make sure that we are NOT in an attribute
  • // and NOT in a comment.
  • if (
  • (NOT LOCAL.State.InAttribute) AND
  • (NOT LOCAL.State.InComment)
  • ){
  •  
  • // Check to see if we are in a CF tag.
  • if (LOCAL.State.InCF){
  •  
  • // Add the span.
  • LOCAL.Value = (LOCAL.Value & "</span>");
  •  
  • // Update the state.
  • LOCAL.State.InCF = false;
  •  
  • }
  •  
  • // Check to see if we are in a HTML tag.
  • if (LOCAL.State.InHTML){
  •  
  • // Add the span.
  • LOCAL.Value = (LOCAL.Value & "</span>");
  •  
  • // Update the state.
  • LOCAL.State.InHTML = false;
  •  
  • }
  •  
  • }
  •  
  • }
  •  
  •  
  •  
  • // Check to see if we found a quote.
  • if (LOCAL.Value EQ """"){
  •  
  • // Check to see if we are in a tag. This is the only time
  • // that we are going to want to do anything with it.
  • if (
  • LOCAL.State.InCF OR
  • LOCAL.State.InHTML
  • ){
  •  
  • // Now, check to see if we are starting or ending an
  • // attribute value.
  • if (NOT LOCAL.State.InAttribute){
  •  
  • // Add the span.
  • LOCAL.Value = ("<span class=""attributecodecolor"">" & LOCAL.Value);
  •  
  • // Update the state.
  • LOCAL.State.InAttribute = true;
  •  
  • } else {
  •  
  • // Add the span.
  • LOCAL.Value = (LOCAL.Value & "</span>");
  •  
  • // Update the state.
  • LOCAL.State.InAttribute = false;
  •  
  • }
  •  
  • }
  •  
  • }
  •  
  •  
  • }
  •  
  •  
  • // Add the replacement text.
  • LOCAL.Matcher.AppendReplacement(
  • LOCAL.Buffer,
  • LOCAL.Value.ReplaceAll( "([\\\$])", "\\$1" )
  • );
  •  
  • }
  •  
  •  
  • // Add the reset of the stuff to buffer.
  • LOCAL.Matcher.AppendTail(
  • LOCAL.Buffer
  • );
  •  
  •  
  • // Return the string buffer.
  • return( LOCAL.Buffer.ToString() );
  •  
  • </cfscript>
  • </cffunction>

Dude, I just color coded my color coding function - doesn't that blow your mind!?!?

As you can see CFScript does not lend itself to good color coding in the solution I have now. But really, that is just a matter of adding more "state" logic. Notice also that this works effortlessly with my highly structured UL/LI code formatting. Furthermore, I use my own CSS classes with lends itself to XHTML validation - sweeeet!

It's not there yet, but I am definitely on the right track now.




Reader Comments

Mar 28, 2007 at 6:14 PM // reply »
76 Comments

Hi Ben,

I noticed that it/something recent seems to have made your website text the same colour as the CFML tags (dark red) - so maybe something is amiss?


Mar 28, 2007 at 6:17 PM // reply »
11,241 Comments

@Shuns,

I am not seeing it. Our server has been having some "issues" today. I think it was getting lonely or something. Anyway, it randomly starting throwing JRUN errors intermittently. It is certainly possible you caught it in a bad mood.

If you still see this, please let me know and I will look into it. Thanks for giving me the heads up.


Mar 28, 2007 at 6:33 PM // reply »
76 Comments

Yeah I am definately seening it, but it may be the browser I am using (IE7)?


Mar 29, 2007 at 7:49 AM // reply »
11,241 Comments

@Shuns,

I see it in IE6. One tiny flaw. I see it. I am not closing my span after CFSCRIPT. Will update now.


Mar 29, 2007 at 7:57 AM // reply »
11,241 Comments

@Shuns,

You the man. I have fixed it. I have also updated the code posting.


Mar 29, 2007 at 6:00 PM // reply »
76 Comments

No worries mate, glad to help.


Nov 29, 2007 at 4:50 PM // reply »
45 Comments

This seems like it might be a great start to becoming a CF Beautifier. A few of us have been hunting around for a Formatter, like HTMLTidy or Oxygen (for XML)...but for Coldfusion.

Do you have any examples on how to pass the CFML as an argument and then to output it without having the return process as a CF script?

For Reference:
http://www.coldfusionjedi.com/index.cfm/2007/10/11/ColdFusion-Code-Beautifiers
http://groups.google.com/group/cfeclipse-users/browse_thread/thread/560d489c8955986d

DB


Nov 29, 2007 at 5:04 PM // reply »
11,241 Comments

@David,

I am not sure what you mean by without having to return process? Can you explain that a bit more?


Mar 9, 2009 at 8:21 PM // reply »
10 Comments

I have rewritten another code coloring script you have also been contributing to for blogCFC.
After the 12 hour rewrite I did, it now color-codes coldfusion code really well, even if there are obscure regular expressions in it etc.
You can check my blog about it at http://www.leeftpaulnog.nl/2009/03/my-supreme-coldfusion-code-coloring.html (in English)


Mar 10, 2009 at 8:38 AM // reply »
11,241 Comments

@Paul,

Looks pretty good! I really need to put some more work into mine. It's crap for things like SQL and Javascript.


Jul 12, 2010 at 2:25 AM // reply »
51 Comments

Hi Ben,
Quick question on the regex used here. What is the purpose of the (?i) in your pattern matcher. Been researching regex for a little while now but cant seems to get this one. Looks like something to do with named groups maybe?
Thanks


Jul 12, 2010 at 10:26 AM // reply »
11,241 Comments

@Steven,

The (?i) is a flag for case-INsensitive. It makes whatever follows it match upper and lower case values the same. So, for example:

(?i)[a-z]

... is the same as:

[a-zA-Z]

There are a number of flags that I love:

x - verbose
m - multi-line mode
s - single-line mode

These can be combined:

(?ix)

... is both case-insensitive and verbose. This kind of stuff can be done for an entire expression if it is at the very beginning; or, it can be done for just a particular group:

Sandard ((?i)text) here

I hope that helps.


Jul 13, 2010 at 3:16 PM // reply »
51 Comments

Great thanks Ben. Can always count on you for great information. How do you get the time to learn/research so much?


Jul 18, 2010 at 12:12 PM // reply »
11,241 Comments

@Steven,

It's my hobby - I just love this stuff :)



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools