diff --git a/CHANGELOG.md b/CHANGELOG.md index 573dbc3..1dcb9cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased](https://github.com/TanklesXL/glint/compare/v1.1.0...HEAD) +- captured each flag's configured default value in the help data + (`help.Flag.default`) and added the `glint.show_flag_defaults` builder + to opt in to rendering `(default: )` in `--help` output + # v1 ## [1.3.0](https://github.com/TanklesXL/glint/compare/v1.2.1...v1.3.0) diff --git a/src/glint.gleam b/src/glint.gleam index 5ba3494..cd8beab 100644 --- a/src/glint.gleam +++ b/src/glint.gleam @@ -29,6 +29,7 @@ type Config { max_output_width: Int, min_first_column_width: Int, column_gap: Int, + show_flag_defaults: Bool, ) } @@ -52,6 +53,7 @@ const default_config = Config( max_output_width: 80, min_first_column_width: 20, column_gap: 2, + show_flag_defaults: False, ) // -- CONFIGURATION: FUNCTIONS -- @@ -127,6 +129,15 @@ pub fn with_column_gap(glint: Glint(a), column_gap: Int) -> Glint(a) { Glint(..glint, config: Config(..glint.config, column_gap:)) } +/// Enable rendering of flag default values in `--help` output. When enabled, +/// each flag with a configured default has `(default: )` appended to +/// its description. +/// +/// Disabled by default to preserve existing help text formatting. +pub fn show_flag_defaults(glint: Glint(a), enabled: Bool) -> Glint(a) { + Glint(..glint, config: Config(..glint.config, show_flag_defaults: enabled)) +} + // --- CORE --- // -- CORE: TYPES -- @@ -682,6 +693,7 @@ fn build_help_config(config: Config) -> help.Config { column_gap: config.column_gap, flag_prefix: flag_prefix, flag_delimiter: flag_delimiter, + show_flag_defaults: config.show_flag_defaults, ) } @@ -729,6 +741,29 @@ fn flag_type_info(flag: FlagEntry) { } } +fn flag_default_info(flag: FlagEntry) -> Option(String) { + case flag.value { + I(FlagInternals(value: Some(v), ..)) -> Some(int.to_string(v)) + F(FlagInternals(value: Some(v), ..)) -> Some(float.to_string(v)) + S(FlagInternals(value: Some(v), ..)) -> Some(v) + B(FlagInternals(value: Some(v), ..)) -> + Some(case v { + True -> "true" + False -> "false" + }) + LI(FlagInternals(value: Some(v), ..)) -> Some(join_csv(v, int.to_string)) + LF(FlagInternals(value: Some(v), ..)) -> Some(join_csv(v, float.to_string)) + LS(FlagInternals(value: Some(v), ..)) -> Some(string.join(v, ",")) + _ -> None + } +} + +/// stringify each item and join with commas, for list-flag defaults. +/// +fn join_csv(items: List(a), to_string: fn(a) -> String) -> String { + items |> list.map(to_string) |> string.join(",") +} + /// build the help representation for a list of flags /// fn build_flags_help(flags: Flags) -> List(help.Flag) { @@ -737,6 +772,7 @@ fn build_flags_help(flags: Flags) -> List(help.Flag) { help.Flag( meta: help.Metadata(name: name, description: flag.description), type_: flag_type_info(flag), + default: flag_default_info(flag), ), ..acc ] diff --git a/src/glint/internal/help.gleam b/src/glint/internal/help.gleam index f1ec672..c8a5015 100644 --- a/src/glint/internal/help.gleam +++ b/src/glint/internal/help.gleam @@ -20,7 +20,7 @@ fn heading_style(heading: String, colour: Colour) -> String { // --- HELP: CONSTANTS --- // -pub const help_flag = Flag(Metadata("help", "Print help information"), "") +pub const help_flag = Flag(Metadata("help", "Print help information"), "", None) const flags_heading = "FLAGS:" @@ -49,6 +49,7 @@ pub type Config { column_gap: Int, flag_prefix: String, flag_delimiter: String, + show_flag_defaults: Bool, ) } @@ -61,7 +62,7 @@ pub type Metadata { /// Help type for flag metadata /// pub type Flag { - Flag(meta: Metadata, type_: String) + Flag(meta: Metadata, type_: String, default: Option(String)) } /// Help type for command metadata @@ -208,7 +209,15 @@ fn flags_help_to_string(help: List(Flag), config: Config) -> String { let content = to_spaced_indented_string( [help_flag, ..help], - fn(help) { #(flag_help_to_string(help, config), help.meta.description) }, + fn(help) { + let description = case config.show_flag_defaults, help.default { + True, Some(default) -> + help.meta.description <> " (default: " <> default <> ")" + _, _ -> help.meta.description + } + + #(flag_help_to_string(help, config), description) + }, longest_flag_length, config, ) diff --git a/test/glint/show_flag_defaults_test.gleam b/test/glint/show_flag_defaults_test.gleam new file mode 100644 index 0000000..da1e439 --- /dev/null +++ b/test/glint/show_flag_defaults_test.gleam @@ -0,0 +1,36 @@ +import gleam/string +import gleeunit/should +import glint.{Help} + +fn cli(show_defaults: Bool) -> glint.Glint(Nil) { + let count = + glint.int_flag("count") + |> glint.flag_default(3) + |> glint.flag_help("How many times") + + glint.new() + |> glint.show_flag_defaults(show_defaults) + |> glint.add(at: [], do: { + use _count <- glint.flag(count) + glint.command(fn(_, _, _) { Nil }) + }) +} + +fn help_text(g: glint.Glint(Nil)) -> String { + let assert Ok(Help(help)) = glint.execute(g, ["--help"]) + help +} + +pub fn enabled_renders_default_test() { + cli(True) + |> help_text + |> string.contains("(default: 3)") + |> should.be_true +} + +pub fn disabled_omits_default_test() { + cli(False) + |> help_text + |> string.contains("(default:") + |> should.be_false +}