| // Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package com.android.tools.r8; |
| |
| import com.android.tools.r8.utils.StringUtils; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Public utility for printing R8/D8 command line flags. |
| * |
| * <p>This utility can be used to support wrapping the compilers command-line interface. |
| */ |
| @Keep |
| public class ParseFlagPrinter { |
| |
| private final List<ParseFlagInfo> flags = new ArrayList<>(); |
| |
| private String prefix = " "; |
| private int helpColumn = 25; |
| private String helpSeparator = " # "; |
| |
| // Formatting state. |
| private StringBuilder builder = null; |
| private int currentColumn = -1; |
| |
| // We use -1 to denote the unstarted line, otherwise we can't distinguish it when prefix is empty. |
| private boolean isLineStarted() { |
| return currentColumn >= 0; |
| } |
| |
| private void append(String string) { |
| assert isLineStarted(); |
| builder.append(string); |
| currentColumn += string.length(); |
| } |
| |
| private void space(int space) { |
| assert isLineStarted(); |
| for (int i = 0; i < space; i++) { |
| builder.append(' '); |
| } |
| currentColumn += space; |
| } |
| |
| private void endLine() { |
| assert isLineStarted(); |
| builder.append(StringUtils.LINE_SEPARATOR); |
| currentColumn = -1; |
| } |
| |
| private void startLine() { |
| assert !isLineStarted(); |
| currentColumn = 0; |
| append(prefix); |
| } |
| |
| private void addFlagLine(String flagLine) { |
| if (isLineStarted()) { |
| endLine(); |
| } |
| startLine(); |
| append(flagLine); |
| } |
| |
| private void addHelpLine(String helpLine) { |
| // If the current line is already past the point for printing help implicitly end the line. |
| if (currentColumn > helpColumn) { |
| endLine(); |
| } |
| if (!isLineStarted()) { |
| startLine(); |
| } |
| int distanceToHelpColum = helpColumn - currentColumn; |
| space(distanceToHelpColum); |
| append(helpSeparator); |
| append(helpLine); |
| endLine(); |
| } |
| |
| private void formatParseFlags() { |
| for (ParseFlagInfo flag : flags) { |
| addFlagLine(flag.getFlagFormat()); |
| flag.getFlagFormatAlternatives().forEach(this::addFlagLine); |
| flag.getFlagHelp().forEach(this::addHelpLine); |
| } |
| } |
| |
| public ParseFlagPrinter addFlags(List<ParseFlagInfo> flags) { |
| this.flags.addAll(flags); |
| return this; |
| } |
| |
| /** Set a prefix which will be prepended to each line (flags and help lines). */ |
| public ParseFlagPrinter setPrefix(String prefix) { |
| this.prefix = prefix; |
| return this; |
| } |
| |
| /** Convenience method to set the prefix to be 'indent' number of spaces. */ |
| public ParseFlagPrinter setIndent(int indent) { |
| return setPrefix(" ".repeat(indent)); |
| } |
| |
| /** |
| * Set the column at which the help information should start. |
| * |
| * <p>If a flag header extends past the end of the help column, then the help will start on a new |
| * line at the point of the specified help column. |
| */ |
| public ParseFlagPrinter setHelpColumn(int helpColumn) { |
| this.helpColumn = helpColumn; |
| return this; |
| } |
| |
| /** |
| * Set the separator to use to split the help information from the flag info. |
| * |
| * <p>This is prefixed to every help line and thus extends the size of each help line. The help |
| * separator will always start at exactly the help column ({@see setHelpColumn(int)}. |
| */ |
| public ParseFlagPrinter setHelpSeparator(String helpSeparator) { |
| this.helpSeparator = helpSeparator; |
| return this; |
| } |
| |
| public void appendLinesToBuilder(StringBuilder builder) { |
| assert this.builder == null; |
| assert this.currentColumn == -1; |
| this.builder = builder; |
| formatParseFlags(); |
| this.builder = null; |
| this.currentColumn = -1; |
| } |
| |
| public static void main(String[] args) { |
| D8.main(new String[] {"--help"}); |
| } |
| } |