Syntax coloring makes a code developer’s life much easier. For those unfamiliar with the concept, consider how ActionScript renders in shades of blue with green strings (by default) within the Flash Actions panel. That color-coding helps focus the eye on relevant keywords in the script.
As I’ve been moving forward on developing Lassie Shepherd’s script panel, I wanted to incorporate some form of syntax coloring to aid the game developer. So, I wrote up a quick class to parse and apply keyword coloring based on standard scripting syntax. Valid keywords can be assigned within the class’ static “keywords” array. Also, this generation of the script only accepts single quotes (apostrophes) as string delimiters.
1) Save as: com/gmacwilliam/parse/SyntaxColoring.as
package com.gmacwilliam.parse
{
import flash.text.TextField;
import flash.text.TextFormat;
public class SyntaxColoring
{
public static var keywords:Array = new Array("if", "gotoAndStop", "play", "true", "false");
public static var backgroundColor:Number = 0xFFFFFF;
public static var foregroundColor:Number = 0x000000;
public static var keywordColor:Number = 0x0000FF;
public static var stringColor:Number = 0x009900;
public static function renderField(tf:TextField):void
{
// apply field background color
tf.backgroundColor = backgroundColor;
// set field-read starting index
var index:int = 0;
// render all lines of text
while(index < tf.text.length)
{
index = renderLine(tf, index) + 1;
}
}
public static function renderLine(tf:TextField, caretIndex:int):int
{
// create text formats
var colorBase:TextFormat = tf.getTextFormat();
colorBase.color = foregroundColor;
var colorKeyword:TextFormat = tf.getTextFormat();
colorKeyword.color = keywordColor;
var colorString:TextFormat = tf.getTextFormat();
colorString.color = stringColor;
// get start and end indicies of the current line
var sindex:int = tf.getFirstCharInParagraph(caretIndex);
var eindex:int = sindex + tf.getParagraphLength(caretIndex);
eindex = Math.min(eindex, tf.text.length);
// if paragraph has any text
if (sindex < eindex)
{
// apply black default text format
tf.setTextFormat(colorBase, sindex, eindex);
// extract source block of text to format
var src:String = tf.text.substr(sindex, eindex-sindex);
// strip all parenthesis and spaces from line and split into an array
var raw:String = src.split(" ").join("");
raw = raw.split("(").join(",");
raw = raw.split(")").join(",");
var lineWords:Array = raw.split(",");
var index:int = 0;
// KEYWORDS
// loop through array of line words
for (var j:int = 0; j < lineWords.length; j++)
{
var word:String = lineWords[j];
// color any words that match a keyword
if (keywords.indexOf(word) > -1)
{
index = src.indexOf(word, index);
tf.setTextFormat(colorKeyword, sindex+index, sindex+index+word.length);
}
}
// STRINGS
// reset render index
index = 0;
while(index > -1)
{
// find index of next quote
index = src.indexOf("'", index);
if (index > -1)
{
// if quote was found...
var qo:int = index; // quote open
var qc:int = src.indexOf("'", index+1); // quote close
var so:int = sindex+qo; // string open
var sc:int = (qc < 0) ? eindex : so+(qc-qo)+1; // string close
// apply text color to closed string or to everything after quote
tf.setTextFormat(colorString, so, sc);
// update render index with close-quote position
index = (qc < 0) ? -1 : qc+1;
}
}
}
// return end-index of rendered text line
return eindex;
}
}
}
Implementation of this class on a TextField is very simple, and the script is surprisingly efficient. Since AS3 can now track the caret’s line index within an editable text field, the full field only needs to be parsed and rendered once on initial load. After that, only the line containing the caret needs to be re-rendered when the field is changed. Here’s the implementation:
import com.gmacwilliam.parse.SyntaxColoring;
var color_txt:TextField; // << create an editable text field on stage
color_txt.addEventListener(Event.CHANGE, this.handleColorize);
// render field with initial formatting
SyntaxColoring.renderField(color_txt);
// handle field updates
function handleColorize(evt:Event):void
{
SyntaxColoring.renderLine(color_txt, color_txt.caretIndex);
}
Wire it up and try entering “gotoAndStop(’sfoo’);” in your editable TextField. It should look quite a bit like ActionScript!
September 9, 2008 at 8:08 pm |
These posts make my head hurt.
I’m quite amazed you can figure this stuff out.
June 8, 2009 at 10:09 pm |
Hey Greg, I just found your blog by chance, really nice articles, tips and classes – it would be awesome if you would zip a few source files and provide some online demos of your classes – usually I don’t have that much time to copy/paste all the files, then recreate and compile everything and I think it’s a shame because your solutions are very good and could help a lot. Please consider that option. I am adding your blog to my RSS now.
Cheers,
Tomek
June 29, 2009 at 9:21 pm |
Very good point! Unfortunately, I’m in about the same boat – I don’t bother with the zips and demo posts since I’m generating content in a hurry.