drccrd commented on code in PR #4005: URL: https://github.com/apache/incubator-kie-tools/pull/4005#discussion_r4004141097
########## packages/drools-lsp/drools-formatter/src/main/java/org/drools/formatter/Emitter.java: ########## @@ -0,0 +1,573 @@ +/* + * 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 + * + * http://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.drools.formatter; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; +import org.drools.drl.parser.antlr4.DRL10Lexer; +import org.drools.drl.parser.antlr4.DRL10Parser; +import org.drools.drl.parser.antlr4.DRL10ParserHelper; + +/** + * Output side of the formatter: the buffer, indentation depth, hidden-token and + * comment emission, {@code @formatter:off} regions, and the two text extractors + * ({@code styledText} normalizes spacing, {@code sourceSlice} is byte-faithful). + * Every area formatter writes through one instance of this. + * + * <p>Comments and blank lines from the hidden channel are emitted by + * {@code emitHiddenTokensBefore} / {@code emitTrailingHiddenTokens}, which + * walk the token stream between the last emitted index and the current node. + * Block comments are re-indented; line comments are preserved. + * + * <p>Emission is STYLE-NORMALIZING and COMMENT-PRESERVING, not byte-preserving: + * token content and comments always survive, while spacing and the sanctioned + * separator/terminator normalizations (statement {@code ;}, accumulate/groupby + * source separator {@code ,} → {@code ;}) come from the formatter, not the + * source. + * <ul> + * <li>{@code styledText} — the standard emission helper: visible tokens + * of a node (or token span) joined per the house spacing rules + * ({@code needsSpaceBetween}), block comments kept inline, hidden + * whitespace discarded.</li> + * <li>{@code sourceSlice} — exact original text of a node (or token span), + * including comments and inter-token whitespace. Reserved for the sites + * where verbatim IS the contract: frozen regions/{@code emitVerbatim}, + * the unparsed-rule fallback, and the multi-line reflow guards that keep + * a line comment's newline.</li> + * <li>Both advance {@code lastEmittedTokenIndex} so hidden-token emission + * never double-prints what a span already contains.</li> + * <li>{@code singleLine} — collapses newline+indent runs to single spaces + * for one-line emission contexts.</li> + * </ul> + */ +final class Emitter { + + final DRL10Parser parser; + final CommonTokenStream tokens; + final StringBuilder out = new StringBuilder(); + final FormatterOptions options; + final TokenSpacing spacing; + int depth = 0; + int lastEmittedTokenIndex = -1; + int consecutiveNewlines = 0; + + // Source-line ranges (1-based, inclusive) frozen by @formatter:off/on + // markers; top-level statements overlapping these are emitted verbatim. + // Populated once the token stream is filled, via computeSkipRegions(). + List<int[]> skipRegions = List.of(); + + Emitter(String text, FormatterOptions options) { + parser = DRL10ParserHelper.createDrlParser(text); + tokens = (CommonTokenStream) parser.getTokenStream(); + this.options = options; + this.spacing = new TokenSpacing(options); + } + + String result() { + return out.toString(); + } + + // ── output helpers ──────────────────────────────────────────────────── + + String indent() { + return options.indentUnit().repeat(Math.max(0, depth)); + } + + String indent(int offset) { + return options.indentUnit().repeat(Math.max(0, depth + offset)); + } + + void emit(String text) { + out.append(text); + if (!text.isEmpty()) { + consecutiveNewlines = 0; + } + } + + void newline() { + out.append('\n'); + consecutiveNewlines++; + } + + void blankLine() { + if (consecutiveNewlines < 2) { + newline(); + } + } + + /** + * Append text to the last line of output (before any trailing newline). + * Used to attach suffixes like "," to a pattern's closing ")". + */ + void appendToLastLine(String suffix) { + // Strip trailing newline, append suffix. Caller must call newline() afterwards. + int len = out.length(); + while (len > 0 && out.charAt(len - 1) == '\n') { + len--; + } + out.setLength(len); + out.append(suffix); + consecutiveNewlines = 0; + } + + /** + * Emits a header line and its metadata items (annotations, attributes) per + * options.headerMetadata(), leaving depth one deeper than on entry — the + * body's level. Comments between items are emitted before the item they + * precede; under INLINE that places them on their own lines after the header. + */ + void emitHeader(String header, List<? extends ParserRuleContext> items) { + FormatterOptions.HeaderMetadata mode = options.headerMetadata(); + if (mode == FormatterOptions.HeaderMetadata.INLINE) { + StringBuilder line = new StringBuilder(header); + for (ParserRuleContext item : items) { + String text = styledText(item); Review Comment: Same as within an accumulate - I don't think inline comments between a rule name and metadata is something that should be supported. However to align with the non-inline modes, comments are no longer dropped per [7a0ae31](https://github.com/apache/incubator-kie-tools/pull/4005/commits/7a0ae31db7f824ec07842939f240bccafd5cd490) -- 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] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
