Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configurable EOL specifier #27

Merged
merged 2 commits into from
Apr 25, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
/.classpath
/.project
/.settings/
/.idea/
/*.iml
8 changes: 4 additions & 4 deletions src/main/java/net/revelc/code/impsort/Grouper.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public boolean getJoinStaticWithNonStatic() {
return joinStaticWithNonStatic;
}

public String groupedImports(Collection<Import> allImports) {
public String groupedImports(Collection<Import> allImports, String eol) {
StringBuilder sb = new StringBuilder();
Map<Integer, ArrayList<Import>> staticImports = groupStatic(allImports);
Map<Integer, ArrayList<Import>> nonStaticImports = groupNonStatic(allImports);
Expand All @@ -135,13 +135,13 @@ public String groupedImports(Collection<Import> allImports) {
AtomicBoolean firstGroup = new AtomicBoolean(true);
Consumer<ArrayList<Import>> consumer = grouping -> {
if (!firstGroup.getAndSet(false)) {
sb.append("\n");
sb.append(eol);
}
grouping.forEach(imp -> sb.append(imp).append("\n"));
grouping.forEach(imp -> sb.append(imp).append(eol));
};
first.values().forEach(consumer);
if (!getJoinStaticWithNonStatic() && !first.isEmpty() && !second.isEmpty()) {
sb.append("\n");
sb.append(eol);
}
firstGroup.set(true);
second.values().forEach(consumer);
Expand Down
44 changes: 28 additions & 16 deletions src/main/java/net/revelc/code/impsort/ImpSort.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
Expand Down Expand Up @@ -55,33 +56,42 @@

public class ImpSort {

private static final Comparator<Node> BY_POSITION =
(a, b) -> a.getBegin().get().compareTo(b.getBegin().get());
private static final Comparator<Node> BY_POSITION = Comparator.comparing(a -> a.getBegin().get());

private final Charset sourceEncoding;
private final Grouper grouper;
private final boolean removeUnused;
private final boolean treatSamePackageAsUnused;
private final LineEnding lineEnding;

public ImpSort(final Charset sourceEncoding, final Grouper grouper, final boolean removeUnused,
final boolean treatSamePackageAsUnused) {
final boolean treatSamePackageAsUnused, final LineEnding lineEnding) {
this.sourceEncoding = sourceEncoding;
this.grouper = grouper;
this.removeUnused = removeUnused;
this.treatSamePackageAsUnused = treatSamePackageAsUnused;
this.lineEnding = lineEnding;
}

public Result parseFile(final Path path) throws IOException {
List<String> fileLines = Files.readAllLines(path, sourceEncoding);
ParseResult<CompilationUnit> parseResult = new JavaParser().parse(String.join("\n", fileLines));
String file = new String(Files.readAllBytes(path), sourceEncoding);
LineEnding fileLineEnding = LineEnding.determineLineEnding(file);
LineEnding impLineEnding;
if (lineEnding == LineEnding.KEEP) {
impLineEnding = fileLineEnding;
} else {
impLineEnding = lineEnding;
}
List<String> fileLines = Arrays.asList(file.split(fileLineEnding.getChars()));
ParseResult<CompilationUnit> parseResult = new JavaParser().parse(file);
CompilationUnit unit =
parseResult.getResult().orElseThrow(() -> new IOException("Unable to parse " + path));
Position packagePosition =
unit.getPackageDeclaration().map(p -> p.getEnd().get()).orElse(unit.getBegin().get());
NodeList<ImportDeclaration> importDeclarations = unit.getImports();
if (importDeclarations.isEmpty()) {
return new Result(path, sourceEncoding, fileLines, 0, fileLines.size(), "", "",
Collections.emptyList());
Collections.emptyList(), impLineEnding);
}

// find orphaned comments before between package and last import
Expand All @@ -107,9 +117,10 @@ public Result parseFile(final Path path) throws IOException {
while (stop < fileLines.size() && fileLines.get(stop).trim().isEmpty()) {
++stop;
}
String originalSection = String.join("\n", fileLines.subList(start, stop)) + "\n";
String originalSection = String.join(impLineEnding.getChars(), fileLines.subList(start, stop))
+ impLineEnding.getChars();

Set<Import> allImports = convertImportSection(importSectionNodes);
Set<Import> allImports = convertImportSection(importSectionNodes, impLineEnding.getChars());

if (removeUnused) {
removeUnusedImports(allImports, tokensInUse(unit));
Expand All @@ -118,22 +129,22 @@ public Result parseFile(final Path path) throws IOException {
}
}

String newSection = grouper.groupedImports(allImports);
String newSection = grouper.groupedImports(allImports, impLineEnding.getChars());
if (start > 0) {
// add newline before imports, as long as imports not at start of file
newSection = "\n" + newSection;
newSection = impLineEnding.getChars() + newSection;
}
if (stop < fileLines.size()) {
// add newline after imports, as long as there's more in file
newSection += "\n";
newSection += impLineEnding.getChars();
}

return new Result(path, sourceEncoding, fileLines, start, stop, originalSection, newSection,
allImports);
allImports, impLineEnding);
}

// return imports, with associated comments, in order found in the file
private static Set<Import> convertImportSection(List<Node> importSectionNodes) {
private static Set<Import> convertImportSection(List<Node> importSectionNodes, String eol) {
List<Comment> recentComments = new ArrayList<>();
LinkedHashSet<Import> allImports = new LinkedHashSet<>(importSectionNodes.size() / 2);
for (Node node : importSectionNodes) {
Expand All @@ -159,7 +170,7 @@ private static Set<Import> convertImportSection(List<Node> importSectionNodes) {
}

recentComments.clear();
convertAndAddImport(allImports, thisImport);
convertAndAddImport(allImports, thisImport, eol);
} else {
throw new IllegalStateException("Unknown node: " + node);
}
Expand All @@ -171,7 +182,8 @@ private static Set<Import> convertImportSection(List<Node> importSectionNodes) {
return allImports;
}

private static void convertAndAddImport(LinkedHashSet<Import> allImports, List<Node> thisImport) {
private static void convertAndAddImport(LinkedHashSet<Import> allImports, List<Node> thisImport,
String eol) {
boolean isStatic = false;
String importItem = null;
String prefix = "";
Expand All @@ -194,7 +206,7 @@ private static void convertAndAddImport(LinkedHashSet<Import> allImports, List<N
if (!suffix.isEmpty()) {
suffix = " " + suffix;
}
Import imp = new Import(isStatic, importItem, prefix.trim(), suffix);
Import imp = new Import(isStatic, importItem, prefix.trim(), suffix, eol);
Iterator<Import> iter = allImports.iterator();
// this de-duplication can probably be made more efficient by doing it all at the end
while (iter.hasNext()) {
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/net/revelc/code/impsort/Import.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ public class Import {
private final String imp;
private final String prefix;
private final String suffix;
private final String eol;

Import(final boolean isStatic, final String imp, final String prefix, final String suffix) {
Import(final boolean isStatic, final String imp, final String prefix, final String suffix,
final String eol) {
this.isStatic = isStatic;
this.imp = Objects.requireNonNull(imp);
this.prefix = Objects.requireNonNull(prefix);
this.suffix = Objects.requireNonNull(suffix);
this.eol = eol;
}

public boolean isStatic() {
Expand All @@ -48,7 +51,7 @@ public String getSuffix() {

@Override
public String toString() {
return prefix + (prefix.isEmpty() ? "" : "\n") + "import" + (isStatic() ? " static" : "") + " "
return prefix + (prefix.isEmpty() ? "" : eol) + "import" + (isStatic() ? " static" : "") + " "
+ getImport() + ";" + suffix;
}

Expand Down Expand Up @@ -83,7 +86,7 @@ public Import combineWith(Import duplicate) {
} else if (duplicate.getPrefix().isEmpty()) {
newPrefix = getPrefix();
} else {
newPrefix = getPrefix() + "\n" + duplicate.getPrefix();
newPrefix = getPrefix() + eol + duplicate.getPrefix();
}
if (getSuffix().isEmpty()) {
newSuffix = duplicate.getSuffix();
Expand All @@ -92,7 +95,7 @@ public Import combineWith(Import duplicate) {
} else {
newSuffix = getSuffix() + duplicate.getSuffix();
}
return new Import(isStatic(), getImport(), newPrefix, newSuffix);
return new Import(isStatic(), getImport(), newPrefix, newSuffix, eol);
}

}
66 changes: 66 additions & 0 deletions src/main/java/net/revelc/code/impsort/LineEnding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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 net.revelc.code.impsort;

/**
* @author marvin.froeder
*/
public enum LineEnding {

AUTO(System.lineSeparator()), KEEP(null), LF("\n"), CRLF("\r\n"), CR("\r"), UNKNOWN(null);

private final String chars;

LineEnding(String value) {
this.chars = value;
}

public String getChars() {
return this.chars;
}

/**
* Returns the most occurring line-ending characters in the file text or null if no line-ending
* occurs the most.
*/
public static LineEnding determineLineEnding(String fileDataString) {
int lfCount = 0;
int crCount = 0;
int crlfCount = 0;

for (int i = 0; i < fileDataString.length(); i++) {
char c = fileDataString.charAt(i);
if (c == '\r') {
if ((i + 1) < fileDataString.length() && fileDataString.charAt(i + 1) == '\n') {
crlfCount++;
i++;
} else {
crCount++;
}
} else if (c == '\n') {
lfCount++;
}
}

if (lfCount > crCount && lfCount > crlfCount) {
return LF;
} else if (crlfCount > lfCount && crlfCount > crCount) {
return CRLF;
} else if (crCount > lfCount && crCount > crlfCount) {
return CR;
}
return UNKNOWN;
}

}
29 changes: 25 additions & 4 deletions src/main/java/net/revelc/code/impsort/Result.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@

package net.revelc.code.impsort;

import static java.nio.file.Files.newOutputStream;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -36,9 +41,11 @@ public class Result {
private final List<String> fileLines;
private final int start;
private final int stop;
private final LineEnding lineEnding;

Result(Path path, Charset sourceEncoding, List<String> fileLines, int start, int stop,
String originalSection, String newSection, Collection<Import> allImports) {
String originalSection, String newSection, Collection<Import> allImports,
LineEnding lineEnding) {
this.path = path;
this.sourceEncoding = sourceEncoding;
this.originalSection = originalSection;
Expand All @@ -47,6 +54,7 @@ public class Result {
this.fileLines = fileLines;
this.start = start;
this.stop = stop;
this.lineEnding = lineEnding;
}

public boolean isSorted() {
Expand All @@ -72,17 +80,30 @@ public void saveSorted(Path destination) throws IOException {
return;
}
List<String> beforeImports = fileLines.subList(0, start);
List<String> importLines = Arrays.asList(newSection.split("\\n"));
List<String> importLines = Arrays.asList(newSection.split(lineEnding.getChars()));
List<String> afterImports = fileLines.subList(stop, fileLines.size());
List<String> allLines =
new ArrayList<>(beforeImports.size() + importLines.size() + afterImports.size() + 1);
allLines.addAll(beforeImports);
allLines.addAll(importLines);
if (afterImports.size() > 0) {
allLines.add(""); // restore blank line lost by split("\\n")
allLines.add(""); // restore blank line lost by split
}
allLines.addAll(afterImports);
Files.write(destination, allLines, sourceEncoding);
writeLines(destination, allLines, sourceEncoding);
}

private Path writeLines(Path destination, List<String> lines, Charset sourceEncoding)
throws IOException {
try (OutputStream out = newOutputStream(destination);
BufferedWriter writer =
new BufferedWriter(new OutputStreamWriter(out, sourceEncoding.newEncoder()))) {
for (String line : lines) {
writer.write(line);
writer.write(lineEnding.getChars());
}
}
return destination;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import net.revelc.code.impsort.Grouper;
import net.revelc.code.impsort.ImpSort;
import net.revelc.code.impsort.LineEnding;
import net.revelc.code.impsort.Result;

abstract class AbstractImpSortMojo extends AbstractMojo {
Expand Down Expand Up @@ -174,6 +175,21 @@ abstract class AbstractImpSortMojo extends AbstractMojo {
defaultValue = "true")
private boolean breadthFirstComparator;

/**
* Sets the line-ending of files after formatting. Valid values are:
* <ul>
* <li><b>"AUTO"</b> - Use line endings of current system</li>
* <li><b>"KEEP"</b> - Preserve line endings of files, default to AUTO if ambiguous</li>
* <li><b>"LF"</b> - Use Unix and Mac style line endings</li>
* <li><b>"CRLF"</b> - Use DOS and Windows style line endings</li>
* <li><b>"CR"</b> - Use early Mac style line endings</li>
* </ul>
*
* @since 1.4.0
*/
@Parameter(defaultValue = "AUTO", property = "lineending", required = true)
private LineEnding lineEnding;

abstract void processResult(Path path, Result results) throws MojoFailureException;

@Override
Expand All @@ -199,7 +215,8 @@ public final void execute() throws MojoExecutionException, MojoFailureException
Grouper grouper = new Grouper(groups, staticGroups, staticAfter, joinStaticWithNonStatic,
breadthFirstComparator);
Charset encoding = Charset.forName(sourceEncoding);
ImpSort impSort = new ImpSort(encoding, grouper, removeUnused, treatSamePackageAsUnused);
ImpSort impSort =
new ImpSort(encoding, grouper, removeUnused, treatSamePackageAsUnused, lineEnding);
AtomicLong numAlreadySorted = new AtomicLong(0);
AtomicLong numProcessed = new AtomicLong(0);

Expand Down
Loading