Subject: 31.0.50; java-ts-mode. Issues with Indentation

From: Artem <[email-masked]>
Date: Fri, 27 Dec 2024 18:34:45 +0300

Hello

I've identified several issues with indentation in java-ts-mode where it
doesn't work as expected. Let me first clarify
what I consider "expected" behavior - there are things that are "GOOD",
"BAD but allowed", and "Opinion-based.

Here are the specific problems:

1) Chaining Methods in the Stream API and Lambda Expressions
Example 1:
class Foo {
    void Foo() {
        List<Customer> customers = customer
        | <-- Actual (BAD)
               | <-- Expected (GOOD) (8 spaces)
    }
}
When continuing the statement
        List<Customer> customers = customer
        .stream
and then adding closing parentheses        
        List<Customer> customers = customer
           .stream() <-- The method filter will move to 4 spaces automatically
        .filter <-- without parentheses 
            .filter() <-- closing bracet and method moving to 4 spaces

This behavior is problematic. In java-mode, this does not occur.IntelliJ
IDEA uses 8 spaces for method chains,which makes the code more readable.
While some examples use 2 spaces (e.g., for web snippets),in production
environments, 8 spaces are more common. This should ideally be customizable for end users.

Moreover, the current indentation is hardcoded and doesn’t allow
flexibility. For instance, in python-ts-mode, pressing TAB allows you to
adjust constructions more freely.
This level of flexibility would be beneficial in this context

This inflexibility prevents writing common patterns like:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/admin/**").hasAuthority("ADMIN")
                .antMatchers("/user").hasAnyAuthority("USER", "ADMIN")
                .antMatchers("/", "/index").permitAll()
Example 2:

The following looks correct -

public class FloodFill {
    public static void main(String[] args) {
        List<Foo> stream = students.stream()
                .filter(item -> {
                    return item.getValue() > 100 &&
                           item.isActive();
                })
                .map()
                .collect();
    }
}

But java-ts-mode produces:

public class FloodFill {
    public static void main(String[] args) {
        List<Foo> stream = students.stream()
            .filter(item -> {
            return item.getValue() > 100 &&
                   item.isActive();
        })
            .map()
            .collect();
    }
}

2) Inner Classes
Example 1:
public class Outer {
class Inner {| <-- cursor here moves Inner class unexpectedly

    }
}
Example 2:
public class Outer {
    class Inner { // ???
        | <-- cursor here.           
    }
}

Why does this happen? I did not request this behavior. While Example 1
demonstrates bad code style, it is technically valid. Such "magical"
formatting should be handled by a Java formatter, not by Emacs or
Tree-sitter rules.
IntelliJ IDEA does not apply such formatting; it leaves this task to the formatter.

Example 3:
public class Outer {
class Inner{
    void foo(){
    }|<--start position. RET
    |<-- expected position
       |<-- actual
    }
}

If Inner class has incorrect indentation, subsequent code will also be incorrectly indented.

3) for, if, else if, while, do-while without braces
public class While {
    {
        while ()
            | <-- Expected      
        | <-- Actual
    }
}
Although this is bad coding style, it’s allowed and compiles correctly.

4) Java 15 text blocks
Text blocks are not properly handled

public class TextBlocks {
    System.out.println(ctx.fetch("""
        SELECT table_schema, count(*)
        FROM information_schema.tables
        """));
}

- Triple quotes handling (should electric-pair-mode be enhanced?)
- Text block alignment is opinion-based and should be adjustable with TAB
- New SQL expressions should be sticky
It seems such multiline strings also do not work well, for example:
"'The time has come,' the Walrus said,\n" +

5) Broken Syntax Highlighting

public class Outer {
   HELLO EMACS <-- Write something here
class Inner{ <-- This class will not be highlighted
    void foo(){
    }

    }
}
Tree-sitter should ignore such uncommon cases to maintain syntax highlighting

6) Multiple Parameters in Methods
Example 1
public record StudentRecord(
  String firstName, 
  String lastName, 
  Long studentId, 
  String email)
Example 2
public String filterData(@RequestParam(required = false) String name,
                         @RequestParam(required = false) String name,
                         @RequestParam(required = false) Integer age
)
java-ts-mode fails to handle these cases correctly.

Desired Fontification (Out of the Box):
- Annotations (@Annotations)
- Diamond Brackets (<>)
- Constants, Static Variables, Enum Variables should be highlighted with
distinct colors and optionally italic font
- Unused Variables or Classes (Grayed Out)
- Unused variables, unused classes, etc., highlighted in gray. Not sure if this can be achieved
with Tree-sitter. Anyway, with Flymake + Eglot, it currently works in a somewhat clunky manner.

Example
public class TextBlocks {
    enum AnEnum { CONST1, CONST2 } <-- No effect for unused AnEnum.
    public static final String HELLO ="HELLO";

    public static void main(String[] args) {
        int i = 0; <-- Flymake identifies as unused but looks unpolished. 
        System.out.println(HELLO);
    }
}

Overall:

I may have missed some aspects, but as it stands, Emacs is not
comfortable for Java development with these issues.

Some information that might be helpful:

- https://github.com/dakrone/eos/blob/dd8aa3a25b496397dd0162d229de571989668619/eos-java.org?plain=1#L30
.Not sure why this Elasticsearch developer created so many custom rules for indentation.
- https://github.com/Michael-Allan/Java_Mode_Tamed A major Java mode with sensible fontification.
- JetBrains Intellij IDEA Community Edition
  - File>Settings>Editor>Color Scheme>Java Java for understanding which colors are needed and what is missing.
  - Editor>Color Scheme>Java>Code Style>Java for indentation settings.