Skip to content

Commit 4aeab2f

Browse files
Merge pull request #128 from stelmo/mo-format-long-docstrings
Break long docstrings into multiple lines
2 parents 947bbad + 3fb146a commit 4aeab2f

File tree

3 files changed

+80
-60
lines changed

3 files changed

+80
-60
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
${{ runner.os }}-test-
3737
${{ runner.os }}-
3838
- uses: julia-actions/julia-runtest@latest
39+
continue-on-error: ${{ matrix.version == 'nightly' }}
3940
- uses: julia-actions/julia-processcoverage@v1
4041
- uses: codecov/codecov-action@v1
4142
with:

src/utilities.jl

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,45 @@ function parsedocs(mod::Module)
174174
end
175175
end
176176

177+
"""
178+
$(:SIGNATURES)
179+
180+
Decides whether a length of method is too big to be visually appealing.
181+
"""
182+
method_length_over_limit(len::Int) = len > 60
183+
184+
function printmethod_format(buffer::IOBuffer, binding::String, args::Vector{String}, kws::Vector{String}; return_type = "")
185+
186+
sep_delim = " "
187+
paren_delim = ""
188+
indent = ""
189+
190+
if method_length_over_limit(
191+
length(binding) +
192+
1 +
193+
sum(length.(args)) +
194+
sum(length.(kws)) +
195+
2*max(0, length(args)-1) +
196+
2*length(kws) +
197+
1 +
198+
length(return_type))
199+
200+
sep_delim = "\n"
201+
paren_delim = "\n"
202+
indent = " "
203+
end
204+
205+
print(buffer, binding)
206+
print(buffer, "($paren_delim")
207+
join(buffer, Ref(indent).*args, ",$sep_delim")
208+
if !isempty(kws)
209+
print(buffer, ";$sep_delim")
210+
join(buffer, Ref(indent).*kws, ",$sep_delim")
211+
end
212+
print(buffer, "$paren_delim)")
213+
print(buffer, return_type)
214+
return buffer
215+
end
177216

178217
"""
179218
$(:SIGNATURES)
@@ -193,19 +232,10 @@ f(x; a = 1, b...) = x
193232
sig = printmethod(Docs.Binding(Main, :f), f, first(methods(f)))
194233
```
195234
"""
196-
function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Method)
197-
# TODO: print qualified?
198-
print(buffer, binding.var)
199-
print(buffer, "(")
200-
join(buffer, arguments(method), ", ")
201-
local kws = keywords(func, method)
202-
if !isempty(kws)
203-
print(buffer, "; ")
204-
join(buffer, kws, ", ")
205-
end
206-
print(buffer, ")")
207-
return buffer
208-
end
235+
printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Method) =
236+
printmethod_format(buffer, string(binding.var),
237+
string.(arguments(method)),
238+
string.(keywords(func, method)))
209239

210240
"""
211241
$(:SIGNATURES)
@@ -273,18 +303,16 @@ sig = printmethod(Docs.Binding(Main, :f), f, first(methods(f)))
273303
"""
274304
function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Method, typesig)
275305
# TODO: print qualified?
276-
print(buffer, binding.var)
277-
print(buffer, "(")
278-
local args = arguments(method)
279-
local where_syntax = []
306+
local args = string.(arguments(method))
307+
local kws = string.(keywords(func, method))
280308

281309
# find inner tuple type
282-
function f(t)
310+
function find_inner_tuple_type(t)
283311
# t is always either a UnionAll which represents a generic type or a Tuple where each parameter is the argument
284312
if t isa DataType && t <: Tuple
285313
t
286314
elseif t isa UnionAll
287-
f(t.body)
315+
find_inner_tuple_type(t.body)
288316
else
289317
error("Expected `typeof($t)` to be `Tuple` or `UnionAll` but found `$typeof(t)`")
290318
end
@@ -308,45 +336,35 @@ function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Meth
308336
typ
309337
end
310338

311-
for (i, sym) in enumerate(args)
312-
if typesig isa UnionAll
313-
# e.g. Tuple{Vector{T}} where T<:Number
314-
# or Tuple{String, T, T} where T<:Number
315-
# or Tuple{Type{T}, String, Union{Nothing, Function}} where T<:Number
316-
t = [x for x in f(typesig).types]
317-
t = [get_typesig(x, x) for x in t][i]
318-
else
319-
# e.g. Tuple{Vector{Int}}
320-
t = typesig.types[i]
321-
end
339+
# if `typesig` is an UnionAll, it may be
340+
# e.g. Tuple{Vector{T}} where T<:Number
341+
# or Tuple{String, T, T} where T<:Number
342+
# or Tuple{Type{T}, String, Union{Nothing, Function}} where T<:Number
343+
# in the other case, it's usually something like Tuple{Vector{Int}}.
344+
argtypes = typesig isa UnionAll ?
345+
[get_typesig(t, t) for t in find_inner_tuple_type(typesig).types] :
346+
collect(typesig.types)
347+
348+
args = map(args, argtypes) do arg,t
349+
type = ""
350+
suffix = ""
322351
if isvarargtype(t)
323-
elt = vararg_eltype(t)
324-
if elt === Any
325-
print(buffer, "$sym...")
326-
else
327-
print(buffer, "$sym::$elt...")
328-
end
329-
elseif t === Any
330-
print(buffer, sym)
331-
else
332-
print(buffer, "$sym::$t")
352+
t = vararg_eltype(t)
353+
suffix = "..."
333354
end
334-
335-
if i != length(args)
336-
print(buffer, ", ")
355+
if t!==Any
356+
type = "::$t"
337357
end
358+
359+
"$arg$type$suffix"
338360
end
339-
local kws = keywords(func, method)
340-
if !isempty(kws)
341-
print(buffer, "; ")
342-
join(buffer, kws, ", ")
343-
end
344-
print(buffer, ")")
361+
345362
rt = Base.return_types(func, typesig)
346-
if length(rt) >= 1 && rt[1] !== Nothing && rt[1] !== Union{}
347-
print(buffer, " -> $(rt[1])")
348-
end
349-
buffer
363+
364+
return printmethod_format(buffer, string(binding.var), args, string.(kws);
365+
return_type =
366+
length(rt) >= 1 && rt[1] !== Nothing && rt[1] !== Union{} ?
367+
" -> $(rt[1])" : "")
350368
end
351369

352370
printmethod(b, f, m) = String(take!(printmethod(IOBuffer(), b, f, m)))

test/tests.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ end
190190
f = str -> replace(str, " " => "")
191191
str = f(str)
192192
if Sys.iswindows()
193-
@test occursin(f("h_1(x::Union{Array{T,4}, Array{T,3}} where T) -> Union{Array{T,4}, Array{T,3}} where T"), str)
193+
@test occursin(f("h_1(\nx::Union{Array{T,4}, Array{T,3}} where T\n) -> Union{Array{T,4}, Array{T,3}} where T"), str)
194194
else
195-
@test occursin(f("h_1(x::Union{Array{T,3}, Array{T,4}} where T) -> Union{Array{T,3}, Array{T,4}} where T"), str)
195+
@test occursin(f("h_1(\nx::Union{Array{T,3}, Array{T,4}} where T\n) -> Union{Array{T,3}, Array{T,4}} where T"), str)
196196
end
197197
@test occursin("\n```\n", str)
198198

@@ -307,7 +307,7 @@ end
307307
@test occursin("\n```julia\n", str)
308308
if VERSION > v"1.3.0"
309309
@test occursin("\nk_5(::Type{T<:Number}, x::String) -> String\n", str)
310-
@test occursin("\nk_5(::Type{T<:Number}, x::String, func::Union{Nothing, Function}) -> String\n", str)
310+
@test occursin("\nk_5(\n ::Type{T<:Number},\n x::String,\n func::Union{Nothing, Function}\n) -> String\n", str)
311311
@test occursin("\n```\n", str)
312312
else
313313
# TODO: remove this test when julia 1.0.0 support is dropped.
@@ -342,12 +342,13 @@ end
342342
DSE.format(DSE.TYPEDSIGNATURES, buf, doc)
343343
str = String(take!(buf))
344344
@test occursin("\n```julia\n", str)
345-
if VERSION > v"1.7" || VERSION < v"1.1"
346-
@test occursin("\nk_7(x::Union{Nothing, T} where T<:Integer) -> Union{Nothing, T} where T<:Integer\n", str)
345+
if VERSION >= v"1.6" && VERSION < v"1.7"
346+
@test occursin("\nk_7(\n x::Union{Nothing, T} where T<:Integer\n) -> Union{Nothing, Integer}\n", str)
347+
@test occursin("\nk_7(\n x::Union{Nothing, T} where T<:Integer,\n y::Integer\n) -> Union{Nothing, Integer}\n", str)
347348
else
348-
@test occursin("\nk_7(x::Union{Nothing, T} where T<:Integer) -> Union{Nothing, Integer}\n", str)
349+
@test occursin("\nk_7(\n x::Union{Nothing, T} where T<:Integer\n) -> Union{Nothing, T} where T<:Integer\n", str)
350+
@test occursin("\nk_7(\n x::Union{Nothing, T} where T<:Integer,\n y::Integer\n) -> Union{Nothing, T} where T<:Integer\n", str)
349351
end
350-
@test occursin("\nk_7(x::Union{Nothing, T} where T<:Integer, y::Integer) -> Union{Nothing, T} where T<:Integer\n", str)
351352
@test occursin("\n```\n", str)
352353

353354
doc.data = Dict(

0 commit comments

Comments
 (0)