From 1723e21b5e5cb274080dafddaafb72e1aa9ae572 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 19 Nov 2013 23:12:16 +0100 Subject: formatpreferences system v1 --- src/delombok/lombok/delombok/Delombok.java | 4 + src/delombok/lombok/delombok/DelombokResult.java | 3 +- .../lombok/delombok/DocCommentIntegrator.java | 21 +++ .../lombok/delombok/FormatPreferenceScanner.java | 165 +++++++++++++++++++++ .../lombok/delombok/FormatPreferences.java | 77 ++++++++++ 5 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 src/delombok/lombok/delombok/FormatPreferenceScanner.java create mode 100644 src/delombok/lombok/delombok/FormatPreferences.java (limited to 'src/delombok') diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 0128e44f..fb376a4e 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -88,6 +88,10 @@ public class Delombok { @Excludes("quiet") private boolean verbose; + @Shorthand("f") + @Description("Sets formatting rules. Use 'help' or 'list' to list all available rules. Unset format rules are inferred by scanning the source for usages.") + private List format = new ArrayList(); + @Shorthand("q") @Description("No warnings or errors will be emitted to standard error") @Excludes("verbose") diff --git a/src/delombok/lombok/delombok/DelombokResult.java b/src/delombok/lombok/delombok/DelombokResult.java index 6fd62bf6..866082d6 100644 --- a/src/delombok/lombok/delombok/DelombokResult.java +++ b/src/delombok/lombok/delombok/DelombokResult.java @@ -18,7 +18,8 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. - */package lombok.delombok; + */ +package lombok.delombok; import java.io.IOException; import java.io.Writer; diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java index 0955a003..c66ff0ec 100644 --- a/src/delombok/lombok/delombok/DocCommentIntegrator.java +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2009-2010 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.delombok; import java.util.ArrayList; diff --git a/src/delombok/lombok/delombok/FormatPreferenceScanner.java b/src/delombok/lombok/delombok/FormatPreferenceScanner.java new file mode 100644 index 00000000..5c388a83 --- /dev/null +++ b/src/delombok/lombok/delombok/FormatPreferenceScanner.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.delombok; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * Scans a java source file to figure out certain format preferences. + * Currently:
    + *
  • Indent style (tab or 2-8 spaces are supported). Default: tab
  • + *
  • Empty lines still carry the appropriate indent, vs. empty lines are empty. Default: empty
  • + */ +public class FormatPreferenceScanner { + /** Checks validity of preferences, and returns with a non-null value if ALL format keys are available, thus negating the need for a scan. */ + private FormatPreferences tryEasy(Map preferences) { + int count = 0; + for (Map.Entry e : preferences.entrySet()) { + if (!FormatPreferences.KEYS.containsKey(e.getKey())) throw new IllegalArgumentException("Unknown format key: " + e.getKey()); + if (!"scan".equalsIgnoreCase(e.getValue())) count++; + } + if (count >= FormatPreferences.KEYS.size()) return new FormatPreferences(preferences, "\t", false); + return null; + } + + public FormatPreferences scan(Map preferences, char[] source) { + FormatPreferences fps = tryEasy(preferences); + if (fps != null) return fps; + + try { + return scan_(preferences, new CharArrayReader(source)); + } catch (IOException e) { + throw new RuntimeException(e); //Can't happen; CAR doesn't throw these. + } + } + + public FormatPreferences scan(Map preferences, Reader in) throws IOException { + FormatPreferences fps = tryEasy(preferences); + if (fps != null) return fps; + + return scan_(preferences, in); + } + + private static FormatPreferences scan_(Map preferences, Reader in) throws IOException { + int filledEmpties = 0; + List indents = new ArrayList(); + + char[] buffer = new char[32700]; + int pos = 1; + int end = 0; + + StringBuilder indentSoFar = new StringBuilder(); + boolean inIndent = true; + boolean inComment = false; + char lastChar = ' '; + + while (true) { + if (pos >= end) { + int r = in.read(buffer); + if (r == -1) break; + pos = 0; + end = r; + continue; + } + + char c = buffer[pos++]; + if (inComment) { + if (lastChar == '*' && c == '/') inComment = false; + lastChar = c; + continue; + } + + if (lastChar == '/' && c == '*') { + inComment = true; + lastChar = ' '; + indentSoFar.setLength(0); + inIndent = false; + continue; + } + + if (inIndent) { + boolean w = Character.isWhitespace(c); + if (c == '\n') { + if (indentSoFar.length() > 0 && indentSoFar.charAt(indentSoFar.length() -1) == '\r') { + indentSoFar.setLength(indentSoFar.length() - 1); + } + + if (indentSoFar.length() > 0) { + filledEmpties++; + } else { + } + indents.add(indentSoFar.toString()); + indentSoFar.setLength(0); + lastChar = c; + continue; + } + + if (w) { + indentSoFar.append(c); + lastChar = c; + continue; + } + + if (indentSoFar.length() > 0) { + indents.add(indentSoFar.toString()); + indentSoFar.setLength(0); + } + lastChar = c; + inIndent = false; + continue; + } + + lastChar = c; + if (c == '\n') { + inIndent = true; + indentSoFar.setLength(0); + } + } + + String indent = null; + int lowestSpaceCount = Integer.MAX_VALUE; + for (String ind : indents) { + if (ind.indexOf('\t') > -1) { + indent = "\t"; + break; + } + if (ind.length() < 2 || ind.length() > 8) continue; + if (ind.length() < lowestSpaceCount) lowestSpaceCount = ind.length(); + } + + if (lowestSpaceCount == Integer.MAX_VALUE) indent = "\t"; + + if (indent == null) { + char[] id = new char[lowestSpaceCount]; + Arrays.fill(id, ' '); + indent = new String(id); + } + + return new FormatPreferences(preferences, indent, filledEmpties > 0); + } +} diff --git a/src/delombok/lombok/delombok/FormatPreferences.java b/src/delombok/lombok/delombok/FormatPreferences.java new file mode 100644 index 00000000..f4e6f143 --- /dev/null +++ b/src/delombok/lombok/delombok/FormatPreferences.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.delombok; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +public final class FormatPreferences { + private final String indent; + private final boolean filledEmpties; + static final Map KEYS; + + static { + Map keys = new LinkedHashMap(); + keys.put("indent", "The indent to use. 'tab' can be used to represent 1 tab. A number means that many spaces. Default: 'tab'"); + keys.put("emptyLines", "Either 'indent' or 'blank'. indent means: Indent an empty line to the right level. Default: 'blank'"); + KEYS = Collections.unmodifiableMap(keys); + } + + public FormatPreferences(Map preferences, String indent, boolean filledEmpties) { + if (preferences == null) preferences = Collections.emptyMap(); + + String indent_ = preferences.get("indent"); + if (indent_ != null && !"scan".equalsIgnoreCase(indent_)) { + try { + int id = Integer.parseInt(indent_); + if (id > 0 && id < 32) { + char[] c = new char[id]; + Arrays.fill(c, ' '); + indent_ = new String(c); + } + } catch (NumberFormatException ignore) {} + indent = indent_.replace("\\t", "\t").replace("tab", "\t"); + } + String empties_ = preferences.get("emptyLines"); + if ("indent".equalsIgnoreCase(empties_)) filledEmpties = true; + else if ("blank".equalsIgnoreCase(empties_)) filledEmpties = false; + else if (empties_ != null && !"scan".equalsIgnoreCase(empties_)) { + throw new IllegalArgumentException("Legal values for 'emptyLines' is scan, indent, or blank."); + } + this.indent = indent; + this.filledEmpties = filledEmpties; + } + public Map getKeysAndDescriptions() { + return KEYS; + } + + /** If true, empty lines should still be appropriately indented. If false, empty lines should be completely blank. */ + public boolean fillEmpties() { + return filledEmpties; + } + + public String indent() { + return indent; + } +} -- cgit