     {
         var begin :int = y*(_width + 1) + x;
         _field.replaceText(begin, begin + str.length, str);
+
+        for (var ii :int = 0; ii < str.length; ii++) {
+            setHighlight(x + ii, y, true);
+        }
+    }
+
+    /**
+     * Sets or clears the highlight at the specified location.
+     */
+    protected function setHighlight (x :int, y :int, lit :Boolean) :void
+    {
+        var idx :int = y*_width + x;
+        var highlight :Bitmap = _highlights[idx];
+        if ((highlight != null) == lit) {
+            return;
+        }
+        var tidx :int = y*(_width + 1) + x;
+        if (lit) {
+            // the char boundaries might not be valid yet, so we compute the location assuming the
+            // text is centered within the field
+            addChildAt(_highlights[idx] = highlight = new Bitmap(_highlightData), 0);
+            var bounds :Rectangle = _field.getCharBoundaries(0);
+            highlight.x = _field.x + bounds.width*x + (_field.width - bounds.width*_width)/2;
+            highlight.y = _field.y + bounds.height*y + (_field.height - bounds.height*_height)/2;
+            _field.setTextFormat(_litFormat, tidx, tidx + 1);
+        } else {
+            removeChild(_highlights[idx]);
+            _highlights[idx] = null;
+            _field.setTextFormat(_unlitFormat, tidx, tidx + 1);
+        }
     }
 
     /**

    /** Our gigantic text field. */
    protected var _field :TextField;

    /** The width and height of the display in characters. */
    protected var _width :int, _height :int;



package {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;

import flash.events.ContextMenuEvent;
