Skip to content
Permalink
Browse files
8276124: Provide snippet support for properties files
Co-authored-by: Jonathan Gibbons <jjg@openjdk.org>
Co-authored-by: Hannes Wallnöfer <hannesw@openjdk.org>
Reviewed-by: jjg
  • Loading branch information
3 people committed Nov 24, 2021
1 parent 96fe1d0 commit e785f699614abc8d557be8fc1782a1f86f272430
Showing 4 changed files with 263 additions and 41 deletions.
@@ -30,6 +30,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.lang.model.element.Element;
@@ -63,6 +64,38 @@
*/
public class SnippetTaglet extends BaseTaglet {

public enum Language {

JAVA("java"),
PROPERTIES("properties");

private static final Map<String, Language> languages;

static {
Map<String, Language> tmp = new HashMap<>();
for (var language : values()) {
String id = Objects.requireNonNull(language.identifier);
if (tmp.put(id, language) != null)
throw new IllegalStateException(); // 1-1 correspondence
}
languages = Map.copyOf(tmp);
}

Language(String id) {
identifier = id;
}

private final String identifier;

public static Optional<Language> of(String identifier) {
if (identifier == null)
return Optional.empty();
return Optional.ofNullable(languages.get(identifier));
}

public String getIdentifier() {return identifier;}
}

public SnippetTaglet() {
super(DocTree.Kind.SNIPPET, true, EnumSet.allOf(Taglet.Location.class));
}
@@ -217,14 +250,27 @@ private Content generateContent(Element holder, DocTree tag, TagletWriter writer
}
}

String lang = null;
AttributeTree langAttr = attributes.get("lang");
if (langAttr != null) {
lang = stringValueOf(langAttr);
} else if (containsClass) {
lang = "java";
} else if (containsFile) {
lang = languageFromFileName(fileObject.getName());
}

Optional<Language> language = Language.of(lang);


// TODO cache parsed external snippet (WeakHashMap)

StyledText inlineSnippet = null;
StyledText externalSnippet = null;

try {
if (inlineContent != null) {
inlineSnippet = parse(writer.configuration().getDocResources(), inlineContent);
inlineSnippet = parse(writer.configuration().getDocResources(), language, inlineContent);
}
} catch (ParseException e) {
var path = writer.configuration().utils.getCommentHelper(holder)
@@ -239,7 +285,7 @@ private Content generateContent(Element holder, DocTree tag, TagletWriter writer

try {
if (externalContent != null) {
externalSnippet = parse(writer.configuration().getDocResources(), externalContent);
externalSnippet = parse(writer.configuration().getDocResources(), language, externalContent);
}
} catch (ParseException e) {
assert fileObject != null;
@@ -289,15 +335,6 @@ private Content generateContent(Element holder, DocTree tag, TagletWriter writer
assert inlineSnippet != null || externalSnippet != null;
StyledText text = inlineSnippet != null ? inlineSnippet : externalSnippet;

String lang = null;
AttributeTree langAttr = attributes.get("lang");
if (langAttr != null) {
lang = stringValueOf(langAttr);
} else if (containsClass) {
lang = "java";
} else if (containsFile) {
lang = languageFromFileName(fileObject.getName());
}
AttributeTree idAttr = attributes.get("id");
String id = idAttr == null
? null
@@ -326,8 +363,8 @@ private static String diff(String inline, String external) {
""".formatted(inline, external);
}

private StyledText parse(Resources resources, String content) throws ParseException {
Parser.Result result = new Parser(resources).parse(content);
private StyledText parse(Resources resources, Optional<Language> language, String content) throws ParseException {
Parser.Result result = new Parser(resources).parse(language, content);
result.actions().forEach(Action::perform);
return result.text();
}
@@ -39,6 +39,7 @@
import java.util.regex.PatternSyntaxException;

import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.taglets.SnippetTaglet;

/*
* Semantics of a EOL comment; plus
@@ -76,10 +77,10 @@
*/
public final class Parser {

// next-line tag behaves as if it were specified on the next line

private String eolMarker;
private Matcher markedUpLine;
private static final Pattern JAVA_COMMENT = Pattern.compile(
"^(?<payload>.*)//(?<markup>\\s*@\\s*\\w+.+?)$");
private static final Pattern PROPERTIES_COMMENT = Pattern.compile(
"^(?<payload>[ \t]*([#!].*)?)[#!](?<markup>\\s*@\\s*\\w+.+?)$");

private final Resources resources;
private final MarkupParser markupParser;
@@ -93,32 +94,23 @@ public Parser(Resources resources) {
this.markupParser = new MarkupParser(resources);
}

public Result parse(String source) throws ParseException {
return parse("//", source);
public Result parse(Optional<SnippetTaglet.Language> language, String source) throws ParseException {
SnippetTaglet.Language lang = language.orElse(SnippetTaglet.Language.JAVA);
var p = switch (lang) {
case JAVA -> JAVA_COMMENT;
case PROPERTIES -> PROPERTIES_COMMENT;
};
return parse(p, source);
}

/*
* Newline characters in the returned text are of the \n form.
*/
public Result parse(String eolMarker, String source) throws ParseException {
Objects.requireNonNull(eolMarker);
private Result parse(Pattern commentPattern, String source) throws ParseException {
Objects.requireNonNull(commentPattern);
Objects.requireNonNull(source);
if (!Objects.equals(eolMarker, this.eolMarker)) {
if (eolMarker.length() < 1) {
throw new IllegalArgumentException();
}
for (int i = 0; i < eolMarker.length(); i++) {
switch (eolMarker.charAt(i)) {
case '\f', '\n', '\r' -> throw new IllegalArgumentException();
}
}
this.eolMarker = eolMarker;
// capture the rightmost eolMarker (e.g. "//")
// The below Pattern.compile should never throw PatternSyntaxException
Pattern pattern = Pattern.compile("^(.*)(" + Pattern.quote(eolMarker)
+ "(\\s*@\\s*\\w+.+?))$");
this.markedUpLine = pattern.matcher(""); // reusable matcher
}

Matcher markedUpLine = commentPattern.matcher(""); // reusable matcher

tags.clear();
regions.clear();
@@ -151,17 +143,17 @@ record OffsetAndLine(int offset, String line) { }
if (!markedUpLine.matches()) { // (1)
line = rawLine + (addLineTerminator ? "\n" : "");
} else {
String maybeMarkup = markedUpLine.group(3);
String maybeMarkup = rawLine.substring(markedUpLine.start("markup"));
List<Tag> parsedTags;
try {
parsedTags = markupParser.parse(maybeMarkup);
} catch (ParseException e) {
// translate error position from markup to file line
throw new ParseException(e::getMessage, markedUpLine.start(3) + e.getPosition());
throw new ParseException(e::getMessage, markedUpLine.start("markup") + e.getPosition());
}
for (Tag t : parsedTags) {
t.lineSourceOffset = next.offset();
t.markupLineOffset = markedUpLine.start(3);
t.markupLineOffset = markedUpLine.start("markup");
}
thisLineTags.addAll(parsedTags);
for (var tagIterator = thisLineTags.iterator(); tagIterator.hasNext(); ) {
@@ -176,7 +168,7 @@ record OffsetAndLine(int offset, String line) { }
// TODO: log this with NOTICE;
line = rawLine + (addLineTerminator ? "\n" : "");
} else { // (3)
String payload = markedUpLine.group(1);
String payload = rawLine.substring(0, markedUpLine.end("payload"));
line = payload + (addLineTerminator ? "\n" : "");
}
}
@@ -101,6 +101,12 @@ protected String getSnippetHtmlRepresentation(String pathToHtmlFile,
return getSnippetHtmlRepresentation(pathToHtmlFile, content, Optional.empty(), Optional.empty());
}

protected String getSnippetHtmlRepresentation(String pathToHtmlFile,
String content,
Optional<String> lang) {
return getSnippetHtmlRepresentation(pathToHtmlFile, content, lang, Optional.empty());
}

protected String getSnippetHtmlRepresentation(String pathToHtmlFile,
String content,
Optional<String> lang,

1 comment on commit e785f69

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on e785f69 Nov 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.