@@ -60,12 +60,11 @@ function.
6060
6161include (" bindings.jl" )
6262
63- import Base. Markdown: @doc_str , MD
6463import Base. Meta: quot, isexpr
6564import Base: Callable, with_output_color
6665import .. CoreDocs: lazy_iterpolate
6766
68- export doc
67+ export doc, apropos
6968
7069# Basic API / Storage
7170
174173
175174docexpr (__source__, __module__, args... ) = Expr (:call , docstr, args... )
176175
177- function formatdoc (d:: DocStr )
178- buffer = IOBuffer ()
179- for part in d. text
180- formatdoc (buffer, d, part)
181- end
182- Markdown. MD (Any[Markdown. parse (seekstart (buffer))])
183- end
184- @noinline formatdoc (buffer, d, part) = print (buffer, part)
185-
186- function parsedoc (d:: DocStr )
187- if d. object === nothing
188- md = formatdoc (d)
189- md. meta[:module ] = d. data[:module ]
190- md. meta[:path ] = d. data[:path ]
191- d. object = md
192- end
193- d. object
194- end
195-
196176"""
197177 MultiDoc
198178
@@ -270,167 +250,6 @@ function getdoc end
270250getdoc (x, sig) = getdoc (x)
271251getdoc (x) = nothing
272252
273- """
274- Docs.doc(binding, sig)
275-
276- Return all documentation that matches both `binding` and `sig`.
277-
278- If `getdoc` returns a non-`nothing` result on the value of the binding, then a
279- dynamic docstring is returned instead of one based on the binding itself.
280- """
281- function doc (binding:: Binding , sig:: Type = Union{})
282- if defined (binding)
283- result = getdoc (resolve (binding), sig)
284- result === nothing || return result
285- end
286- results, groups = DocStr[], MultiDoc[]
287- # Lookup `binding` and `sig` for matches in all modules of the docsystem.
288- for mod in modules
289- dict = meta (mod)
290- if haskey (dict, binding)
291- multidoc = dict[binding]
292- push! (groups, multidoc)
293- for msig in multidoc. order
294- sig <: msig && push! (results, multidoc. docs[msig])
295- end
296- end
297- end
298- if isempty (groups)
299- # When no `MultiDoc`s are found that match `binding` then we check whether `binding`
300- # is an alias of some other `Binding`. When it is we then re-run `doc` with that
301- # `Binding`, otherwise if it's not an alias then we generate a summary for the
302- # `binding` and display that to the user instead.
303- alias = aliasof (binding)
304- alias == binding ? summarize (alias, sig) : doc (alias, sig)
305- else
306- # There was at least one match for `binding` while searching. If there weren't any
307- # matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
308- if isempty (results)
309- for group in groups, each in group. order
310- push! (results, group. docs[each])
311- end
312- end
313- # Get parsed docs and concatenate them.
314- md = catdoc (map (parsedoc, results)... )
315- # Save metadata in the generated markdown.
316- if isa (md, Markdown. MD)
317- md. meta[:results ] = results
318- md. meta[:binding ] = binding
319- md. meta[:typesig ] = sig
320- end
321- return md
322- end
323- end
324-
325- # Some additional convenience `doc` methods that take objects rather than `Binding`s.
326- doc (obj:: UnionAll ) = doc (Base. unwrap_unionall (obj))
327- doc (object, sig:: Type = Union{}) = doc (aliasof (object, typeof (object)), sig)
328- doc (object, sig... ) = doc (object, Tuple{sig... })
329-
330- """
331- Docs.fielddoc(binding, field)
332-
333- Return documentation for a particular `field` of a type if it exists.
334- """
335- function fielddoc (binding:: Binding , field:: Symbol )
336- for mod in modules
337- dict = meta (mod)
338- if haskey (dict, binding)
339- multidoc = dict[binding]
340- if haskey (multidoc. docs, Union{})
341- fields = multidoc. docs[Union{}]. data[:fields ]
342- if haskey (fields, field)
343- doc = fields[field]
344- return isa (doc, Markdown. MD) ? doc : Markdown. parse (doc)
345- end
346- end
347- end
348- end
349- fields = join ([" `$f `" for f in fieldnames (resolve (binding))], " , " , " , and " )
350- fields = isempty (fields) ? " no fields" : " fields $fields "
351- Markdown. parse (" `$(resolve (binding)) ` has $fields ." )
352- end
353-
354- # As with the additional `doc` methods, this converts an object to a `Binding` first.
355- fielddoc (object, field:: Symbol ) = fielddoc (aliasof (object, typeof (object)), field)
356-
357- # Object Summaries.
358- # =================
359-
360- function summarize (binding:: Binding , sig)
361- io = IOBuffer ()
362- println (io, " No documentation found.\n " )
363- if defined (binding)
364- summarize (io, resolve (binding), binding)
365- else
366- println (io, " Binding `" , binding, " ` does not exist." )
367- end
368- md = Markdown. parse (seekstart (io))
369- # Save metadata in the generated markdown.
370- md. meta[:results ] = DocStr[]
371- md. meta[:binding ] = binding
372- md. meta[:typesig ] = sig
373- return md
374- end
375-
376- function summarize (io:: IO , λ:: Function , binding)
377- kind = startswith (string (binding. var), ' @' ) ? " macro" : " `Function`"
378- println (io, " `" , binding, " ` is a " , kind, " ." )
379- println (io, " ```\n " , methods (λ), " \n ```" )
380- end
381-
382- function summarize (io:: IO , T:: DataType , binding)
383- println (io, " # Summary" )
384- println (io, " ```" )
385- println (io,
386- T. abstract ? " abstract type" :
387- T. mutable ? " mutable struct" :
388- Base. isstructtype (T) ? " struct" : " primitive type" ,
389- " " , T, " <: " , supertype (T)
390- )
391- println (io, " ```" )
392- if ! T. abstract && T. name != = Tuple. name && ! isempty (fieldnames (T))
393- println (io, " # Fields" )
394- println (io, " ```" )
395- pad = maximum (length (string (f)) for f in fieldnames (T))
396- for (f, t) in zip (fieldnames (T), T. types)
397- println (io, rpad (f, pad), " :: " , t)
398- end
399- println (io, " ```" )
400- end
401- if ! isempty (subtypes (T))
402- println (io, " # Subtypes" )
403- println (io, " ```" )
404- for t in subtypes (T)
405- println (io, t)
406- end
407- println (io, " ```" )
408- end
409- if supertype (T) != Any
410- println (io, " # Supertype Hierarchy" )
411- println (io, " ```" )
412- Base. show_supertypes (io, T)
413- println (io)
414- println (io, " ```" )
415- end
416- end
417-
418- function summarize (io:: IO , m:: Module , binding)
419- readme = Pkg. dir (string (m), " README.md" )
420- if isfile (readme)
421- println (io, " Displaying the `README.md` for the module instead.\n " )
422- println (io, " ---\n " )
423- println (io, read (readme, String))
424- else
425- println (io, " No docstring or `README.md` found for module `" , m, " `.\n " )
426- end
427- end
428-
429- function summarize (io:: IO , :: T , binding) where T
430- println (io, " `" , binding, " ` is of type `" , T, " `.\n " )
431- summarize (io, T, binding)
432- end
433-
434253# Utilities.
435254# ==========
436255
@@ -442,12 +261,6 @@ catdoc(xs...) = vcat(xs...)
442261
443262const keywords = Dict {Symbol, DocStr} ()
444263
445- isdoc (s:: AbstractString ) = true
446-
447- isdoc (x) = isexpr (x, :string ) ||
448- (isexpr (x, :macrocall ) && x. args[1 ] === Symbol (" @doc_str" )) ||
449- (isexpr (x, :call ) && x. args[1 ] === Base. Markdown. doc_str)
450-
451264function unblock (ex)
452265 isexpr (ex, :block ) || return ex
453266 exs = filter (ex -> ! (isa (ex, LineNumberNode) || isexpr (ex, :line )), ex. args)
@@ -511,13 +324,20 @@ function metadata(__source__, __module__, expr, ismodule)
511324 if isexpr (expr, :struct )
512325 # Field docs for concrete types.
513326 fields = []
514- tmp = nothing
327+ last_docstr = nothing
515328 for each in expr. args[3 ]. args
516- if isdoc (each)
517- tmp = each
518- elseif tmp != = nothing && (isa (each, Symbol) || isexpr (each, :(:: )))
519- push! (fields, (namify (each), tmp))
520- tmp = nothing
329+ if isa (each, Symbol) || isexpr (each, :(:: ))
330+ # a field declaration
331+ if last_docstr != = nothing
332+ push! (fields, (namify (each), last_docstr))
333+ last_docstr = nothing
334+ end
335+ elseif isexpr (each, :function ) || isexpr (each, :(= ))
336+ break
337+ elseif isa (each, String) || isexpr (each, :string ) || isexpr (each, :call ) ||
338+ (isexpr (each, :macrocall ) && each. args[1 ] === Symbol (" @doc_str" ))
339+ # forms that might be doc strings
340+ last_docstr = each
521341 end
522342 end
523343 dict = :($ (Dict)($ ([:($ (Pair)($ (quot (f)), $ d)) for (f, d) in fields]. .. )))
@@ -654,6 +474,16 @@ isquotedmacrocall(x) =
654474isbasicdoc (x) = isexpr (x, :.) || isa (x, Union{QuoteNode, Symbol})
655475is_signature (x) = isexpr (x, :call ) || (isexpr (x, :(:: ), 2 ) && isexpr (x. args[1 ], :call )) || isexpr (x, :where )
656476
477+ function docm (source:: LineNumberNode , mod:: Module , ex)
478+ if isexpr (ex, :-> ) && length (ex. args) > 1
479+ docm (source, mod, ex. args... )
480+ else
481+ # TODO : this is a shim to continue to allow `@doc` for looking up docstrings
482+ REPL = Base. root_module (Base, :REPL )
483+ return REPL. lookup_doc (ex)
484+ end
485+ end
486+
657487function docm (source:: LineNumberNode , mod:: Module , meta, ex, define = true )
658488 # Some documented expressions may be decorated with macro calls which obscure the actual
659489 # expression. Expand the macro calls and remove extra blocks.
@@ -730,27 +560,6 @@ function docerror(ex)
730560 :($ (error)($ txt, " \n " ))
731561end
732562
733- function docm (source:: LineNumberNode , mod:: Module , ex)
734- if isexpr (ex, :-> )
735- docm (source, mod, ex. args... )
736- elseif haskey (keywords, ex)
737- parsedoc (keywords[ex])
738- elseif isa (ex, Union{Expr, Symbol})
739- binding = esc (bindingexpr (namify (ex)))
740- if isexpr (ex, :call ) || isexpr (ex, :macrocall )
741- sig = esc (signature (ex))
742- :($ (doc)($ binding, $ sig))
743- else
744- :($ (doc)($ binding))
745- end
746- else
747- :($ (doc)($ (typeof)($ (esc (ex)))))
748- end
749- end
750-
751- # MD support
752- catdoc (md:: MD... ) = MD (md... )
753-
754563include (" utils.jl" )
755564
756565# Swap out the bootstrap macro with the real one.
@@ -775,4 +584,9 @@ function loaddocs(docs)
775584 empty! (docs)
776585end
777586
587+ function formatdoc end
588+ function parsedoc end
589+ function apropos end
590+ function doc end
591+
778592end
0 commit comments