diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 000000000..1338cd77d --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,34 @@ +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + time: "07:00" + groups: + google-annotations: + patterns: + - "com.google.auto.value:*" + - "com.google.auto.service:*" + - "com.google.errorprone:*" + test-dependencies: + patterns: + - "junit:*" + - "com.google.truth:*" + - "com.google.guava:guava-testlib" + maven-plugins: + patterns: + - "org.apache.maven.plugins:*" + - "org.apache.felix:maven-bundle-plugin" + - "org.codehaus.mojo:*" + - "org.graalvm.buildtools:*" + - "org.sonatype.central:*" + - "com.google.code.maven-replacer-plugin:*" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + time: "07:00" \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 000000000..cc1e136eb --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,73 @@ +# Copyright 2020 The Google Java Format Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + test-OpenJDK: + name: "JDK ${{ matrix.java }} on ${{ matrix.os }}" + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + java: [25] + experimental: [false] + include: + # Only test on MacOS and Windows with a single recent JDK to avoid a + # combinatorial explosion of test configurations. + - os: macos-latest + java: 25 + experimental: false + - os: windows-latest + java: 25 + experimental: false + - os: ubuntu-latest + java: EA + experimental: true + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} + steps: + - name: Cancel previous + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{ github.token }} + - name: "Check out repository" + uses: actions/checkout@v5 + - name: "Set up JDK ${{ matrix.java }} from jdk.java.net" + if: ${{ matrix.java == 'EA' }} + uses: oracle-actions/setup-java@v1 + with: + website: jdk.java.net + release: ${{ matrix.java }} + - name: "Set up JDK ${{ matrix.java }} from Zulu" + if: ${{ matrix.java != 'EA' && matrix.java != 'GraalVM' }} + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: "zulu" + cache: "maven" + - name: "Install" + shell: bash + run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - name: "Test" + shell: bash + run: mvn test -B diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 735cccaf7..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2020 The Google Java Format Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: CI - -on: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - test-OpenJDK: - name: "JDK ${{ matrix.java }} on ${{ matrix.os }}" - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - java: [25, 21] - experimental: [false] - include: - # Only test on MacOS and Windows with a single recent JDK to avoid a - # combinatorial explosion of test configurations. - - os: macos-latest - java: 25 - experimental: false - - os: windows-latest - java: 25 - experimental: false - - os: ubuntu-latest - java: EA - experimental: true - runs-on: ${{ matrix.os }} - continue-on-error: ${{ matrix.experimental }} - steps: - - name: Cancel previous - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - name: "Check out repository" - uses: actions/checkout@v4 - - name: "Set up JDK ${{ matrix.java }} from jdk.java.net" - if: ${{ matrix.java == 'EA' }} - uses: oracle-actions/setup-java@v1 - with: - website: jdk.java.net - release: ${{ matrix.java }} - - name: "Set up JDK ${{ matrix.java }} from Zulu" - if: ${{ matrix.java != 'EA' && matrix.java != 'GraalVM' }} - uses: actions/setup-java@v4 - with: - java-version: ${{ matrix.java }} - distribution: "zulu" - cache: "maven" - - name: "Install" - shell: bash - run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V - - name: "Test" - shell: bash - run: mvn test -B - - test-GraalVM: - name: "GraalVM on ${{ matrix.os }}" - strategy: - fail-fast: false - matrix: - # Use "oldest" available ubuntu-* instead of -latest, - # see https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories; - # due to https://github.com/google/google-java-format/issues/1072. - os: [ubuntu-22.04, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - continue-on-error: true - steps: - - name: Cancel previous - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - name: "Check out repository" - uses: actions/checkout@v4 - - name: "Set up GraalVM ${{ matrix.java }}" - uses: graalvm/setup-graalvm@v1 - with: - java-version: "25" - distribution: "graalvm-community" - github-token: ${{ secrets.GITHUB_TOKEN }} - native-image-job-reports: "true" - cache: "maven" - - name: "Native Build" - run: mvn -Pnative -DskipTests package -pl core -am - - name: "Native Test" - # Bash script for testing won't work on Windows - # TODO: Anyone reading this wants to write a *.bat or *.ps1 equivalent? - if: ${{ matrix.os != 'windows-latest' }} - run: util/test-native.sh - - publish_snapshot: - name: "Publish snapshot" - needs: test-OpenJDK - if: github.event_name == 'push' && github.repository == 'google/google-java-format' && github.ref == 'refs/heads/master' - runs-on: ubuntu-latest - steps: - - name: "Check out repository" - uses: actions/checkout@v4 - - name: "Set up JDK 21" - uses: actions/setup-java@v4 - with: - java-version: 21 - distribution: "zulu" - cache: "maven" - server-id: sonatype-nexus-snapshots - server-username: CI_DEPLOY_USERNAME - server-password: CI_DEPLOY_PASSWORD - - name: "Publish" - env: - CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} - CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} - run: mvn -pl '!eclipse_plugin' source:jar deploy -B -DskipTests=true -Dinvoker.skip=true -Dmaven.javadoc.skip=true diff --git a/.github/workflows/github-release.yaml b/.github/workflows/github-release.yaml new file mode 100644 index 000000000..9c9be8f2c --- /dev/null +++ b/.github/workflows/github-release.yaml @@ -0,0 +1,34 @@ +name: Release on GitHub + +on: + push: + tags: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + + steps: + - uses: actions/checkout@v5 + + - name: "Set up JDK 25 from Zulu" + uses: actions/setup-java@v4 + with: + java-version: 25 + distribution: "zulu" + + - name: Build with Maven + run: mvn verify -DskipTests=true -Dmaven.javadoc.skip=true -B -V + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "${{ github.ref_name }}" \ + --title "${{ github.ref_name }}" \ + --generate-notes \ + core/target/*-all-deps.jar \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 43dd0ed29..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2020 The Google Java Format Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Release google-java-format - -on: - workflow_dispatch: - inputs: - version: - description: "version number for this release." - required: true - -jobs: - build-maven-jars: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up JDK - uses: actions/setup-java@v4 - with: - java-version: 21 - distribution: "zulu" - cache: "maven" - server-id: central - server-username: CI_DEPLOY_USERNAME - server-password: CI_DEPLOY_PASSWORD - gpg-private-key: ${{ secrets.GPG_SIGNING_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - - name: Bump Version Number - run: | - mvn --no-transfer-progress versions:set versions:commit -DnewVersion="${{ github.event.inputs.version }}" - mvn --no-transfer-progress versions:set versions:commit -DnewVersion="${{ github.event.inputs.version }}" -pl eclipse_plugin - mvn tycho-versions:update-eclipse-metadata -pl eclipse_plugin - git ls-files | grep -E '(pom.xml|MANIFEST.MF)$' | xargs git add - git config --global user.email "${{ github.actor }}@users.noreply.github.com" - git config --global user.name "${{ github.actor }}" - git commit -m "Release google-java-format ${{ github.event.inputs.version }}" - git tag "v${{ github.event.inputs.version }}" - echo "TARGET_COMMITISH=$(git rev-parse HEAD)" >> $GITHUB_ENV - git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/google/google-java-format.git - - - name: Deploy to Sonatype staging - env: - CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} - CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - run: mvn --no-transfer-progress -pl '!eclipse_plugin' -P sonatype-oss-release clean deploy -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" - - - name: Build Eclipse plugin - run: mvn --no-transfer-progress -pl 'eclipse_plugin' verify gpg:sign -DskipTests=true -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" - - - name: Push tag - run: | - git push origin "v${{ github.event.inputs.version }}" - - - name: Add Artifacts to Release Entry - uses: softprops/action-gh-release@v0.1.14 - with: - draft: true - name: ${{ github.event.input.version }} - tag_name: "v${{ github.event.inputs.version }}" - target_commitish: ${{ env.TARGET_COMMITISH }} - files: | - core/target/google-java-format-*.jar - eclipse_plugin/target/google-java-format-eclipse-plugin-*.jar - - build-native-image: - name: "Build GraalVM native-image on ${{ matrix.os }}" - runs-on: ${{ matrix.os }} - permissions: - contents: write - needs: build-maven-jars - strategy: - matrix: - # Use "oldest" available ubuntu-* instead of -latest, - # see https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories; - # due to https://github.com/google/google-java-format/issues/1072. - os: [ubuntu-22.04, ubuntu-22.04-arm, macos-latest, windows-latest] - env: - # NB: Must keep the keys in this inline JSON below in line with the os: above! - SUFFIX: ${{fromJson('{"ubuntu-22.04":"linux-x86-64", "ubuntu-22.04-arm":"linux-arm64", "macos-latest":"darwin-arm64", "windows-latest":"windows-x86-64"}')[matrix.os]}} - EXTENSION: ${{ matrix.os == 'windows-latest' && '.exe' || '' }} - steps: - - name: "Check out repository" - uses: actions/checkout@v4 - - name: "Set up GraalVM" - uses: graalvm/setup-graalvm@v1 - with: - java-version: "25" - distribution: "graalvm-community" - github-token: ${{ secrets.GITHUB_TOKEN }} - native-image-job-reports: "true" - cache: "maven" - - name: Bump Version Number - run: mvn --no-transfer-progress versions:set versions:commit -DnewVersion="${{ github.event.inputs.version }}" - - name: "Native" - run: mvn -Pnative -DskipTests package -pl core -am - - name: "Move outputs" - run: cp core/target/google-java-format${{ env.EXTENSION }} google-java-format_${{ env.SUFFIX }}${{ env.EXTENSION }} - - name: "Upload native-image" - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - run: gh release upload "v${{ github.event.inputs.version }}" "google-java-format_${{ env.SUFFIX }}${{ env.EXTENSION }}" diff --git a/.github/workflows/sync-from-upstream.yaml b/.github/workflows/sync-from-upstream.yaml new file mode 100644 index 000000000..85383cf2b --- /dev/null +++ b/.github/workflows/sync-from-upstream.yaml @@ -0,0 +1,64 @@ +name: Sync from Upstream Release + +on: + schedule: + - cron: '0 6 * * *' + workflow_dispatch: + pull_request: + types: [closed] + branches: [master] + +permissions: + contents: write + pull-requests: write + +jobs: + sync: + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.UPSTREAM_SYNC_PAT }} + + - name: Check and sync upstream release + env: + GH_TOKEN: ${{ secrets.UPSTREAM_SYNC_PAT }} + run: | + LATEST=$(gh api repos/google/google-java-format/releases/latest --jq '.tag_name') + + if git tag -l | grep -qx "$LATEST"; then + echo "Already synced $LATEST" + exit 0 + fi + + git config user.email "actions@github.com" + git config user.name "GitHub Actions" + + git remote add upstream https://github.com/google/google-java-format.git + git fetch upstream --tags + git checkout -B sync-upstream "$LATEST" + git push -fu origin sync-upstream + + gh pr create --head sync-upstream --base master \ + --title "Sync upstream release $LATEST" \ + --body "Sync [upstream $LATEST](https://github.com/google/google-java-format/releases/tag/$LATEST)" \ + || gh pr edit --title "Sync upstream release $LATEST" + + tag: + if: github.event.pull_request.merged && startsWith(github.event.pull_request.title, 'Sync upstream release ') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + token: ${{ secrets.UPSTREAM_SYNC_PAT }} + + - name: Create tag + run: | + TAG="${{ github.event.pull_request.title }}" + TAG="${TAG#Sync upstream release }" + git config user.email "actions@github.com" + git config user.name "GitHub Actions" + git tag "$TAG" + git push origin "$TAG" \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 0f5b8cf48..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -Want to contribute? Great! First, read this page (including the small print at -the end). - -### Before you contribute - -Before we can use your code, you must sign the [Google Individual Contributor -License -Agreement](https://developers.google.com/open-source/cla/individual?csw=1) -(CLA), which you can do online. The CLA is necessary mainly because you own the -copyright to your changes, even after your contribution becomes part of our -codebase, so we need your permission to use and distribute your code. We also -need to be sure of various other things—for instance that you'll tell us if you -know that your code infringes on other people's patents. You don't have to sign -the CLA until after you've submitted your code for review and a member has -approved it, but you must do it before we can put your code into our codebase. -Before you start working on a larger contribution, you should get in touch with -us first through the issue tracker with your idea so that we can help out and -possibly guide you. Coordinating up front makes it much easier to avoid -frustration later on. - -### Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. - -### The small print - -Contributions made by corporations are covered by a different agreement than the -one above, the Software Grant and Corporate Contributor License Agreement. diff --git a/FORK.md b/FORK.md new file mode 100644 index 000000000..f3967696b --- /dev/null +++ b/FORK.md @@ -0,0 +1,39 @@ +# Configurable Java Format + +[![Coverity Scan Build Status](https://scan.coverity.com/projects/31383/badge.svg)](https://scan.coverity.com/projects/configurable-java-format) + +This is a fork of `google-java-format` with extended configurability. This project is not affiliated with Google. + +## Changes from the Original + +- Removed all plugins – this fork contains only the core formatter. +- Added the `--width` option to specify a custom page width. +- Supports setting options via environment variables. + +## Usage + +```sh +# Help +java -jar configurable-java-format.jar --help + +# Format +java -jar configurable-java-format.jar --width=120 File.java + +# Format in place +java -jar configurable-java-format.jar --width=120 -i File.java +``` + +Alternatively, options can be passed as environment variables: + +```sh +export JAVA_FORMAT_WIDTH=120 +java -jar configurable-java-format.jar File.java +``` + +## Acknowledgments + +Thanks to [MrDolch](https://github.com/MrDolch) for his contributions. + +## License + +This project is based on `google-java-format` and follows the same licensing terms. \ No newline at end of file diff --git a/LICENSE b/LICENSE index 6c4ca5a2c..27cce7e4f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,3 @@ -The following Apache 2.0 license applies to all code in this package except -google-java-format-diff.py. - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/core/pom.xml b/core/pom.xml index 3b106cf71..26cad2080 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,19 +15,17 @@ ~ limitations under the License. --> - - 4.0.0 - - com.google.googlejavaformat - google-java-format-parent - HEAD-SNAPSHOT - + + 4.0.0 + + io.github.mrdolch.formatter + configurable-java-format-parent + 2026.1.0 + - google-java-format + configurable-java-format - Google Java Format + Configurable Java Format A Java source code formatter that follows Google Java Style. @@ -67,24 +65,13 @@ junit junit - - com.google.guava - guava-testlib - com.google.truth truth - com.google.truth.extensions - truth-java8-extension - test - - - com.google.testing.compile - compile-testing - 0.19 - test + com.google.guava + guava-testlib @@ -93,13 +80,13 @@ maven-javadoc-plugin - 17 + 21 UTF-8 UTF-8 UTF-8 https://guava.dev/releases/${guava.version}/api/docs/ - https://docs.oracle.com/en/java/javase/11/docs/api + https://docs.oracle.com/en/java/javase/21/docs/api --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED,com.google.googlejavaformat @@ -123,7 +110,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + 3.6.0 shade-all-deps @@ -195,7 +182,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.3.0 + 3.6.1 add-source @@ -215,8 +202,8 @@ org.apache.maven.plugins maven-compiler-plugin - 17 - 17 + 21 + 21 @@ -230,7 +217,7 @@ org.graalvm.buildtools native-maven-plugin - 0.10.0 + 0.11.0 true diff --git a/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptions.java b/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptions.java index e794a1815..674c4f75c 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptions.java +++ b/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptions.java @@ -29,6 +29,7 @@ * @param offsets Character offsets for partial formatting, paired with {@code lengths}. * @param lengths Partial formatting region lengths, paired with {@code offsets}. * @param aosp Use AOSP style instead of Google Style (4-space indentation). + * @param width max line length. * @param version Print the version. * @param help Print usage information. * @param stdin Format input from stdin. @@ -47,6 +48,7 @@ record CommandLineOptions( ImmutableList offsets, ImmutableList lengths, boolean aosp, + int width, boolean version, boolean help, boolean stdin, @@ -71,6 +73,7 @@ static Builder builder() { .reflowLongStrings(true) .formatJavadoc(true) .aosp(false) + .width(100) .version(false) .help(false) .stdin(false) @@ -107,6 +110,8 @@ default Builder addLength(Integer length) { Builder aosp(boolean aosp); + Builder width(int width); + Builder version(boolean version); Builder help(boolean help); diff --git a/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptionsParser.java b/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptionsParser.java index f5ce703e8..cba8086ee 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptionsParser.java +++ b/core/src/main/java/com/google/googlejavaformat/java/CommandLineOptionsParser.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; /** A parser for {@link CommandLineOptions}. */ final class CommandLineOptionsParser { @@ -44,6 +45,7 @@ static CommandLineOptions parse(Iterable options) { CommandLineOptions.Builder optionsBuilder = CommandLineOptions.builder(); List expandedOptions = new ArrayList<>(); expandParamsFiles(options, expandedOptions); + expandEnvironmentParams(System.getenv(), expandedOptions); Iterator it = expandedOptions.iterator(); // Accumulate the ranges in a mutable builder to merge overlapping ranges, // which ImmutableRangeSet doesn't support. @@ -72,6 +74,7 @@ static CommandLineOptions parse(Iterable options) { case "--offset", "-offset" -> optionsBuilder.addOffset(parseInteger(it, flag, value)); case "--length", "-length" -> optionsBuilder.addLength(parseInteger(it, flag, value)); case "--aosp", "-aosp", "-a" -> optionsBuilder.aosp(true); + case "--width", "-width", "-w" -> optionsBuilder.width(parseInteger(it, flag, value)); case "--version", "-version", "-v" -> optionsBuilder.version(true); case "--help", "-help", "-h" -> optionsBuilder.help(true); case "--fix-imports-only" -> optionsBuilder.fixImportsOnly(true); @@ -166,4 +169,21 @@ private static void expandParamsFiles(Iterable args, List expand } } } + + static void expandEnvironmentParams( + Map environment, List expandedOptions) { + String prefix = "JAVA_FORMAT_"; + environment.forEach( + (key, value) -> { + if (key.startsWith(prefix)) { + if (!"FALSE".equalsIgnoreCase(value)) { + expandedOptions.add( + "-" + key.substring(prefix.length()).toLowerCase().replace('_', '-')); + if (!"TRUE".equalsIgnoreCase(value)) { + expandedOptions.add(value); + } + } + } + }); + } } diff --git a/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java b/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java index 7cec1fca8..688650be5 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java +++ b/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java @@ -71,11 +71,11 @@ public Result call() { return Result.create(path, input, fixImports(input), /* exception= */ null); } - Formatter formatter = new Formatter(options); + Formatter formatter = new Formatter(options); String formatted = formatter.formatSource(input, characterRanges(input).asRanges()); formatted = fixImports(formatted); if (parameters.reflowLongStrings()) { - formatted = StringWrapper.wrap(Formatter.MAX_LINE_LENGTH, formatted, formatter); + formatted = StringWrapper.wrap(options.maxLineWidth(), formatted, formatter); } return Result.create(path, input, formatted, /* exception= */ null); } catch (FormatterException e) { diff --git a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java index ff87eaab7..8a2ab73f4 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java +++ b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java @@ -14,7 +14,6 @@ package com.google.googlejavaformat.java; - import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import com.google.common.collect.Range; @@ -73,10 +72,6 @@ @Immutable public final class Formatter { - public static final int MAX_LINE_LENGTH = 100; - - static final Range EMPTY_RANGE = Range.closedOpen(-1, -1); - private final JavaFormatterOptions options; /** A new Formatter instance with default options. */ @@ -88,6 +83,9 @@ public Formatter(JavaFormatterOptions options) { this.options = options; } + public int getMaxLineLength() { + return this.options.maxLineWidth(); + } /** * Construct a {@code Formatter} given a Java compilation unit. Parses the code; builds a {@link * JavaInput} and the corresponding {@link JavaOutput}. @@ -114,8 +112,9 @@ static void format(final JavaInput javaInput, JavaOutput javaOutput, JavaFormatt visitor.scan(unit, null); builder.sync(javaInput.getText().length()); builder.drain(); - Doc doc = new DocBuilder().withOps(builder.build()).build(); - doc.computeBreaks(javaOutput.getCommentsHelper(), MAX_LINE_LENGTH, new Doc.State(+0, 0)); + final Doc doc = new DocBuilder().withOps(builder.build()).build(); + doc.computeBreaks( + javaOutput.getCommentsHelper(), options.maxLineWidth(), new Doc.State(+0, 0)); doc.write(javaOutput); javaOutput.flush(); } diff --git a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java deleted file mode 100644 index 3c315aaf1..000000000 --- a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2021 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import static com.google.common.collect.Sets.toImmutableEnumSet; - -import com.google.auto.service.AutoService; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.Arrays; -import java.util.Set; -import javax.lang.model.SourceVersion; -import javax.tools.Tool; - -/** Provide a way to be invoked without necessarily starting a new VM. */ -@AutoService(Tool.class) -public class GoogleJavaFormatTool implements Tool { - @Override - public String name() { - return "google-java-format"; - } - - @Override - public Set getSourceVersions() { - return Arrays.stream(SourceVersion.values()).collect(toImmutableEnumSet()); - } - - @Override - public int run(InputStream in, OutputStream out, OutputStream err, String... args) { - PrintStream outStream = new PrintStream(out); - PrintStream errStream = new PrintStream(err); - try { - return Main.main(in, outStream, errStream, args); - } catch (RuntimeException e) { - errStream.print(e.getMessage()); - errStream.flush(); - return 1; // pass non-zero value back indicating an error has happened - } - } -} diff --git a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java deleted file mode 100644 index 438eac596..000000000 --- a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2021 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import com.google.auto.service.AutoService; -import java.io.PrintWriter; -import java.util.spi.ToolProvider; - -/** Provide a way to be invoked without necessarily starting a new VM. */ -@AutoService(ToolProvider.class) -public class GoogleJavaFormatToolProvider implements ToolProvider { - @Override - public String name() { - return "google-java-format"; - } - - @Override - public int run(PrintWriter out, PrintWriter err, String... args) { - try { - return Main.main(System.in, out, err, args); - } catch (RuntimeException e) { - err.print(e.getMessage()); - err.flush(); - return 1; // pass non-zero value back indicating an error has happened - } - } -} diff --git a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatVersion.java.template b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatVersion.java.template index 88706fbf1..7e1b1dbcf 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatVersion.java.template +++ b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatVersion.java.template @@ -19,4 +19,8 @@ class GoogleJavaFormatVersion { static String version() { return "%VERSION%"; } + + static String versionString() { + return "google-java-format: Version " + version(); + } } diff --git a/core/src/main/java/com/google/googlejavaformat/java/ImportOrderer.java b/core/src/main/java/com/google/googlejavaformat/java/ImportOrderer.java index 375a3289b..c5a0b1545 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/ImportOrderer.java +++ b/core/src/main/java/com/google/googlejavaformat/java/ImportOrderer.java @@ -13,9 +13,6 @@ */ package com.google.googlejavaformat.java; -import static com.google.common.collect.Iterables.getLast; -import static com.google.common.primitives.Booleans.trueFirst; - import com.google.common.base.CharMatcher; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; @@ -26,6 +23,7 @@ import com.google.googlejavaformat.java.JavaFormatterOptions.Style; import com.google.googlejavaformat.java.JavaInput.Tok; import com.sun.tools.javac.parser.Tokens.TokenKind; + import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -33,6 +31,9 @@ import java.util.function.BiFunction; import java.util.stream.Stream; +import static com.google.common.collect.Iterables.getLast; +import static com.google.common.primitives.Booleans.trueFirst; + /** Orders imports in Java source code. */ public class ImportOrderer { @@ -44,8 +45,8 @@ public class ImportOrderer { * * @throws FormatterException if the input could not be parsed. */ - public static String reorderImports(String text, Style style) throws FormatterException { - ImmutableList toks = JavaInput.buildToks(text, CLASS_START); + public static String reorderImports(final String text, final Style style) throws FormatterException { + final ImmutableList toks = JavaInput.buildToks(text, CLASS_START); return new ImportOrderer(text, toks, style).reorderImports(); } @@ -58,42 +59,42 @@ public static String reorderImports(String text, Style style) throws FormatterEx * @throws FormatterException if the input could not be parsed. */ @Deprecated - public static String reorderImports(String text) throws FormatterException { + public static String reorderImports(final String text) throws FormatterException { return reorderImports(text, Style.GOOGLE); } private String reorderImports() throws FormatterException { - int firstImportStart; - Optional maybeFirstImport = findIdentifier(0, IMPORT_OR_CLASS_START); + final int firstImportStart; + final Optional maybeFirstImport = findIdentifier(0, IMPORT_OR_CLASS_START); if (!maybeFirstImport.isPresent() || !tokenAt(maybeFirstImport.get()).equals("import")) { // No imports, so nothing to do. return text; } firstImportStart = maybeFirstImport.get(); - int unindentedFirstImportStart = unindent(firstImportStart); + final int unindentedFirstImportStart = unindent(firstImportStart); - ImportsAndIndex imports = scanImports(firstImportStart); - int afterLastImport = imports.index; + final ImportsAndIndex imports = scanImports(firstImportStart); + final int afterLastImport = imports.index; // Make sure there are no more imports before the next class (etc) definition. - Optional maybeLaterImport = findIdentifier(afterLastImport, IMPORT_OR_CLASS_START); + final Optional maybeLaterImport = findIdentifier(afterLastImport, IMPORT_OR_CLASS_START); if (maybeLaterImport.isPresent() && tokenAt(maybeLaterImport.get()).equals("import")) { throw new FormatterException("Imports not contiguous (perhaps a comment separates them?)"); } - StringBuilder result = new StringBuilder(); - String prefix = tokString(0, unindentedFirstImportStart); + final StringBuilder result = new StringBuilder(); + final String prefix = tokString(0, unindentedFirstImportStart); result.append(prefix); if (!prefix.isEmpty() && Newlines.getLineEnding(prefix) == null) { result.append(lineSeparator).append(lineSeparator); } result.append(reorderedImportsString(imports.imports)); - List tail = new ArrayList<>(); + final List tail = new ArrayList<>(); tail.add(CharMatcher.whitespace().trimLeadingFrom(tokString(afterLastImport, toks.size()))); if (!toks.isEmpty()) { - Tok lastTok = getLast(toks); - int tailStart = lastTok.getPosition() + lastTok.length(); + final Tok lastTok = getLast(toks); + final int tailStart = lastTok.getPosition() + lastTok.length(); tail.add(text.substring(tailStart)); } if (tail.stream().anyMatch(s -> !s.isEmpty())) { @@ -149,7 +150,7 @@ private String reorderImports() throws FormatterException { * Determines whether to insert a blank line between the {@code prev} and {@code curr} {@link * Import}s based on Google style. */ - private static boolean shouldInsertBlankLineGoogle(Import prev, Import curr) { + private static boolean shouldInsertBlankLineGoogle(final Import prev, final Import curr) { return !prev.importType().equals(curr.importType()); } @@ -157,7 +158,7 @@ private static boolean shouldInsertBlankLineGoogle(Import prev, Import curr) { * Determines whether to insert a blank line between the {@code prev} and {@code curr} {@link * Import}s based on AOSP style. */ - private static boolean shouldInsertBlankLineAosp(Import prev, Import curr) { + private static boolean shouldInsertBlankLineAosp(final Import prev, final Import curr) { if (!prev.importType().equals(curr.importType())) { return true; } @@ -174,18 +175,21 @@ private static boolean shouldInsertBlankLineAosp(Import prev, Import curr) { private final Comparator importComparator; private final BiFunction shouldInsertBlankLineFn; - private ImportOrderer(String text, ImmutableList toks, Style style) { + private ImportOrderer(final String text, final ImmutableList toks, final Style style) { this.text = text; this.toks = toks; this.lineSeparator = Newlines.guessLineSeparator(text); - if (style.equals(Style.GOOGLE)) { - this.importComparator = GOOGLE_IMPORT_COMPARATOR; - this.shouldInsertBlankLineFn = ImportOrderer::shouldInsertBlankLineGoogle; - } else if (style.equals(Style.AOSP)) { - this.importComparator = AOSP_IMPORT_COMPARATOR; - this.shouldInsertBlankLineFn = ImportOrderer::shouldInsertBlankLineAosp; - } else { - throw new IllegalArgumentException("Unsupported code style: " + style); + switch (style) { + case GOOGLE: + this.importComparator = GOOGLE_IMPORT_COMPARATOR; + this.shouldInsertBlankLineFn = ImportOrderer::shouldInsertBlankLineGoogle; + break; + case AOSP: + this.importComparator = AOSP_IMPORT_COMPARATOR; + this.shouldInsertBlankLineFn = ImportOrderer::shouldInsertBlankLineAosp; + break; + default: + throw new IllegalArgumentException("Unsupported code style: " + style); } } @@ -201,7 +205,7 @@ class Import { private final String trailing; private final ImportType importType; - Import(String imported, String trailing, ImportType importType) { + Import(final String imported, final String trailing, final ImportType importType) { this.imported = imported; this.trailing = trailing; this.importType = importType; @@ -255,7 +259,7 @@ public boolean isThirdParty() { // terminator. @Override public String toString() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append("import "); switch (importType) { case STATIC -> sb.append("static "); @@ -272,8 +276,8 @@ public String toString() { } } - private String tokString(int start, int end) { - StringBuilder sb = new StringBuilder(); + private String tokString(final int start, final int end) { + final StringBuilder sb = new StringBuilder(); for (int i = start; i < end; i++) { sb.append(toks.get(i).getOriginalText()); } @@ -284,7 +288,7 @@ private static class ImportsAndIndex { final ImmutableSortedSet imports; final int index; - ImportsAndIndex(ImmutableSortedSet imports, int index) { + ImportsAndIndex(final ImmutableSortedSet imports, final int index) { this.imports = imports; this.index = index; } @@ -306,7 +310,7 @@ private static class ImportsAndIndex { */ private ImportsAndIndex scanImports(int i) throws FormatterException { int afterLastImport = i; - ImmutableSortedSet.Builder imports = ImmutableSortedSet.orderedBy(importComparator); + final ImmutableSortedSet.Builder imports = ImmutableSortedSet.orderedBy(importComparator); // JavaInput.buildToks appends a zero-width EOF token after all tokens. It won't match any // of our tests here and protects us from running off the end of the toks list. Since it is // zero-width it doesn't matter if we include it in our string concatenation at the end. @@ -315,7 +319,7 @@ private ImportsAndIndex scanImports(int i) throws FormatterException { if (isSpaceToken(i)) { i++; } - ImportType importType = + final ImportType importType = switch (tokenAt(i)) { case "static" -> ImportType.STATIC; case "module" -> ImportType.MODULE; @@ -330,8 +334,8 @@ private ImportsAndIndex scanImports(int i) throws FormatterException { if (!isIdentifierToken(i)) { throw new FormatterException("Unexpected token after import: " + tokenAt(i)); } - StringAndIndex imported = scanImported(i); - String importedName = imported.string; + final StringAndIndex imported = scanImported(i); + final String importedName = imported.string; i = imported.index; if (isSpaceToken(i)) { i++; @@ -343,7 +347,7 @@ private ImportsAndIndex scanImports(int i) throws FormatterException { // Extra semicolons are not allowed by the JLS but are accepted by javac. i++; } - StringBuilder trailing = new StringBuilder(); + final StringBuilder trailing = new StringBuilder(); if (isSpaceToken(i)) { trailing.append(tokenAt(i)); i++; @@ -379,15 +383,15 @@ private ImportsAndIndex scanImports(int i) throws FormatterException { } // Produces the sorted output based on the imports we have scanned. - private String reorderedImportsString(ImmutableSortedSet imports) { + private String reorderedImportsString(final ImmutableSortedSet imports) { Preconditions.checkArgument(!imports.isEmpty(), "imports"); // Pretend that the first import was preceded by another import of the same kind, so we don't // insert a newline there. Import prevImport = imports.iterator().next(); - StringBuilder sb = new StringBuilder(); - for (Import currImport : imports) { + final StringBuilder sb = new StringBuilder(); + for (final Import currImport : imports) { if (shouldInsertBlankLineFn.apply(prevImport, currImport)) { // Blank line between static and non-static imports. sb.append(lineSeparator); @@ -402,7 +406,7 @@ private static class StringAndIndex { private final String string; private final int index; - StringAndIndex(String string, int index) { + StringAndIndex(final String string, final int index) { this.string = string; this.index = index; } @@ -420,9 +424,9 @@ private static class StringAndIndex { * token after the imported thing ({@code ;} in the example). * @throws FormatterException if the imported name could not be parsed. */ - private StringAndIndex scanImported(int start) throws FormatterException { + private StringAndIndex scanImported(final int start) throws FormatterException { int i = start; - StringBuilder imported = new StringBuilder(); + final StringBuilder imported = new StringBuilder(); // At the start of each iteration of this loop, i points to an identifier. // On exit from the loop, i points to a token after an identifier or after *. while (true) { @@ -450,10 +454,10 @@ private StringAndIndex scanImported(int start) throws FormatterException { * @param start the index to start looking at * @param identifiers the identifiers to look for */ - private Optional findIdentifier(int start, ImmutableSet identifiers) { + private Optional findIdentifier(final int start, final ImmutableSet identifiers) { for (int i = start; i < toks.size(); i++) { if (isIdentifierToken(i)) { - String id = tokenAt(i); + final String id = tokenAt(i); if (identifiers.contains(id)) { return Optional.of(i); } @@ -463,7 +467,7 @@ private Optional findIdentifier(int start, ImmutableSet identif } /** Returns the given token, or the preceding token if it is a whitespace token. */ - private int unindent(int i) { + private int unindent(final int i) { if (i > 0 && isSpaceToken(i - 1)) { return i - 1; } else { @@ -471,17 +475,17 @@ private int unindent(int i) { } } - private String tokenAt(int i) { + private String tokenAt(final int i) { return toks.get(i).getOriginalText(); } - private boolean isIdentifierToken(int i) { - String s = tokenAt(i); + private boolean isIdentifierToken(final int i) { + final String s = tokenAt(i); return !s.isEmpty() && Character.isJavaIdentifierStart(s.codePointAt(0)); } - private boolean isSpaceToken(int i) { - String s = tokenAt(i); + private boolean isSpaceToken(final int i) { + final String s = tokenAt(i); if (s.isEmpty()) { return false; } else { @@ -489,11 +493,11 @@ private boolean isSpaceToken(int i) { } } - private boolean isSlashSlashCommentToken(int i) { + private boolean isSlashSlashCommentToken(final int i) { return toks.get(i).isSlashSlashComment(); } - private boolean isNewlineToken(int i) { + private boolean isNewlineToken(final int i) { return toks.get(i).isNewline(); } } diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java b/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java index 9526b892c..aed05cd9b 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java @@ -32,22 +32,22 @@ public final class JavaCommentsHelper implements CommentsHelper { private final String lineSeparator; private final JavaFormatterOptions options; - public JavaCommentsHelper(String lineSeparator, JavaFormatterOptions options) { + public JavaCommentsHelper(final String lineSeparator, final JavaFormatterOptions options) { this.lineSeparator = lineSeparator; this.options = options; } @Override - public String rewrite(Tok tok, int maxWidth, int column0) { + public String rewrite(final Tok tok, final int maxWidth, final int column0) { if (!tok.isComment()) { return tok.getOriginalText(); } String text = tok.getOriginalText(); if (tok.isJavadocComment() && options.formatJavadoc()) { - text = JavadocFormatter.formatJavadoc(text, column0); + text = JavadocFormatter.formatJavadoc(text, column0, maxWidth); } - List lines = new ArrayList<>(); - Iterator it = Newlines.lineIterator(text); + final List lines = new ArrayList<>(); + final Iterator it = Newlines.lineIterator(text); while (it.hasNext()) { if (tok.isSlashSlashComment()) { lines.add(CharMatcher.whitespace().trimFrom(it.next())); @@ -68,13 +68,13 @@ public String rewrite(Tok tok, int maxWidth, int column0) { // For non-javadoc-shaped block comments, shift the entire block to the correct // column, but do not adjust relative indentation. - private String preserveIndentation(List lines, int column0) { - StringBuilder builder = new StringBuilder(); + private String preserveIndentation(final List lines, final int column0) { + final StringBuilder builder = new StringBuilder(); // find the leftmost non-whitespace character in all trailing lines int startCol = -1; for (int i = 1; i < lines.size(); i++) { - int lineIdx = CharMatcher.whitespace().negate().indexIn(lines.get(i)); + final int lineIdx = CharMatcher.whitespace().negate().indexIn(lines.get(i)); if (lineIdx >= 0 && (startCol == -1 || lineIdx < startCol)) { startCol = lineIdx; } @@ -97,11 +97,11 @@ private String preserveIndentation(List lines, int column0) { } // Wraps and re-indents line comments. - private String indentLineComments(List lines, int column0) { + private String indentLineComments(List lines, final int column0) { lines = wrapLineComments(lines, column0); - StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); builder.append(lines.get(0).trim()); - String indentString = Strings.repeat(" ", column0); + final String indentString = Strings.repeat(" ", column0); for (int i = 1; i < lines.size(); ++i) { builder.append(lineSeparator).append(indentString).append(lines.get(i).trim()); } @@ -113,13 +113,13 @@ private String indentLineComments(List lines, int column0) { private static final Pattern LINE_COMMENT_MISSING_SPACE_PREFIX = Pattern.compile("^(//+)(?!noinspection|\\$NON-NLS-\\d+\\$)[^\\s/]"); - private List wrapLineComments(List lines, int column0) { - List result = new ArrayList<>(); + private List wrapLineComments(final List lines, final int column0) { + final List result = new ArrayList<>(); for (String line : lines) { // Add missing leading spaces to line comments: `//foo` -> `// foo`. - Matcher matcher = LINE_COMMENT_MISSING_SPACE_PREFIX.matcher(line); + final Matcher matcher = LINE_COMMENT_MISSING_SPACE_PREFIX.matcher(line); if (matcher.find()) { - int length = matcher.group(1).length(); + final int length = matcher.group(1).length(); line = Strings.repeat("/", length) + " " + line.substring(length); } if (line.startsWith("// MOE:")) { @@ -127,8 +127,8 @@ private List wrapLineComments(List lines, int column0) { result.add(line); continue; } - while (line.length() + column0 > Formatter.MAX_LINE_LENGTH) { - int idx = Formatter.MAX_LINE_LENGTH - column0; + while (line.length() + column0 > options.maxLineWidth()) { + int idx = options.maxLineWidth() - column0; // only break on whitespace characters, and ignore the leading `// ` while (idx >= 2 && !CharMatcher.whitespace().matches(line.charAt(idx))) { idx--; @@ -146,14 +146,14 @@ private List wrapLineComments(List lines, int column0) { // Remove leading whitespace (trailing was already removed), and re-indent. // Add a +1 indent before '*', and add the '*' if necessary. - private String indentJavadoc(List lines, int column0) { - StringBuilder builder = new StringBuilder(); + private String indentJavadoc(final List lines, final int column0) { + final StringBuilder builder = new StringBuilder(); builder.append(lines.get(0).trim()); - int indent = column0 + 1; - String indentString = Strings.repeat(" ", indent); + final int indent = column0 + 1; + final String indentString = Strings.repeat(" ", indent); for (int i = 1; i < lines.size(); ++i) { builder.append(lineSeparator).append(indentString); - String line = lines.get(i).trim(); + final String line = lines.get(i).trim(); if (!line.startsWith("*")) { builder.append("* "); } @@ -163,12 +163,12 @@ private String indentJavadoc(List lines, int column0) { } // Returns true if the comment looks like javadoc - private static boolean javadocShaped(List lines) { - Iterator it = lines.iterator(); + private static boolean javadocShaped(final List lines) { + final Iterator it = lines.iterator(); if (!it.hasNext()) { return false; } - String first = it.next().trim(); + final String first = it.next().trim(); // if it's actually javadoc, we're done if (first.startsWith("/**")) { return true; diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java b/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java index 67c13d0b3..cacc4f543 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java @@ -58,6 +58,8 @@ public int indentationMultiplier() { public abstract boolean reorderModifiers(); + public abstract int maxLineWidth(); + /** Returns the code style. */ public abstract Style style(); @@ -71,7 +73,8 @@ public static Builder builder() { return new AutoValue_JavaFormatterOptions.Builder() .style(Style.GOOGLE) .formatJavadoc(true) - .reorderModifiers(true); + .reorderModifiers(true) + .maxLineWidth(100); } /** A builder for {@link JavaFormatterOptions}. */ @@ -84,6 +87,8 @@ public abstract static class Builder { public abstract Builder reorderModifiers(boolean reorderModifiers); + public abstract Builder maxLineWidth(int maxLineWidth); + public abstract JavaFormatterOptions build(); } } diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java b/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java index ea3731131..4e92b17ea 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java @@ -163,7 +163,7 @@ public void append(String text, Range range) { if (!range.isEmpty()) { if (!rangesSet) { while (ranges.size() <= mutableLines.size()) { - ranges.add(Formatter.EMPTY_RANGE); + ranges.add(EMPTY_RANGE); } ranges.set(mutableLines.size(), union(ranges.get(mutableLines.size()), range)); rangesSet = true; @@ -191,7 +191,7 @@ public void flush() { int jN = mutableLines.size(); Range eofRange = Range.closedOpen(kN, kN + 1); while (ranges.size() < jN) { - ranges.add(Formatter.EMPTY_RANGE); + ranges.add(EMPTY_RANGE); } ranges.add(eofRange); setLines(ImmutableList.copyOf(mutableLines)); diff --git a/core/src/main/java/com/google/googlejavaformat/java/Main.java b/core/src/main/java/com/google/googlejavaformat/java/Main.java index f1affa74d..55f865ce8 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/Main.java +++ b/core/src/main/java/com/google/googlejavaformat/java/Main.java @@ -39,15 +39,13 @@ import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; /** The main class for the Java formatter CLI. */ public final class Main { private static final int MAX_THREADS = 20; private static final String STDIN_FILENAME = ""; - static String versionString() { - return "google-java-format: Version " + GoogleJavaFormatVersion.version(); - } private final PrintWriter outWriter; private final PrintWriter errWriter; @@ -109,7 +107,7 @@ static int main(InputStream in, PrintWriter out, PrintWriter err, String... args public int format(String... args) throws UsageException { CommandLineOptions parameters = processArgs(args); if (parameters.version()) { - errWriter.println(versionString()); + errWriter.println(GoogleJavaFormatVersion.versionString()); return 0; } if (parameters.help()) { @@ -120,6 +118,7 @@ public int format(String... args) throws UsageException { JavaFormatterOptions.builder() .style(parameters.aosp() ? Style.AOSP : Style.GOOGLE) .formatJavadoc(parameters.formatJavadoc()) + .maxLineWidth(parameters.width()) .build(); if (parameters.stdin()) { diff --git a/core/src/main/java/com/google/googlejavaformat/java/SnippetFormatter.java b/core/src/main/java/com/google/googlejavaformat/java/SnippetFormatter.java deleted file mode 100644 index 60fd77ea8..000000000 --- a/core/src/main/java/com/google/googlejavaformat/java/SnippetFormatter.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import static com.google.common.collect.ImmutableList.toImmutableList; - -import com.google.common.base.CharMatcher; -import com.google.common.base.Preconditions; -import com.google.common.collect.DiscreteDomain; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Range; -import com.google.common.collect.RangeSet; -import com.google.common.collect.TreeRangeSet; -import java.util.ArrayList; -import java.util.List; - -/** Formats a subset of a compilation unit. */ -public class SnippetFormatter { - - /** The kind of snippet to format. */ - public enum SnippetKind { - COMPILATION_UNIT, - CLASS_BODY_DECLARATIONS, - STATEMENTS, - EXPRESSION - } - - private class SnippetWrapper { - int offset; - final StringBuilder contents = new StringBuilder(); - - public SnippetWrapper append(String str) { - contents.append(str); - return this; - } - - public SnippetWrapper appendSource(String source) { - this.offset = contents.length(); - contents.append(source); - return this; - } - - public void closeBraces(int initialIndent) { - for (int i = initialIndent; --i >= 0; ) { - contents.append("\n").append(createIndentationString(i)).append("}"); - } - } - } - - private static final int INDENTATION_SIZE = 2; - private final Formatter formatter; - private static final CharMatcher NOT_WHITESPACE = CharMatcher.whitespace().negate(); - - public SnippetFormatter() { - this(JavaFormatterOptions.defaultOptions()); - } - - public SnippetFormatter(JavaFormatterOptions formatterOptions) { - formatter = new Formatter(formatterOptions); - } - - public String createIndentationString(int indentationLevel) { - Preconditions.checkArgument( - indentationLevel >= 0, - "Indentation level cannot be less than zero. Given: %s", - indentationLevel); - int spaces = indentationLevel * INDENTATION_SIZE; - StringBuilder buf = new StringBuilder(spaces); - for (int i = 0; i < spaces; i++) { - buf.append(' '); - } - return buf.toString(); - } - - private static Range offsetRange(Range range, int offset) { - range = range.canonical(DiscreteDomain.integers()); - return Range.closedOpen(range.lowerEndpoint() + offset, range.upperEndpoint() + offset); - } - - private static List> offsetRanges(List> ranges, int offset) { - List> result = new ArrayList<>(); - for (Range range : ranges) { - result.add(offsetRange(range, offset)); - } - return result; - } - - /** Runs the Google Java formatter on the given source, with only the given ranges specified. */ - public ImmutableList format( - SnippetKind kind, - String source, - List> ranges, - int initialIndent, - boolean includeComments) - throws FormatterException { - RangeSet rangeSet = TreeRangeSet.create(); - for (Range range : ranges) { - rangeSet.add(range); - } - if (includeComments) { - if (kind != SnippetKind.COMPILATION_UNIT) { - throw new IllegalArgumentException( - "comment formatting is only supported for compilation units"); - } - return formatter.getFormatReplacements(source, ranges); - } - SnippetWrapper wrapper = snippetWrapper(kind, source, initialIndent); - ranges = offsetRanges(ranges, wrapper.offset); - - String replacement = formatter.formatSource(wrapper.contents.toString(), ranges); - replacement = - replacement.substring( - wrapper.offset, - replacement.length() - (wrapper.contents.length() - wrapper.offset - source.length())); - - return toReplacements(source, replacement).stream() - .filter(r -> rangeSet.encloses(r.getReplaceRange())) - .collect(toImmutableList()); - } - - /** - * Generates {@code Replacement}s rewriting {@code source} to {@code replacement}, under the - * assumption that they differ in whitespace alone. - */ - private static List toReplacements(String source, String replacement) { - if (!NOT_WHITESPACE.retainFrom(source).equals(NOT_WHITESPACE.retainFrom(replacement))) { - throw new IllegalArgumentException( - "source = \"" + source + "\", replacement = \"" + replacement + "\""); - } - /* - * In the past we seemed to have problems touching non-whitespace text in the formatter, even - * just replacing some code with itself. Retrospective attempts to reproduce this have failed, - * but this may be an issue for future changes. - */ - List replacements = new ArrayList<>(); - int i = NOT_WHITESPACE.indexIn(source); - int j = NOT_WHITESPACE.indexIn(replacement); - if (i != 0 || j != 0) { - replacements.add(Replacement.create(0, i, replacement.substring(0, j))); - } - while (i != -1 && j != -1) { - int i2 = NOT_WHITESPACE.indexIn(source, i + 1); - int j2 = NOT_WHITESPACE.indexIn(replacement, j + 1); - if (i2 == -1 || j2 == -1) { - break; - } - if ((i2 - i) != (j2 - j) - || !source.substring(i + 1, i2).equals(replacement.substring(j + 1, j2))) { - replacements.add(Replacement.create(i + 1, i2, replacement.substring(j + 1, j2))); - } - i = i2; - j = j2; - } - return replacements; - } - - private SnippetWrapper snippetWrapper(SnippetKind kind, String source, int initialIndent) { - /* - * Synthesize a dummy class around the code snippet provided by Eclipse. The dummy class is - * correctly formatted -- the blocks use correct indentation, etc. - */ - return switch (kind) { - case COMPILATION_UNIT, CLASS_BODY_DECLARATIONS -> { - SnippetWrapper wrapper = new SnippetWrapper(); - for (int i = 1; i <= initialIndent; i++) { - wrapper.append("class Dummy {\n").append(createIndentationString(i)); - } - wrapper.appendSource(source); - wrapper.closeBraces(initialIndent); - yield wrapper; - } - case STATEMENTS -> { - SnippetWrapper wrapper = new SnippetWrapper(); - wrapper.append("class Dummy {\n").append(createIndentationString(1)); - for (int i = 2; i <= initialIndent; i++) { - wrapper.append("{\n").append(createIndentationString(i)); - } - wrapper.appendSource(source); - wrapper.closeBraces(initialIndent); - yield wrapper; - } - case EXPRESSION -> { - SnippetWrapper wrapper = new SnippetWrapper(); - wrapper.append("class Dummy {\n").append(createIndentationString(1)); - for (int i = 2; i <= initialIndent; i++) { - wrapper.append("{\n").append(createIndentationString(i)); - } - wrapper.append("Object o = "); - wrapper.appendSource(source); - wrapper.append(";"); - wrapper.closeBraces(initialIndent); - yield wrapper; - } - }; - } -} diff --git a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java index 22110ad8a..968f20cdb 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -55,7 +55,7 @@ public final class StringWrapper { /** Reflows long string literals in the given Java source code. */ public static String wrap(String input, Formatter formatter) throws FormatterException { - return StringWrapper.wrap(Formatter.MAX_LINE_LENGTH, input, formatter); + return StringWrapper.wrap(formatter.getMaxLineLength(), input, formatter); } /** diff --git a/core/src/main/java/com/google/googlejavaformat/java/UsageException.java b/core/src/main/java/com/google/googlejavaformat/java/UsageException.java index 50d55d4d4..1897d8167 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/UsageException.java +++ b/core/src/main/java/com/google/googlejavaformat/java/UsageException.java @@ -93,7 +93,7 @@ private static String buildMessage(String message) { appendLines(builder, USAGE); appendLines(builder, ADDITIONAL_USAGE); appendLines(builder, new String[] {""}); - appendLine(builder, Main.versionString()); + appendLine(builder, GoogleJavaFormatVersion.versionString()); appendLines(builder, DOCS_LINK); return builder.toString(); } diff --git a/core/src/main/java/com/google/googlejavaformat/java/filer/FormattingFiler.java b/core/src/main/java/com/google/googlejavaformat/java/filer/FormattingFiler.java deleted file mode 100644 index e8da9fac9..000000000 --- a/core/src/main/java/com/google/googlejavaformat/java/filer/FormattingFiler.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java.filer; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.googlejavaformat.java.Formatter; -import java.io.IOException; -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.tools.FileObject; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import org.jspecify.annotations.Nullable; - -/** - * A decorating {@link Filer} implementation which formats Java source files with a {@link - * Formatter}. - */ -public final class FormattingFiler implements Filer { - - private final Filer delegate; - // TODO(ronshapiro): consider allowing users to create their own Formatter instance - private final Formatter formatter = new Formatter(); - private final Messager messager; - - /** - * Create a new {@link FormattingFiler}. - * - * @param processingEnv the processing environment - */ - public static Filer create(ProcessingEnvironment processingEnv) { - Filer delegate = processingEnv.getFiler(); - if (processingEnv.getOptions().containsKey("experimental_turbine_hjar")) { - return delegate; - } - return new FormattingFiler(delegate, processingEnv.getMessager()); - } - - /** - * Create a new {@link FormattingFiler}. - * - * @param delegate filer to decorate - * @deprecated prefer {@link #create(ProcessingEnvironment)} - */ - @Deprecated - public - FormattingFiler(Filer delegate) { - this(delegate, null); - } - - /** - * Create a new {@link FormattingFiler}. An optional {@link Messager} may be specified to make - * logs more visible. - * - * @param delegate filer to decorate - * @param messager to log warnings to - * @deprecated prefer {@link #create(ProcessingEnvironment)} - */ - @Deprecated - public - FormattingFiler(Filer delegate, @Nullable Messager messager) { - this.delegate = checkNotNull(delegate); - this.messager = messager; - } - - @Override - public JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) - throws IOException { - return new FormattingJavaFileObject( - delegate.createSourceFile(name, originatingElements), formatter, messager); - } - - @Override - public JavaFileObject createClassFile(CharSequence name, Element... originatingElements) - throws IOException { - return delegate.createClassFile(name, originatingElements); - } - - @Override - public FileObject createResource( - JavaFileManager.Location location, - CharSequence pkg, - CharSequence relativeName, - Element... originatingElements) - throws IOException { - return delegate.createResource(location, pkg, relativeName, originatingElements); - } - - @Override - public FileObject getResource( - JavaFileManager.Location location, CharSequence pkg, CharSequence relativeName) - throws IOException { - return delegate.getResource(location, pkg, relativeName); - } -} diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocFormatter.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocFormatter.java index bb9f70040..a81ed346b 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocFormatter.java +++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocFormatter.java @@ -14,18 +14,19 @@ package com.google.googlejavaformat.java.javadoc; -import static com.google.googlejavaformat.java.javadoc.JavadocLexer.lex; -import static com.google.googlejavaformat.java.javadoc.Token.Type.BR_TAG; -import static com.google.googlejavaformat.java.javadoc.Token.Type.PARAGRAPH_OPEN_TAG; -import static java.util.regex.Pattern.CASE_INSENSITIVE; -import static java.util.regex.Pattern.compile; - import com.google.common.collect.ImmutableList; import com.google.googlejavaformat.java.javadoc.JavadocLexer.LexException; + import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.google.googlejavaformat.java.javadoc.JavadocLexer.lex; +import static com.google.googlejavaformat.java.javadoc.Token.Type.BR_TAG; +import static com.google.googlejavaformat.java.javadoc.Token.Type.PARAGRAPH_OPEN_TAG; +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.regex.Pattern.compile; + /** * Entry point for formatting Javadoc. * @@ -36,26 +37,25 @@ */ public final class JavadocFormatter { - static final int MAX_LINE_LENGTH = 100; /** * Formats the given Javadoc comment, which must start with ∕✱✱ and end with ✱∕. The output will * start and end with the same characters. */ - public static String formatJavadoc(String input, int blockIndent) { - ImmutableList tokens; + public static String formatJavadoc(final String input, final int blockIndent, final int maxWidth) { + final ImmutableList tokens; try { tokens = lex(input); - } catch (LexException e) { + } catch (final LexException e) { return input; } - String result = render(tokens, blockIndent); - return makeSingleLineIfPossible(blockIndent, result); + final String result = render(tokens, blockIndent, maxWidth); + return makeSingleLineIfPossible(blockIndent, result, maxWidth); } - private static String render(List input, int blockIndent) { - JavadocWriter output = new JavadocWriter(blockIndent); - for (Token token : input) { + private static String render(final List input, final int blockIndent, final int maxWidth) { + final JavadocWriter output = new JavadocWriter(blockIndent, maxWidth); + for (final Token token : input) { switch (token.getType()) { case BEGIN_JAVADOC -> output.writeBeginJavadoc(); case END_JAVADOC -> { @@ -96,15 +96,15 @@ private static String render(List input, int blockIndent) { * should include them as part of its own postprocessing? Or even the writer could make sense. */ - private static Token standardizeBrToken(Token token) { + private static Token standardizeBrToken(final Token token) { return standardize(token, STANDARD_BR_TOKEN); } - private static Token standardizePToken(Token token) { + private static Token standardizePToken(final Token token) { return standardize(token, STANDARD_P_TOKEN); } - private static Token standardize(Token token, Token standardToken) { + private static Token standardize(final Token token, final Token standardToken) { return SIMPLE_TAG_PATTERN.matcher(token.getValue()).matches() ? standardToken : token; } @@ -118,21 +118,21 @@ private static Token standardize(Token token, Token standardToken) { * Returns the given string or a one-line version of it (e.g., "∕✱✱ Tests for foos. ✱∕") if it * fits on one line. */ - private static String makeSingleLineIfPossible(int blockIndent, String input) { - Matcher matcher = ONE_CONTENT_LINE_PATTERN.matcher(input); + private static String makeSingleLineIfPossible(final int blockIndent, final String input, final int maxWidth) { + final Matcher matcher = ONE_CONTENT_LINE_PATTERN.matcher(input); if (matcher.matches()) { - String line = matcher.group(1); + final String line = matcher.group(1); if (line.isEmpty()) { return "/** */"; - } else if (oneLineJavadoc(line, blockIndent)) { + } else if (oneLineJavadoc(line, blockIndent, maxWidth)) { return "/** " + line + " */"; } } return input; } - private static boolean oneLineJavadoc(String line, int blockIndent) { - int oneLinerContentLength = MAX_LINE_LENGTH - "/** */".length() - blockIndent; + private static boolean oneLineJavadoc(final String line, final int blockIndent, final int maxWidth) { + final int oneLinerContentLength = maxWidth - "/** */".length() - blockIndent; if (line.length() > oneLinerContentLength) { return false; } diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java index 5e6af1795..5196163c5 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java +++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java @@ -14,21 +14,17 @@ package com.google.googlejavaformat.java.javadoc; +import com.google.common.collect.ImmutableSet; +import com.google.googlejavaformat.java.javadoc.Token.Type; + import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Comparators.max; import static com.google.common.collect.Sets.immutableEnumSet; import static com.google.googlejavaformat.java.javadoc.JavadocWriter.AutoIndent.AUTO_INDENT; import static com.google.googlejavaformat.java.javadoc.JavadocWriter.AutoIndent.NO_AUTO_INDENT; -import static com.google.googlejavaformat.java.javadoc.JavadocWriter.RequestedWhitespace.BLANK_LINE; -import static com.google.googlejavaformat.java.javadoc.JavadocWriter.RequestedWhitespace.NEWLINE; -import static com.google.googlejavaformat.java.javadoc.JavadocWriter.RequestedWhitespace.NONE; import static com.google.googlejavaformat.java.javadoc.JavadocWriter.RequestedWhitespace.WHITESPACE; -import static com.google.googlejavaformat.java.javadoc.Token.Type.HEADER_OPEN_TAG; -import static com.google.googlejavaformat.java.javadoc.Token.Type.LIST_ITEM_OPEN_TAG; -import static com.google.googlejavaformat.java.javadoc.Token.Type.PARAGRAPH_OPEN_TAG; - -import com.google.common.collect.ImmutableSet; -import com.google.googlejavaformat.java.javadoc.Token.Type; +import static com.google.googlejavaformat.java.javadoc.JavadocWriter.RequestedWhitespace.*; +import static com.google.googlejavaformat.java.javadoc.Token.Type.*; /** * Stateful object that accepts "requests" and "writes," producing formatted Javadoc. @@ -39,6 +35,8 @@ */ final class JavadocWriter { private final int blockIndent; + private final int maxWidth; + private final StringBuilder output = new StringBuilder(); /** @@ -59,8 +57,9 @@ final class JavadocWriter { private int indentForMoeEndStripComment; private boolean wroteAnythingSignificant; - JavadocWriter(int blockIndent) { + JavadocWriter(final int blockIndent, final int maxWidth) { this.blockIndent = blockIndent; + this.maxWidth = maxWidth; } /** @@ -404,7 +403,7 @@ private void writeNewline(AutoIndent autoIndent) { appendSpaces(blockIndent + 1); output.append("*"); appendSpaces(1); - remainingOnLine = JavadocFormatter.MAX_LINE_LENGTH - blockIndent - 3; + remainingOnLine = maxWidth - blockIndent - 3; if (autoIndent == AUTO_INDENT) { appendSpaces(innerIndent()); remainingOnLine -= innerIndent(); diff --git a/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java b/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java index 93dfb79c2..27f6e8efb 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java @@ -22,7 +22,9 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Map; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -81,6 +83,23 @@ public void help() { assertThat(CommandLineOptionsParser.parse(Arrays.asList("-help")).help()).isTrue(); } + @Test + public void help_fromEnvironment() { + Map environement = + Map.of( + "JAVA_FORMAT_HELP", + "TRUE", + "JAVA_FORMAT_V", + "FALSE", + "OTHER_SETTING", + "TRUE", + "JAVA_FORMAT_WIDTH", + "100"); + ArrayList expandedOptions = new ArrayList<>(); + CommandLineOptionsParser.expandEnvironmentParams(environement, expandedOptions); + assertThat(expandedOptions).containsExactly("-help", "-width", "100"); + } + @Test public void lengths() { assertThat( diff --git a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java deleted file mode 100644 index 461bd6793..000000000 --- a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import static com.google.common.truth.Truth.assertThat; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ServiceLoader; -import java.util.spi.ToolProvider; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link GoogleJavaFormatToolProvider}. */ -@RunWith(JUnit4.class) -public class GoogleJavaFormatToolProviderTest { - - @Test - public void testUsageOutputAfterLoadingViaToolName() { - String name = "google-java-format"; - - assertThat( - ServiceLoader.load(ToolProvider.class).stream() - .map(ServiceLoader.Provider::get) - .map(ToolProvider::name)) - .contains(name); - - ToolProvider format = ToolProvider.findFirst(name).get(); - - StringWriter out = new StringWriter(); - StringWriter err = new StringWriter(); - - int result = format.run(new PrintWriter(out, true), new PrintWriter(err, true), "--help"); - - assertThat(result).isNotEqualTo(0); - - String usage = err.toString(); - - // Check that doc links are included. - assertThat(usage).containsMatch("http.*/google-java-format"); - assertThat(usage).contains("Usage: google-java-format"); - } -} diff --git a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java deleted file mode 100644 index e3a7573a7..000000000 --- a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import static com.google.common.truth.Truth.assertThat; -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.ServiceLoader; -import javax.tools.Tool; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link GoogleJavaFormatToolProvider}. */ -@RunWith(JUnit4.class) -public class GoogleJavaFormatToolTest { - - @Test - public void testUsageOutputAfterLoadingViaToolName() { - String name = "google-java-format"; - - assertThat( - ServiceLoader.load(Tool.class).stream() - .map(ServiceLoader.Provider::get) - .map(Tool::name)) - .contains(name); - - Tool format = - ServiceLoader.load(Tool.class).stream() - .filter(provider -> name.equals(provider.get().name())) - .findFirst() - .get() - .get(); - - InputStream in = new ByteArrayInputStream(new byte[0]); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - - int result = format.run(in, out, err, "--help"); - - assertThat(result).isNotEqualTo(0); - - String usage = new String(err.toByteArray(), UTF_8); - - // Check that doc links are included. - assertThat(usage).containsMatch("http.*/google-java-format"); - assertThat(usage).contains("Usage: google-java-format"); - } -} diff --git a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java index 2d9364082..bdd9012eb 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java @@ -49,6 +49,15 @@ public class MainTest { @Rule public TemporaryFolder testFolder = new TemporaryFolder(); + /** Filters out JVM "Picked up" messages from stderr (e.g., JAVA_TOOL_OPTIONS, _JAVA_OPTIONS). */ + private static String filterJvmStderr(String stderr) { + return stderr.lines() + .filter(line -> !line.startsWith("Picked up ")) + .reduce((a, b) -> a + System.lineSeparator() + b) + .map(s -> s + System.lineSeparator()) + .orElse(""); + } + // PrintWriter instances used below are hard-coded to use system-default line separator. private final Joiner joiner = Joiner.on(System.lineSeparator()); @@ -463,7 +472,7 @@ public void exitIfChangedStdin() throws Exception { process.waitFor(); String err = new String(ByteStreams.toByteArray(process.getErrorStream()), UTF_8); String out = new String(ByteStreams.toByteArray(process.getInputStream()), UTF_8); - assertThat(err).isEmpty(); + assertThat(filterJvmStderr(err)).isEmpty(); assertThat(out).isEqualTo("" + System.lineSeparator()); assertThat(process.exitValue()).isEqualTo(1); } @@ -490,7 +499,7 @@ public void exitIfChangedFiles() throws Exception { process.waitFor(); String err = new String(ByteStreams.toByteArray(process.getErrorStream()), UTF_8); String out = new String(ByteStreams.toByteArray(process.getInputStream()), UTF_8); - assertThat(err).isEmpty(); + assertThat(filterJvmStderr(err)).isEmpty(); assertThat(out).isEqualTo(path.toAbsolutePath() + System.lineSeparator()); assertThat(process.exitValue()).isEqualTo(1); } diff --git a/core/src/test/java/com/google/googlejavaformat/java/SnippetFormatterTest.java b/core/src/test/java/com/google/googlejavaformat/java/SnippetFormatterTest.java deleted file mode 100644 index f763dd524..000000000 --- a/core/src/test/java/com/google/googlejavaformat/java/SnippetFormatterTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Range; -import com.google.googlejavaformat.java.SnippetFormatter.SnippetKind; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** {@link SnippetFormatter}Test */ -@RunWith(JUnit4.class) -public class SnippetFormatterTest { - @Test - public void expression() throws FormatterException { - String input = "x\n=42"; - List replacements = - new SnippetFormatter() - .format( - SnippetKind.EXPRESSION, - input, - ImmutableList.of(Range.closedOpen(0, input.length())), - 4, - false); - assertThat(replacements) - .containsExactly(Replacement.create(1, 2, " "), Replacement.create(3, 3, " ")); - } - - @Test - public void statement() throws FormatterException { - String input = "int x\n=42;"; - List replacements = - new SnippetFormatter() - .format( - SnippetKind.STATEMENTS, - input, - ImmutableList.of(Range.closedOpen(0, input.length())), - 4, - false); - assertThat(replacements) - .containsExactly(Replacement.create(5, 6, " "), Replacement.create(7, 7, " ")); - } - - @Test - public void classMember() throws FormatterException { - String input = "void f() {\n}"; - List replacements = - new SnippetFormatter() - .format( - SnippetKind.CLASS_BODY_DECLARATIONS, - input, - ImmutableList.of(Range.closedOpen(0, input.length())), - 4, - false); - assertThat(replacements).containsExactly(Replacement.create(10, 11, "")); - } - - @Test - public void compilation() throws FormatterException { - String input = "/** a\nb*/\nclass Test {\n}"; - List replacements = - new SnippetFormatter() - .format( - SnippetKind.COMPILATION_UNIT, - input, - ImmutableList.of(Range.closedOpen(input.indexOf("class"), input.length())), - 4, - false); - assertThat(replacements).containsExactly(Replacement.create(22, 23, "")); - } - - @Test - public void compilationWithComments() throws FormatterException { - String input = "/** a\nb*/\nclass Test {\n}"; - List replacements = - new SnippetFormatter() - .format( - SnippetKind.COMPILATION_UNIT, - input, - ImmutableList.of(Range.closedOpen(0, input.length())), - 4, - true); - assertThat(replacements) - .containsExactly(Replacement.create(0, 24, "/** a b */\nclass Test {}\n")); - } -} diff --git a/core/src/test/java/com/google/googlejavaformat/java/filer/FormattingFilerTest.java b/core/src/test/java/com/google/googlejavaformat/java/filer/FormattingFilerTest.java deleted file mode 100644 index 38cac3550..000000000 --- a/core/src/test/java/com/google/googlejavaformat/java/filer/FormattingFilerTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java.filer; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.base.Joiner; -import com.google.testing.compile.CompilationRule; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.tools.FileObject; -import javax.tools.JavaFileManager.Location; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.SimpleJavaFileObject; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link com.google.googlejavaformat.java.filer.FormattingFiler}. */ -@RunWith(JUnit4.class) -public class FormattingFilerTest { - - @Rule public CompilationRule compilationRule = new CompilationRule(); - - @Test - public void invalidSyntaxDoesNotThrowError() throws IOException { - List logMessages = new ArrayList<>(); - Messager messager = - new Messager() { - @Override - public void printMessage(javax.tools.Diagnostic.Kind kind, CharSequence msg) { - logMessages.add(kind + ";" + msg); - } - - @Override - public void printMessage(javax.tools.Diagnostic.Kind kind, CharSequence msg, Element e) {} - - @Override - public void printMessage( - javax.tools.Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a) {} - - @Override - public void printMessage( - javax.tools.Diagnostic.Kind kind, - CharSequence msg, - Element e, - AnnotationMirror a, - AnnotationValue v) {} - }; - - String file = Joiner.on('\n').join("package foo;", "public class Bar {"); - FormattingFiler formattingFiler = new FormattingFiler(new FakeFiler(), messager); - try (Writer writer = formattingFiler.createSourceFile("foo.Bar").openWriter()) { - writer.write(file); - } - - assertThat(logMessages).containsExactly("NOTE;Error formatting foo.Bar"); - } - - @Test - public void formatsFile() throws IOException { - FormattingFiler formattingFiler = new FormattingFiler(new FakeFiler()); - JavaFileObject sourceFile = formattingFiler.createSourceFile("foo.Bar"); - try (Writer writer = sourceFile.openWriter()) { - writer.write("package foo;class Bar{private String baz;\n\n\n\n}"); - } - - assertThat(sourceFile.getCharContent(false).toString()) - .isEqualTo( - Joiner.on('\n') - .join( - "package foo;", - "", - "class Bar {", - " private String baz;", - "}", - "")); // trailing newline - } - - private static class FakeFiler implements Filer { - @Override - public JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) - throws IOException { - return new ObservingJavaFileObject(name.toString(), Kind.SOURCE); - } - - @Override - public JavaFileObject createClassFile(CharSequence name, Element... originatingElements) - throws IOException { - return new ObservingJavaFileObject(name.toString(), Kind.CLASS); - } - - @Override - public FileObject createResource( - Location location, - CharSequence pkg, - CharSequence relativeName, - Element... originatingElements) - throws IOException { - return new ObservingJavaFileObject(pkg.toString() + relativeName, Kind.OTHER); - } - - @Override - public FileObject getResource(Location location, CharSequence pkg, CharSequence relativeName) - throws IOException { - return new ObservingJavaFileObject(pkg.toString() + relativeName, Kind.OTHER); - } - } - - private static class ObservingJavaFileObject extends SimpleJavaFileObject { - private final StringWriter output = new StringWriter(); - - ObservingJavaFileObject(String name, Kind kind) { - super(URI.create(name), kind); - } - - @Override - public Writer openWriter() throws IOException { - return output; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return output.toString(); - } - } -} diff --git a/eclipse_plugin/META-INF/MANIFEST.MF b/eclipse_plugin/META-INF/MANIFEST.MF deleted file mode 100644 index 4170ad643..000000000 --- a/eclipse_plugin/META-INF/MANIFEST.MF +++ /dev/null @@ -1,15 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: google-java-format -Bundle-SymbolicName: google-java-format-eclipse-plugin;singleton:=true -Bundle-Vendor: Google -Bundle-Version: 1.31.0 -Bundle-RequiredExecutionEnvironment: JavaSE-11 -Require-Bundle: org.eclipse.jdt.core;bundle-version="3.10.0", - org.eclipse.jface, - org.eclipse.text, - org.eclipse.ui, - org.eclipse.equinox.common -Bundle-ClassPath: ., - lib/guava.jar, - lib/google-java-format.jar diff --git a/eclipse_plugin/README.md b/eclipse_plugin/README.md deleted file mode 100644 index 395a368dc..000000000 --- a/eclipse_plugin/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Google Java Format Eclipse Plugin - -## Enabling - -See https://github.com/google/google-java-format#eclipse - -## Development - -### Prerequisites - -Before building the plugin, make sure to run `mvn -tycho-versions:update-eclipse-metadata` to update the bundle version in -`META-INF/MANIFEST.MF`. - -### Building the Plugin - -1) Run `mvn clean package` in the `eclipse_plugin` directory. This will first copy the dependencies -of the plugin to `eclipse_plugin/lib/` and then triggers the tycho build that uses these -dependencies (as declared in `build.properties`) for the actual Eclipse plugin build.

-If you also want to add the build artifact to the local maven repository, you can use -`mvn clean install -Dtycho.localArtifacts=ignore` instead. Note, however, that you then must use -this build command for every build with that specific version number until you clear the build -artifact (or the -[p2-local-metadata.properties](https://wiki.eclipse.org/Tycho/Target_Platform#Locally_built_artifacts)) -from your local repository. Otherwise, you might run into issues caused by the build using an -outdated build artifact created by a previous build instead of re-building the plugin. More -information on this issue is given -[in this thread](https://www.eclipse.org/lists/tycho-user/msg00952.html) and -[this bug tracker entry](https://bugs.eclipse.org/bugs/show_bug.cgi?id=355367). - -2) You can find the built plugin in -`eclipse_plugin/target/google-java-format-eclipse-plugin-.jar` - -#### Building against a local (snapshot) release of the core - -With the current build setup, the Eclipse plugin build pulls the needed build -artifacts of the google java format core from the maven repository and copies it -into the `eclipse_plugin/lib/` directory. - -If you instead want to build against a local (snapshot) build of the core which -is not available in a maven repository (local or otherwise), you will have to -place the appropriate version into the `eclipse_plugin/lib/` directory yourself -before the build. diff --git a/eclipse_plugin/build.properties b/eclipse_plugin/build.properties deleted file mode 100644 index dd1d835c5..000000000 --- a/eclipse_plugin/build.properties +++ /dev/null @@ -1,7 +0,0 @@ -source.. = src/ -output.. = target/classes -bin.includes = META-INF/,\ - .,\ - plugin.xml,\ - lib/guava.jar,\ - lib/google-java-format.jar diff --git a/eclipse_plugin/plugin.xml b/eclipse_plugin/plugin.xml deleted file mode 100644 index e40b59aea..000000000 --- a/eclipse_plugin/plugin.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - diff --git a/eclipse_plugin/pom.xml b/eclipse_plugin/pom.xml deleted file mode 100644 index a5d8c23ae..000000000 --- a/eclipse_plugin/pom.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - 4.0.0 - - com.google.googlejavaformat - google-java-format-eclipse-plugin - eclipse-plugin - 1.31.0 - - Google Java Format Plugin for Eclipse 4.5+ - - - A Java source code formatter plugin for Eclipse that follows Google Java Style. - - - - UTF-8 - 3.0.5 - - - - - com.google.googlejavaformat - google-java-format - ${project.version} - - - - - - mars - p2 - https://download.eclipse.org/releases/mars - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - 3.3.0 - - - copy-dependencies - initialize - - copy-dependencies - - - - - lib - runtime - true - true - true - guava,google-java-format - - - - - org.eclipse.tycho - tycho-maven-plugin - ${tycho-version} - true - - - - org.eclipse.tycho - tycho-versions-plugin - ${tycho-version} - - ${project.version} - - - - - org.eclipse.tycho - target-platform-configuration - ${tycho-version} - - - - linux - gtk - x86 - - - linux - gtk - x86_64 - - - win32 - win32 - x86 - - - win32 - win32 - x86_64 - - - macosx - cocoa - x86_64 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - 11 - 11 - - - - - diff --git a/eclipse_plugin/src/com/google/googlejavaformat/java/AospJavaFormatter.java b/eclipse_plugin/src/com/google/googlejavaformat/java/AospJavaFormatter.java deleted file mode 100644 index ac501fcb6..000000000 --- a/eclipse_plugin/src/com/google/googlejavaformat/java/AospJavaFormatter.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2025 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -/** Runs the Google Java formatter on the given code. */ -public class AospJavaFormatter extends JavaFormatterBase { - public AospJavaFormatter() { - super(JavaFormatterOptions.builder().style(JavaFormatterOptions.Style.AOSP).build()); - } -} diff --git a/eclipse_plugin/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java b/eclipse_plugin/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java deleted file mode 100644 index 5402b5f8b..000000000 --- a/eclipse_plugin/src/com/google/googlejavaformat/java/GoogleJavaFormatter.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -/** Runs the Google Java formatter on the given code. */ -public class GoogleJavaFormatter extends JavaFormatterBase { - public GoogleJavaFormatter() { - super(JavaFormatterOptions.defaultOptions()); - } -} diff --git a/eclipse_plugin/src/com/google/googlejavaformat/java/JavaFormatterBase.java b/eclipse_plugin/src/com/google/googlejavaformat/java/JavaFormatterBase.java deleted file mode 100644 index abeb17297..000000000 --- a/eclipse_plugin/src/com/google/googlejavaformat/java/JavaFormatterBase.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2025 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Range; -import com.google.googlejavaformat.java.SnippetFormatter.SnippetKind; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.formatter.CodeFormatter; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Region; -import org.eclipse.text.edits.MultiTextEdit; -import org.eclipse.text.edits.ReplaceEdit; -import org.eclipse.text.edits.TextEdit; - -/** Runs the Google Java formatter on the given code. */ -public class JavaFormatterBase extends CodeFormatter { - - private static final int INDENTATION_SIZE = 2; - private final JavaFormatterOptions formatterOptions; - - JavaFormatterBase(JavaFormatterOptions formatterOptions) { - this.formatterOptions = formatterOptions; - } - - @Override - public TextEdit format( - int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { - IRegion[] regions = new IRegion[] {new Region(offset, length)}; - return formatInternal(kind, source, regions, indentationLevel); - } - - @Override - public TextEdit format( - int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { - return formatInternal(kind, source, regions, indentationLevel); - } - - @Override - public String createIndentationString(int indentationLevel) { - Preconditions.checkArgument( - indentationLevel >= 0, - "Indentation level cannot be less than zero. Given: %s", - indentationLevel); - int spaces = indentationLevel * INDENTATION_SIZE; - StringBuilder buf = new StringBuilder(spaces); - for (int i = 0; i < spaces; i++) { - buf.append(' '); - } - return buf.toString(); - } - - /** Runs the Google Java formatter on the given source, with only the given ranges specified. */ - private TextEdit formatInternal(int kind, String source, IRegion[] regions, int initialIndent) { - try { - boolean includeComments = - (kind & CodeFormatter.F_INCLUDE_COMMENTS) == CodeFormatter.F_INCLUDE_COMMENTS; - kind &= ~CodeFormatter.F_INCLUDE_COMMENTS; - SnippetKind snippetKind; - switch (kind) { - case ASTParser.K_EXPRESSION: - snippetKind = SnippetKind.EXPRESSION; - break; - case ASTParser.K_STATEMENTS: - snippetKind = SnippetKind.STATEMENTS; - break; - case ASTParser.K_CLASS_BODY_DECLARATIONS: - snippetKind = SnippetKind.CLASS_BODY_DECLARATIONS; - break; - case ASTParser.K_COMPILATION_UNIT: - snippetKind = SnippetKind.COMPILATION_UNIT; - break; - default: - throw new IllegalArgumentException(String.format("Unknown snippet kind: %d", kind)); - } - List replacements = - new SnippetFormatter(formatterOptions) - .format( - snippetKind, source, rangesFromRegions(regions), initialIndent, includeComments); - if (idempotent(source, regions, replacements)) { - // Do not create edits if there's no diff. - return null; - } - // Convert replacements to text edits. - return editFromReplacements(replacements); - } catch (IllegalArgumentException | FormatterException exception) { - // Do not format on errors. - return null; - } - } - - private List> rangesFromRegions(IRegion[] regions) { - List> ranges = new ArrayList<>(); - for (IRegion region : regions) { - ranges.add(Range.closedOpen(region.getOffset(), region.getOffset() + region.getLength())); - } - return ranges; - } - - /** - * @return {@code true} if input and output texts are equal, else {@code false}. - */ - private boolean idempotent(String source, IRegion[] regions, List replacements) { - // This implementation only checks for single replacement. - if (replacements.size() == 1) { - Replacement replacement = replacements.get(0); - String output = replacement.getReplacementString(); - // Entire source case: input = output, nothing changed. - if (output.equals(source)) { - return true; - } - // Single region and single replacement case: if they are equal, nothing changed. - if (regions.length == 1) { - Range range = replacement.getReplaceRange(); - String snippet = source.substring(range.lowerEndpoint(), range.upperEndpoint()); - if (output.equals(snippet)) { - return true; - } - } - } - return false; - } - - private TextEdit editFromReplacements(List replacements) { - // Split the replacements that cross line boundaries. - TextEdit edit = new MultiTextEdit(); - for (Replacement replacement : replacements) { - Range replaceRange = replacement.getReplaceRange(); - edit.addChild( - new ReplaceEdit( - replaceRange.lowerEndpoint(), - replaceRange.upperEndpoint() - replaceRange.lowerEndpoint(), - replacement.getReplacementString())); - } - return edit; - } -} diff --git a/idea_plugin/.gitignore b/idea_plugin/.gitignore deleted file mode 100644 index a5e690ca2..000000000 --- a/idea_plugin/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -build -.gradle -gradle -gradlew -gradlew.bat -.intellijPlatform \ No newline at end of file diff --git a/idea_plugin/build.gradle.kts b/idea_plugin/build.gradle.kts deleted file mode 100644 index c529963f5..000000000 --- a/idea_plugin/build.gradle.kts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.jetbrains.intellij.platform.gradle.TestFrameworkType - -// https://github.com/JetBrains/intellij-platform-gradle-plugin/releases -plugins { - id("org.jetbrains.intellij.platform") version "2.10.2" - // See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#bundled-stdlib-versions - // This version of Kotlin will crash if your Gradle daemon is running under Java 25 (even if that - // isn't the JDK you're using to compile). So make sure to update JAVA_HOME and then - // `./gradlew --stop` - kotlin("jvm") version "2.0.21" -} - -repositories { - mavenCentral() - - intellijPlatform { defaultRepositories() } -} - -// https://github.com/google/google-java-format/releases -val googleJavaFormatVersion = "1.31.0" -val pluginPatchVersion = "0" - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 -} - -kotlin { jvmToolchain(21) } - -intellijPlatform { - pluginConfiguration { - name = "google-java-format" - version = "${googleJavaFormatVersion}.${pluginPatchVersion}" - ideaVersion { - sinceBuild = "242" - untilBuild = provider { null } - } - } - - publishing { - val jetbrainsPluginRepoToken: String by project - token.set(jetbrainsPluginRepoToken) - } -} - -var gjfRequiredJvmArgs = - listOf( - "--add-exports", - "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - "--add-exports", - "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "--add-exports", - "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", - "--add-exports", - "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", - "--add-exports", - "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "--add-exports", - "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - ) - -tasks { runIde { jvmArgumentProviders += CommandLineArgumentProvider { gjfRequiredJvmArgs } } } - -tasks { withType().configureEach { jvmArgs(gjfRequiredJvmArgs) } } - -dependencies { - intellijPlatform { - intellijIdeaCommunity("2024.3") - bundledPlugin("com.intellij.java") - testFramework(TestFrameworkType.Plugin.Java) - } - implementation("com.google.googlejavaformat:google-java-format:${googleJavaFormatVersion}") - // https://mvnrepository.com/artifact/junit/junit - testImplementation("junit:junit:4.13.2") - // https://mvnrepository.com/artifact/com.google.truth/truth - testImplementation("com.google.truth:truth:1.4.5") - implementation(kotlin("stdlib-jdk8")) -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.form b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.form deleted file mode 100644 index 1db1d7920..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.form +++ /dev/null @@ -1,40 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.java deleted file mode 100644 index 3a98c2eb9..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatConfigurable.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.googlejavaformat.intellij.GoogleJavaFormatSettings.EnabledState; -import com.intellij.openapi.options.BaseConfigurable; -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.ComboBox; -import com.intellij.uiDesigner.core.GridConstraints; -import com.intellij.uiDesigner.core.GridLayoutManager; -import com.intellij.uiDesigner.core.Spacer; -import java.awt.Insets; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -class GoogleJavaFormatConfigurable extends BaseConfigurable implements SearchableConfigurable { - - private final Project project; - private JPanel panel; - private JCheckBox enable; - private JComboBox styleComboBox; - - public GoogleJavaFormatConfigurable(Project project) { - this.project = project; - } - - @NotNull - @Override - public String getId() { - return "google-java-format.settings"; - } - - @Nullable - @Override - public Runnable enableSearch(String option) { - return null; - } - - @Nls - @Override - public String getDisplayName() { - return "google-java-format Settings"; - } - - @Nullable - @Override - public String getHelpTopic() { - return null; - } - - @Nullable - @Override - public JComponent createComponent() { - return panel; - } - - @Override - public void apply() throws ConfigurationException { - GoogleJavaFormatSettings settings = GoogleJavaFormatSettings.getInstance(project); - settings.setEnabled(enable.isSelected() ? EnabledState.ENABLED : getDisabledState()); - settings.setStyle(((UiFormatterStyle) styleComboBox.getSelectedItem()).convert()); - } - - private EnabledState getDisabledState() { - // The default settings (inherited by new projects) are either 'enabled' or - // 'show notification'. There's no way to default new projects to disabled. If someone wants - // that, we can add another checkbox, I suppose. - return project.isDefault() ? EnabledState.UNKNOWN : EnabledState.DISABLED; - } - - @Override - public void reset() { - GoogleJavaFormatSettings settings = GoogleJavaFormatSettings.getInstance(project); - enable.setSelected(settings.isEnabled()); - styleComboBox.setSelectedItem(UiFormatterStyle.convert(settings.getStyle())); - } - - @Override - public boolean isModified() { - GoogleJavaFormatSettings settings = GoogleJavaFormatSettings.getInstance(project); - return enable.isSelected() != settings.isEnabled() - || !styleComboBox.getSelectedItem().equals(UiFormatterStyle.convert(settings.getStyle())); - } - - @Override - public void disposeUIResources() {} - - private void createUIComponents() { - styleComboBox = new ComboBox<>(UiFormatterStyle.values()); - } - - { - // GUI initializer generated by IntelliJ IDEA GUI Designer - // >>> IMPORTANT!! <<< - // DO NOT EDIT OR ADD ANY CODE HERE! - $$$setupUI$$$(); - } - - /** - * Method generated by IntelliJ IDEA GUI Designer >>> IMPORTANT!! <<< DO NOT edit this method OR - * call it in your code! - * - * @noinspection ALL - */ - private void $$$setupUI$$$() { - createUIComponents(); - panel = new JPanel(); - panel.setLayout(new GridLayoutManager(3, 2, new Insets(0, 0, 0, 0), -1, -1)); - enable = new JCheckBox(); - enable.setText("Enable google-java-format"); - panel.add( - enable, - new GridConstraints( - 0, - 0, - 1, - 2, - GridConstraints.ANCHOR_WEST, - GridConstraints.FILL_NONE, - GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, - GridConstraints.SIZEPOLICY_FIXED, - null, - null, - null, - 0, - false)); - final Spacer spacer1 = new Spacer(); - panel.add( - spacer1, - new GridConstraints( - 2, - 0, - 1, - 2, - GridConstraints.ANCHOR_CENTER, - GridConstraints.FILL_VERTICAL, - 1, - GridConstraints.SIZEPOLICY_WANT_GROW, - null, - null, - null, - 0, - false)); - final JLabel label1 = new JLabel(); - label1.setText("Code style"); - panel.add( - label1, - new GridConstraints( - 1, - 0, - 1, - 1, - GridConstraints.ANCHOR_WEST, - GridConstraints.FILL_NONE, - GridConstraints.SIZEPOLICY_FIXED, - GridConstraints.SIZEPOLICY_FIXED, - null, - null, - null, - 0, - false)); - panel.add( - styleComboBox, - new GridConstraints( - 1, - 1, - 1, - 1, - GridConstraints.ANCHOR_WEST, - GridConstraints.FILL_HORIZONTAL, - GridConstraints.SIZEPOLICY_CAN_GROW, - GridConstraints.SIZEPOLICY_FIXED, - null, - null, - null, - 1, - false)); - } - - /** - * @noinspection ALL - */ - public JComponent $$$getRootComponent$$$() { - return panel; - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingService.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingService.java deleted file mode 100644 index 9d2d7a595..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingService.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Range; -import com.google.googlejavaformat.java.Formatter; -import com.google.googlejavaformat.java.FormatterException; -import com.google.googlejavaformat.java.JavaFormatterOptions; -import com.google.googlejavaformat.java.JavaFormatterOptions.Style; -import com.intellij.formatting.service.AsyncDocumentFormattingService; -import com.intellij.formatting.service.AsyncFormattingRequest; -import com.intellij.ide.highlighter.JavaFileType; -import com.intellij.lang.ImportOptimizer; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import org.jetbrains.annotations.NotNull; - -/** Uses {@code google-java-format} to reformat code. */ -public class GoogleJavaFormatFormattingService extends AsyncDocumentFormattingService { - - public static final ImmutableSet IMPORT_OPTIMIZERS = - ImmutableSet.of(new GoogleJavaFormatImportOptimizer()); - - @Override - protected FormattingTask createFormattingTask(AsyncFormattingRequest request) { - Project project = request.getContext().getProject(); - - if (!JreConfigurationChecker.checkJreConfiguration(project)) { - return null; - } - - Style style = GoogleJavaFormatSettings.getInstance(project).getStyle(); - Formatter formatter = createFormatter(style, request.canChangeWhitespaceOnly()); - return new GoogleJavaFormatFormattingTask(formatter, request); - } - - @Override - protected String getNotificationGroupId() { - return Notifications.PARSING_ERROR_NOTIFICATION_GROUP; - } - - @Override - protected String getName() { - return "google-java-format"; - } - - private static Formatter createFormatter(Style style, boolean canChangeWhiteSpaceOnly) { - JavaFormatterOptions.Builder optBuilder = JavaFormatterOptions.builder().style(style); - if (canChangeWhiteSpaceOnly) { - optBuilder.formatJavadoc(false).reorderModifiers(false); - } - return new Formatter(optBuilder.build()); - } - - @Override - public @NotNull Set getFeatures() { - return Set.of(Feature.FORMAT_FRAGMENTS, Feature.OPTIMIZE_IMPORTS); - } - - @Override - public boolean canFormat(@NotNull PsiFile file) { - return JavaFileType.INSTANCE.equals(file.getFileType()) - && GoogleJavaFormatSettings.getInstance(file.getProject()).isEnabled(); - } - - @Override - public @NotNull Set getImportOptimizers(@NotNull PsiFile file) { - return IMPORT_OPTIMIZERS; - } - - private static final class GoogleJavaFormatFormattingTask implements FormattingTask { - private final Formatter formatter; - private final AsyncFormattingRequest request; - - private GoogleJavaFormatFormattingTask(Formatter formatter, AsyncFormattingRequest request) { - this.formatter = formatter; - this.request = request; - } - - @Override - public void run() { - try { - String formattedText = formatter.formatSource(request.getDocumentText(), toRanges(request)); - request.onTextReady(formattedText); - } catch (FormatterException e) { - request.onError( - Notifications.PARSING_ERROR_TITLE, - Notifications.parsingErrorMessage(request.getContext().getContainingFile().getName())); - } - } - - private static Collection> toRanges(AsyncFormattingRequest request) { - if (isWholeFile(request)) { - // The IDE sometimes passes invalid ranges when the file is unsaved before invoking the - // formatter. So this is a workaround for that issue. - return ImmutableList.of(Range.closedOpen(0, request.getDocumentText().length())); - } - return request.getFormattingRanges().stream() - .map(textRange -> Range.closedOpen(textRange.getStartOffset(), textRange.getEndOffset())) - .collect(ImmutableList.toImmutableList()); - } - - private static boolean isWholeFile(AsyncFormattingRequest request) { - List ranges = request.getFormattingRanges(); - return ranges.size() == 1 - && ranges.get(0).getStartOffset() == 0 - // using greater than or equal because ranges are sometimes passed inaccurately - && ranges.get(0).getEndOffset() >= request.getDocumentText().length(); - } - - @Override - public boolean isRunUnderProgress() { - return true; - } - - @Override - public boolean cancel() { - return false; - } - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizer.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizer.java deleted file mode 100644 index 425124219..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizer.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.common.util.concurrent.Runnables; -import com.google.googlejavaformat.java.FormatterException; -import com.google.googlejavaformat.java.ImportOrderer; -import com.google.googlejavaformat.java.JavaFormatterOptions; -import com.google.googlejavaformat.java.RemoveUnusedImports; -import com.intellij.ide.highlighter.JavaFileType; -import com.intellij.lang.ImportOptimizer; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.NotNull; - -/** Uses {@code google-java-format} to optimize imports. */ -public class GoogleJavaFormatImportOptimizer implements ImportOptimizer { - - @Override - public boolean supports(@NotNull PsiFile file) { - return JavaFileType.INSTANCE.equals(file.getFileType()) - && GoogleJavaFormatSettings.getInstance(file.getProject()).isEnabled(); - } - - @Override - public @NotNull Runnable processFile(@NotNull PsiFile file) { - Project project = file.getProject(); - - if (!JreConfigurationChecker.checkJreConfiguration(file.getProject())) { - return Runnables.doNothing(); - } - - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); - Document document = documentManager.getDocument(file); - - if (document == null) { - return Runnables.doNothing(); - } - - JavaFormatterOptions.Style style = GoogleJavaFormatSettings.getInstance(project).getStyle(); - - final String origText = document.getText(); - String text; - try { - text = ImportOrderer.reorderImports(RemoveUnusedImports.removeUnusedImports(origText), style); - } catch (FormatterException e) { - Notifications.displayParsingErrorNotification(project, file.getName()); - return Runnables.doNothing(); - } - - // pointless to change document text if it hasn't changed, plus this can interfere with - // e.g. GoogleJavaFormattingService's output, i.e. it can overwrite the results from the main - // formatter. - if (text.equals(origText)) { - return Runnables.doNothing(); - } - - return () -> { - if (documentManager.isDocumentBlockedByPsi(document)) { - documentManager.doPostponedOperationsAndUnblockDocument(document); - } - - // similarly to above, don't overwrite new document text if it has changed - we use - // getCharsSequence() as we should have `writeAction()` (which I think means effectively a - // write-lock) and it saves calling getText(), which apparently is expensive. - CharSequence newText = document.getCharsSequence(); - if (CharSequence.compare(origText, newText) != 0) { - return; - } - - document.setText(text); - }; - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatSettings.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatSettings.java deleted file mode 100644 index 4546f68a3..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/GoogleJavaFormatSettings.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.googlejavaformat.java.JavaFormatterOptions; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@State( - name = "GoogleJavaFormatSettings", - storages = {@Storage("google-java-format.xml")}) -class GoogleJavaFormatSettings implements PersistentStateComponent { - - private final Project project; - - private State state = new State(); - - GoogleJavaFormatSettings(Project project) { - this.project = project; - } - - static GoogleJavaFormatSettings getInstance(Project project) { - return project.getService(GoogleJavaFormatSettings.class); - } - - @Nullable - @Override - public State getState() { - return state; - } - - @Override - public void loadState(@NotNull State state) { - this.state = state; - } - - boolean isEnabled() { - return state.enabled.equals(EnabledState.ENABLED); - } - - void setEnabled(boolean enabled) { - setEnabled(enabled ? EnabledState.ENABLED : EnabledState.DISABLED); - } - - void setEnabled(EnabledState enabled) { - if (enabled.equals(EnabledState.ENABLED)) { - JreConfigurationChecker.checkJreConfiguration(project); - } - state.enabled = enabled; - } - - boolean isUninitialized() { - return state.enabled.equals(EnabledState.UNKNOWN); - } - - JavaFormatterOptions.Style getStyle() { - return state.style; - } - - void setStyle(JavaFormatterOptions.Style style) { - state.style = style; - } - - enum EnabledState { - UNKNOWN, - ENABLED, - DISABLED - } - - static class State { - - private EnabledState enabled = EnabledState.UNKNOWN; - public JavaFormatterOptions.Style style = JavaFormatterOptions.Style.GOOGLE; - - // enabled used to be a boolean so we use bean property methods for backwards compatibility - public void setEnabled(@Nullable String enabledStr) { - if (enabledStr == null) { - enabled = EnabledState.UNKNOWN; - } else if (Boolean.parseBoolean(enabledStr)) { - enabled = EnabledState.ENABLED; - } else { - enabled = EnabledState.DISABLED; - } - } - - public String getEnabled() { - switch (enabled) { - case ENABLED: - return "true"; - case DISABLED: - return "false"; - default: - return null; - } - } - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationNotifier.kt b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationNotifier.kt deleted file mode 100644 index d5d4c83da..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/InitialConfigurationNotifier.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2025 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij - -import com.intellij.notification.Notification -import com.intellij.notification.NotificationAction -import com.intellij.notification.NotificationGroupManager -import com.intellij.notification.NotificationType -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.intellij.openapi.startup.ProjectActivity - -private class InitialConfigurationNotifier : ProjectActivity { - - companion object { - const val NOTIFICATION_TITLE: String = "Enable google-java-format" - } - - override suspend fun execute(project: Project) { - val settings = GoogleJavaFormatSettings.getInstance(project) - - if (settings.isUninitialized) { - settings.isEnabled = false - displayNewUserNotification(project, settings) - } else if (settings.isEnabled) { - JreConfigurationChecker.checkJreConfiguration(project) - } - } - - private fun displayNewUserNotification(project: Project?, settings: GoogleJavaFormatSettings) { - val groupManager = NotificationGroupManager.getInstance() - val group = groupManager.getNotificationGroup(NOTIFICATION_TITLE) - val notification = - Notification( - group.displayId, - NOTIFICATION_TITLE, - "The google-java-format plugin is disabled by default.", - NotificationType.INFORMATION - ) - notification.addAction( - object : NotificationAction("Enable for this project") { - override fun actionPerformed( - anActionEvent: AnActionEvent, notification: Notification - ) { - settings.isEnabled = true - notification.expire() - } - }) - notification.notify(project) - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/JreConfigurationChecker.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/JreConfigurationChecker.java deleted file mode 100644 index 0bc3572e8..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/JreConfigurationChecker.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.common.base.Suppliers; -import com.intellij.ide.BrowserUtil; -import com.intellij.notification.Notification; -import com.intellij.notification.NotificationAction; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import java.util.function.Supplier; -import org.jetbrains.annotations.NotNull; - -class JreConfigurationChecker { - - private static final Supplier hasAccess = - Suppliers.memoize(JreConfigurationChecker::checkJreConfiguration); - private static final Logger logger = Logger.getInstance(JreConfigurationChecker.class); - - private final Project project; - - public JreConfigurationChecker(Project project) { - this.project = project; - } - - static boolean checkJreConfiguration(Project project) { - var success = hasAccess.get(); - if (!success) { - project.getService(JreConfigurationChecker.class).displayConfigurationErrorNotification(); - } - return success; - } - - /** - * Determine whether the JRE is configured to work with the google-java-format plugin. If not, - * display a notification with instructions and return false. - */ - private static boolean checkJreConfiguration() { - try { - return testClassAccess( - "com.sun.tools.javac.api.JavacTrees", - "com.sun.tools.javac.code.Flags", - "com.sun.tools.javac.file.JavacFileManager", - "com.sun.tools.javac.parser.JavacParser", - "com.sun.tools.javac.tree.JCTree", - "com.sun.tools.javac.util.Log"); - } catch (ClassNotFoundException e) { - logger.error("Error checking jre configuration for google-java-format", e); - return false; - } - } - - private static boolean testClassAccess(String... classNames) throws ClassNotFoundException { - for (String className : classNames) { - if (!testClassAccess(className)) { - return false; - } - } - return true; - } - - private static boolean testClassAccess(String className) throws ClassNotFoundException { - Class klass = Class.forName(className); - return klass - .getModule() - // isExported returns true if the package is either open or exported. Either one is - // sufficient - // to run the google-java-format code (even though the documentation specifies --add-opens). - .isExported( - klass.getPackageName(), - JreConfigurationChecker.class.getClassLoader().getUnnamedModule()); - } - - private void displayConfigurationErrorNotification() { - Notification notification = - new Notification( - "Configure JRE for google-java-format", - "Configure the JRE for google-java-format", - "The google-java-format plugin needs additional configuration before it can be used.", - NotificationType.INFORMATION); - notification.addAction( - new NotificationAction("Follow the instructions here") { - @Override - public void actionPerformed( - @NotNull AnActionEvent anActionEvent, @NotNull Notification notification) { - BrowserUtil.browse( - "https://github.com/google/google-java-format/blob/master/README.md#intellij-jre-config"); - notification.expire(); - } - }); - notification.notify(project); - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/Notifications.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/Notifications.java deleted file mode 100644 index d32aa98b9..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/Notifications.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.intellij.formatting.service.FormattingNotificationService; -import com.intellij.openapi.project.Project; - -class Notifications { - - static final String PARSING_ERROR_NOTIFICATION_GROUP = "google-java-format parsing error"; - static final String PARSING_ERROR_TITLE = PARSING_ERROR_NOTIFICATION_GROUP; - - static String parsingErrorMessage(String filename) { - return "google-java-format failed. Does " + filename + " have syntax errors?"; - } - - static void displayParsingErrorNotification(Project project, String filename) { - FormattingNotificationService.getInstance(project) - .reportError( - Notifications.PARSING_ERROR_NOTIFICATION_GROUP, - Notifications.PARSING_ERROR_TITLE, - Notifications.parsingErrorMessage(filename)); - } -} diff --git a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/UiFormatterStyle.java b/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/UiFormatterStyle.java deleted file mode 100644 index 24ed6f62c..000000000 --- a/idea_plugin/src/main/java/com/google/googlejavaformat/intellij/UiFormatterStyle.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import com.google.googlejavaformat.java.JavaFormatterOptions; -import com.google.googlejavaformat.java.JavaFormatterOptions.Style; -import java.util.Arrays; -import java.util.Objects; - -/** Configuration options for the formatting style. */ -enum UiFormatterStyle { - GOOGLE("Default Google Java style", Style.GOOGLE), - AOSP("Android Open Source Project (AOSP) style", Style.AOSP); - - private final String description; - private final JavaFormatterOptions.Style style; - - UiFormatterStyle(String description, JavaFormatterOptions.Style style) { - this.description = description; - this.style = style; - } - - @Override - public String toString() { - return description; - } - - public JavaFormatterOptions.Style convert() { - return style; - } - - static UiFormatterStyle convert(JavaFormatterOptions.Style style) { - return Arrays.stream(UiFormatterStyle.values()) - .filter(value -> Objects.equals(value.style, style)) - .findFirst() - .get(); - } -} diff --git a/idea_plugin/src/main/resources/META-INF/plugin.xml b/idea_plugin/src/main/resources/META-INF/plugin.xml deleted file mode 100644 index 11d7d4877..000000000 --- a/idea_plugin/src/main/resources/META-INF/plugin.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - google-java-format - google-java-format - - Google - - - com.intellij.modules.java - com.intellij.modules.lang - com.intellij.modules.platform - - - - This plugin requires additional IDE configuration. For more information, - read - the documentation. - ]]> - -
1.31.0.0
-
Updated to use google-java-format 1.31.0.
-
1.30.0.1
-
Add support for 2024.2 IDE versions, which were mistakenly excluded.
-
1.30.0.0
-
Updated to use google-java-format 1.30.0.
-
1.29.0.1
-
Remove uses of deprecated IntelliJ plugin APIs.
-
1.29.0.0
-
Updated to use google-java-format 1.29.0.
-
Minimum supported IntelliJ version is now 2024.3.
-
1.28.0.0
-
Updated to use google-java-format 1.28.0.
-
1.27.0.0
-
Updated to use google-java-format 1.27.0.
-
1.26.0.0
-
Updated to use google-java-format 1.26.0.
-
1.25.2.0
-
Updated to use google-java-format 1.25.2.
-
1.25.1.0
-
Updated to use google-java-format 1.25.1.
-
1.25.0.0
-
Updated to use google-java-format 1.25.0.
-
1.24.0.0
-
Updated to use google-java-format 1.24.0.
-
1.23.0.0
-
Updated to use google-java-format 1.23.0.
-
Fix crashes in IntelliJ 2024.2 (Thanks, @nrayburn-tech!)
-
Updated to the latest IntelliJ build system (Thanks, @mmaeller!)
-
1.22.0.0
-
Updated to use google-java-format 1.22.0.
-
1.21.0.0
-
Updated to use google-java-format 1.21.0.
-
1.20.0.0
-
Updated to use google-java-format 1.20.0.
-
1.19.2.0
-
Updated to use google-java-format 1.19.2.
-
1.17.0.0
-
Updated to use google-java-format 1.17.0.
-
Fixed "Document is locked" errors (Thanks, @facboy!)
-
1.16.0.2
-
Disable AD_HOC_FORMATTING, which should stop the formatter from running so often when it wasn't specifically requested. -
1.16.0.1
-
When the plugin isn't configured correctly, show the error on every - format command. Previously it was only being shown at startup and going - unnoticed. -
1.16.0.0
-
Updated to use google-java-format 1.16.0.
-
Use the new IDE formatting APIs for a simplified plugin.
-
Optimize Imports now uses google-java-format.
-
1.15.0.0
-
Updated to use google-java-format 1.15.0.
-
1.14.0.0
-
Updated to use google-java-format 1.14.
-
1.13.0.0
-
Updated to use google-java-format 1.13.
-
1.12.0.0
-
Updated to use google-java-format 1.12.
-
1.11.0.0
-
Updated to use google-java-format 1.11.
-
1.10.0.0
-
Updated to use google-java-format 1.10.
-
1.9.0.0
-
Updated to use google-java-format 1.9.
-
1.8.0.1
-
Fixed support for 2020.2 IDEs.
-
1.8.0.0
-
Updated to use google-java-format 1.8.
-
1.7.0.5
-
Added a version for 2020.1+ IDEs.
-
1.7.0.4
-
Marked the plugin as being incompatible with 2020.1+ IDEs.
-
1.7.0.3
-
Fixed the plugin on 2019.3 IDEs.
-
1.7.0.2
-
Added support for all IDEs after 2017.3.
-
1.7.0.1
-
Added support for 2019.1 IDEs.
-
1.7.0.0
-
Upgraded to google-java-format 1.7.
- - ]]>
- - - - - - - - - - - - -
diff --git a/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingServiceTest.java b/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingServiceTest.java deleted file mode 100644 index fec086c68..000000000 --- a/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatFormattingServiceTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; -import com.google.googlejavaformat.intellij.GoogleJavaFormatSettings.State; -import com.google.googlejavaformat.java.Formatter; -import com.google.googlejavaformat.java.JavaFormatterOptions; -import com.google.googlejavaformat.java.JavaFormatterOptions.Style; -import com.intellij.formatting.service.AsyncFormattingRequest; -import com.intellij.formatting.service.FormattingService; -import com.intellij.formatting.service.FormattingServiceUtil; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.testFramework.ExtensionTestUtil; -import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; -import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; -import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; -import com.intellij.testFramework.fixtures.JavaTestFixtureFactory; -import com.intellij.testFramework.fixtures.TestFixtureBuilder; -import java.io.IOException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class GoogleJavaFormatFormattingServiceTest { - private JavaCodeInsightTestFixture fixture; - private GoogleJavaFormatSettings settings; - private DelegatingFormatter delegatingFormatter; - - @Before - public void setUp() throws Exception { - TestFixtureBuilder projectBuilder = - IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getClass().getName()); - fixture = - JavaTestFixtureFactory.getFixtureFactory() - .createCodeInsightFixture(projectBuilder.getFixture()); - fixture.setUp(); - - delegatingFormatter = new DelegatingFormatter(); - ExtensionTestUtil.maskExtensions( - FormattingService.EP_NAME, - ImmutableList.of(delegatingFormatter), - fixture.getProjectDisposable()); - - settings = GoogleJavaFormatSettings.getInstance(fixture.getProject()); - State resetState = new State(); - resetState.setEnabled("true"); - settings.loadState(resetState); - } - - @After - public void tearDown() throws Exception { - fixture.tearDown(); - } - - @Test - public void defaultFormatSettings() throws Exception { - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "static final String CONST_STR = \"Hello\";", - "}"); - String origText = file.getText(); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - WriteCommandAction.runWriteCommandAction( - file.getProject(), () -> manager.reformatText(file, 0, file.getTextLength())); - - assertThat(file.getText()).isEqualTo(new Formatter().formatSource(origText)); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void aospStyle() throws Exception { - settings.setStyle(Style.AOSP); - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "static final String CONST_STR = \"Hello\";", - "}"); - String origText = file.getText(); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - WriteCommandAction.runWriteCommandAction( - file.getProject(), () -> manager.reformatText(file, 0, file.getTextLength())); - - assertThat(file.getText()) - .isEqualTo( - new Formatter(JavaFormatterOptions.builder().style(Style.AOSP).build()) - .formatSource(origText)); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void canChangeWhitespaceOnlyDoesNotReorderModifiers() throws Exception { - settings.setStyle(Style.GOOGLE); - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "final static String CONST_STR = \"Hello\";", - "}"); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - var offset = file.getText().indexOf("final static"); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> - FormattingServiceUtil.formatElement( - file.findElementAt(offset), /* canChangeWhitespaceOnly= */ true)); - - // In non-whitespace mode, this would flip the order of these modifiers. (Also check for leading - // spaces to make sure the formatter actually ran. - assertThat(file.getText()).containsMatch(" final static"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void canChangeWhitespaceOnlyDoesNotReformatJavadoc() throws Exception { - settings.setStyle(Style.GOOGLE); - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "/**", - " * hello", - " */", - "static final String CONST_STR = \"Hello\";", - "}"); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - var offset = file.getText().indexOf("hello"); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> - FormattingServiceUtil.formatElement( - file.findElementAt(offset), /* canChangeWhitespaceOnly= */ true)); - - // In non-whitespace mode, this would join the Javadoc into a single line. - assertThat(file.getText()).containsMatch(" \\* hello"); - // Also check for leading spaces to make sure the formatter actually ran. (Technically, this is - // outside the range that we asked to be formatted, but gjf will still format it.) - assertThat(file.getText()).containsMatch(" static final"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void canChangeNonWhitespaceReordersModifiers() throws Exception { - settings.setStyle(Style.GOOGLE); - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "final static String CONST_STR = \"Hello\";", - "}"); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - var offset = file.getText().indexOf("final static"); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> - FormattingServiceUtil.formatElement( - file.findElementAt(offset), /* canChangeWhitespaceOnly= */ false)); - - assertThat(file.getText()).containsMatch("static final"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void canChangeNonWhitespaceReformatsJavadoc() throws Exception { - settings.setStyle(Style.GOOGLE); - PsiFile file = - createPsiFile( - "com/foo/FormatTest.java", - "package com.foo;", - "public class FormatTest {", - "/**", - " * hello", - " */", - "static final String CONST_STR = \"Hello\";", - "}"); - CodeStyleManager manager = CodeStyleManager.getInstance(file.getProject()); - var offset = file.getText().indexOf("hello"); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> - FormattingServiceUtil.formatElement( - file.findElementAt(offset), /* canChangeWhitespaceOnly= */ false)); - - assertThat(file.getText()).containsMatch("/\\*\\* hello \\*/"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - private PsiFile createPsiFile(String path, String... contents) throws IOException { - VirtualFile virtualFile = - fixture.getTempDirFixture().createFile(path, String.join("\n", contents)); - fixture.configureFromExistingVirtualFile(virtualFile); - PsiFile psiFile = fixture.getFile(); - assertThat(psiFile).isNotNull(); - return psiFile; - } - - private static final class DelegatingFormatter extends GoogleJavaFormatFormattingService { - - private boolean invoked = false; - - private boolean wasInvoked() { - return invoked; - } - - @Override - protected FormattingTask createFormattingTask(AsyncFormattingRequest request) { - FormattingTask delegateTask = super.createFormattingTask(request); - return new FormattingTask() { - @Override - public boolean cancel() { - return delegateTask.cancel(); - } - - @Override - public void run() { - invoked = true; - delegateTask.run(); - } - }; - } - } -} diff --git a/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizerTest.java b/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizerTest.java deleted file mode 100644 index ad9fe2744..000000000 --- a/idea_plugin/src/test/java/com/google/googlejavaformat/intellij/GoogleJavaFormatImportOptimizerTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2023 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.googlejavaformat.intellij; - -import static com.google.common.collect.ImmutableSet.toImmutableSet; -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; -import com.google.googlejavaformat.intellij.GoogleJavaFormatSettings.State; -import com.intellij.codeInsight.actions.OptimizeImportsProcessor; -import com.intellij.formatting.service.FormattingService; -import com.intellij.lang.ImportOptimizer; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.testFramework.ExtensionTestUtil; -import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; -import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; -import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; -import com.intellij.testFramework.fixtures.JavaTestFixtureFactory; -import com.intellij.testFramework.fixtures.TestFixtureBuilder; -import java.io.IOException; -import java.util.Set; -import org.jetbrains.annotations.NotNull; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class GoogleJavaFormatImportOptimizerTest { - private JavaCodeInsightTestFixture fixture; - private DelegatingFormatter delegatingFormatter; - - @Before - public void setUp() throws Exception { - TestFixtureBuilder projectBuilder = - IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getClass().getName()); - fixture = - JavaTestFixtureFactory.getFixtureFactory() - .createCodeInsightFixture(projectBuilder.getFixture()); - fixture.setUp(); - - delegatingFormatter = new DelegatingFormatter(); - ExtensionTestUtil.maskExtensions( - FormattingService.EP_NAME, - ImmutableList.of(delegatingFormatter), - fixture.getProjectDisposable()); - - var settings = GoogleJavaFormatSettings.getInstance(fixture.getProject()); - State resetState = new State(); - resetState.setEnabled("true"); - settings.loadState(resetState); - } - - @After - public void tearDown() throws Exception { - fixture.tearDown(); - } - - @Test - public void removesUnusedImports() throws Exception { - PsiFile file = - createPsiFile( - "com/foo/ImportTest.java", - "package com.foo;", - "import java.util.List;", - "import java.util.ArrayList;", - "import java.util.Map;", - "public class ImportTest {", - "static final Map map;", - "}"); - OptimizeImportsProcessor processor = new OptimizeImportsProcessor(file.getProject(), file); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> { - processor.run(); - PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments(); - }); - - assertThat(file.getText()).doesNotContain("List"); - assertThat(file.getText()).contains("import java.util.Map;"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - @Test - public void reordersImports() throws Exception { - PsiFile file = - createPsiFile( - "com/foo/ImportTest.java", - "package com.foo;", - "import java.util.List;", - "import java.util.ArrayList;", - "import java.util.Map;", - "public class ImportTest {", - "static final ArrayList arrayList;", - "static final List list;", - "static final Map map;", - "}"); - OptimizeImportsProcessor processor = new OptimizeImportsProcessor(file.getProject(), file); - WriteCommandAction.runWriteCommandAction( - file.getProject(), - () -> { - processor.run(); - PsiDocumentManager.getInstance(file.getProject()).commitAllDocuments(); - }); - - assertThat(file.getText()) - .contains( - "import java.util.ArrayList;\n" - + "import java.util.List;\n" - + "import java.util.Map;\n"); - assertThat(delegatingFormatter.wasInvoked()).isTrue(); - } - - private PsiFile createPsiFile(String path, String... contents) throws IOException { - VirtualFile virtualFile = - fixture.getTempDirFixture().createFile(path, String.join("\n", contents)); - fixture.configureFromExistingVirtualFile(virtualFile); - PsiFile psiFile = fixture.getFile(); - assertThat(psiFile).isNotNull(); - return psiFile; - } - - private static final class DelegatingFormatter extends GoogleJavaFormatFormattingService { - - private boolean invoked = false; - - private boolean wasInvoked() { - return invoked; - } - - @Override - public @NotNull Set getImportOptimizers(@NotNull PsiFile file) { - return super.getImportOptimizers(file).stream().map(this::wrap).collect(toImmutableSet()); - } - - private ImportOptimizer wrap(ImportOptimizer delegate) { - return new ImportOptimizer() { - @Override - public boolean supports(@NotNull PsiFile file) { - return delegate.supports(file); - } - - @Override - public @NotNull Runnable processFile(@NotNull PsiFile file) { - return () -> { - invoked = true; - delegate.processFile(file).run(); - }; - } - }; - } - } -} diff --git a/pom.xml b/pom.xml index 46306c196..77fa2746c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,21 +15,25 @@ ~ limitations under the License. --> - + 4.0.0 - com.google.googlejavaformat - google-java-format-parent + io.github.mrdolch.formatter + configurable-java-format-parent pom - HEAD-SNAPSHOT + 2026.1.0 + Java Format Parent + + + https://github.com/trick77/configurable-google-java-format + scm:git:https://github.com/trick77/configurable-google-java-format.git + HEAD + core - Google Java Format Parent A Java source code formatter that follows Google Java Style. @@ -67,18 +71,6 @@ - - http://github.com/google/google-java-format/ - scm:git:git://github.com/google/google-java-format.git - scm:git:ssh://git@github.com/google/google-java-format.git - HEAD - - - - GitHub Issues - http://github.com/google/google-java-format/issues - - 3.0.3 @@ -86,15 +78,14 @@ UTF-8 1.8 - 32.1.3-jre - 1.4.0 + 33.4.8-jre + 1.4.4 1.0.0 2.45.0 - 1.9 - 1.0.1 - 3.6.3 - 3.2.1 - 0.8.0 + 1.11.0 + 1.1.1 + 3.11.2 + 3.3.1 @@ -161,15 +152,15 @@ maven-compiler-plugin - 3.9.0 + 3.14.0 maven-jar-plugin - 3.2.2 + 3.4.2 maven-source-plugin - 3.2.1 + 3.3.1 maven-javadoc-plugin @@ -177,12 +168,22 @@ maven-gpg-plugin - 3.0.1 + 3.2.8 org.apache.felix maven-bundle-plugin - 5.1.4 + 6.0.0 + + + org.apache.maven.plugins + maven-release-plugin + 3.1.1 + + -ntp + + @{project.version} + @@ -254,7 +255,7 @@ attach-sources - jar + jar-no-fork
@@ -278,7 +279,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.5.3 @@ -299,13 +300,6 @@ - - - sonatype-nexus-snapshots - https://central.sonatype.com/repository/maven-snapshots/ - - - sonatype-oss-release @@ -314,42 +308,18 @@ org.sonatype.central central-publishing-maven-plugin - ${central-publishing-maven-plugin.version} + 0.8.0 true - central + false + ${project.artifactId}:${project.version} + validated - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin.version} - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - - attach-javadocs - - jar - - - - org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.2.8 sign-artifacts @@ -363,14 +333,5 @@ - - eclipse - - [17,) - - - eclipse_plugin - -
diff --git a/scripts/google-java-format-diff.py b/scripts/google-java-format-diff.py deleted file mode 100755 index 7f52ed1ec..000000000 --- a/scripts/google-java-format-diff.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env python3 -# -# ===- google-java-format-diff.py - google-java-format Diff Reformatter -----===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -# ===------------------------------------------------------------------------===# - -""" -google-java-format Diff Reformatter -============================ - -This script reads input from a unified diff and reformats all the changed -lines. This is useful to reformat all the lines touched by a specific patch. -Example usage for git/svn users: - - git diff -U0 HEAD^ | google-java-format-diff.py -p1 -i - svn diff --diff-cmd=diff -x-U0 | google-java-format-diff.py -i - -For perforce users: - - P4DIFF="git --no-pager diff --no-index" p4 diff | ./google-java-format-diff.py -i -p7 - -""" - -import argparse -import difflib -import re -import string -import subprocess -import io -import sys -from concurrent.futures import ThreadPoolExecutor,wait,FIRST_EXCEPTION -from shutil import which - -def _apply_format(filename, lines, base_command, args): - """Apply format on filename.""" - if args.i and args.verbose: - print('Formatting', filename) - - command = base_command[:] - command.extend(lines) - command.append(filename) - p = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=None, stdin=subprocess.PIPE) - stdout, _ = p.communicate() - if p.returncode != 0: - sys.exit(p.returncode) - - if not args.i: - with open(filename) as f: - code = f.readlines() - formatted_code = io.StringIO(stdout.decode('utf-8')).readlines() - diff = difflib.unified_diff(code, formatted_code, - filename, filename, - '(before formatting)', '(after formatting)') - diff_string = ''.join(diff) - if len(diff_string) > 0: - sys.stdout.write(diff_string) - -def main(): - parser = argparse.ArgumentParser(description= - 'Reformat changed lines in diff. Without -i ' - 'option just output the diff that would be ' - 'introduced.') - parser.add_argument('-i', action='store_true', default=False, - help='apply edits to files instead of displaying a diff') - - parser.add_argument('-p', metavar='NUM', default=0, - help='strip the smallest prefix containing P slashes') - parser.add_argument('-regex', metavar='PATTERN', default=None, - help='custom pattern selecting file paths to reformat ' - '(case sensitive, overrides -iregex)') - parser.add_argument('-iregex', metavar='PATTERN', default=r'.*\.java', - help='custom pattern selecting file paths to reformat ' - '(case insensitive, overridden by -regex)') - parser.add_argument('-v', '--verbose', action='store_true', - help='be more verbose, ineffective without -i') - parser.add_argument('-a', '--aosp', action='store_true', - help='use AOSP style instead of Google Style (4-space indentation)') - parser.add_argument('--skip-sorting-imports', action='store_true', - help='do not fix the import order') - parser.add_argument('--skip-removing-unused-imports', action='store_true', - help='do not remove ununsed imports') - parser.add_argument( - '--skip-javadoc-formatting', - action='store_true', - default=False, - help='do not reformat javadoc') - parser.add_argument('-b', '--binary', help='path to google-java-format binary') - parser.add_argument('--google-java-format-jar', metavar='ABSOLUTE_PATH', default=None, - help='use a custom google-java-format jar') - - args = parser.parse_args() - - # Extract changed lines for each file. - filename = None - lines_by_file = {} - - for line in sys.stdin: - match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) - if match: - filename = match.group(2) - if filename == None: - continue - - if args.regex is not None: - if not re.match('^%s$' % args.regex, filename): - continue - else: - if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): - continue - - match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) - if match: - start_line = int(match.group(1)) - line_count = 1 - if match.group(3): - line_count = int(match.group(3)) - if line_count == 0: - continue - end_line = start_line + line_count - 1; - lines_by_file.setdefault(filename, []).extend( - ['-lines', str(start_line) + ':' + str(end_line)]) - - if args.binary: - base_command = [args.binary] - elif args.google_java_format_jar: - base_command = ['java', '-jar', args.google_java_format_jar] - else: - binary = which('google-java-format') or '/usr/bin/google-java-format' - base_command = [binary] - - if args.i: - base_command.append('-i') - if args.aosp: - base_command.append('--aosp') - if args.skip_sorting_imports: - base_command.append('--skip-sorting-imports') - if args.skip_removing_unused_imports: - base_command.append('--skip-removing-unused-imports') - if args.skip_javadoc_formatting: - base_command.append('--skip-javadoc-formatting') - - with ThreadPoolExecutor() as executor: - format_futures = [] - for filename, lines in lines_by_file.items(): - format_futures.append( - executor.submit(_apply_format, filename, lines, base_command, args) - ) - - done, _ = wait(format_futures, return_when=FIRST_EXCEPTION) - for future in done: - if exception := future.exception(): - executor.shutdown(wait=True, cancel_futures=True) - sys.exit(exception.args[0]) - -if __name__ == '__main__': - main() diff --git a/util/publish-snapshot-on-commit.sh b/util/publish-snapshot-on-commit.sh deleted file mode 100755 index c14368da1..000000000 --- a/util/publish-snapshot-on-commit.sh +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2020 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# https://github.com/google/dagger/blob/master/util/publish-snapshot-on-commit.sh - -if [ "$TRAVIS_REPO_SLUG" == "google/google-java-format" ] && \ - [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ] && \ - [ "$TRAVIS_PULL_REQUEST" == "false" ] && \ - [ "$TRAVIS_BRANCH" == "master" ]; then - echo -e "Publishing maven snapshot...\n" - - mvn clean source:jar deploy --settings="util/settings.xml" -DskipTests=true -Dinvoker.skip=true -Dmaven.javadoc.skip=true - - echo -e "Published maven snapshot" -fi diff --git a/util/settings.xml b/util/settings.xml deleted file mode 100644 index aea3d4ef7..000000000 --- a/util/settings.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - sonatype-nexus-snapshots - ${env.CI_DEPLOY_USERNAME} - ${env.CI_DEPLOY_PASSWORD} - - - diff --git a/util/test-native.sh b/util/test-native.sh deleted file mode 100755 index a8643baf2..000000000 --- a/util/test-native.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2024 The Google Java Format Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euox pipefail - -time java -jar core/target/google-java-format-*-all-deps.jar || true - -status=-1 -chmod +x core/target/google-java-format -if time core/target/google-java-format; then - status=0 -else - status=$? -fi -if [[ $status -ne 2 ]]; then - echo "google-java-format_linux (native) without arguments should have printed usage help and exited with 2, but did not :(" - exit 1 -fi