@@ -29,20 +29,14 @@ function helpmode(io::IO, line::AbstractString, mod::Module=Main)
29
29
end
30
30
helpmode (line:: AbstractString , mod:: Module = Main) = helpmode (stdout , line, mod)
31
31
32
- # A hack to make the line entered at the REPL available at trimdocs without
33
- # passing the string through the entire mechanism.
34
- const extended_help_on = Ref {Any} (nothing )
35
-
36
32
function _helpmode (io:: IO , line:: AbstractString , mod:: Module = Main, internal_accesses:: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing )
37
33
line = strip (line)
38
34
ternary_operator_help = (line == " ?" || line == " ?:" )
39
35
if startswith (line, ' ?' ) && ! ternary_operator_help
40
36
line = line[2 : end ]
41
- extended_help_on[] = nothing
42
- brief = false
37
+ extended_help = true
43
38
else
44
- extended_help_on[] = line
45
- brief = true
39
+ extended_help = String (line):: String
46
40
end
47
41
# interpret anything starting with # or #= as asking for help on comments
48
42
if startswith (line, " #" )
@@ -72,7 +66,7 @@ function _helpmode(io::IO, line::AbstractString, mod::Module=Main, internal_acce
72
66
end
73
67
# the following must call repl(io, expr) via the @repl macro
74
68
# so that the resulting expressions are evaluated in the Base.Docs namespace
75
- :($ REPL. @repl $ io $ expr $ brief $ mod $ internal_accesses)
69
+ :($ REPL. @repl $ io $ expr $ extended_help $ mod $ internal_accesses)
76
70
end
77
71
_helpmode (line:: AbstractString , mod:: Module = Main) = _helpmode (stdout , line, mod)
78
72
@@ -123,51 +117,35 @@ struct Message # For direct messages to the terminal
123
117
msg # AbstractString
124
118
fmt # keywords to `printstyled`
125
119
end
126
- Message (msg) = Message (msg, ())
127
-
128
120
function Markdown. term (io:: IO , msg:: Message , columns)
129
121
printstyled (io, msg. msg; msg. fmt... )
130
122
end
131
123
132
- trimdocs (doc, brief:: Bool ) = doc
133
-
134
- function trimdocs (md:: Markdown.MD , brief:: Bool )
135
- brief || return md
136
- md, trimmed = _trimdocs (md, brief)
137
- if trimmed
138
- line = extended_help_on[]
139
- line = isa (line, AbstractString) ? line : " "
140
- push! (md. content, Message (" Extended help is available with `??$line `" , (color= Base. info_color (), bold= true )))
141
- end
124
+ add_extended_help! (doc, :: String ) = doc
125
+ function add_extended_help! (md:: Markdown.MD , extended_help:: String )
126
+ msg = Message (" Extended help is available with `help?> ?$extended_help `" , (color= Base. info_color (), bold= true ))
127
+ push! (md. content, msg)
142
128
return md
143
129
end
144
130
145
- function _trimdocs (md:: Markdown.MD , brief:: Bool )
146
- content, trimmed = [], false
131
+ trimdocs (doc) = doc
132
+ function trimdocs (md:: Markdown.MD )
133
+ content = []
147
134
for c in md. content
148
135
if isa (c, Markdown. Header{1 }) && isa (c. text, AbstractArray) && ! isempty (c. text)
149
136
item = c. text[1 ]
150
137
if isa (item, AbstractString) &&
151
138
lowercase (item) ∈ (" extended help" ,
152
139
" extended documentation" ,
153
140
" extended docs" )
154
- trimmed = true
155
141
break
156
142
end
157
143
end
158
- c, trm = _trimdocs (c, brief)
159
- trimmed |= trm
160
- push! (content, c)
144
+ push! (content, trimdocs (c))
161
145
end
162
- return Markdown. MD (content, md. meta), trimmed
146
+ return Markdown. MD (content, md. meta)
163
147
end
164
148
165
- _trimdocs (md, brief:: Bool ) = md, false
166
-
167
-
168
- is_tuple (expr) = false
169
- is_tuple (expr:: Expr ) = expr. head == :tuple
170
-
171
149
struct Logged{F}
172
150
f:: F
173
151
mod:: Module
180
158
(la:: Logged )(args... ) = la. f (args... )
181
159
182
160
function log_nonpublic_access (expr:: Expr , mod:: Module , internal_access:: Set{Pair{Module,Symbol}} )
183
- if expr. head === :. && length (expr. args) == 2 && ! is_tuple (expr. args[2 ])
161
+ if expr. head === :. && length (expr. args) == 2 && ! Meta . isexpr (expr. args[2 ], :tuple )
184
162
Expr (:call , Logged (getproperty, mod, internal_access), log_nonpublic_access .(expr. args, (mod,), (internal_access,))... )
185
163
elseif expr. head === :call && expr. args[1 ] === Base. Docs. Binding
186
164
Expr (:call , Logged (Base. Docs. Binding, mod, internal_access), log_nonpublic_access .(expr. args[2 : end ], (mod,), (internal_access,))... )
@@ -206,10 +184,17 @@ function insert_internal_warning(other, internal_access::Set{Pair{Module,Symbol}
206
184
other
207
185
end
208
186
209
- function doc (binding:: Binding , sig:: Type = Union{})
187
+ function doc (binding:: Binding , @nospecialize (sig:: Type = Union{});
188
+ extended_help:: Union{Bool,String} = false )
210
189
if defined (binding)
211
190
result = getdoc (resolve (binding), sig)
212
- result === nothing || return result
191
+ if result != = nothing
192
+ if extended_help isa String
193
+ result = trimdocs (result)
194
+ add_extended_help! (result, extended_help)
195
+ end
196
+ return result
197
+ end
213
198
end
214
199
results, groups = DocStr[], MultiDoc[]
215
200
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
@@ -230,7 +215,7 @@ function doc(binding::Binding, sig::Type = Union{})
230
215
# `Binding`, otherwise if it's not an alias then we generate a summary for the
231
216
# `binding` and display that to the user instead.
232
217
alias = aliasof (binding)
233
- alias == binding ? summarize (alias, sig) : doc (alias, sig)
218
+ return alias == binding ? summarize (alias, sig) : doc (alias, sig; extended_help )
234
219
else
235
220
# There was at least one match for `binding` while searching. If there weren't any
236
221
# matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
@@ -240,7 +225,17 @@ function doc(binding::Binding, sig::Type = Union{})
240
225
end
241
226
end
242
227
# Get parsed docs and concatenate them.
243
- md = catdoc (mapany (parsedoc, results)... )
228
+ docs = mapany (parsedoc, results)
229
+ if extended_help isa String # in the "brief" documentation mode
230
+ md = catdoc (docs... )
231
+ md = trimdocs (md)
232
+ add_extended_help! (md, extended_help)
233
+ elseif extended_help # in the extended documentation mode
234
+ push! (docs, summarize (binding, sig; extended= true )) # add summary docs too in extended help mode
235
+ md = catdoc (docs... )
236
+ else # in the simple documentation mode (e.g., called from `@doc`)
237
+ md = catdoc (docs... )
238
+ end
244
239
# Save metadata in the generated markdown.
245
240
if isa (md, Markdown. MD)
246
241
md. meta[:results ] = results
@@ -252,11 +247,30 @@ function doc(binding::Binding, sig::Type = Union{})
252
247
end
253
248
254
249
# Some additional convenience `doc` methods that take objects rather than `Binding`s.
255
- doc (obj:: UnionAll ) = doc (Base. unwrap_unionall (obj))
256
- doc (object, sig:: Type = Union{}) = doc (aliasof (object, typeof (object)), sig)
257
- doc (object, sig... ) = doc (object, Tuple{sig... })
250
+ doc (obj:: UnionAll ; kws... ) = doc (Base. unwrap_unionall (obj); kws... )
251
+ doc (object, @nospecialize (sig:: Type = Union{}); kws... ) = doc (aliasof (object, typeof (object)), sig; kws... )
252
+
253
+ function lookup_doc_ex (@nospecialize (x); extended_help:: Union{Bool,String} = false )
254
+ docex = lookup_doc (x; extended_help)
255
+ return Core. _ensure_doc_expr (docex, @__MODULE__ , LineNumberNode (@__LINE__ , @__FILE__ ))
256
+ end
257
+
258
+ function lookup_doc (@nospecialize (x); extended_help:: Union{Bool,String} = false )
259
+ docs = _lookup_doc (x, extended_help)
260
+ if isfield (x)
261
+ return :(let
262
+ T, field = $ (esc (x. args[1 ])), $ (esc (x. args[2 ]))
263
+ if T isa DataType
264
+ fielddoc (T, field)
265
+ else
266
+ $ docs
267
+ end
268
+ end )
269
+ end
270
+ return docs
271
+ end
258
272
259
- function lookup_doc (ex )
273
+ function _lookup_doc ( @nospecialize (ex), extended_help :: Union{Bool,String} = false )
260
274
if isa (ex, Expr) && ex. head != = :(.) && Base. isoperator (ex. head)
261
275
# handle syntactic operators, e.g. +=, ::, .=
262
276
ex = ex. head
@@ -266,7 +280,7 @@ function lookup_doc(ex)
266
280
elseif Meta. isexpr (ex, :incomplete )
267
281
return :($ (Markdown. md " No documentation found." ))
268
282
elseif ! isa (ex, Expr) && ! isa (ex, Symbol)
269
- return :($ ( doc)( $ ( typeof) ($ (esc (ex)))))
283
+ return :($ doc ( typeof ($ (esc (ex))); extended_help = $ extended_help ))
270
284
end
271
285
if isa (ex, Symbol) && Base. isoperator (ex)
272
286
str = string (ex)
@@ -287,30 +301,42 @@ function lookup_doc(ex)
287
301
binding = esc (bindingexpr (namify (ex)))
288
302
if isexpr (ex, :call ) || isexpr (ex, :macrocall ) || isexpr (ex, :where )
289
303
sig = esc (signature (ex))
290
- :($ ( doc) ($ binding, $ sig))
304
+ :($ doc ($ binding, $ sig; extended_help = $ extended_help ))
291
305
else
292
- :($ ( doc) ($ binding))
306
+ :($ doc ($ binding; extended_help = $ extended_help ))
293
307
end
294
308
end
295
309
296
310
# Object Summaries.
297
311
# =================
298
312
299
- function summarize (binding:: Binding , sig)
313
+ function summarize (binding:: Binding , @nospecialize ( sig); extended :: Bool = false )
300
314
io = IOBuffer ()
301
315
if defined (binding)
302
316
binding_res = resolve (binding)
303
317
if ! isa (binding_res, Module)
304
- varstr = " $(binding. mod) .$(binding. var) "
318
+ varstr = " ` $(binding. mod) .$(binding. var) ` "
305
319
if Base. ispublic (binding. mod, binding. var)
306
- println (io, " No documentation found for public binding `$varstr `.\n " )
320
+ if extended
321
+ println (io, " Extended information found for public binding $varstr .\n " )
322
+ else
323
+ println (io, " No documentation found for public binding $varstr .\n " )
324
+ end
307
325
else
308
- println (io, " No documentation found for private binding `$varstr `.\n " )
326
+ if extended
327
+ println (io, " Extended information found for private binding $varstr .\n " )
328
+ else
329
+ println (io, " No documentation found for private binding $varstr .\n " )
330
+ end
309
331
end
310
332
end
311
333
summarize (io, binding_res, binding)
312
334
else
313
- println (io, " No documentation found.\n " )
335
+ if extended
336
+ println (io, " Extended information found.\n " )
337
+ else
338
+ println (io, " No documentation found.\n " )
339
+ end
314
340
quot = any (isspace, sprint (print, binding)) ? " '" : " "
315
341
if Base. isbindingresolved (binding. mod, binding. var)
316
342
println (io, " Binding " , quot, " `" , binding, " `" , quot, " exists, but has not been assigned a value." )
@@ -559,10 +585,17 @@ function repl_latex(io::IO, s0::String)
559
585
end
560
586
repl_latex (s:: String ) = repl_latex (stdout , s)
561
587
562
- macro repl (ex, brief:: Bool = false , mod:: Module = Main) repl (ex; brief, mod) end
563
- macro repl (io, ex, brief, mod, internal_accesses) repl (io, ex; brief, mod, internal_accesses) end
588
+ macro repl (ex, extended_help= false , mod= Main)
589
+ repl (ex; extended_help, mod)
590
+ end
591
+ macro repl (io, ex, extended_help, mod, internal_accesses)
592
+ repl (io, ex; extended_help, mod, internal_accesses)
593
+ end
564
594
565
- function repl (io:: IO , s:: Symbol ; brief:: Bool = true , mod:: Module = Main, internal_accesses:: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing )
595
+ function repl (io:: IO , s:: Symbol ;
596
+ extended_help:: Union{Bool,String} = false ,
597
+ mod:: Module = Main,
598
+ internal_accesses:: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing )
566
599
str = string (s)
567
600
quote
568
601
repl_latex ($ io, $ str)
@@ -571,19 +604,20 @@ function repl(io::IO, s::Symbol; brief::Bool=true, mod::Module=Main, internal_ac
571
604
# n.b. we call isdefined for the side-effect of resolving the binding, if possible
572
605
:(repl_corrections ($ io, $ str, $ mod))
573
606
end )
574
- $ (_repl (s, brief , mod, internal_accesses))
607
+ $ (_repl (s; extended_help , mod, internal_accesses))
575
608
end
576
609
end
577
610
isregex (x) = isexpr (x, :macrocall , 3 ) && x. args[1 ] === Symbol (" @r_str" ) && ! isempty (x. args[3 ])
578
611
579
- repl (io:: IO , ex:: Expr ; brief :: Bool = true , mod :: Module = Main, internal_accesses :: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing ) = isregex (ex) ? :(apropos ($ io, $ ex)) : _repl (ex, brief, mod, internal_accesses )
580
- repl (io:: IO , str:: AbstractString ; brief :: Bool = true , mod :: Module = Main, internal_accesses :: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing ) = :(apropos ($ io, $ str))
581
- repl (io:: IO , other; brief :: Bool = true , mod :: Module = Main, internal_accesses :: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing ) = esc (:( @doc $ other)) # TODO : track internal_accesses
582
- # repl(io::IO, other ) = lookup_doc(other) # TODO
612
+ repl (io:: IO , ex:: Expr ; kws ... ) = isregex (ex) ? :(apropos ($ io, $ ex)) : _repl (ex; kws ... )
613
+ repl (io:: IO , str:: AbstractString ; _ ... ) = :(apropos ($ io, $ str))
614
+ repl (io:: IO , other; extended_help :: Union{Bool,String} = false , _ ... ) = lookup_doc_ex ( other; extended_help)
615
+ repl (x; kws ... ) = repl ( stdout , x; kws ... )
583
616
584
- repl (x; brief:: Bool = true , mod:: Module = Main) = repl (stdout , x; brief, mod)
585
-
586
- function _repl (x, brief:: Bool = true , mod:: Module = Main, internal_accesses:: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing )
617
+ function _repl (x;
618
+ extended_help:: Union{Bool,String} = false ,
619
+ mod:: Module = Main,
620
+ internal_accesses:: Union{Nothing, Set{Pair{Module,Symbol}}} = nothing )
587
621
if isexpr (x, :call )
588
622
x = x:: Expr
589
623
# determine the types of the values
@@ -636,21 +670,9 @@ function _repl(x, brief::Bool=true, mod::Module=Main, internal_accesses::Union{N
636
670
x. args = Any[x. args[1 ], Expr (:parameters , kwargs... ), pargs... ]
637
671
end
638
672
end
639
- # docs = lookup_doc(x) # TODO
640
- docs = esc (:(@doc $ x))
641
- docs = if isfield (x)
642
- quote
643
- if isa ($ (esc (x. args[1 ])), DataType)
644
- fielddoc ($ (esc (x. args[1 ])), $ (esc (x. args[2 ])))
645
- else
646
- $ docs
647
- end
648
- end
649
- else
650
- docs
651
- end
673
+ docs = lookup_doc_ex (x; extended_help)
652
674
docs = log_nonpublic_access (macroexpand (mod, docs), mod, internal_accesses)
653
- :(REPL . trimdocs ( $ docs, $ brief))
675
+ return docs
654
676
end
655
677
656
678
"""
686
708
# As with the additional `doc` methods, this converts an object to a `Binding` first.
687
709
fielddoc (object, field:: Symbol ) = fielddoc (aliasof (object, typeof (object)), field)
688
710
689
-
690
711
# Search & Rescue
691
712
# Utilities for correcting user mistakes and (eventually)
692
713
# doing full documentation searches from the repl.
0 commit comments