src/main/java/de/unixwork/uwproj/Feature.java

Sun, 28 Jan 2024 14:02:41 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 28 Jan 2024 14:02:41 +0100
changeset 113
24f32dbd88cd
parent 98
4bf47ea3fc64
permissions
-rw-r--r--

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();
    }
}

mercurial