diff --git a/CHANGES.md b/CHANGES.md index b1413c29a5..fa877292a3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ Core Grammars: - enh(json) add json5 support [Kerry Shetline][] - fix(css) `unicode-range` parsing, issue #4253 [Kerry Shetline][] - fix(csharp) Support digit separators [te-ing][] +- enh(java) improve detection of types, including generic and array types [Hannes Wallnoefer][] Documentation: @@ -55,6 +56,7 @@ CONTRIBUTORS [te-ing]: https://github.com/te-ing [Anthony Martin]: https://github.com/anthony-c-martin [NriotHrreion]: https://github.com/NriotHrreion +[Hannes Wallnoefer]: https://github.com/hns ## Version 11.11.1 diff --git a/src/languages/java.js b/src/languages/java.js index b826eb94cf..b986ffe7b6 100644 --- a/src/languages/java.js +++ b/src/languages/java.js @@ -30,8 +30,9 @@ function recurRegex(re, substitution, depth) { export default function(hljs) { const regex = hljs.regex; const JAVA_IDENT_RE = '[\u00C0-\u02B8a-zA-Z_$][\u00C0-\u02B8a-zA-Z_$0-9]*'; - const GENERIC_IDENT_RE = JAVA_IDENT_RE - + recurRegex('(?:<' + JAVA_IDENT_RE + '~~~(?:\\s*,\\s*' + JAVA_IDENT_RE + '~~~)*>)?', /~~~/g, 2); + const TYPE_ARG_RE = '(?:(?:' + JAVA_IDENT_RE + '~~~)|(?:\\?\\s+(?:extends|super)\\s+' + JAVA_IDENT_RE + '~~~)|(?:\\?))'; + const GENERIC_RE = recurRegex('(?:\\s*<\\s*' + TYPE_ARG_RE + '(?:\\s*,\\s*' + TYPE_ARG_RE + ')*\\s*>)?', /~~~/g, 2); + const ARRAY_RE = '(?:(?:\\s*\\[\\s*])+)?'; const MAIN_KEYWORDS = [ 'synchronized', 'abstract', @@ -188,7 +189,7 @@ export default function(hljs) { { begin: [ regex.concat(/(?!else)/, JAVA_IDENT_RE), - /\s+/, + regex.concat(GENERIC_RE, ARRAY_RE, /\s+/), JAVA_IDENT_RE, /\s+/, /=(?!=)/ @@ -223,11 +224,15 @@ export default function(hljs) { }, { begin: [ - '(?:' + GENERIC_IDENT_RE + '\\s+)', - hljs.UNDERSCORE_IDENT_RE, + JAVA_IDENT_RE, + regex.concat(GENERIC_RE, ARRAY_RE, /\s+/), + JAVA_IDENT_RE, /\s*(?=\()/ ], - className: { 2: "title.function" }, + className: { + 1: "type", + 3: "title.function" + }, keywords: KEYWORDS, contains: [ { diff --git a/test/api/highlight.js b/test/api/highlight.js index 0f85e7247c..f50ab9e459 100644 --- a/test/api/highlight.js +++ b/test/api/highlight.js @@ -36,7 +36,7 @@ describe('.highlight()', () => { result.value.should.equal( 'public ' + - 'void moveTo' + + 'void moveTo' + '(int x, ' + 'int y, ' + 'int z);' @@ -48,7 +48,7 @@ describe('.highlight()', () => { result.value.should.equal( 'public ' + - 'void moveTo' + + 'void moveTo' + '(int x, ' + 'int y, ' + 'int z);' diff --git a/test/markup/java/annotations.expect.txt b/test/markup/java/annotations.expect.txt index 3f801e1606..9b22b4530c 100644 --- a/test/markup/java/annotations.expect.txt +++ b/test/markup/java/annotations.expect.txt @@ -8,5 +8,5 @@ } class Example { - void foo(@SuppressWarnings("unused") int bar) { } + void foo(@SuppressWarnings("unused") int bar) { } } diff --git a/test/markup/java/arrays.expect.txt b/test/markup/java/arrays.expect.txt new file mode 100644 index 0000000000..f43d5c8e3d --- /dev/null +++ b/test/markup/java/arrays.expect.txt @@ -0,0 +1,4 @@ +String[] helloWorld = new String() {"hello", "world"}; +int[][] matrix = {{1, 2}, {3, 4}}; +private byte[] getBytes(); +public Object [ ] [ ] [ ] cubic() { ... } diff --git a/test/markup/java/arrays.txt b/test/markup/java/arrays.txt new file mode 100644 index 0000000000..4e48bc77c2 --- /dev/null +++ b/test/markup/java/arrays.txt @@ -0,0 +1,4 @@ +String[] helloWorld = new String() {"hello", "world"}; +int[][] matrix = {{1, 2}, {3, 4}}; +private byte[] getBytes(); +public Object [ ] [ ] [ ] cubic() { ... } diff --git a/test/markup/java/functions.expect.txt b/test/markup/java/functions.expect.txt index 8f638287f3..bc77cf546a 100644 --- a/test/markup/java/functions.expect.txt +++ b/test/markup/java/functions.expect.txt @@ -1,5 +1,5 @@ -public static <A,B,C> Tuple<A,B,C> fun(Future<Tuple<A,B,C>> future) throws Exceptions { +public static <A,B,C> Tuple<A,B,C> fun(Future<Tuple<A,B,C>> future) throws Exceptions { } -static Optional<List<Token>> parseAll(String s) { +static Optional<List<Token>> parseAll(String s) { } diff --git a/test/markup/java/generics.expect.txt b/test/markup/java/generics.expect.txt new file mode 100644 index 0000000000..9081997180 --- /dev/null +++ b/test/markup/java/generics.expect.txt @@ -0,0 +1,10 @@ +List<String> strings = new ArrayList<>(); +Generic<Object, ?, String> g = null; +public static <T, R> Generic<T, ?, R> map(Function<? super T, ? extends R> mapper); +Map<? extends Key, List<? super Value>> map = getMap(); +static Set < Integer > getInts() { ... } + +public interface Map<K, V> { + void put(K key, V value); + V get(K key); +} diff --git a/test/markup/java/generics.txt b/test/markup/java/generics.txt new file mode 100644 index 0000000000..db24764324 --- /dev/null +++ b/test/markup/java/generics.txt @@ -0,0 +1,10 @@ +List strings = new ArrayList<>(); +Generic g = null; +public static Generic map(Function mapper); +Map> map = getMap(); +static Set < Integer > getInts() { ... } + +public interface Map { + void put(K key, V value); + V get(K key); +} diff --git a/test/markup/java/numbers.expect.txt b/test/markup/java/numbers.expect.txt index ed7cb946bd..cc3870aa95 100644 --- a/test/markup/java/numbers.expect.txt +++ b/test/markup/java/numbers.expect.txt @@ -1,81 +1,81 @@ -int[] decimalIntegers = { +int[] decimalIntegers = { 0, 1, 10, 999, 0, 1, 1_0, 9_9__9, }; -long[] longDecimalIntegers = { +long[] longDecimalIntegers = { 0l, 1L, 10l, 999L, 0L, 1l, 1_0L, 9_9__9l, }; -int[] hexIntegers = { +int[] hexIntegers = { 0x0, 0Xa0, 0X7FF, 0xd3aD, 0x00000000ffffffff, 0X0, 0xa_0, 0x7__FF, 0Xd__3_aD, 0X0000_0000__ffff_ffff, }; -long[] longHexIntegers = { +long[] longHexIntegers = { 0x0L, 0Xa0l, 0X7FFL, 0xd3aDl, 0x7fffffffffffffffL, 0X0l, 0xa_0L, 0x7__FFl, 0Xd__3_aDL, 0X7fff_ffff__ffff_ffffl, }; -int[] octalIntegers = { +int[] octalIntegers = { 00, 001, 0777, 0_0, 0__01, 07__77, }; -long[] longOctalIntegers = { +long[] longOctalIntegers = { 00l, 001L, 0777l, 0_0L, 0__01l, 07__77L, }; -int[] binaryIntegers = { +int[] binaryIntegers = { 0b0, 0B11, 0B000, 0b01011, 0b0, 0B1_1, 0B00__0, 0b01__0_1__1, }; -long[] longBinaryIntegers = { +long[] longBinaryIntegers = { 0b0l, 0B11L, 0B000l, 0b01011L, 0b0L, 0B1_1l, 0B00__0L, 0b01__0_1__1l, }; -double[] doubleDecimalIntegers = { +double[] doubleDecimalIntegers = { 0d, 00D, 1d, 00800d, 0D, 0_0d, 1D, 0_0__8__0_0D, }; -float[] floatDecimalIntegers = { +float[] floatDecimalIntegers = { 0f, 00F, 1f, 00800f, 0F, 0_0f, 1F, 0_0__8__0_0F, }; -double[] doubleDecimals = { +double[] doubleDecimals = { .0, .00, .9, 4.2, 40.010, 0., 00., 10., .0, .0__0, .9, 4.2, 4_0.0__1_0, 0., 0_0., 1__0., .0D, .00d, .9D, 4.2d, 40.010D, 0.d, 00.D, 10.d, .0d, .0__0D, .9d, 4.2D, 4_0.0__1_0d, 0.D, 0_0.d, 1__0.D, }; -float[] floatDecimals = { +float[] floatDecimals = { .0F, .00f, .9F, 4.2f, 40.010F, 0.f, 00.F, 10.f, .0f, .0__0F, .9f, 4.2F, 4_0.0__1_0f, 0.F, 0_0.f, 1__0.F, }; -double[] doubleDecimalExponents = { +double[] doubleDecimalExponents = { .0e10, .00e+10, .9e-10, 4.2E10, 40.010E+08, 0.E-10, 00.e100, 00800e+10, .0e1_0, .0_0e+10, .9e-1_0, 4.2E1_0, 4_0.0__1_0E+0_8, 0.E-1_0, 0_0.e1_0_0, 0_0__8__00e+1___0, .0e10d, .00e+10D, .9e-10d, 4.2E10D, 40.010E+08d, 0.E-10D, 00.e100d, 00800e+10D, .0e1_0D, .0_0e+10d, .9e-1_0D, 4.2E1_0d, 4_0.0__1_0E+0_8D, 0.E-1_0d, 0_0.e1_0_0D, 0_0__8__00e+1___0d, }; -float[] floatDecimalExponents = { +float[] floatDecimalExponents = { .0e10f, .00e+10F, .9e-10f, 4.2E10F, 40.010E+08f, 0.E-10F, 00.e100f, 00800e+10F, .0e1_0F, .0_0e+10f, .9e-1_0F, 4.2E1_0f, 4_0.0__1_0E+0_8F, 0.E-1_0f, 0_0.e1_0_0F, 0_0__8__00e+1___0f, }; -double[] doubleHexExponents = { +double[] doubleHexExponents = { 0x0p0, 0x.ep6, 0Xa0.p+01, 0X.7FFp-18, 0xd3aD.B00p9, 0X0P0, 0x.Ep6, 0xa_0.p+0_1, 0X.7__F_FP-1__8, 0Xd__3_aD.b00p9, 0x0p0D, 0x.ep6D, 0Xa0.p+01d, 0X.7FFp-18D, 0xd3aD.B00p9d, 0X0P0d, 0x.eP6d, 0xa_0.p+0_1D, 0X.7__F_FP-1__8d, 0Xd__3_aD.b00p9D, }; -float[] floatHexExponents = { +float[] floatHexExponents = { 0x0p0F, 0x.ep6F, 0Xa0.p+01f, 0X.7FFp-18F, 0xf3aF.B00p9f, 0X0P0f, 0x.eP6f, 0xa_0.p+0_1F, 0X.7__F_FP-1__8f, 0Xf__3_aF.b00p9F, }; @@ -89,17 +89,17 @@ fn(5.); fn(x0.d); // invalid pseudo-numeric literals -int[] badNonDecimalIntegers = { 08, 0_8, 019, 0x0g, 0B02, }; -long[] longBadNonDecimalIntegers = { 08L, 0_8l, 01_9L, 0x0__GL, 0B0_2l, }; +int[] badNonDecimalIntegers = { 08, 0_8, 019, 0x0g, 0B02, }; +long[] longBadNonDecimalIntegers = { 08L, 0_8l, 01_9L, 0x0__GL, 0B0_2l, }; -int[] badUnderscoreIntegers = { 3_, 0x_0, 0X1_, 0B_0, 0b1_, }; -long[] longBadUnderscoreIntegers = { 3_l, 0X_0L, 0x1_l, 0b_0L, 0B1_l, }; +int[] badUnderscoreIntegers = { 3_, 0x_0, 0X1_, 0B_0, 0b1_, }; +long[] longBadUnderscoreIntegers = { 3_l, 0X_0L, 0x1_l, 0b_0L, 0B1_l, }; -double[] doubleBadDecimals = { 0_d, 0_., 0._1, 0._D, 0.1_d, }; -float[] floatBadDecimals = { 0_F, 0_.f, 0._1F, 0._f, 0.1_F, }; +double[] doubleBadDecimals = { 0_d, 0_., 0._1, 0._D, 0.1_d, }; +float[] floatBadDecimals = { 0_F, 0_.f, 0._1F, 0._f, 0.1_F, }; -double[] doubleBadDecimalExponents = { 0_e0, 0._E1, 1e_2, 2E3_, 3e4_d, }; -float[] floatBadDecimalExponents = { 0_e0f, 0._E1F, 1e_2f, 2E3_F, 3e4_f, }; +double[] doubleBadDecimalExponents = { 0_e0, 0._E1, 1e_2, 2E3_, 3e4_d, }; +float[] floatBadDecimalExponents = { 0_e0f, 0._E1F, 1e_2f, 2E3_F, 3e4_f, }; -double[] doubleBadHexExponents = { 0x0pA, 0x0_P0, 0x0._p1, 0x1P_2, 0x2p3_, 0x3P4_D, }; -float[] floatBadHexExponents = { 0x0pAF, 0x0_P0f, 0x0._p1F, 0x1P_2f, 0x2p3_F, 0x3P4_f, }; +double[] doubleBadHexExponents = { 0x0pA, 0x0_P0, 0x0._p1, 0x1P_2, 0x2p3_, 0x3P4_D, }; +float[] floatBadHexExponents = { 0x0pAF, 0x0_P0f, 0x0._p1F, 0x1P_2f, 0x2p3_F, 0x3P4_f, }; diff --git a/test/markup/java/titles.expect.txt b/test/markup/java/titles.expect.txt index 5162edadf6..af346c1e60 100644 --- a/test/markup/java/titles.expect.txt +++ b/test/markup/java/titles.expect.txt @@ -1,5 +1,5 @@ public class Greet { - public Either<Integer, String> f(int val) { + public Either<Integer, String> f(int val) { new Type(); if (val) { return getType(); @@ -10,9 +10,9 @@ } sealed interface Command permits LoginCommand { - void run(); + void run(); } non-sealed abstract class UserPluginCommand extends Command { - void runAsUser(); + void runAsUser(); }