@@ -35,9 +35,17 @@ public final class Comment extends Doc implements Op {
3535 /** For a comment of NON-NLS markers, the index of the string literal each marker marks, or -1; else empty. */
3636 private final List <Integer > nonNlsLiterals ;
3737
38- private Comment (Input .Tok tok , List <Integer > nonNlsLiterals ) {
38+ /** Whether the comment trails code on its line. */
39+ private final boolean trailing ;
40+
41+ /** Set by {@link #withFirstWordOnly}. */
42+ private final boolean firstWordOnly ;
43+
44+ private Comment (Input .Tok tok , List <Integer > nonNlsLiterals , boolean trailing , boolean firstWordOnly ) {
3945 this .tok = tok ;
4046 this .nonNlsLiterals = nonNlsLiterals ;
47+ this .trailing = trailing ;
48+ this .firstWordOnly = firstWordOnly ;
4149 }
4250
4351 /**
@@ -47,7 +55,12 @@ private Comment(Input.Tok tok, List<Integer> nonNlsLiterals) {
4755 * @return the new {@code Tok}
4856 */
4957 public static Comment make (Input .Tok tok ) {
50- return new Comment (tok , List .of ());
58+ return new Comment (tok , List .of (), false , false );
59+ }
60+
61+ /** A comment that trails code on its line. */
62+ public static Comment makeTrailing (Input .Tok tok ) {
63+ return new Comment (tok , List .of (), true , false );
5164 }
5265
5366 /**
@@ -58,7 +71,32 @@ public static Comment make(Input.Tok tok) {
5871 * @param literals for each marker, the index of the string literal it marks, or -1
5972 */
6073 public static Comment makeNonNlsMarkers (Input .Tok tok , List <Integer > literals ) {
61- return new Comment (tok , List .copyOf (literals ));
74+ return new Comment (tok , List .copyOf (literals ), false , false );
75+ }
76+
77+ /**
78+ * This comment, laid out by its slashes and its first word only, as a line comment that spans lines is. The next
79+ * run reads a wrapped trailing comment back as one that spans lines, so laying it out that way from the start gives
80+ * both runs the same layout, and the code before it is not broken for room that the comment does not get.
81+ */
82+ public Comment withFirstWordOnly () {
83+ return new Comment (tok , nonNlsLiterals , trailing , true );
84+ }
85+
86+ /**
87+ * Whether this trailing line comment, counted in full by the layout, came out of {@code state} wrapped: it did not
88+ * fit after the code before it, however that was broken.
89+ */
90+ public boolean wrappedIn (State state ) {
91+ return trailing
92+ && tok .isSlashSlashComment ()
93+ && !countsFirstWordOnly ()
94+ && Newlines .containsBreaks (state .getTokText (this ));
95+ }
96+
97+ /** Whether the layout counts only the slashes and the first word of this line comment. */
98+ boolean countsFirstWordOnly () {
99+ return tok .isSlashSlashComment () && (firstWordOnly || Newlines .containsBreaks (tok .getOriginalText ()));
62100 }
63101
64102 @ Override
@@ -79,6 +117,11 @@ protected float computeWidth() {
79117 }
80118 return width ;
81119 }
120+ if (countsFirstWordOnly ()) {
121+ // The rest of the comment goes where the wrap puts it, so the code before it is laid out as if it were not
122+ // there; see withFirstWordOnly.
123+ return JavaCommentsHelper .firstWordLength (getFlat ());
124+ }
82125 int idx = Newlines .firstBreak (tok .getOriginalText ());
83126 // only count the first line of multi-line block comments
84127 if (tok .isComment ()) {
0 commit comments