Skip to content

Commit d290beb

Browse files
committed
Add support for Kotlin and Groovy source code
Closes gh-55
1 parent 74364e4 commit d290beb

12 files changed

+190
-90
lines changed

src/main/java/io/spring/asciidoctor/backend/codetools/ChompListingContentConverter.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 the original author or authors.
2+
* Copyright 2021-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import java.util.regex.Matcher;
2222
import java.util.regex.Pattern;
2323

24+
import io.spring.asciidoctor.backend.language.Language;
2425
import org.asciidoctor.ast.Block;
2526

2627
/**
@@ -37,14 +38,14 @@ public String convert(Block listingBlock, String content) {
3738
Options<ChompOption> options = Options.get(listingBlock, "chomp", ChompOption.class, ChompOption.DEFAULTS);
3839
String packageReplacement = (String) listingBlock.getAttribute(PACKAGE_REPLACEMENT_ATTR,
3940
listingBlock.getDocument().getAttribute(PACKAGE_REPLACEMENT_ATTR));
40-
String lang = (String) listingBlock.getAttribute("language");
41-
if ("java".equals(lang)) {
41+
Language language = Language.get(listingBlock);
42+
if (Language.isJavaLike(language)) {
4243
List<Chomper> chompers = new ArrayList<>();
4344
if (options.has(ChompOption.HEADERS)) {
44-
chompers.add(new HeaderChomper());
45+
chompers.add(new HeaderChomper(language));
4546
}
4647
if (options.has(ChompOption.PACKAGES)) {
47-
chompers.add(new PackageChomper(packageReplacement));
48+
chompers.add(new PackageChomper(language, packageReplacement));
4849
}
4950
if (options.has(ChompOption.TAGS)) {
5051
chompers.add(new TagChomper());
@@ -81,11 +82,16 @@ private interface Chomper {
8182
*/
8283
private static class HeaderChomper implements Chomper {
8384

84-
private static final Pattern PATTERN = Pattern.compile("^.*?(package\\ [\\w\\.]+;)", Pattern.DOTALL);
85+
private final Pattern pattern;
86+
87+
HeaderChomper(Language language) {
88+
this.pattern = Pattern.compile("^.*?(package\\ [\\w\\.]+" + language.getStatementTerminator() + ")",
89+
Pattern.DOTALL);
90+
}
8591

8692
@Override
8793
public String chomp(String content) {
88-
Matcher matcher = PATTERN.matcher(content);
94+
Matcher matcher = this.pattern.matcher(content);
8995
if (matcher.find()) {
9096
StringBuffer updated = new StringBuffer();
9197
matcher.appendReplacement(updated, matcher.group(1));
@@ -102,18 +108,20 @@ public String chomp(String content) {
102108
*/
103109
private static class PackageChomper implements Chomper {
104110

105-
private static final Pattern PATTERN = Pattern.compile("package\\ [\\w\\.]+;\\s*", Pattern.DOTALL);
111+
private static Pattern pattern;
106112

107113
private final String replacement;
108114

109-
PackageChomper(String replacement) {
110-
this.replacement = (replacement != null && !replacement.isEmpty()) ? "package " + replacement + ";\n\n"
111-
: "";
115+
PackageChomper(Language language, String replacement) {
116+
pattern = Pattern.compile("package\\ [\\w\\.]+" + language.getStatementTerminator() + "\\s*",
117+
Pattern.DOTALL);
118+
this.replacement = (replacement != null && !replacement.isEmpty())
119+
? "package " + replacement + language.getStatementTerminator() + "\n\n" : "";
112120
}
113121

114122
@Override
115123
public String chomp(String content) {
116-
return PATTERN.matcher(content).replaceFirst(this.replacement);
124+
return pattern.matcher(content).replaceFirst(this.replacement);
117125
}
118126

119127
}

src/main/java/io/spring/asciidoctor/backend/codetools/FoldListingContentConverter.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 the original author or authors.
2+
* Copyright 2021-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import java.util.stream.Collectors;
2525
import java.util.stream.Stream;
2626

27+
import io.spring.asciidoctor.backend.language.Language;
2728
import org.asciidoctor.ast.Block;
2829

2930
/**
@@ -36,8 +37,8 @@ class FoldListingContentConverter implements ListingContentConverter {
3637
@Override
3738
public String convert(Block listingBlock, String content) {
3839
Options<FoldOption> options = Options.get(listingBlock, "fold", FoldOption.class, FoldOption.DEFAULTS);
39-
String lang = (String) listingBlock.getAttribute("language");
40-
if ("java".equals(lang)) {
40+
Language language = Language.get(listingBlock);
41+
if (Language.isJavaLike(language)) {
4142
List<Folder> folders = new ArrayList<>();
4243
if (options.has(FoldOption.IMPORTS)) {
4344
folders.add(new ImportsFolder());

src/main/java/io/spring/asciidoctor/backend/codetools/FoldRemovalListingContentConverter.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 the original author or authors.
2+
* Copyright 2021-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package io.spring.asciidoctor.backend.codetools;
1818

19+
import io.spring.asciidoctor.backend.language.Language;
1920
import org.asciidoctor.ast.Block;
2021

2122
/**
@@ -28,8 +29,8 @@ class FoldRemovalListingContentConverter implements ListingContentConverter {
2829
@Override
2930
public String convert(Block listingBlock, String content) {
3031
Options<FoldOption> options = Options.get(listingBlock, "fold", FoldOption.class, FoldOption.DEFAULTS);
31-
String lang = (String) listingBlock.getAttribute("language");
32-
if ("java".equals(lang) && options.has(FoldOption.TAGS)) {
32+
Language language = Language.get(listingBlock);
33+
if (Language.isJavaLike(language) && options.has(FoldOption.TAGS)) {
3334
return removeFoldTags(content);
3435
}
3536
return content;

src/main/java/io/spring/asciidoctor/backend/includecode/IncludeCodeBlockMacroProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.stream.Collectors;
2727
import java.util.stream.Stream;
2828

29+
import io.spring.asciidoctor.backend.language.Language;
2930
import org.asciidoctor.ast.Block;
3031
import org.asciidoctor.ast.ContentNode;
3132
import org.asciidoctor.ast.Document;
@@ -126,7 +127,7 @@ static class Content {
126127
Block createBlock(Processor processor, StructuralNode parent) {
127128
Block block = processor.createBlock(parent, "listing", this.content);
128129
block.setStyle("source");
129-
block.setAttribute("language", this.language.getLanguage(), true);
130+
block.setAttribute("language", this.language.getId(), true);
130131
block.setAttribute("indent", 0, true);
131132
block.setAttribute("subs", "verbatim", true);
132133
block.setTitle(this.language.getTitle());

src/main/java/io/spring/asciidoctor/backend/includecode/Language.java

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2021-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.asciidoctor.backend.language;
18+
19+
import org.asciidoctor.ast.ContentNode;
20+
21+
/**
22+
* Languages supported by the backend.
23+
*
24+
* @author Phillip Webb
25+
*/
26+
public enum Language {
27+
28+
/**
29+
* Java.
30+
*/
31+
JAVA("Java", "docs-java", "java", true, ";"),
32+
33+
/**
34+
* Kotlin.
35+
*/
36+
KOTLIN("Kotlin", "docs-kotlin", "kt", true, ""),
37+
38+
/**
39+
* Groovy.
40+
*/
41+
GROOVY("Groovy", "docs-groovy", "groovy", true, "");
42+
43+
private final String title;
44+
45+
private final String pathAttribute;
46+
47+
private final String extension;
48+
49+
private final boolean javaLike;
50+
51+
private final String statementTerminator;
52+
53+
Language(String title, String pathAttribute, String extension, boolean javaLike, String statementTerminator) {
54+
this.title = title;
55+
this.pathAttribute = pathAttribute;
56+
this.extension = extension;
57+
this.javaLike = javaLike;
58+
this.statementTerminator = statementTerminator;
59+
}
60+
61+
public String getTitle() {
62+
return this.title;
63+
}
64+
65+
public String getPathAttribute() {
66+
return this.pathAttribute;
67+
}
68+
69+
public String GetExtension() {
70+
return this.extension;
71+
}
72+
73+
public String getId() {
74+
return this.name().toLowerCase();
75+
}
76+
77+
public boolean isJavaLike() {
78+
return this.javaLike;
79+
}
80+
81+
public String getStatementTerminator() {
82+
return this.statementTerminator;
83+
}
84+
85+
public static Language get(ContentNode node) {
86+
String language = (String) node.getAttribute("language");
87+
for (Language candidate : values()) {
88+
if (candidate.getId().equals(language)) {
89+
return candidate;
90+
}
91+
}
92+
return null;
93+
94+
}
95+
96+
public static boolean isJavaLike(Language language) {
97+
return language != null && language.isJavaLike();
98+
}
99+
100+
}

src/test/java/io/spring/asciidoctor/backend/codetools/ChompListingContentConverterTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,26 @@ void convertWhenChompHeaderReturnsWithoutHeader(ConvertedHtml html) {
4242
assertThat(html.getElementByTag("code")).isEqualTo("package com.example;");
4343
}
4444

45+
@Test
46+
void convertWhenChompHeaderAndKotlinReturnsWithoutHeader(ConvertedHtml html) {
47+
assertThat(html.getElementByTag("code")).isEqualTo("package com.example");
48+
}
49+
4550
@Test
4651
void convertWhenChompPackageReturnsWithoutPackage(ConvertedHtml html) {
4752
assertThat(html.getElementByTag("code")).isEqualTo("public class Example {}");
4853
}
4954

55+
@Test
56+
void convertWhenChompPackageAndKotlinReturnsWithoutPackage(ConvertedHtml html) {
57+
assertThat(html.getElementByTag("code")).isEqualTo("public class Example {}");
58+
}
59+
60+
@Test
61+
void convertWhenChompPackageAndGroovyReturnsWithoutPackage(ConvertedHtml html) {
62+
assertThat(html.getElementByTag("code")).isEqualTo("public class Example {}");
63+
}
64+
5065
@Test
5166
void convertWhenChompPackageAndReplacementReturnsWithReplacedPackage(ConvertedHtml html, ExpectedHtml expected) {
5267
assertThat(html.getElementByTag("code")).satisfies(expected);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
= Test Document
2+
:chomp: headers
3+
4+
[source,kotlin]
5+
----
6+
/*
7+
* Copyright 2014-2020 the original author or authors.
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* https://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*/
21+
22+
package com.example
23+
----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
= Test Document
2+
:chomp: packages
3+
4+
[source,groovy]
5+
----
6+
package com.example
7+
8+
public class Example {}
9+
----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
= Test Document
2+
:chomp: packages
3+
4+
[source,kotlin]
5+
----
6+
package com.example
7+
8+
public class Example {}
9+
----

0 commit comments

Comments
 (0)