jdaugherty commented on code in PR #16551: URL: https://github.com/apache/grails-core/pull/16551#discussion_r4218247527
########## grails-gsp/core/src/main/groovy/org/grails/gsp/compiler/LogicLineTrimmer.java: ########## @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.gsp.compiler; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Removes the lines of a page that hold only template logic, for a page declaring + * {@code trimLogicLines="true"}: a line holding nothing but page directives, scriptlets and comments, + * besides spaces and tabs, writes neither its indentation nor its line break. A line holding text, an + * expression, a declaration or a tag is left as it is. + * + * <p>The page is walked the way {@link GroovyPageScanner} reads it, so only a line of the page's + * text can be removed: text inside an expression, a tag, a scriptlet or a comment is never touched, + * whatever it looks like.</p> + * + * <p>The line break of a removed line is moved inside the line's last construct, just after its + * opening delimiter, rather than dropped, so that every line of the page keeps its number in the + * compiled page and in the errors reported against it.</p> + */ +final class LogicLineTrimmer { + + private static final Pattern TAG_NAMESPACE_PATTERN = Pattern.compile("^\\p{Alpha}\\w*$"); + + private static final int UNCLOSED = -1; + + private final String source; + private final int length; + + private LogicLineTrimmer(String source) { + this.source = source; + this.length = source.length(); + } + + static String trim(String gspSource) { + return new LogicLineTrimmer(gspSource).trim(); + } + + private String trim() { + StringBuilder result = new StringBuilder(length); + int copied = 0; + int position = 0; + while (position < length) { + if (position == 0 || source.charAt(position - 1) == '\n') { + int lineEnd = trimLogicLine(position, result, copied); + if (lineEnd != position) { + copied = position = lineEnd; + continue; + } + } + Construct construct = constructAt(position); + if (construct == null) { + position++; + } else if (construct.end() == UNCLOSED) { + // left for the parser to report + break; + } else { + position = construct.end(); + } + } + result.append(source, copied, length); + return result.toString(); + } + + /** + * Writes the line starting at {@code lineStart} without its blanks if it holds only template + * logic, the line break going just after the opening delimiter of its last construct. + * + * @return where the line ends, after its line break, or {@code lineStart} when it is not a logic line + */ + private int trimLogicLine(int lineStart, StringBuilder result, int copied) { + List<Construct> constructs = new ArrayList<>(); + int position = skipBlanks(lineStart); + String lineBreak = null; + while (lineBreak == null) { + Construct construct = constructAt(position); Review Comment: Fixed in 27068cdbbf. When the blanks run to the end of the page, `trimLogicLine` now returns before looking for a construct, so that last line is left as it is. `GspTrimLogicLinesSpec` has new cases for a page that ends with spaces, tabs, or both and no line break. All three threw `StringIndexOutOfBoundsException` before the fix. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
