Skip to content

Commit

Permalink
new function-based ansi colouring for helptext headers
Browse files Browse the repository at this point in the history
  • Loading branch information
TanklesXL committed Aug 13, 2024
1 parent e8b0135 commit 77a875a
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub fn main() {
// with an app name of "hello", this is used when printing help text
|> glint.with_name("hello")
// with pretty help enabled, using the built-in colours
|> glint.pretty_help(glint.default_pretty_help())
|> glint.with_default_header_style
// with a root command that executes the `hello` function
|> glint.add(at: [], do: hello())
// execute given arguments from stdin
Expand Down
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "glint"
version = "1.0.1"
version = "1.1.0-dev"

# Fill out these fields if you intend to generate HTML documentation or publishname = "glint"
# your project to the Hex package manager.
Expand Down
5 changes: 3 additions & 2 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

packages = [
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
{ name = "birdie", version = "1.1.8", build_tools = ["gleam"], requirements = ["argv", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "D225C0A3035FCD73A88402925A903AAD3567A1515C9EAE8364F11C17AD1805BB" },
{ name = "birdie", version = "1.2.0", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "7EE6286C5660650143A5AC69E1D900DA1B6EAF3C6EBB7E50AC3DBF06511279CC" },
{ name = "edit_distance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "edit_distance", source = "hex", outer_checksum = "A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05" },
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
{ name = "glance", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "8F3314D27773B7C3B9FB58D8C02C634290422CE531988C0394FA0DF8676B964D" },
{ name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" },
{ name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" },
{ name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" },
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
Expand Down
111 changes: 104 additions & 7 deletions src/glint.gleam
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import gleam
import gleam/dict
import gleam/float
import gleam/function
import gleam/int
import gleam/io
import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/result
import gleam/string
import gleam_community/ansi
import gleam_community/colour.{type Colour}
import glint/constraint
import glint/internal/help
Expand All @@ -20,7 +22,7 @@ import snag.{type Snag}
///
type Config {
Config(
pretty_help: Option(PrettyHelp),
pretty_help: HeaderFormat,
name: Option(String),
as_module: Bool,
description: Option(String),
Expand All @@ -32,8 +34,83 @@ type Config {
)
}

type HeaderFormat {
HeaderFormat(
usage: fn(String) -> String,
flags: fn(String) -> String,
subcommands: fn(String) -> String,
)
}

/// Set the style for each of the glint helptext headers (usage, flags, subcommands).
///
/// This function will likely be used with colouring functions from [gleam_community/ansi](https://hexdocs.pm/gleam_community_ansi/).
///
/// When setting your own header styles, you may want to leverage the default formatting as provided by [`glint.default_header_format`](#default_header_format)
/// which can be composed witth other functions from [gleam_community/ansi](https://hexdocs.pm/gleam_community_ansi/)..
///
///
/// Example:
///
/// ```gleam
/// glint.with_header_style(
/// glint,
/// usage: fn(s) { s |> glint.default_header_format |> ansi.cyan },
/// flags: fn(s) { s |> glint.default_header_format |> ansi.magenta },
/// subcommands: fn(s) { s |> glint.default_header_format |> ansi.yellow },
/// )
/// ```
pub fn with_header_style(
glint: Glint(a),
usage usage: fn(String) -> String,
flags flags: fn(String) -> String,
subcommands subcommands: fn(String) -> String,
) -> Glint(a) {
Glint(
..glint,
config: Config(
..glint.config,
pretty_help: HeaderFormat(
usage: usage,
flags: flags,
subcommands: subcommands,
),
),
)
}

/// This function sets the glint help text header styles using glint's defaults.
///
/// Each help text header is formatted as bold, italic and underline (see [`glint.default_header_format`](#default_header_format)).
///
/// The default colours are ANSI compatible as follows:
/// - usage: cyan
/// - flags: pink
/// - subcommands: yellow
///
pub fn with_default_header_style(glint: Glint(a)) -> Glint(a) {
with_header_style(
glint,
usage: fn(s) { s |> default_header_format |> ansi.cyan },
flags: fn(s) { s |> default_header_format |> ansi.pink },
subcommands: fn(s) { s |> default_header_format |> ansi.yellow },
)
}

/// Style heading text as bold, underlined and italic.
///
/// This function can be combined with other functions from [gleam_community/ansi](https://hexdocs.pm/gleam_community_ansi/)
///
pub fn default_header_format(heading: String) -> String {
heading
|> ansi.bold
|> ansi.underline
|> ansi.italic
}

/// PrettyHelp defines the header colours to be used when styling help text
///
@deprecated("this type will be removed in an upcoming version of glint")
pub type PrettyHelp {
PrettyHelp(usage: Colour, flags: Colour, subcommands: Colour)
}
Expand All @@ -43,7 +120,11 @@ pub type PrettyHelp {
/// default config
///
const default_config = Config(
pretty_help: None,
pretty_help: HeaderFormat(
function.identity,
function.identity,
function.identity,
),
name: None,
as_module: False,
description: None,
Expand All @@ -58,10 +139,25 @@ const default_config = Config(

/// Enable custom colours for help text headers.
///
/// For a pre-made style, pass in [`glint.default_pretty_help`](#default_pretty_help)
/// For a pre-made style, pass in [`glint.with_default_header_style`](#with_default_header_style) instead.
///
@deprecated("use glint.with_header_style instead")
pub fn pretty_help(glint: Glint(a), pretty: PrettyHelp) -> Glint(a) {
Glint(..glint, config: Config(..glint.config, pretty_help: Some(pretty)))
let style = fn(s: String, colour: colour.Colour) -> String {
s |> default_header_format |> ansi.colour(colour)
}

Glint(
..glint,
config: Config(
..glint.config,
pretty_help: HeaderFormat(
usage: style(_, pretty.usage),
flags: style(_, pretty.flags),
subcommands: style(_, pretty.subcommands),
),
),
)
}

/// Give the current glint application a name.
Expand Down Expand Up @@ -623,6 +719,7 @@ pub fn run_and_handle(
///
/// buttercup (r: 252, g: 226, b: 174) colour for subcommands
///
@deprecated("use glint.with_default_header_style instead")
pub fn default_pretty_help() -> PrettyHelp {
let assert Ok(usage_colour) = colour.from_rgb255(182, 255, 234)
let assert Ok(flags_colour) = colour.from_rgb255(255, 175, 243)
Expand Down Expand Up @@ -652,9 +749,9 @@ fn cmd_help(path: List(String), cmd: CommandNode(a), config: Config) -> String {
fn build_help_config(config: Config) -> help.Config {
help.Config(
name: config.name,
usage_colour: option.map(config.pretty_help, fn(p) { p.usage }),
flags_colour: option.map(config.pretty_help, fn(p) { p.flags }),
subcommands_colour: option.map(config.pretty_help, fn(p) { p.subcommands }),
usage_colour: config.pretty_help.usage,
flags_colour: config.pretty_help.flags,
subcommands_colour: config.pretty_help.subcommands,
as_module: config.as_module,
description: config.description,
indent_width: config.indent_width,
Expand Down
34 changes: 6 additions & 28 deletions src/glint/internal/help.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,8 @@ import gleam/int
import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/string
import gleam_community/ansi
import gleam_community/colour.{type Colour}
import glint/internal/utils

/// Style heading text with the provided rgb colouring
/// this is only intended for use within glint itself.
///
fn heading_style(heading: String, colour: Colour) -> String {
heading
|> ansi.bold
|> ansi.underline
|> ansi.italic
|> ansi.hex(colour.to_rgb_hex(colour))
}

// --- HELP: CONSTANTS ---
//
pub const help_flag = Flag(Metadata("help", "Print help information"), "")
Expand All @@ -38,9 +25,9 @@ pub type ArgsCount {
pub type Config {
Config(
name: Option(String),
usage_colour: Option(Colour),
flags_colour: Option(Colour),
subcommands_colour: Option(Colour),
usage_colour: fn(String) -> String,
flags_colour: fn(String) -> String,
subcommands_colour: fn(String) -> String,
as_module: Bool,
description: Option(String),
indent_width: Int,
Expand Down Expand Up @@ -175,10 +162,7 @@ fn command_help_to_usage_string(help: Command, config: Config) -> String {
|> utils.wordwrap(max_usage_width)
|> string.join("\n" <> string.repeat(" ", config.indent_width * 2))

case config.usage_colour {
None -> usage_heading
Some(pretty) -> heading_style(usage_heading, pretty)
}
config.usage_colour(usage_heading)
<> "\n"
<> string.repeat(" ", config.indent_width)
<> content
Expand All @@ -197,10 +181,7 @@ fn flags_help_to_string(help: List(Flag), config: Config) -> String {
|> utils.max_string_length
|> int.max(config.min_first_column_width)

let heading = case config.flags_colour {
None -> flags_heading
Some(pretty) -> heading_style(flags_heading, pretty)
}
let heading = config.flags_colour(flags_heading)

let content =
to_spaced_indented_string(
Expand Down Expand Up @@ -237,10 +218,7 @@ fn subcommands_help_to_string(help: List(Metadata), config: Config) -> String {
|> utils.max_string_length
|> int.max(config.min_first_column_width)

let heading = case config.subcommands_colour {
None -> subcommands_heading
Some(pretty) -> heading_style(subcommands_heading, pretty)
}
let heading = config.subcommands_colour(subcommands_heading)

let content =
to_spaced_indented_string(
Expand Down
2 changes: 1 addition & 1 deletion test/examples/hello.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ pub fn app() {
// show in usage text that the current app is run as a gleam module
|> glint.as_module
// with pretty help enabled, using the built-in colours
|> glint.pretty_help(glint.default_pretty_help())
|> glint.with_default_header_style
// with group level flags
// with flag `caps` for all commands (equivalent of using glint.global_flag)
|> glint.group_flag([], caps_flag())
Expand Down
1 change: 1 addition & 0 deletions test/glint_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub fn global_and_group_flags_test() {
|> glint.execute(["sub", "sub", "--sub_group_flag=2"])
}

@deprecated("remove when the pretty help removal happens")
pub fn default_pretty_help_test() {
// default_pretty_help has asserts
// we need to call the function to make sure it does not crash
Expand Down

0 comments on commit 77a875a

Please sign in to comment.