Index: trunk/lib/Text/FormBuilder.pm
===================================================================
--- trunk/lib/Text/FormBuilder.pm	(revision 57)
+++ trunk/lib/Text/FormBuilder.pm	(revision 59)
@@ -530,9 +530,9 @@
                 $OUT .= qq[</th>\n];
                 
-                $OUT .= qq[    <td>];
+                $OUT .= qq[    <td><span class="fieldgroup">];
                 $OUT .= join(' ', map { qq[<small class="sublabel">$$_{label}</small> $$_{field} $$_{comment}] } @group_fields);
                 $OUT .= " $msg_invalid" if $$_{invalid};
-
-                $OUT .= qq[    </td>\n];
+                
+                $OUT .= qq[    </span></td>\n];
                 $OUT .= qq[  </tr>\n];
             }   
Index: trunk/lib/Text/FormBuilder/grammar
===================================================================
--- trunk/lib/Text/FormBuilder/grammar	(revision 57)
+++ trunk/lib/Text/FormBuilder/grammar	(revision 59)
@@ -234,5 +234,17 @@
 value: identifier
 
-display_text: '[' /[^\]]+/i ']'    { $item[2] }
+display_text: brace_block
+    { (my $text = $item[1]) =~ s/^\[\s*|\s*\]$//g; $text }
+
+# square brace delimited block, that can contain properly
+# nested square braces, along with any other characters
+# return with the '[...]' so that nested blocks get the
+# braces treated as literals
+brace_block: '[' <skip:''> brace_block_content(s) ']'
+    {
+	'[' . join('', @{ $item[3] }) . ']';
+    }
+brace_block_content: /[^\[\]]+?/ | brace_block
+
 
 validate: '//' (optional_pattern | required_pattern)    { $item[2] }
