11/*
2- * Copyright (c) 2017, 2025 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2017, 2026 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
4949 * The tags can be used as follows:
5050 *
5151 * <pre>
52- * @jls section-number description
52+ * @jls chapter.section description
53+ * @jls preview-feature-chapter.section description
5354 * </pre>
5455 *
5556 * For example:
5657 *
5758 * <pre>
5859 * @jls 3.4 Line Terminators
60+ * @jls primitive-types-in-patterns-instanceof-switch-5.7.1 Exact Testing Conversions
5961 * </pre>
6062 *
6163 * will produce the following HTML, depending on the file containing
6466 * <pre>{@code
6567 * <dt>See <i>Java Language Specification</i>:
6668 * <dd><a href="../../specs/jls/jls-3.html#jls-3.4">3.4 Line terminators</a>
69+ * <dd><a href="../../specs/primitive-types-in-patterns-instanceof-switch-jls.html#jls-5.7.1">
70+ * 5.7.1 Exact Testing Conversions</a><sup class="preview-mark">
71+ * <a href="../../specs/jls/jls-1.html#jls-1.5.1">PREVIEW</a></sup>
6772 * }</pre>
6873 *
69- * Copies of JLS and JVMS are expected to have been placed in the {@code specs}
70- * folder. These documents are not included in open-source repositories.
74+ * In inline tags (note you need manual JLS/JVMS prefix):
75+ * <pre>
76+ * JLS {@jls 3.4}
77+ * </pre>
78+ *
79+ * produces (note the section sign and no trailing dot):
80+ * <pre>
81+ * JLS <a href="../../specs/jls/jls-3.html#jls-3.4">§3.4</a>
82+ * </pre>
83+ *
84+ * Copies of JLS, JVMS, and preview JLS and JVMS changes are expected to have
85+ * been placed in the {@code specs} folder. These documents are not included
86+ * in open-source repositories.
7187 */
7288public class JSpec implements Taglet {
7389
@@ -87,9 +103,9 @@ public JVMS() {
87103 }
88104 }
89105
90- private String tagName ;
91- private String specTitle ;
92- private String idPrefix ;
106+ private final String tagName ;
107+ private final String specTitle ;
108+ private final String idPrefix ;
93109
94110 JSpec (String tagName , String specTitle , String idPrefix ) {
95111 this .tagName = tagName ;
@@ -98,7 +114,7 @@ public JVMS() {
98114 }
99115
100116 // Note: Matches special cases like @jvms 6.5.checkcast
101- private static final Pattern TAG_PATTERN = Pattern .compile ("(?s)(.+ )?(?<chapter>[1-9][0-9]*)(?<section>[0-9a-z_.]*)( .*)?$" );
117+ private static final Pattern TAG_PATTERN = Pattern .compile ("(?s)(.+ )?(?<preview>([a-z0-9]+-)+)?(?< chapter>[1-9][0-9]*)(?<section>[0-9a-z_.]*)( .*)?$" );
102118
103119 /**
104120 * Returns the set of locations in which the tag may be used.
@@ -157,19 +173,50 @@ public String toString(List<? extends DocTree> tags, Element elem) {
157173 .trim ();
158174 Matcher m = TAG_PATTERN .matcher (tagText );
159175 if (m .find ()) {
176+ // preview-feature-4.6 is preview-feature-, 4, .6
177+ String preview = m .group ("preview" ); // null if no preview feature
160178 String chapter = m .group ("chapter" );
161179 String section = m .group ("section" );
162180 String rootParent = currentPath ().replaceAll ("[^/]+" , ".." );
163181
164- String url = String .format ("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s" ,
165- rootParent , idPrefix , chapter , section );
182+ String url = preview == null ?
183+ String .format ("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s" ,
184+ rootParent , idPrefix , chapter , section ) :
185+ String .format ("%1$s/specs/%5$s%2$s.html#%2$s-%3$s%4$s" ,
186+ rootParent , idPrefix , chapter , section , preview );
187+
188+ var literal = expand (contents ).trim ();
189+ var prefix = (preview == null ? "" : preview ) + chapter + section ;
190+ if (literal .startsWith (prefix )) {
191+ var hasFullTitle = literal .length () > prefix .length ();
192+ if (hasFullTitle ) {
193+ // Drop the preview identifier
194+ literal = chapter + section + literal .substring (prefix .length ());
195+ } else {
196+ // No section sign if the tag refers to a chapter, like {@jvms 4}
197+ String sectionSign = section .isEmpty () ? "" : "§" ;
198+ // Change whole text to "§chapter.x" in inline tags.
199+ literal = sectionSign + chapter + section ;
200+ }
201+ }
166202
167203 sb .append ("<a href=\" " )
168204 .append (url )
169205 .append ("\" >" )
170- .append (expand ( contents ) )
206+ .append (literal )
171207 .append ("</a>" );
172208
209+ if (preview != null ) {
210+ // Add PREVIEW superscript that links to JLS/JVMS 1.5.1
211+ // "Restrictions on the Use of Preview Features"
212+ // Similar to how APIs link to the Preview info box warning
213+ var sectionLink = String .format ("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s" ,
214+ rootParent , idPrefix , "1" , ".5.1" );
215+ sb .append ("<sup class=\" preview-mark\" ><a href=\" " )
216+ .append (sectionLink )
217+ .append ("\" >PREVIEW</a></sup>" );
218+ }
219+
173220 if (tag .getKind () == DocTree .Kind .UNKNOWN_BLOCK_TAG ) {
174221 sb .append ("<br>" );
175222 }
0 commit comments