Sun, 28 Jan 2024 14:02:41 +0100
minimize application code
package de.unixwork.uwproj; import org.w3c.dom.Element; import java.util.List; import static de.unixwork.uwproj.Util.shId; public final class Feature { private final String name; private final String arg; private final boolean auto; private final String desc; private final TargetData targetData; public Feature(Element e) { name = e.getAttribute("name"); arg = Util.getAttrOrDefault(e, "arg", name); auto = Boolean.parseBoolean(e.getAttribute("default")); targetData = new TargetData(e); // TODO: when Option also receives descriptions, we will move desc to TargetData desc = Util.getChildElements(e) .filter(c -> c.getNodeName().equals("desc")) .map(Util::getContent) .findAny() .orElse(""); } public String getVarName() { return shId("FEATURE_" + name.toUpperCase()); } public List<String> getDependencies() { return getTargetData().getDependencies(); } public List<Define> getDefines() { return getTargetData().getDefines(); } public String getMake() { return targetData.getMake(); } public boolean hasMake() { return targetData.hasMake(); } public String getName() { return name; } public String getArg() { return arg; } public String getDesc() { return desc; } public boolean isAuto() { return auto; } public TargetData getTargetData() { return targetData; } /** * Generates help text for the feature option. * <p> * If {@link #isAuto()} returns true, the option name will be --disable-${@link #getArg()}, otherwise * it will be --enable-${@link #getArg()}, preceded by two spaces, respectively. * <p> * If no description is available via {@link #getDesc()}, only the option name is generated. Otherwise, * description is added according to the following rules: * <p> * When the option name does not consume more than 25 characters, the description starts in the same line. * Otherwise, a line break is added, first. The description will be placed in a block starting from column * 27 to 80 and automatically break when necessary. The description must not contain a single word * that is longer than 54 characters, or it will break the layout. * * @return a help text for terminal output */ public String getHelpText() { final var builder = new StringBuilder(); // Compute option name final var opt = (auto ? " --disable-" : " --enable-")+arg; // Add option name builder.append(opt); // Stop, if there is no description if (desc.isBlank()) return builder.toString(); // Prepare the description by replacing some unwanted spaces final var hdesc = desc.trim() .replaceAll("\\r", "") .replaceAll("\\t", " "); // Declare our frame where the description shall be placed final int startx = 26; final int endx = 80; // Move to startx (break, if we already past that) if (opt.length() >= startx) { builder.append("\n"); builder.append(" ".repeat(startx)); } else { builder.append(" ".repeat(startx-opt.length())); } // Append the description keeping the layout intact int x = startx; for (int i = 0 ; i < hdesc.length() ;) { // get the next word and see where we would end int s = hdesc.indexOf(' ', i); if (s < 0) s = hdesc.length(); int n = hdesc.indexOf('\n', i); if (n < 0) n = hdesc.length(); s = Math.min(s, n); int l = s-i; if (x + l > endx) { // does not fit, break into next line builder.append('\n'); builder.append(" ".repeat(startx)); x = startx; } // append the word builder.append(hdesc, i, s); x += l; i += l; // append the next spaces while (i < hdesc.length()) { int c = hdesc.charAt(i); if (c == ' ') { // as long as we don't need to break, add the spaces i++; x++; if (x < endx) builder.append(' '); } else if (c == '\n') { // if user wants us to break, comply i++; // if we have still space, just move to the end of the line if (x < endx) { x = endx; } else { // otherwise, we need to add an extra blank line builder.append('\n'); } } else { // we have found the next word, so continue with the outer loop break; } } // break to new line, when spaces moved us outside the frame if (x > endx) { builder.append('\n'); builder.append(" ".repeat(startx)); x = startx; } } return builder.toString(); } }