Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 9 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {

// Import-block step for Spotless and its fixture tests (docs/code-format.md).
apply from: 'gradle/import-blocks.gradle'
apply from: 'gradle/line-limit.gradle'

def env = System.getenv()
def tag = providers.environmentVariable('TAG')
Expand Down Expand Up @@ -216,12 +217,18 @@ tasks.named('javadoc', Javadoc) {
}

// Formatting (docs/code-format.md): Eclipse JDT with the shared profile in
// gradle/java-formatter.xml (VS Code uses the same one), then the import-block step.
// gradle/java-formatter.xml (VS Code uses the same one), then the import-block step. Lines the
// formatter can't wrap below 80 may run to 120; `lineLimit` (gradle/line-limit.gradle) warns past
// that, without failing.
// Ratcheted: only files changed since the base branch are checked and formatted, so code is
// brought over to this style as it is next edited. Never reformat unrelated files in a change.
// spotlessCheck is part of check/build; `./gradlew spotlessApply` (or `format`) fixes files.
// `-PformatAll` drops the ratchet, so the whole tree is checked or formatted: use it once after
// changing the style, in its own commit (listed in .git-blame-ignore-revs).
spotless {
ratchetFrom 'origin/master-2.0-1.21.1-neo'
if (!providers.gradleProperty('formatAll').isPresent()) {
ratchetFrom 'origin/master-2.0-1.21.1-neo'
}
java {
target 'src/**/*.java'
eclipse('4.35')
Expand Down
33 changes: 23 additions & 10 deletions docs/code-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ Java follows the [Google Java Style Guide](https://google.github.io/styleguide/j
with these overrides:

- **Indentation: 4 spaces for both blocks and continuations.** Wrapped expressions and array
initializers add one four-space level, not eight spaces. Existing explicit line breaks are kept
where the formatter supports it. The 100-column limit and the other Google conventions (brace
style, one statement per line, naming, `@Override` always, no wildcard imports, ...) still apply.
initializers add one four-space level, not eight spaces.
- **Lines aim for 80 columns.** Parameter, argument and record component lists are packed up to
the limit and wrapped only where needed, never one per line; breaks that fit are rejoined.
- **Up to 120 columns for what can't be wrapped**, such as a long string constant. Past 120,
`./gradlew lineLimit` (part of `check`) warns with the file and line. It never fails the build:
some lines read worse split than long.
- **Wildcard imports are allowed**, static or not; in a mod they usually mean less code.
- **Keep methods short**: aim for 25 to 30 lines. This is a review guideline; no tool enforces it.
- The other Google conventions (brace style, one statement per line, naming, `@Override` always,
...) still apply.
- **Imports are split into blocks, one per second-level package, separated by a single blank
line.** Order:
1. All static imports, as one block.
Expand All @@ -15,7 +22,8 @@ with these overrides:
`mezz.jei`, `net.minecraft`, `net.neoforged`, `org.slf4j`, ...).
4. MMDLib's own imports (`zone.moddev.*`, the library and the companion) last, as one block.

Within a block, imports are ASCII-sorted. Example:
Within a block, imports are ASCII-sorted, so a wildcard comes before that package's single-type
imports. Example:

```java
import java.util.List;
Expand All @@ -35,11 +43,11 @@ with these overrides:
import zone.moddev.mc.lib.MMDLib;
```

## Code written before this style
## Changing the style

Most of the code predates this style: it uses google-java-format's 2-space indentation. It is
**not** reformatted in bulk. A file is brought over to the new style when it is next edited, as
part of that change, and only then. Don't reformat files a change doesn't otherwise touch.
Day to day, formatting only touches the files a change edits (see the ratchet below); don't
reformat files a change doesn't otherwise touch. When the style itself changes, reformat the whole
tree once, as described under Tools.

## Tools

Expand All @@ -53,11 +61,15 @@ Both are **ratcheted** from `origin/master-2.0-1.21.1-neo`: they only look at fi
from that branch, which is how older files are left alone until edited. Keep that branch fetched;
CI checks out with full history for this reason.

After changing the style, `./gradlew spotlessApply -PformatAll` drops the ratchet and formats the
whole tree. Commit that on its own and add the commit to `.git-blame-ignore-revs`, so `git blame`
skips it.

The Java formatter is Eclipse JDT with the `MMDLib` profile in `gradle/java-formatter.xml`. Imports
are regrouped afterwards by a custom step, `gradle/import-blocks.gradle`, since Spotless's own
`importOrder` can't express rule 3. The step refuses, with the line number, input it can't rewrite
safely: comments between imports, more than one import or a trailing comment on a line, and
wildcard imports. Its fixtures in `gradle/import-blocks/` run as `testImportBlocks`, part of
safely: comments between imports, and more than one import or a trailing comment on a line. Its
fixtures in `gradle/import-blocks/` run as `testImportBlocks`, part of
`check`.

### VS Code
Expand All @@ -69,6 +81,7 @@ The same profile formats in VS Code. `.vscode/` is not committed, so add this to
"java.format.settings.url": "gradle/java-formatter.xml",
"java.format.settings.profile": "MMDLib",
"[java]": {
"editor.rulers": [80, 120],
"editor.tabSize": 4,
"editor.insertSpaces": true
}
Expand Down
12 changes: 5 additions & 7 deletions gradle/import-blocks.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
* this is a custom step.
*
* Input the step can't rewrite safely is rejected with an error naming the line, never guessed at:
* comments between imports (they would lose their position), more than one import or a trailing
* comment on an import line, and wildcard imports (forbidden by Google style, which
* docs/code-format.md follows).
* comments between imports (they would lose their position), and more than one import or a
* trailing comment on an import line.
*
* Wildcard imports, static or not, are allowed (unlike Google style): they go in their package's
* block like any other import, and sort ahead of that package's single-type imports.
*
* Applied from build.gradle, this script exposes:
* - `importBlocksStep`: a closure for `spotless { java { custom 'importBlocks', ... } } }`;
Expand Down Expand Up @@ -89,10 +91,6 @@ class ImportBlocks {
+ "import statement with nothing else on the line, found: ${line.trim()}")
}
String name = match.group(2)
if (match.group(3) != null) {
throw new IllegalArgumentException("line ${lineNumber}: wildcard imports are not "
+ "allowed (Google style, docs/code-format.md): ${line.trim()}")
}
if (match.group(1) != null) {
statics.add("import static ${name};".toString())
} else {
Expand Down
1 change: 0 additions & 1 deletion gradle/import-blocks/static-wildcard.error.txt

This file was deleted.

13 changes: 13 additions & 0 deletions gradle/import-blocks/wildcard-with-single-types.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package zone.moddev.mc.lib;

import static net.minecraft.core.Direction.*;

import java.util.*;
import java.util.List;

import net.minecraft.world.item.*;
import net.minecraft.world.item.ItemStack;

import zone.moddev.mc.lib.api.*;

public final class Example {}
10 changes: 10 additions & 0 deletions gradle/import-blocks/wildcard-with-single-types.input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package zone.moddev.mc.lib;

import net.minecraft.world.item.ItemStack;
import static net.minecraft.core.Direction.*;
import zone.moddev.mc.lib.api.*;
import java.util.List;
import net.minecraft.world.item.*;
import java.util.*;

public final class Example {}
1 change: 0 additions & 1 deletion gradle/import-blocks/wildcard.error.txt

This file was deleted.

19 changes: 16 additions & 3 deletions gradle/java-formatter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,22 @@
<!-- Continuation values count indentation levels, not spaces: 1 * 4 = 4. -->
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<!-- Rejoin earlier breaks that fit (such as one parameter per line), up to lineSplit. -->
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<!-- 16 = wrap where necessary: lists are packed to the line limit, never one per line. -->
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
Expand Down
34 changes: 34 additions & 0 deletions gradle/line-limit.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Soft line-length limit (docs/code-format.md). The Eclipse profile wraps at 80 columns, but it
* never splits what can't be split, such as a long string constant, and leaves such a line long.
* Up to 120 columns is fine for those. Past that, `lineLimit` warns, naming the file and line; it
* never fails the build, since some lines can't be shortened without hurting readability.
*
* Applied from build.gradle; `check` runs it.
*/

def lineLimitSources = fileTree('src') { include '**/*.java' }

tasks.register('lineLimit') {
group = 'verification'
description = 'Warns about Java lines longer than 120 columns (never fails).'
// No outputs: always runs, so the warnings are shown on every check, not only the first.
doLast {
int count = 0
lineLimitSources.files.sort().each { File file ->
file.readLines('UTF-8').eachWithIndex { String line, int index ->
if (line.length() > 120) {
def path = project.relativePath(file)
logger.warn("${path}:${index + 1}: warning: line is ${line.length()} columns"
+ ' (limit 120)')
count++
}
}
}
if (count > 0) logger.warn("${count} line(s) over 120 columns")
}
}

tasks.named('check') {
dependsOn 'lineLimit'
}
Loading
Loading