Repository: comonicon/Comonicon.jl
Pull request #207 (2022-07-21 17:25:00)

smarter hint generation for long default value

originally raised by @GiggleLiu that default hint will error when the default value is too long. Now we limit the default hint generation to 10 chars by default and raise an error points to how to override the default hint in docstring.


Patch:
diff --git a/src/ast/printing.jl b/src/ast/printing.jl
index 6f99ea0..f7fa0ce 100644
--- a/src/ast/printing.jl
+++ b/src/ast/printing.jl
@@ -271,12 +271,7 @@ function print_with_brief(f, io::IO, cmd, t::Terminal)
 
     middle = t.width - t.left - t.right
     firstline = length(s) + 2
-    t.left - firstline + middle > 0 || error(
-        "signature of $(cmd.name) is too long, consider " *
-        "set `command.width` in `Comonicon.toml` to " *
-        "larger value, or truncate your argument and command name length " *
-        "current terminal width is $(t.width)",
-    )
+    t.left - firstline + middle > 0 || print_with_brief_error(cmd, t)
 
     print(io, tab(2))
     f(io, cmd, t)
@@ -291,6 +286,26 @@ function print_with_brief(f, io::IO, cmd, t::Terminal)
     return
 end
 
+function print_with_brief_error(cmd::Option, t::Terminal)
+    error(
+        "signature of $(cmd.name) is too long, consider " *
+        "this might due to default hint of this option is too long " *
+        "override the hint with --option=<your own hint> or " *
+        "set `command.width` in `Comonicon.toml` to " *
+        "larger value, or truncate your argument and command name length " *
+        "current terminal width is $(t.width)",
+    )
+end
+
+function print_with_brief_error(cmd, t::Terminal)
+    error(
+        "signature of $(cmd.name) is too long, consider " *
+        "set `command.width` in `Comonicon.toml` to " *
+        "larger value, or truncate your argument and command name length " *
+        "current terminal width is $(t.width)",
+    )
+end
+
 function print_indent_content(io::IO, text::String, t::Terminal, firstline::Int)
     middle = t.width - t.left - t.right
     lines = splitlines(text, t.right)
diff --git a/src/frontend/cast.jl b/src/frontend/cast.jl
index e46a66d..cf91a2b 100644
--- a/src/frontend/cast.jl
+++ b/src/frontend/cast.jl
@@ -296,7 +296,7 @@ function parse_arguments(fn::JLFunction)
                 name = QuoteNode(name),
                 type = wrap_type(fn, type),
                 require = false,
-                default = string(value),
+                default = emit_default_hint(value),
             )
         elseif Meta.isexpr(each, :...) # :($name...)
             xcall(
@@ -354,12 +354,21 @@ function parse_required_kwargs!(flags, options, @nospecialize(expr))::Nothing
     return
 end
 
+function emit_default_hint(ex)
+    hint = string(ex)
+    return if length(hint) > 10
+        hint[1:7] * "..."
+    else
+        hint
+    end
+end
+
 function parse_optional_kwargs!(flags, options, kw_expr::Expr)::Nothing
     # expr == Expr(:kw, expr, value)
     expr = kw_expr.args[1]
     value = kw_expr.args[2]
     if expr isa Symbol # Expr(:kw, name::Symbol, value)
-        push!(options, xcall(Comonicon, :JLOption, QuoteNode(expr), false, Any, string(value)))
+        push!(options, xcall(Comonicon, :JLOption, QuoteNode(expr), false, Any, emit_default_hint(value)))
     elseif Meta.isexpr(expr, :(::)) # Expr(:kw, ($name::$type), value)
         name = expr.args[1]
         type = expr.args[2]
@@ -380,7 +389,7 @@ function parse_optional_kwargs!(flags, options, kw_expr::Expr)::Nothing
                     QuoteNode(name),
                     false,
                     type,
-                    string(value) * "::" * string(type),
+                    emit_default_hint(value) * "::" * string(type),
                 ),
             )
         end


Test patch:
diff --git a/test/long_print.jl b/test/long_print.jl
new file mode 100644
index 0000000..4e6ae78
--- /dev/null
+++ b/test/long_print.jl
@@ -0,0 +1,13 @@
+module LongPrint
+
+using Comonicon
+
+@cast function long_non_typed(;option="super long string super long string super long string")
+end
+
+@cast function long_typed(;option::String="super long string super long string super long string")
+end
+
+@main
+
+end
diff --git a/test/runtests.jl b/test/runtests.jl
index ab8491f..530e6d2 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -22,6 +22,7 @@ end
 @testset "frontend" begin
     include("frontend/cast.jl")
     include("frontend/markdown.jl")
+    include("long_print.jl")
 end
 
 @testset "codegen" begin