From a69327afba53168e490ef09d5a780b3ea799c65e Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 13:14:00 +0100 Subject: [PATCH 01/17] WIP: take own arguments instead of ARGS --- .gitignore | 35 ++++++++++++++++++++++++++++++++++- src/SimpleArgParse.jl | 13 +++++++------ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index dbe9c82..35c5454 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,34 @@ -.vscode/ \ No newline at end of file +.vscode/ + +# Files generated by invoking Julia with --code-coverage +*.jl.cov +*.jl.*.cov + +# Files generated by invoking Julia with --track-allocation +*.jl.mem + +# Build artifacts for creating documentation generated by the Documenter package +docs/build/ +docs/site/ + +# File generated by Pkg, the package manager, based on a corresponding Project.toml +# It records a fixed state of all packages used by the project. As such, it should not be +# committed for packages, but should be committed for applications that require a static +# environment. +Manifest.toml +LocalPreferences.toml + +# MS Office temporary files +~$*.* + +# Mac +**/.DS_Store + +auxillary +lcov.info +.vscode/ + +src/tmp* +tmp* +test* +src/olds/* diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 27e5673..9e16ce6 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,4 +1,5 @@ module SimpleArgParse +__precompile__(false) export ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, get_value, set_value, has_key, get_key, colorize @@ -185,16 +186,16 @@ function help(parser::ArgumentParser; color::String="default") end "Parse command-line arguments." -function parse_args(parser::ArgumentParser) +function parse_args(parser::ArgumentParser; args=ARGS) :ArgumentParser if parser.add_help parser = add_argument(parser, "-h", "--help", type=Bool, default=false, description="Print the help message.") parser.usage = generate_usage(parser) end parser.filename = PROGRAM_FILE - n::Int64 = length(ARGS) - for i::Int64 in eachindex(ARGS) - arg::String = ARGS[i] + n::Int64 = length(args) + for i::Int64 in eachindex(args) + arg::String = args[i] argkey::String = arg2key(arg) if startswith(arg, "-") !haskey(parser.arg_store, argkey) && error("Argument not found: $(arg). Call `add_argument` before parsing.") @@ -205,10 +206,10 @@ function parse_args(parser::ArgumentParser) end # if next iteration is at the end or is an argument, treat current argument as flag/boolean # otherwise, capture the value and skip iterating over it for efficiency - if (i + 1 > n) || startswith(ARGS[i+1], "-") + if (i + 1 > n) || startswith(args[i+1], "-") value = true elseif (i + 1 <= n) - value = ARGS[i+1] + value = args[i+1] i += 1 else error("Value failed to parse for arg: $(arg)") From f8137283ba7d1e4558fe628082e6335252bb881c Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 13:15:28 +0100 Subject: [PATCH 02/17] delete Manifest --- Manifest.toml | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 Manifest.toml diff --git a/Manifest.toml b/Manifest.toml deleted file mode 100644 index d95a18c..0000000 --- a/Manifest.toml +++ /dev/null @@ -1,39 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.9.4" -manifest_format = "2.0" -project_hash = "bc7b41257fd1cd9c096093083d4ff85654ff7051" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.OrderedCollections]] -git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.6.3" - -[[deps.Random]] -deps = ["SHA", "Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" -version = "0.7.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From 5a5e989bb0bb84f829e5baf08739387ec20c8348 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 13:36:52 +0100 Subject: [PATCH 03/17] comment out empty constructor, enable precompike back --- src/SimpleArgParse.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 9e16ce6..d7fdd24 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,5 +1,4 @@ module SimpleArgParse -__precompile__(false) export ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, get_value, set_value, has_key, get_key, colorize @@ -52,8 +51,8 @@ mutable struct ArgumentParser examples::Vector{String} "flag to automatically generate a help message" add_help::Bool - "empty constructor" - ArgumentParser() = new(OrderedDict(), OrderedDict(), "", "", "", "", "", "", "", "", false) + # "empty constructor" + # ArgumentParser() = new(OrderedDict(), OrderedDict(), "", "", "", "", "", "", "", "", false) "keyword argument constructor" function ArgumentParser(; filename="", description::String="", authors::Vector{String}=String[], From 523720f8e9b623dd047212060900e9e4b2010090 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 13:45:32 +0100 Subject: [PATCH 04/17] bikeshedding in parse_args() --- src/SimpleArgParse.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index d7fdd24..ee8d44f 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -185,16 +185,16 @@ function help(parser::ArgumentParser; color::String="default") end "Parse command-line arguments." -function parse_args(parser::ArgumentParser; args=ARGS) +function parse_args(parser::ArgumentParser; cli_args=ARGS) :ArgumentParser if parser.add_help parser = add_argument(parser, "-h", "--help", type=Bool, default=false, description="Print the help message.") parser.usage = generate_usage(parser) end parser.filename = PROGRAM_FILE - n::Int64 = length(args) - for i::Int64 in eachindex(args) - arg::String = args[i] + n::Int64 = length(cli_args) + for i::Int64 in eachindex(cli_args) + arg::String = cli_args[i] argkey::String = arg2key(arg) if startswith(arg, "-") !haskey(parser.arg_store, argkey) && error("Argument not found: $(arg). Call `add_argument` before parsing.") @@ -205,10 +205,10 @@ function parse_args(parser::ArgumentParser; args=ARGS) end # if next iteration is at the end or is an argument, treat current argument as flag/boolean # otherwise, capture the value and skip iterating over it for efficiency - if (i + 1 > n) || startswith(args[i+1], "-") + if (i + 1 > n) || startswith(cli_args[i+1], "-") value = true elseif (i + 1 <= n) - value = args[i+1] + value = cli_args[i+1] i += 1 else error("Value failed to parse for arg: $(arg)") From c9765b6dcc2ecf2a4d4014bcec368a297347ac5f Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 19:33:31 +0100 Subject: [PATCH 05/17] keys(parser::ArgumentParser) --- src/SimpleArgParse.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index ee8d44f..f21d50d 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -240,6 +240,8 @@ function has_key(parser::ArgumentParser, arg::String) return result end +keys(parser::ArgumentParser) = keys(parser.arg_store) + "Get argument key from parser." function get_key(parser::ArgumentParser, arg::String) :Union From ded46ab5f920aaaccf7c1e78d87d869e3da3f854 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 19:46:44 +0100 Subject: [PATCH 06/17] Base.keys(parser::ArgumentParser) --- src/SimpleArgParse.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index f21d50d..4a0db0d 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,6 +1,8 @@ module SimpleArgParse -export ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, get_value, set_value, has_key, get_key, colorize +export ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, + get_value, set_value, has_key, get_key, colorize, + keys using Base using SHA: sha256 @@ -240,7 +242,7 @@ function has_key(parser::ArgumentParser, arg::String) return result end -keys(parser::ArgumentParser) = keys(parser.arg_store) +Base.keys(parser::ArgumentParser) = [lstrip(v.args.long, '-') for v in values(parser.kv_store)] "Get argument key from parser." function get_key(parser::ArgumentParser, arg::String) From 39eef7bda213dab76f7477a93e9aaebadff6f0f5 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 20:42:40 +0100 Subject: [PATCH 07/17] ::String => ::AbstractString --- src/SimpleArgParse.jl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 4a0db0d..1859d78 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -86,9 +86,9 @@ function args2vec(args::Arguments) end "Argument to argument-store key conversion by removing hypenation from prefix." -function arg2key(arg::String) +function arg2key(arg::AbstractString) :String - return strip(arg, '-') + return lstrip(arg, '-') end "Add command-line argument to ArgumentParser object instance." @@ -126,7 +126,7 @@ function add_argument(parser::ArgumentParser, arg_short::String="", arg_long::St end "Add command-line usage example." -function add_example(parser::ArgumentParser, example::String) +function add_example(parser::ArgumentParser, example::AbstractString) :ArgumentParser push!(parser.examples, example) return parser @@ -180,7 +180,7 @@ function generate_usage(parser::ArgumentParser) end "Helper function to print usage/help message." -function help(parser::ArgumentParser; color::String="default") +function help(parser::ArgumentParser; color::AbstractString="default") :Nothing println(colorize(parser.usage, color=color)) return nothing @@ -225,7 +225,7 @@ function parse_args(parser::ArgumentParser; cli_args=ARGS) end "Get argument value from parser." -function get_value(parser::ArgumentParser, arg::String) +function get_value(parser::ArgumentParser, arg::AbstractString) :Any argkey::String = arg2key(arg) !haskey(parser.arg_store, argkey) && error("Argument not found: $(arg). Run `add_argument` first.") @@ -235,17 +235,17 @@ function get_value(parser::ArgumentParser, arg::String) end "Check if argument key exists in store." -function has_key(parser::ArgumentParser, arg::String) +function has_key(parser::ArgumentParser, arg::AbstractString) :Bool argkey::String = arg2key(arg) result::Bool = haskey(parser.arg_store, argkey) ? true : false return result end -Base.keys(parser::ArgumentParser) = [lstrip(v.args.long, '-') for v in values(parser.kv_store)] +Base.keys(parser::ArgumentParser) = [arg2key(v.args.long) for v in values(parser.kv_store)] "Get argument key from parser." -function get_key(parser::ArgumentParser, arg::String) +function get_key(parser::ArgumentParser, arg::AbstractString) :Union argkey::String = arg2key(arg) key::Union{UInt16,Nothing} = haskey(parser.arg_store, argkey) ? parser.arg_store[argkey] : nothing @@ -253,7 +253,7 @@ function get_key(parser::ArgumentParser, arg::String) end "Prepend hyphenation back onto argument after stripping it for the argument-store key." -function hyphenate(arg::String) +function hyphenate(arg::AbstractString) :String argkey::String = arg2key(arg) # supports "foo" or "--foo" argument form result::String = length(argkey) == 1 ? "-" * argkey : "--" * argkey @@ -261,7 +261,7 @@ function hyphenate(arg::String) end "Set/update value of argument in parser." -function set_value(parser::ArgumentParser, arg::String, value::Any) +function set_value(parser::ArgumentParser, arg::AbstractString, value::Any) :ArgumentParser argkey::String = arg2key(arg) !haskey(parser.arg_store, argkey) && error("Argument not found in store.") From c124c8470295ccb348dd7cf556ce1f1ac3b3a63b Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Wed, 20 Mar 2024 23:53:26 +0100 Subject: [PATCH 08/17] UInt16 keys now sequentially ordered --- Project.toml | 3 +-- src/SimpleArgParse.jl | 18 +++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index e90d6c8..c73f573 100644 --- a/Project.toml +++ b/Project.toml @@ -5,9 +5,8 @@ version = "1.0.1" [deps] OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -julia = "1.0" OrderedCollections = "1.5" +julia = "1.0" diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 1859d78..73b7dc5 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -4,8 +4,8 @@ export ArgumentParser, add_argument, add_example, generate_usage, help, parse_ar get_value, set_value, has_key, get_key, colorize, keys -using Base -using SHA: sha256 +# using Base +# using SHA: sha256 using OrderedCollections: OrderedDict ### @@ -34,6 +34,8 @@ mutable struct ArgumentParser kv_store::OrderedDict{UInt16,ArgumentValues} "key-value store: { arg: key }" arg_store::OrderedDict{String,UInt16} + "number of stored args" + lng::UInt16 # attributes "file name" filename::String @@ -54,14 +56,14 @@ mutable struct ArgumentParser "flag to automatically generate a help message" add_help::Bool # "empty constructor" - # ArgumentParser() = new(OrderedDict(), OrderedDict(), "", "", "", "", "", "", "", "", false) + # ArgumentParser() = new(OrderedDict(), OrderedDict(), 0, "", "", "", "", "", "", "", "", false) "keyword argument constructor" function ArgumentParser(; - filename="", description::String="", authors::Vector{String}=String[], + filename="", description::String="", lng=0, authors::Vector{String}=String[], documentation::String="", repository::String="", license::String="", usage::String="", examples::Vector{String}=String[], add_help::Bool=false) :ArgumentParser - new(OrderedDict(), OrderedDict(), filename, description, authors, documentation, + new(OrderedDict(), OrderedDict(), lng, filename, description, authors, documentation, repository, license, usage, examples, add_help) end end @@ -112,10 +114,8 @@ function add_argument(parser::ArgumentParser, arg_short::String="", arg_long::St # prefer stripped long argument for higher entropy arg::String = !isempty(arg_long) ? arg_long : !isempty(arg_short) ? arg_short : "" isempty(arg) && error("Argument(s) missing. See usage examples.") - # remove prepended hyphenation to increase entropy - argkey::String = arg2key(arg) - # key is first two bytes of SHA-256 hash of argument name; up to 65,536 argument keys - key::UInt16 = read(IOBuffer(sha256(argkey)[1:2]), UInt16) + parser.lng += 1 + key::UInt16 = parser.lng # map both argument names to the same key !isempty(arg_short) && (parser.arg_store[arg2key(arg_short)] = key) !isempty(arg_long) && (parser.arg_store[arg2key(arg_long)] = key) From 7aca9374ec5c9b93d3f84dc942332baee1d1610b Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Thu, 21 Mar 2024 21:09:10 +0100 Subject: [PATCH 09/17] rename! functions mutating argument --- src/SimpleArgParse.jl | 26 +++++++++++++++++++------- test/runtests.jl | 10 +++++----- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 73b7dc5..8344943 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,7 +1,7 @@ module SimpleArgParse -export ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, - get_value, set_value, has_key, get_key, colorize, +export ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, + get_value, set_value, has_key, get_key, colorize, colorprint, nt_args, keys # using Base @@ -94,7 +94,7 @@ function arg2key(arg::AbstractString) end "Add command-line argument to ArgumentParser object instance." -function add_argument(parser::ArgumentParser, arg_short::String="", arg_long::String=""; +function add_argument!(parser::ArgumentParser, arg_short::String="", arg_long::String=""; type::Type=Any, required::Bool=false, default::Any=nothing, description::String="") """ # Arguments @@ -126,7 +126,7 @@ function add_argument(parser::ArgumentParser, arg_short::String="", arg_long::St end "Add command-line usage example." -function add_example(parser::ArgumentParser, example::AbstractString) +function add_example!(parser::ArgumentParser, example::AbstractString) :ArgumentParser push!(parser.examples, example) return parser @@ -187,10 +187,10 @@ function help(parser::ArgumentParser; color::AbstractString="default") end "Parse command-line arguments." -function parse_args(parser::ArgumentParser; cli_args=ARGS) +function parse_args!(parser::ArgumentParser; cli_args=ARGS) :ArgumentParser if parser.add_help - parser = add_argument(parser, "-h", "--help", type=Bool, default=false, description="Print the help message.") + parser = add_argument!(parser, "-h", "--help", type=Bool, default=false, description="Print the help message.") parser.usage = generate_usage(parser) end parser.filename = PROGRAM_FILE @@ -299,7 +299,7 @@ ANSICODES::Base.ImmutableDict{String,Int} = Base.ImmutableDict( "default" => 39 ) -function colorize(text::String; color::String="default", background::Bool=false, bright::Bool=false) +function colorize(text::AbstractString; color::AbstractString="default", background::Bool=false, bright::Bool=false) :String """ Colorize strings or backgrounds using ANSI codes and escape sequences. @@ -329,4 +329,16 @@ function colorize(text::String; color::String="default", background::Bool=false, return "\033[" * code_string * "m" * text * "\033[0m" end +# # # # # # # # + +colorprint(text, color="default"; background=false, bright=false) = println(colorize(text; color, background, bright)) + +argpair(s, args) = Symbol(s) => get_value(args, s) + +function nt_args(args::ArgumentParser) + allkeys = keys(args) + filter!(x -> x != "help", allkeys) + return NamedTuple(argpair(k, args) for k in allkeys) +end + end # module SimpleArgParse diff --git a/test/runtests.jl b/test/runtests.jl index 5d93092..7a05cc4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using SimpleArgParse: ArgumentParser, add_argument, add_example, generate_usage, help, parse_args, get_value, set_value, has_key, get_key +using SimpleArgParse: ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, get_value, set_value, has_key, get_key using Test @testset "SimpleArgParse tests" begin @@ -33,9 +33,9 @@ using Test @test p.add_help end - @testset "Testset add_argument" begin + @testset "Testset add_argument!" begin p = ArgumentParser() - p = add_argument(p, "-f", "--foo", type=String, default="bar", description="baz") + p = add_argument!(p, "-f", "--foo", type=String, default="bar", description="baz") @test "bar" == get_value(p, "--foo") @test "bar" == get_value(p, "-f") @test "bar" == get_value(p, "f") @@ -43,7 +43,7 @@ using Test @testset "Testset get_value" begin p = ArgumentParser() - p = add_argument(p, "-f", "--foo", type=String, default="bar", description="baz") + p = add_argument!(p, "-f", "--foo", type=String, default="bar", description="baz") @test "bar" == get_value(p, "--foo") @test "bar" == get_value(p, "-f") @test "bar" == get_value(p, "f") @@ -52,7 +52,7 @@ using Test @testset "Testset set_value" begin p = ArgumentParser() - p = add_argument(p, "-f", "--foo", type=String, default="bar") + p = add_argument!(p, "-f", "--foo", type=String, default="bar") @test "bar" == get_value(p, "--foo") p = set_value(p, "--foo", "baz") @test "baz" == get_value(p, "--foo") From a34eda17d35e0f4171f602cefea0f44b426add33 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Thu, 21 Mar 2024 21:48:10 +0100 Subject: [PATCH 10/17] optional newline in colorprint --- src/SimpleArgParse.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 8344943..c27a6d6 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -331,7 +331,10 @@ end # # # # # # # # -colorprint(text, color="default"; background=false, bright=false) = println(colorize(text; color, background, bright)) +function colorprint(text, color="default", newline=false; background=false, bright=false) + print(colorize(text; color, background, bright)) + newline && println() +end argpair(s, args) = Symbol(s) => get_value(args, s) From 227a1abfce2ca741a1699b5ce5deecc643e65d7e Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Thu, 21 Mar 2024 21:49:18 +0100 Subject: [PATCH 11/17] newline=true --- src/SimpleArgParse.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index c27a6d6..009963d 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -331,7 +331,7 @@ end # # # # # # # # -function colorprint(text, color="default", newline=false; background=false, bright=false) +function colorprint(text, color="default", newline=true; background=false, bright=false) print(colorize(text; color, background, bright)) newline && println() end From f7e611128c6819d2f1b99e6a04264c104fa78591 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Thu, 21 Mar 2024 22:30:56 +0100 Subject: [PATCH 12/17] mutable struct PromptedParser --- src/SimpleArgParse.jl | 17 +++++++++++++++-- test/runtests.jl | 6 +++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 009963d..fddb325 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,7 +1,7 @@ module SimpleArgParse export ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, - get_value, set_value, has_key, get_key, colorize, colorprint, nt_args, + get_value, set_value!, has_key, get_key, colorize, colorprint, nt_args, keys # using Base @@ -261,7 +261,7 @@ function hyphenate(arg::AbstractString) end "Set/update value of argument in parser." -function set_value(parser::ArgumentParser, arg::AbstractString, value::Any) +function set_value!(parser::ArgumentParser, arg::AbstractString, value::Any) :ArgumentParser argkey::String = arg2key(arg) !haskey(parser.arg_store, argkey) && error("Argument not found in store.") @@ -344,4 +344,17 @@ function nt_args(args::ArgumentParser) return NamedTuple(argpair(k, args) for k in allkeys) end +@kwdef mutable struct PromptedParser + parser::ArgumentParser + color::String = "default" + introduction::String = "" + prompt::String = "> " +end + +nt_args(p::PromptedParser) = nt_args(p.parser) +set_value!(p::PromptedParser, arg, value) = set_value!(p.parser, arg, value) +add_argument!(p::PromptedParser, arg_short, arg_long; kwargs...) = add_argument!(p.parser, arg_short, arg_long; kwargs...) +parse_args!(p::PromptedParser, cli_args) = parse_args!(p.parser; cli_args) +add_example!(p::PromptedParser, example) = add_example!(p.parser, example) + end # module SimpleArgParse diff --git a/test/runtests.jl b/test/runtests.jl index 7a05cc4..c980a02 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using SimpleArgParse: ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, get_value, set_value, has_key, get_key +using SimpleArgParse: ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, get_value, set_value!, has_key, get_key using Test @testset "SimpleArgParse tests" begin @@ -50,11 +50,11 @@ using Test @test isa(get_value(p, "foo"), String) end - @testset "Testset set_value" begin + @testset "Testset set_value!" begin p = ArgumentParser() p = add_argument!(p, "-f", "--foo", type=String, default="bar") @test "bar" == get_value(p, "--foo") - p = set_value(p, "--foo", "baz") + p = set_value!(p, "--foo", "baz") @test "baz" == get_value(p, "--foo") end From 89f9f5b03e10d3873606325ff8fd10067877cc18 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Thu, 21 Mar 2024 23:57:40 +0100 Subject: [PATCH 13/17] WIP --- src/SimpleArgParse.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index fddb325..14ac927 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -1,7 +1,8 @@ module SimpleArgParse export ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, - get_value, set_value!, has_key, get_key, colorize, colorprint, nt_args, + get_value, set_value!, has_key, get_key, colorize, + colorprint, nt_args, PromptedParser, keys # using Base @@ -345,7 +346,7 @@ function nt_args(args::ArgumentParser) end @kwdef mutable struct PromptedParser - parser::ArgumentParser + parser::ArgumentParser = ArgumentParser() color::String = "default" introduction::String = "" prompt::String = "> " From 93c3a465a6d1c59c262c9cfedb35c6dd3ba192e8 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Fri, 22 Mar 2024 17:49:56 +0100 Subject: [PATCH 14/17] nt_args() => args_pairs() --- src/SimpleArgParse.jl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index 14ac927..a724269 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -2,7 +2,7 @@ module SimpleArgParse export ArgumentParser, add_argument!, add_example!, generate_usage, help, parse_args!, get_value, set_value!, has_key, get_key, colorize, - colorprint, nt_args, PromptedParser, + colorprint, args_pairs, PromptedParser, keys # using Base @@ -111,6 +111,7 @@ function add_argument!(parser::ArgumentParser, arg_short::String="", arg_long::S - `description::String=nothing`: argument description. """ :ArgumentParser + args::Arguments = Arguments(arg_short, arg_long) # prefer stripped long argument for higher entropy arg::String = !isempty(arg_long) ? arg_long : !isempty(arg_short) ? arg_short : "" @@ -120,7 +121,7 @@ function add_argument!(parser::ArgumentParser, arg_short::String="", arg_long::S # map both argument names to the same key !isempty(arg_short) && (parser.arg_store[arg2key(arg_short)] = key) !isempty(arg_long) && (parser.arg_store[arg2key(arg_long)] = key) - default = type == Any ? default : convert(type, default) + default = (type == Any) | isnothing(default) ? default : convert(type, default) values::ArgumentValues = ArgumentValues(args, default, type, required, description) parser.kv_store[key] = values return parser @@ -280,8 +281,8 @@ Base.parse(::Type{String}, x::String) = x Base.parse(::Type{Bool}, x::Bool) = x Base.parse(::Type{Number}, x::Number) = x Base.parse(::Type{String}, x::Bool) = x ? "true" : "false" -Base.convert(::Type{Char}, x::Nothing) = ' ' -Base.convert(::Type{String}, x::Nothing) = "" +# Base.convert(::Type{Char}, x::Nothing) = ' ' +# Base.convert(::Type{String}, x::Nothing) = "" ### ### Utilities @@ -339,10 +340,12 @@ end argpair(s, args) = Symbol(s) => get_value(args, s) -function nt_args(args::ArgumentParser) +function args_pairs(args::ArgumentParser) allkeys = keys(args) filter!(x -> x != "help", allkeys) - return NamedTuple(argpair(k, args) for k in allkeys) + ps = [argpair(k, args) for k in allkeys] + filter!(p -> !isnothing(p[2]) , ps) + return ps end @kwdef mutable struct PromptedParser @@ -352,7 +355,7 @@ end prompt::String = "> " end -nt_args(p::PromptedParser) = nt_args(p.parser) +args_pairs(p::PromptedParser) = args_pairs(p.parser) set_value!(p::PromptedParser, arg, value) = set_value!(p.parser, arg, value) add_argument!(p::PromptedParser, arg_short, arg_long; kwargs...) = add_argument!(p.parser, arg_short, arg_long; kwargs...) parse_args!(p::PromptedParser, cli_args) = parse_args!(p.parser; cli_args) From 9cbebb150bd34d69558db466189887a413015701 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Fri, 22 Mar 2024 22:17:45 +0100 Subject: [PATCH 15/17] add PromptedParser methods --- src/SimpleArgParse.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index a724269..ecc09e7 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -360,5 +360,8 @@ set_value!(p::PromptedParser, arg, value) = set_value!(p.parser, arg, value) add_argument!(p::PromptedParser, arg_short, arg_long; kwargs...) = add_argument!(p.parser, arg_short, arg_long; kwargs...) parse_args!(p::PromptedParser, cli_args) = parse_args!(p.parser; cli_args) add_example!(p::PromptedParser, example) = add_example!(p.parser, example) +help(p::PromptedParser; color=p.color) = help(p.parser; color) +get_value(p::PromptedParser, arg) = get_value(p.parser, arg) + end # module SimpleArgParse From 59486a4ae64120c39f681d21f07dcde805aabd0d Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Fri, 22 Mar 2024 22:39:19 +0100 Subject: [PATCH 16/17] @kwdef ArgumentParser --- src/SimpleArgParse.jl | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index ecc09e7..fce4481 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -29,44 +29,33 @@ struct ArgumentValues end "Command-line argument parser with key-value stores and attributes." -mutable struct ArgumentParser +@kwdef mutable struct ArgumentParser # stores "key-value store: { key: ArgumentValues(value, type, required, help) }; up to 65,536 argument keys" - kv_store::OrderedDict{UInt16,ArgumentValues} + kv_store::OrderedDict{UInt16,ArgumentValues} = OrderedDict() "key-value store: { arg: key }" - arg_store::OrderedDict{String,UInt16} + arg_store::OrderedDict{String,UInt16} = OrderedDict() "number of stored args" - lng::UInt16 + lng::UInt16 = 0 # attributes "file name" - filename::String + filename::String = "" "description" - description::String + description::String = "" "name of author(s): First Last " - authors::Vector{String} + authors::Vector{String} = String[] "URL of documentations" - documentation::String + documentation::String = "" "URL of software repository" - repository::String + repository::String = "" "name of license" - license::String + license::String = "" "usage/help message" - usage::String + usage::String = "" "usage examples" - examples::Vector{String} + examples::Vector{String} = String[] "flag to automatically generate a help message" - add_help::Bool - # "empty constructor" - # ArgumentParser() = new(OrderedDict(), OrderedDict(), 0, "", "", "", "", "", "", "", "", false) - "keyword argument constructor" - function ArgumentParser(; - filename="", description::String="", lng=0, authors::Vector{String}=String[], - documentation::String="", repository::String="", license::String="", - usage::String="", examples::Vector{String}=String[], add_help::Bool=false) - :ArgumentParser - new(OrderedDict(), OrderedDict(), lng, filename, description, authors, documentation, - repository, license, usage, examples, add_help) - end + add_help::Bool = false end ### From f801aceb6097c66c013855bd0fd3d3bb36a7c639 Mon Sep 17 00:00:00 2001 From: Ben Elkin <8xe8n-cm@online.de> Date: Sun, 24 Mar 2024 22:03:03 +0100 Subject: [PATCH 17/17] undo Base.parse() type piracy --- src/SimpleArgParse.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/SimpleArgParse.jl b/src/SimpleArgParse.jl index fce4481..da6f626 100644 --- a/src/SimpleArgParse.jl +++ b/src/SimpleArgParse.jl @@ -209,7 +209,7 @@ function parse_args!(parser::ArgumentParser; cli_args=ARGS) # extract default value and update given an argument value values::ArgumentValues = parser.kv_store[key] # type cast value into tuple index 1 - value = values.type == Any ? value : parse(values.type, value) + value = values.type == Any ? value : _parse(values.type, value) parser.kv_store[key] = ArgumentValues(values.args, value, values.type, values.required, values.description) end return parser @@ -265,13 +265,12 @@ function set_value!(parser::ArgumentParser, arg::AbstractString, value::Any) end # Type conversion helper methods. -Base.parse(::Type{String}, x::Number) = x -Base.parse(::Type{String}, x::String) = x -Base.parse(::Type{Bool}, x::Bool) = x -Base.parse(::Type{Number}, x::Number) = x -Base.parse(::Type{String}, x::Bool) = x ? "true" : "false" -# Base.convert(::Type{Char}, x::Nothing) = ' ' -# Base.convert(::Type{String}, x::Nothing) = "" +_parse(x, y) = parse(x, y) +_parse(::Type{String}, x::Number) = x +_parse(::Type{String}, x::String) = x +_parse(::Type{Bool}, x::Bool) = x +_parse(::Type{Number}, x::Number) = x +_parse(::Type{String}, x::Bool) = x ? "true" : "false" ### ### Utilities @@ -331,7 +330,7 @@ argpair(s, args) = Symbol(s) => get_value(args, s) function args_pairs(args::ArgumentParser) allkeys = keys(args) - filter!(x -> x != "help", allkeys) + filter!(x -> !(x in ["help", "abort"]), allkeys) ps = [argpair(k, args) for k in allkeys] filter!(p -> !isnothing(p[2]) , ps) return ps