@@ -77,6 +77,7 @@ public class GroovyPageParser implements Tokens {
7777 private GSPWriter out ;
7878 private String className ;
7979 private String packageName ;
80+ private String sourceName ; // last segment of the file name (eg- index.gsp)
8081 private boolean finalPass = false ;
8182 private int tagIndex ;
8283 private Map tagContext ;
@@ -207,6 +208,7 @@ public GroovyPageParser(String name, String uri, String filename, InputStream in
207208 this .pageName = uri ;
208209 this .environment = Environment .getCurrent ();
209210 makeName (name );
211+ makeSourceName (filename );
210212 } // Parse()
211213
212214 private Map <String , String > parseDirectives (String gspSource ) {
@@ -642,6 +644,22 @@ else if (ix == 0 && c >= '0' && c <= '9')
642644 className = buf .toString ();
643645 } // makeName()
644646
647+ /**
648+ * find the simple name of this gsp
649+ * @param filename the fully qualified file name
650+ */
651+ private void makeSourceName (String filename ) {
652+ if (filename != null ) {
653+ int lastSegmentStart = filename .lastIndexOf ('/' );
654+ if (lastSegmentStart == -1 ) {
655+ lastSegmentStart = filename .lastIndexOf ('\\' );
656+ }
657+ sourceName = filename .substring (lastSegmentStart + 1 );
658+ } else {
659+ sourceName = className ;
660+ }
661+ }
662+
645663 private static boolean match (CharSequence pat , CharSequence text , int start ) {
646664 int ix = start , ixz = text .length (), ixy = start + pat .length ();
647665 if (ixz > ixy )
@@ -789,6 +807,10 @@ private void page() {
789807 out .println ("null" );
790808 }
791809 out .println ("}" );
810+
811+ if (shouldAddLineNumbers ()) {
812+ addLineNumbers ();
813+ }
792814 } else {
793815 for (int i = 0 ; i < DEFAULT_IMPORTS .length ; i ++) {
794816 out .print ("import " );
@@ -798,6 +820,64 @@ private void page() {
798820 }
799821 } // page()
800822
823+ /**
824+ * Determines if the line numbers array should be added to the generated Groovy class.
825+ * @return true if they should
826+ */
827+ private boolean shouldAddLineNumbers () {
828+ try {
829+ // for now, we support this through a system property.
830+ String prop = System .getenv ("GROOVY_PAGE_ADD_LINE_NUMBERS" );
831+ return Boolean .valueOf (prop ).booleanValue ();
832+ } catch (Exception e ) {
833+ // something wild happened
834+ return false ;
835+ }
836+ }
837+
838+ /**
839+ * Adds the line numbers array to the end of the generated Groovy ModuleNode
840+ * in a way suitable for the LineNumberTransform AST transform to operate on it
841+ */
842+ private void addLineNumbers () {
843+ out .println ();
844+ out .println ("@org.codehaus.groovy.grails.web.transform.LineNumber(" );
845+ out .print ("\t lines = [" );
846+ // get the line numbers here. this will mean that the last 2 lines will not be captured in the
847+ // line number information, but that's OK since a user cannot set a breakpoint there anyway.
848+ int [] lineNumbers = filterTrailing0s (out .getLineNumbers ());
849+
850+ for (int i = 0 ; i < lineNumbers .length ; i ++) {
851+ out .print (lineNumbers [i ]);
852+ if (i < lineNumbers .length - 1 ) {
853+ out .print (", " );
854+ }
855+ }
856+ out .println ("]," );
857+ out .println ("\t sourceName = \" " + sourceName + "\" " );
858+ out .println (")" );
859+ out .println ("class ___LineNumberPlaceholder { }" );
860+ }
861+
862+ /**
863+ * Filters trailing 0s from the line number array
864+ * @param lineNumbers the line number array
865+ * @return a new array that removes all 0s from the end of it
866+ */
867+ private int [] filterTrailing0s (int [] lineNumbers ) {
868+ int startLocation = lineNumbers .length - 1 ;
869+ for (int i = lineNumbers .length -1 ; i >= 0 ; i --) {
870+ if (lineNumbers [i ] > 0 ) {
871+ startLocation = i + 1 ;
872+ break ;
873+ }
874+ }
875+
876+ int [] newLineNumbers = new int [startLocation ];
877+ System .arraycopy (lineNumbers , 0 , newLineNumbers , 0 , startLocation );
878+ return newLineNumbers ;
879+ }
880+
801881 private void endTag () {
802882 if (!finalPass )
803883 return ;
0 commit comments