diff --git a/Core/src/main/java/com/songoda/core/configuration/Comment.java b/Core/src/main/java/com/songoda/core/configuration/Comment.java index e0bb84b0..bbc97482 100644 --- a/Core/src/main/java/com/songoda/core/configuration/Comment.java +++ b/Core/src/main/java/com/songoda/core/configuration/Comment.java @@ -60,6 +60,14 @@ public class Comment { public String toString() { return lines.isEmpty() ? "" : lines.stream().collect(Collectors.joining("\n")); } + + public static Comment loadComment(List lines) { + CommentStyle style = ConfigFormattingRules.parseStyle(lines); + int linePad = (style.drawBorder ? 1 : 0) + (style.drawSpace ? 1 : 0); + int prefix = style.commentPrefix.length(); + int suffix = style.commentSuffix.length(); + return new Comment(style, lines.subList(linePad, lines.size() - linePad).stream().map(s -> s.substring(prefix, s.length() - suffix).trim()).collect(Collectors.toList())); + } public void writeComment(Writer output, int offset, CommentStyle defaultStyle) throws IOException { CommentStyle style = commentStyle != null ? commentStyle : defaultStyle; diff --git a/Core/src/main/java/com/songoda/core/configuration/Config.java b/Core/src/main/java/com/songoda/core/configuration/Config.java index 1cf164e7..1be0f9ec 100644 --- a/Core/src/main/java/com/songoda/core/configuration/Config.java +++ b/Core/src/main/java/com/songoda/core/configuration/Config.java @@ -16,6 +16,7 @@ import java.io.StringWriter; import java.io.Writer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; @@ -59,11 +60,12 @@ public class Config extends ConfigSection { // public static valueOf(Map args); // public new (Map args) */ - protected static final String COMMENT_PREFIX = "# "; protected static final String BLANK_CONFIG = "{}\n"; protected File file; protected final ConfigFileConfigurationAdapter config = new ConfigFileConfigurationAdapter(this); + protected Comment headerComment = null; + protected Comment footerComment = null; final String dirName, fileName; final Plugin plugin; final DumperOptions yamlOptions = new DumperOptions(); @@ -306,9 +308,9 @@ public class Config extends ConfigSection { @NotNull public Config setHeader(@NotNull String... description) { if (description.length == 0) { - configComments.remove(null); + headerComment = null; } else { - configComments.put(null, new Comment(description)); + headerComment = new Comment(description); } return this; } @@ -316,9 +318,9 @@ public class Config extends ConfigSection { @NotNull public Config setHeader(@Nullable ConfigFormattingRules.CommentStyle commentStyle, @NotNull String... description) { if (description.length == 0) { - configComments.remove(null); + headerComment = null; } else { - configComments.put(null, new Comment(commentStyle, description)); + headerComment = new Comment(commentStyle, description); } return this; } @@ -326,9 +328,9 @@ public class Config extends ConfigSection { @NotNull public Config setHeader(@Nullable List description) { if (description == null || description.isEmpty()) { - configComments.remove(null); + headerComment = null; } else { - configComments.put(null, new Comment(description)); + headerComment = new Comment(description); } return this; } @@ -336,17 +338,17 @@ public class Config extends ConfigSection { @NotNull public Config setHeader(@Nullable ConfigFormattingRules.CommentStyle commentStyle, @Nullable List description) { if (description == null || description.isEmpty()) { - configComments.remove(null); + headerComment = null; } else { - configComments.put(null, new Comment(commentStyle, description)); + headerComment = new Comment(commentStyle, description); } return this; } @NotNull public List getHeader() { - if (configComments.containsKey(null)) { - return configComments.get(null).getLines(); + if (headerComment != null) { + return headerComment.getLines(); } else { return Collections.EMPTY_LIST; } @@ -442,6 +444,67 @@ public class Config extends ConfigSection { // if starts with a comment, load all nonbreaking comments as a header // then load all comments and assign to the next valid node loaded // (Only load comments that are on their own line) + + BufferedReader in = new BufferedReader(new StringReader(contents)); + String line; + boolean insideScalar = false; + boolean firstNode = true; + int index = 0; + LinkedList currentPath = new LinkedList(); + ArrayList commentBlock = new ArrayList(); + try { + while ((line = in.readLine()) != null) { + if (line.isEmpty()) { + if (firstNode && !commentBlock.isEmpty()) { + // header comment + firstNode = false; + headerComment = Comment.loadComment(commentBlock); + commentBlock.clear(); + } + continue; + } else if (line.trim().startsWith("#")) { + // only load full-line comments + commentBlock.add(line.trim()); + continue; + } + + // check to see if this is a line that we can process + int lineOffset = getOffset(line); + insideScalar &= lineOffset <= index; + Matcher m; + if (!insideScalar && (m = yamlNode.matcher(line)).find()) { + // we found a config node! ^.^ + // check to see what the full path is + int depth = (m.group(1).length() / indentation); + while (depth < currentPath.size()) { + currentPath.removeLast(); + } + currentPath.add(m.group(2)); + + // do we have a comment for this node? + if (!commentBlock.isEmpty()) { + String path = currentPath.stream().collect(Collectors.joining(String.valueOf(pathChar))); + Comment comment = Comment.loadComment(commentBlock); + commentBlock.clear(); + setComment(path, comment); + } + + firstNode = false; // we're no longer on the first node + + // ignore scalars + index = lineOffset; + if (m.group(3).trim().equals("|") || m.group(3).trim().equals(">")) { + insideScalar = true; + } + } + } + if (!commentBlock.isEmpty()) { + footerComment = Comment.loadComment(commentBlock); + commentBlock.clear(); + } + } catch (IOException ex) { + } + } public void deleteNonDefaultSettings() { @@ -510,7 +573,7 @@ public class Config extends ConfigSection { public boolean save(@NotNull File file) { Validate.notNull(file, "File cannot be null"); - if (!file.getParentFile().exists()) { + if (file.getParentFile() != null && !file.getParentFile().exists()) { file.getParentFile().mkdirs(); } String data = this.saveToString(); @@ -525,22 +588,26 @@ public class Config extends ConfigSection { @NotNull public String saveToString() { try { - if(autoremove) { + if (autoremove) { deleteNonDefaultSettings(); } yamlOptions.setIndent(indentation); yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); StringWriter str = new StringWriter(); - Comment header = configComments.get(null); - if (header != null) { - header.writeComment(str, 0, ConfigFormattingRules.CommentStyle.SPACED); + if (headerComment != null) { + headerComment.writeComment(str, 0, ConfigFormattingRules.CommentStyle.BLOCKED); str.write("\n"); // add one space after the header } String dump = yaml.dump(this.getValues(false)); if (!dump.equals(BLANK_CONFIG)) { writeComments(dump, str); } + if (footerComment != null) { + str.write("\n"); + footerComment.writeComment(str, 0, ConfigFormattingRules.CommentStyle.BLOCKED); + str.write("\n"); // add one space at the end of the file + } return str.toString(); } catch (Throwable ex) { Logger.getLogger(Config.class.getName()).log(Level.SEVERE, "Error saving config", ex); diff --git a/Core/src/main/java/com/songoda/core/configuration/ConfigFormattingRules.java b/Core/src/main/java/com/songoda/core/configuration/ConfigFormattingRules.java index 8dd4320e..2f6a130f 100644 --- a/Core/src/main/java/com/songoda/core/configuration/ConfigFormattingRules.java +++ b/Core/src/main/java/com/songoda/core/configuration/ConfigFormattingRules.java @@ -1,5 +1,7 @@ package com.songoda.core.configuration; +import java.util.List; + public class ConfigFormattingRules { int spacesBetweenMainCategories; @@ -66,4 +68,27 @@ public class ConfigFormattingRules { } } + + public static CommentStyle parseStyle(List lines) { + if(lines == null || lines.size() <= 2) { + return CommentStyle.SIMPLE; + } else if(lines.size() > 2 && lines.get(0).trim().equals("#") && lines.get(lines.size() - 1).trim().equals("#")) { + return CommentStyle.SPACED; + } + boolean hasBorders = lines.size() > 2 && lines.get(0).trim().matches("^##+$") && lines.get(lines.size() - 1).trim().matches("^##+$"); + if(!hasBorders) { + // default return + return CommentStyle.SIMPLE; + } + // now need to figure out if this is blocked or not + if(lines.size() > 4 && lines.get(1).trim().matches(("^#" + + CommentStyle.BLOCKSPACED.spacePrefixTop + CommentStyle.BLOCKSPACED.spaceCharTop + "+" + + CommentStyle.BLOCKSPACED.spaceSuffixTop + "#$").replace("|", "\\|")) + && lines.get(1).trim().matches(("^#" + + CommentStyle.BLOCKSPACED.spacePrefixTop + CommentStyle.BLOCKSPACED.spaceCharTop + "+" + + CommentStyle.BLOCKSPACED.spaceSuffixTop + "#$").replace("|", "\\|"))) { + return CommentStyle.BLOCKSPACED; + } + return CommentStyle.BLOCKED; + } } diff --git a/Core/src/main/java/com/songoda/core/configuration/ConfigSection.java b/Core/src/main/java/com/songoda/core/configuration/ConfigSection.java index 4a25576c..e357568f 100644 --- a/Core/src/main/java/com/songoda/core/configuration/ConfigSection.java +++ b/Core/src/main/java/com/songoda/core/configuration/ConfigSection.java @@ -168,16 +168,21 @@ public class ConfigSection extends MemoryConfiguration { @NotNull public ConfigSection setComment(@NotNull String path, @Nullable ConfigFormattingRules.CommentStyle commentStyle, String... lines) { - return setComment(path, commentStyle, lines.length == 0 ? (List) null : Arrays.asList(lines)); + return setComment(path, lines != null ? new Comment(commentStyle, lines) : null); } @NotNull public ConfigSection setComment(@NotNull String path, @Nullable ConfigFormattingRules.CommentStyle commentStyle, @Nullable List lines) { + return setComment(path, lines != null ? new Comment(commentStyle, lines) : null); + } + + @NotNull + public ConfigSection setComment(@NotNull String path, @Nullable Comment comment) { synchronized (root.lock) { if (isDefault) { - root.defaultComments.put(fullPath + path, lines != null ? new Comment(commentStyle, lines) : null); + root.defaultComments.put(fullPath + path, comment); } else { - root.configComments.put(fullPath + path, lines != null ? new Comment(commentStyle, lines) : null); + root.configComments.put(fullPath + path, comment); } } return this; @@ -195,7 +200,6 @@ public class ConfigSection extends MemoryConfiguration { } return this; } - @NotNull public ConfigSection setDefaultComment(@NotNull String path, ConfigFormattingRules.CommentStyle commentStyle, String... lines) { return setDefaultComment(path, commentStyle, lines.length == 0 ? (List) null : Arrays.asList(lines)); @@ -209,6 +213,14 @@ public class ConfigSection extends MemoryConfiguration { return this; } + @NotNull + public ConfigSection setDefaultComment(@NotNull String path, @Nullable Comment comment) { + synchronized (root.lock) { + root.defaultComments.put(fullPath + path, comment); + } + return this; + } + @Nullable public Comment getComment(@NotNull String path) { Comment result = root.configComments.get(fullPath + path);