1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
package cmd
import (
"errors"
"flag"
"fmt"
"io"
"strings"
"github.com/andybalholm/cascadia"
)
// selectorFlag sets up a flag that parses a CSS selector string into a cascadia.Selector.
func (cli *CLI) selectorFlag(target *cascadia.SelectorGroup, name string, usage string) {
cli.flags.Func(name, usage, func(flagValue string) error {
if strings.TrimSpace(flagValue) == "" {
return fmt.Errorf("invalid css selector: empty string")
}
// Compile the provided CSS selector string
sel, err := cascadia.ParseGroup(flagValue)
if err != nil {
return fmt.Errorf("invalid css selector: %w", err)
}
*target = append(*target, sel...)
return nil
})
}
func (cli *CLI) singleStringFlag(target *string, name string, usage string) {
cli.flags.Func(name, usage, func(flagValue string) error {
if strings.TrimSpace(flagValue) == "" {
return errors.New("empty string")
}
if *target != "" {
return fmt.Errorf("another value has already been set")
}
*target = strings.TrimSpace(flagValue)
return nil
})
}
func (cli *CLI) initFlags(progname string) {
cli.flags = flag.NewFlagSet(progname, flag.ContinueOnError)
cli.flags.SetOutput(io.Discard)
// - - - - - General - - - - - //
cli.flags.BoolVar(&cli.config.version, "version", false, "display the version")
cli.flags.BoolVar(&cli.config.version, "v", false, "display the version")
cli.singleStringFlag(
&cli.config.inputFilepath,
"input",
"Read input from FILE instead of stdin",
)
cli.singleStringFlag(
&cli.config.outputFilepath,
"output",
"Write output to FILE instead of stdout",
)
cli.flags.BoolVar(&cli.config.outputOverwrite, "output-overwrite", false, "replace existing files")
// TODO: --tag-type-block=script,style (and check that it is not a selector)
// TODO: --tag-type-inline=script,style (and check that it is not a selector)
cli.flags.StringVar(
&cli.config.domain,
"domain",
"",
"The url of the web page, used to convert relative links to absolute links.",
)
cli.selectorFlag(&cli.config.includeSelector, "include-selector", "css query selector to only include parts of the input")
cli.selectorFlag(&cli.config.excludeSelector, "exclude-selector", "css query selector to exclude parts of the input")
// - - - - - Options - - - - - //
cli.flags.StringVar(
&cli.config.strongDelimiter,
"opt-strong-delimiter",
"**",
`Make bold text. Should <strong> be indicated by two asterisks or two underscores?
"**" or "__" (default: "**")`,
)
// - - - - - Plugins - - - - - //
// TODO: --opt-strikethrough-delimiter for the strikethrough plugin
cli.flags.BoolVar(&cli.config.enablePluginStrikethrough, "plugin-strikethrough", false, "enable the plugin ~~strikethrough~~")
cli.flags.BoolVar(&cli.config.enablePluginTable, "plugin-table", false, "enable the plugin table")
cli.flags.BoolVar(&cli.config.tableSkipEmptyRows, "opt-table-skip-empty-rows", false, "[for --plugin-table] omit empty rows from the output")
cli.flags.BoolVar(&cli.config.tableHeaderPromotion, "opt-table-header-promotion", false, "[for --plugin-table] first row should be treated as a header")
cli.flags.StringVar(&cli.config.tableSpanCellBehavior, "opt-table-span-cell-behavior", "", `[for --plugin-table] how colspan/rowspan should be rendered: "empty" or "mirror"`)
cli.flags.BoolVar(&cli.config.tablePresentationTables, "opt-table-presentation-tables", false, `[for --plugin-table] whether tables with role="presentation" should be converted`)
cli.flags.StringVar(&cli.config.tableNewlineBehavior, "opt-table-newline-behavior", "", `[for --plugin-table] how tables containing newlines should be handled: "skip" or "preserve"`)
}
func (cli *CLI) parseFlags(args []string) error {
err := cli.flags.Parse(args)
if err != nil {
return cli.categorizeFlagError(err)
}
cli.config.args = cli.flags.Args()
// Validate flag dependencies
if cli.config.tableSkipEmptyRows && !cli.config.enablePluginTable {
return fmt.Errorf("--opt-table-skip-empty-rows requires --plugin-table to be enabled")
}
if cli.config.tableHeaderPromotion && !cli.config.enablePluginTable {
return fmt.Errorf("--opt-table-header-promotion requires --plugin-table to be enabled")
}
if cli.config.tableSpanCellBehavior != "" && !cli.config.enablePluginTable {
return fmt.Errorf("--opt-table-span-cell-behavior requires --plugin-table to be enabled")
}
if cli.config.tablePresentationTables && !cli.config.enablePluginTable {
return fmt.Errorf("--opt-table-presentation-tables requires --plugin-table to be enabled")
}
if cli.config.tableNewlineBehavior != "" && !cli.config.enablePluginTable {
return fmt.Errorf("--opt-table-newline-behavior requires --plugin-table to be enabled")
}
// TODO: use constant for flag name & use formatFlag
// var keyStrongDelimiter = "opt-strong-delimiter"
return nil
}
|