diff --git a/assets/highlighting-tests/java.java b/assets/highlighting-tests/java.java new file mode 100644 index 00000000000..36c0b1df367 --- /dev/null +++ b/assets/highlighting-tests/java.java @@ -0,0 +1,131 @@ +// Line comment +/* Block comment */ +/** Javadoc @param x @return y */ + +package com.example.highlighting; + +import java.util.List; +import java.util.ArrayList; +import static java.lang.Math.max; +import java.util.*; + +const int CONST = 0; +goto label; + +open module com.example { + requires transitive java.base; + exports com.example.pkg to other.module; + opens com.example.internal; + provides Greeter with Dog; + uses Greeter; +} + +enum Color { RED, GREEN, BLUE } + +record Point(int x, int y) { + Point { + if (x < 0) throw new IllegalArgumentException(); + } +} + +sealed interface Shape permits Circle {} +non-sealed class Circle implements Shape {} + +@FunctionalInterface +interface Greeter> { + String greet(T name); + default boolean ok() { return true; } +} + +@Deprecated +public abstract strictfp class Animal implements Comparable { + // Numbers + static final int I = 42, HEX = 0xFF, BIN = 0b1010, OCT = 077, US = 1_000_000; + static final long L = 0xCAFE_BABEL; + static final double D = 3.14, E = 1.5e-3, HALF = .5; + static final float F = 3.14f; + private byte b; + protected short s; + private volatile transient int flags; + + // Strings, char, escapes, text block + String str = "quotes \" \n \t \\ \u00e9"; + char c = '\n'; + String block = """ + text block + with "quotes" + """; + + Animal() { super(); } + + native void nativeMethod(); + + abstract String speak() throws Exception; + + @Override + public synchronized int compareTo(Animal o) { + return this.flags - o.flags; + } +} + +final class Dog extends Animal { + String speak() { return "bark"; } + + // Constants, control flow + void flow() { + boolean t = true, f = false; + Object n = null; + + if (t) { + } else if (f) { + } else { + } + + for (int i = 0; i < 10; i++) { + if (i == 5) continue; + if (i == 8) break; + } + for (int x : new int[] { 1, 2, 3 }) {} + while (f) {} + do {} while (f); + + try { + throw new RuntimeException("oops"); + } catch (RuntimeException e) { + } finally { + } + + assert t : "message"; + return; + } + + // var, switch expression, yield, pattern guards, instanceof, lambda + U run(Object obj) { + var list = new ArrayList(); + int r = switch (list.size()) { + case 1 -> 10; + case 2 -> { yield 20; } + default -> 0; + }; + String desc = switch (obj) { + case Integer i when i > 0 -> "pos"; + case String p -> "str"; + default -> "other"; + }; + if (obj instanceof String p) { + System.out.println(p.length()); + } + Greeter g = name -> "Hi " + name; + return null; + } +} + +// Function calls +class Main { + public static void main(String[] args) { + System.out.println("hello"); + int v = Integer.parseInt("42"); + max(1, 2); + new Dog().speak(); + } +} diff --git a/crates/edit/src/buffer/mod.rs b/crates/edit/src/buffer/mod.rs index 9277192e500..468eb6898f1 100644 --- a/crates/edit/src/buffer/mod.rs +++ b/crates/edit/src/buffer/mod.rs @@ -2187,6 +2187,8 @@ impl TextBuffer { HighlightKind::MarkupList => Some(IndexedColor::BrightBlue), HighlightKind::MarkupStrikethrough => None, HighlightKind::MetaHeader => Some(IndexedColor::BrightBlue), + HighlightKind::StorageAnnotation => Some(IndexedColor::Cyan), + HighlightKind::StorageType => Some(IndexedColor::Cyan), }; let attr = match curr.kind { HighlightKind::MarkupBold => Some(Attributes::Bold), diff --git a/crates/lsh/definitions/java.lsh b/crates/lsh/definitions/java.lsh new file mode 100644 index 00000000000..8c664ef8ee1 --- /dev/null +++ b/crates/lsh/definitions/java.lsh @@ -0,0 +1,55 @@ +#[display_name="Java"] +#[path="**/*.java"] +pub fn java() { + until /$/ { + yield other; + + if /\/\/.*/ { + yield comment; + } else if /\/\*/ { + loop { + yield comment; + await input; + if /\*\// { + yield comment; + break; + } + } + } else if /"""/ { + loop { + yield string; + await input; + if /"""/ { + yield string; + break; + } + } + } else if /'/ { + single_quote_string(); + } else if /"/ { + double_quote_string(); + } else if /@[\w.]+/ { + yield storage.annotation; + } else if /(?:break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\>/ { + yield keyword.control; + } else if /(?:abstract|assert|class|const|enum|exports|extends|final|goto|implements|import|instanceof|interface|module|native|new|non-sealed|open|opens|package|permits|private|protected|provides|public|record|requires|sealed|static|strictfp|super|synchronized|this|throws|transient|transitive|uses|var|volatile|with|yield)\>/ { + yield keyword.other; + } else if /(?:true|false|null)\>/ { + yield constant.language; + } else if /(?:boolean|byte|char|double|float|int|long|short|void)\>/ { + yield storage.type; + } else if /(?i:-?(?:0x[\da-f_]+|0b[01_]+|[\d_]+\.?[\d_]*|\.[\d_]+)(?:e[+-]?[\d_]+)?[dfl]?)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + } else if /(\w+)\s*\(/ { + yield $1 as method; + } else if /\w+/ { + // Gobble word chars to align the next iteration on a word boundary. + } + + yield other; + } +}