-
Notifications
You must be signed in to change notification settings - Fork 13
/
README
2947 lines (2121 loc) · 104 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# PAX Manual
###### \[in package MGL-PAX with nicknames PAX\]
## Introduction
*What if documentation really lived in the code?*
Docstrings are already there. If some narrative glued them together,
we'd be able develop and explore the code along with the
documentation due to their physical proximity. The main tool that
PAX provides for this is DEFSECTION:
```
(defsection @foo-random-manual (:title "Foo Random manual")
"Foo Random is a random number generator library."
(foo-random-state class)
(uniform-random function)
(@foo-random-examples section))
```
Like this one, sections can have docstrings and
references to
definitions (e.g. `(UNIFORM-RANDOM FUNCTION)`). These docstrings and
references are the glue. To support interactive development, PAX
- makes @SLIME's @M-. work with references and
- adds a documentation browser.
See @EMACS-SETUP.
Beyond interactive workflows, @GENERATING-DOCUMENTATION from
sections and all the referenced items in Markdown or HTML format is
also implemented.
With the simplistic tools provided, one may emphasize the narrative
as with Literate Programming, but documentation is generated from
code, not vice versa, and there is no support for chunking.
*Code is first, code must look pretty, documentation is code*.
##### Docstrings
PAX automatically recognizes and marks up code with
backticks and links code to their definitions.
Take, for instance, SBCL's ABORT function, whose docstring is
written in the usual style, uppercasing names of symbols:
```
(docstring #'abort)
=> "Transfer control to a restart named ABORT, signalling a CONTROL-ERROR if
none exists."
```
Note how in the generated documentation, ABORT is set with a
monospace font, while `CONTROL-ERROR` is autolinked:
- \[function\] **ABORT** *\&OPTIONAL CONDITION*
Transfer control to a restart named `ABORT`, signalling a
[`CONTROL-ERROR`][6bc0] if none exists.
[6bc0]: http://www.lispworks.com/documentation/HyperSpec/Body/e_contro.htm "CONTROL-ERROR CONDITION"
In the following transcript, the above output is
rendered from the raw markdown:
```
(document #'abort :format :markdown)
.. - [function] **ABORT** *&OPTIONAL CONDITION*
..
.. Transfer control to a restart named `ABORT`, signalling a [`CONTROL-ERROR`][7c2c] if
.. none exists.
..
.. [7c2c]: http://www.lispworks.com/documentation/HyperSpec/Body/e_contro.htm "CONTROL-ERROR (MGL-PAX:CLHS CONDITION)"
..
```
##### A Complete Example
Here is an example of how it all works together:
```
(mgl-pax:define-package :foo-random
(:documentation "This package provides various utilities for random.
See FOO-RANDOM:@FOO-RANDOM-MANUAL.")
(:use #:common-lisp #:mgl-pax))
(in-package :foo-random)
(defsection @foo-random-manual (:title "Foo Random manual")
"FOO-RANDOM is a random number generator library inspired by CL:RANDOM.
Functions such as UNIFORM-RANDOM use *FOO-STATE* and have a
:RANDOM-STATE keyword arg."
(foo-random-state class)
(state (reader foo-random-state))
"Hey we can also print states!"
(print-object (method () (foo-random-state t)))
(*foo-state* variable)
(gaussian-random function)
(uniform-random function)
;; This is a subsection.
(@foo-random-examples section))
(defclass foo-random-state ()
((state :reader state)))
(defmethod print-object ((object foo-random-state) stream)
(print-unreadable-object (object stream :type t)))
(defvar *foo-state* (make-instance 'foo-random-state)
"Much like *RANDOM-STATE* but uses the FOO algorithm.")
(defun uniform-random (limit &key (random-state *foo-state*))
"Return a random number from the between 0 and LIMIT (exclusive)
uniform distribution."
nil)
(defun gaussian-random (stddev &key (random-state *foo-state*))
"Return a random number from a zero mean normal distribution with
STDDEV."
nil)
(defsection @foo-random-examples (:title "Examples")
"Let's see the transcript of a real session of someone working
with FOO:
```cl-transcript
(values (princ :hello) (list 1 2))
.. HELLO
=> :HELLO
=> (1 2)
(make-instance 'foo-random-state)
==> #<FOO-RANDOM-STATE >
```")
```
Note how `(VARIABLE *FOO-STATE*)` in the DEFSECTION form both
exports `*FOO-STATE*` and includes its documentation in
`@FOO-RANDOM-MANUAL`. The symbols VARIABLE and
FUNCTION are just two instances of DREF::@LOCATIVEs,
which are used in DEFSECTION to refer to definitions tied to
symbols.
`(DOCUMENT @FOO-RANDOM-MANUAL)` generates fancy markdown or HTML
output with automatic markup and autolinks uppercase @WORDs
found in docstrings, numbers sections, and creates a table of
contents.
One can even generate documentation for different but related
libraries at the same time with the output going to different files
but with cross-page links being automatically added for symbols
mentioned in docstrings. In fact, this is what @PAX-WORLD does. See
@GENERATING-DOCUMENTATION for some convenience functions to cover
the most common cases.
The transcript in the code block tagged with
`cl-transcript` is automatically checked for up-to-dateness when
documentation is generated.
## Emacs Setup
Load `src/mgl-pax.el` in Emacs, and maybe set up some key bindings.
If you installed PAX with Quicklisp, the location of `mgl-pax.el`
may change with updates, and you may want to copy the current
version of `mgl-pax.el` to a stable location:
(mgl-pax:install-pax-elisp "~/quicklisp/")
Then, assuming the Elisp file is in the quicklisp directory, add
something like this to your `.emacs`:
```elisp
(load "~/quicklisp/mgl-pax.el")
(mgl-pax-hijack-slime-doc-keys)
(global-set-key (kbd "C-.") 'mgl-pax-document)
(global-set-key (kbd "s-x t") 'mgl-pax-transcribe-last-expression)
(global-set-key (kbd "s-x r") 'mgl-pax-retranscribe-region)
```
For @BROWSING-LIVE-DOCUMENTATION, `mgl-pax-browser-function` can be
customized in Elisp. To browse within Emacs, choose
`w3m-browse-url` (see
[w3m](https://emacs-w3m.github.io/info/emacs-w3m.html)), and make
sure both the w3m binary and the w3m Emacs package are installed. On
Debian, simply install the `w3m-el` package. With other browser
functions, a HUNCHENTOOT web server is started.
See @NAVIGATING-IN-EMACS, @GENERATING-DOCUMENTATION and
@TRANSCRIBING-WITH-EMACS for how to use the relevant features.
- [function] INSTALL-PAX-ELISP TARGET-DIR
Copy `mgl-pax.el` distributed with this package to TARGET-DIR.
## Links and Systems
Here is the [official
repository](https://github.com/melisgl/mgl-pax) and the [HTML
documentation](http://melisgl.github.io/mgl-pax-world/mgl-pax-manual.html)
for the latest version.
PAX is built on top of the DRef
library (bundled in the same repository). See
[DRef's HTML
documentation](http://melisgl.github.io/mgl-pax-world/dref-manual.html)
### The mgl-pax ASDF System
- Version: 0.3.0
- Description: Documentation system, browser, generator.
- Long Description: The set of dependencies of the MGL-PAX system is
kept light, and its heavier dependencies are autoloaded via ASDF
when the relevant functionality is accessed. See the
MGL-PAX/NAVIGATE, MGL-PAX/DOCUMENT, MGL-PAX/TRANSCRIBE and
MGL-PAX/FULL systems. To keep deployed code small, client systems
should declare an ASDF dependency on this system, never on the
others, which are intended for autoloading and interactive use.
- Licence: MIT, see COPYING.
- Author: Gábor Melis
- Mailto: [mega@retes.hu](mailto:mega@retes.hu)
- Homepage: [http://melisgl.github.io/mgl-pax](http://melisgl.github.io/mgl-pax)
- Bug tracker: [https://github.com/melisgl/mgl-pax/issues](https://github.com/melisgl/mgl-pax/issues)
- Source control: [GIT](https://github.com/melisgl/mgl-pax.git)
### The mgl-pax/full ASDF System
- Description: MGL-PAX with all features preloaded except MGL-PAX/WEB.
- Long Description: Do not declare a dependency on this system. It
is autoloaded.
- Licence: MIT, see COPYING.
- Author: Gábor Melis
- Mailto: [mega@retes.hu](mailto:mega@retes.hu)
## Background
As a user, I frequently run into documentation that's incomplete
and out of date, so I tend to stay in the editor and explore the
code by jumping around with @SLIME's @M-. (`slime-edit-definition`).
As a library author, I spend a great deal of time polishing code but
precious little writing documentation.
In fact, I rarely write anything more comprehensive than docstrings
for exported stuff. Writing docstrings feels easier than writing a
separate user manual, and they are always close at hand during
development. The drawback of this style is that users of the library
have to piece the big picture together themselves.
That's easy to solve, I thought, let's just put all the narrative
that holds docstrings together in the code and be a bit like a
Literate Programmer turned inside out. The original prototype, which
did almost everything I wanted, was this:
```
(defmacro defsection (name docstring)
`(defun ,name () ,docstring))
```
Armed with this DEFSECTION, I soon found myself
organizing code following the flow of user-level documentation and
relegated comments to implementation details entirely. However, some
parts of `DEFSECTION` docstrings were just listings of
all the functions, macros and variables related to the narrative,
and this list was repeated in the DEFPACKAGE form complete with
little comments that were like section names. A clear violation of
@OAOO, one of them had to go, so DEFSECTION got a list
of symbols to export.
That was great, but soon I found that the listing of symbols is
ambiguous if, for example, a function, a compiler macro and a class
were named by the same symbol. This did not concern exporting, of
course, but it didn't help readability. Distractingly, on such
symbols, `M-.` was popping up selection dialogs. There were two
birds to kill, and the symbol got accompanied by a type, which was
later generalized into the concept of locatives:
```
(defsection @introduction ()
"A single line for one man ..."
(foo class)
(bar function))
```
After a bit of elisp hacking, `M-.` was smart enough to
disambiguate based on the locative found in the vicinity of the
symbol, and everything was good for a while.
Then, I realized that sections could refer to other sections if
there were a SECTION locative. Going down that path, I soon began to
feel the urge to generate pretty documentation as all the necessary
information was available in the DEFSECTION forms. The design
constraint imposed on documentation generation was that following
the typical style of upcasing symbols in docstrings, there should be
no need to explicitly mark up links: if `M-.` works, then the
documentation generator shall also be able figure out what's being
referred to.
I settled on @MARKDOWN as a reasonably non-intrusive format, and a
few thousand lines later PAX was born. Since then, locatives and
references were factored out into the DRef
library to let PAX focus on `M-.` and documentation.
## Basics
Now let's examine the most important pieces.
- [macro] DEFSECTION NAME (&KEY (PACKAGE '\*PACKAGE\*) (READTABLE '\*READTABLE\*) (EXPORT T) TITLE LINK-TITLE-TO (DISCARD-DOCUMENTATION-P \*DISCARD-DOCUMENTATION-P\*)) &BODY ENTRIES
Define a documentation section and maybe export referenced symbols.
A bit behind the scenes, a global variable with NAME is defined and
is bound to a SECTION object. By convention, section names
start with the character `@`. See @INTRODUCTION for an example.
**Entries**
ENTRIES consists of docstrings and references in any order.
Docstrings are arbitrary strings in markdown format.
References are XREFs given in the form `(NAME LOCATIVE)`.
For example, `(FOO FUNCTION)` refers to the function `FOO`, `(@BAR
SECTION)` says that `@BAR` is a subsection of this
one. `(BAZ (METHOD () (T T T)))` refers to the default method of the
three argument generic function `BAZ`. `(FOO FUNCTION)` is
equivalent to `(FOO (FUNCTION))`. See the DRef DREF::@INTRODUCTION
for more.
The same name may occur in multiple references, typically with
different locatives, but this is not required.
The references are not LOCATEd until documentation is generated, so
they may refer to things yet to be defined.
**Exporting**
If EXPORT is true (the default), NAME and the @NAMEs of references
among ENTRIES which are SYMBOLs are candidates for exporting. A
candidate symbol is exported if
- it is accessible in PACKAGE, and
- there is a reference to it in the section being defined which is
approved by EXPORTABLE-REFERENCE-P.
See DEFINE-PACKAGE if you use the export feature. The idea with
confounding documentation and exporting is to force documentation of
all exported symbols.
**Misc**
TITLE is a string containing markdown or NIL. If non-NIL, it
determines the text of the heading in the generated output.
LINK-TITLE-TO is a reference given as an `(NAME LOCATIVE)` pair or
NIL, to which the heading will link when generating HTML. If not
specified, the heading will link to its own anchor.
When DISCARD-DOCUMENTATION-P (defaults to *DISCARD-DOCUMENTATION-P*)
is true, ENTRIES will not be recorded to save memory.
- [variable] *DISCARD-DOCUMENTATION-P* NIL
The default value of DEFSECTION's DISCARD-DOCUMENTATION-P argument.
One may want to set *DISCARD-DOCUMENTATION-P* to true before
building a binary application.
- [macro] DEFINE-PACKAGE PACKAGE &REST OPTIONS
This is like CL:DEFPACKAGE but silences warnings and errors
signalled when the redefined package is at variance with the current
state of the package. Typically this situation occurs when symbols
are exported by calling EXPORT (as is the case with DEFSECTION) as
opposed to adding :EXPORT forms to the DEFPACKAGE form and the
package definition is subsequently reevaluated. See the section on
[package variance](http://www.sbcl.org/manual/#Package-Variance) in
the SBCL manual.
The bottom line is that if you rely on DEFSECTION to do the
exporting, then you'd better use DEFINE-PACKAGE.
- [macro] DEFINE-GLOSSARY-TERM NAME (&KEY TITLE URL (DISCARD-DOCUMENTATION-P \*DISCARD-DOCUMENTATION-P\*)) &OPTIONAL DOCSTRING
Define a global variable with NAME, and set it to a GLOSSARY-TERM object. TITLE, URL and DOCSTRING are markdown strings or
NIL. Glossary terms are DOCUMENTed in the lightweight bullet +
locative + name/title style. See the glossary entry @NAME for an
example.
When a glossary term is linked to in documentation, its TITLE will
be the link text instead of the name of the symbol (as with
SECTIONs).
Glossary entries with a non-NIL URL are like external links: they
are linked to their URL in the generated documentation. These offer
a more reliable alternative to using markdown reference links and
are usually not included in SECTIONs.
When DISCARD-DOCUMENTATION-P (defaults to *DISCARD-DOCUMENTATION-P*)
is true, DOCSTRING will not be recorded to save memory.
### Parsing
When @NAVIGATING-IN-EMACS or @GENERATING-DOCUMENTATION, references
are parsed from the buffer content or docstrings, respectively. In
either case, @NAMEs are extracted from @WORDs and then turned into
DRef names to form DRef references maybe with locatives found next to the @WORD.
- [glossary-term] word
A *word* is a string from which we want to extract a @NAME. When
Navigating, the word is
`slime-symbol-at-point`. When @GENERATING-DOCUMENTATION, it is a
non-empty string between whitespace characters in a docstring.
- [glossary-term] name
A *name* is a string that denotes a possible DRef
name (e.g. an INTERNed SYMBOL, the name of a PACKAGE
or an ASDF:SYSTEM). Names are constructed from @WORDs by trimming
some prefixes and suffixes. For a given word, multiple candidate
names are considered in the following order.
1. The entire word.
2. Trimming the characters \`#\<{;"'\`\` from the left of the word.
3. Trimming the characters \`,;:.>}"'\`\` from the right of the word.
4. Trimming both of the previous two at the same time.
5. From the result of 4., further removing some plural markers.
6. From the result of 4., further removing non-uppercase prefixes
and suffixes.
For example, when `M-.` is pressed while point is over
`nonREADable.`, the last word of the sentence `It may be
nonREADable.`, the following names are considered until one is found
with a definition:
1. The entire word, `"nonREADable."`.
2. Trimming left does not produce a new word.
3. Trimming right removes the dot and gives `"nonREADable"`.
4. Trimming both is the same as trimming right.
5. No plural markers are found.
6. The lowercase prefix and suffix is removed around the uppercase
core, giving `"READ"`. This has a definition, which \`M-.' will
visit.
The exact rules for steps 5. and 6. are the following.
- If a @WORD ends with what looks like a plural
marker (case-insensitive), then a @NAME is created by removing it.
For example, from the @WORD `BUSES` the plural marker `ES` is
removed to produce the @NAME `BUS`. The list of plural markers
considered is `S` (e.g. `CARS`), `ES` (e.g. `BUSES`), `SES` (e.g.
`GASSES`), `ZES` (e.g. `FEZZES`), and `REN` (e.g. `CHILDREN`).
- From a @CODIFIABLE @WORD, a @NAME is created by removing the prefix
before the first and the suffix after the last uppercase character
if they contain at least one lowercase character.
## PAX Locatives
To the DREF::@LOCATIVE-TYPES defined by DRef, PAX adds a few of its own.
- [locative] SECTION
Refers to a SECTION defined by DEFSECTION.
SECTION is EXPORTABLE-LOCATIVE-TYPE-P but not exported by
default (see EXPORTABLE-REFERENCE-P).
- [locative] GLOSSARY-TERM
Refers to a GLOSSARY-TERM defined by DEFINE-GLOSSARY-TERM.
GLOSSARY-TERM is EXPORTABLE-LOCATIVE-TYPE-P but not exported by
default (see EXPORTABLE-REFERENCE-P).
- [locative] DISLOCATED
Refers to a symbol in a non-specific context. Useful for preventing
autolinking. For example, if
there is a function called `FOO` then
`FOO`
will be linked (if *DOCUMENT-LINK-CODE*) to its definition. However,
[`FOO`][dislocated]
will not be. With a dislocated locative, LOCATE always fails with a
LOCATE-ERROR condition. Also see @PREVENTING-AUTOLINKING.
DISLOCATED references do not RESOLVE.
- [locative] ARGUMENT
An alias for DISLOCATED, so that one can refer to an argument of
a macro without accidentally linking to a class that has the same
name as that argument. In the following example,
FORMAT may link to CL:FORMAT (if we generated
documentation for it):
```
"See FORMAT in DOCUMENT."
```
Since ARGUMENT is a locative, we can prevent that linking by writing:
```
"See the FORMAT argument of DOCUMENT."
```
ARGUMENT references do not RESOLVE.
- [locative] INCLUDE SOURCE &KEY LINE-PREFIX HEADER FOOTER HEADER-NL FOOTER-NL
This pseudolocative refers to a region of a file. SOURCE can be a
STRING or a PATHNAME, in which case the whole file
is being pointed to, or it can explicitly supply START, END
locatives. INCLUDE is typically used to include non-lisp files in
the documentation (say markdown or Elisp as in the next example) or
regions of Lisp source files. This can reduce clutter and
duplication.
```
(defsection @example-section ()
(mgl-pax.el (include #.(asdf:system-relative-pathname
:mgl-pax "src/mgl-pax.el")
:header-nl "```elisp" :footer-nl "```"))
(foo-example (include (:start (dref-ext:make-source-location function)
:end (dref-ext:source-location-p function))
:header-nl "```"
:footer-nl "```")))
```
In the above example, when documentation is generated, the entire
`src/mgl-pax.el` file is included in the markdown output surrounded
by the strings given as HEADER-NL and FOOTER-NL. The documentation
of `FOO-EXAMPLE` will be the region of the file from the
SOURCE-LOCATION of the START reference (inclusive) to the
SOURCE-LOCATION of the END reference (exclusive). If only one of
START and END is specified, then they default to the beginning and
end of the file, respectively.
Since START and END are literal references, pressing `M-.` on
`PAX.EL` will open the `src/mgl-pax.el` file and put the cursor on
its first character. `M-.` on `FOO-EXAMPLE` will go to the source
location of the `FOO` function.
With the LAMBDA locative, one can specify positions in arbitrary
files as in, for example, PAX::@EMACS-SETUP-FOR-BROWSING.
- SOURCE is either an absolute pathname designator or a list
matching the destructuring lambda list `(&KEY START END)`,
where START and END must be NIL or `(<NAME> <LOCATIVE>)`
lists (not evaluated) like a DEFSECTION entry. Their
SOURCE-LOCATIONs constitute the bounds of the region of the file
to be included. Note that the file of the source location of START
and END must be the same. If SOURCE is a pathname designator, then
it must be absolute so that the locative is context independent.
- If specified, LINE-PREFIX is a string that's prepended to each
line included in the documentation. For example, a string of four
spaces makes markdown think it's a code block.
- HEADER and FOOTER, if non-NIL, are printed before the included
string.
- HEADER-NL and FOOTER-NL, if non-NIL, are printed between two
FRESH-LINE calls.
INCLUDE is not EXPORTABLE-LOCATIVE-TYPE-P, and INCLUDE references do
not RESOLVE.
- [locative] DOCSTRING
DOCSTRING is a pseudolocative for including the parse tree of the
markdown DOCSTRING of a definition in the parse tree of
a docstring when generating documentation. It has no source location
information and only works as an explicit link. This construct is
intended to allow docstrings to live closer to their implementation,
which typically involves a non-exported definition.
```common-lisp
(defun div2 (x)
"X must be [even* type][docstring]."
(/ x 2))
(deftype even* ()
"an even integer"
'(satisfies evenp))
(document #'div2)
.. - [function] DIV2 X
..
.. X must be an even integer.
..
```
There is no way to LOCATE DOCSTRINGs, so nothing to RESOLVE either.
- [locative] GO (NAME LOCATIVE)
Redirect to a definition in the context of the DREF::@REFERENCE
designated by NAME and LOCATIVE. This pseudolocative is intended for
things that have no explicit global definition.
As an example, consider this part of a hypothetical documentation of
CLOS:
(defsection @clos ()
(defmethod macro)
(call-next-method (go (defmethod macro))))
The GO reference exports the symbol CALL-NEXT-METHOD and also
produces a terse redirection message in the documentation.
GO behaves as described below.
- A GO reference RESOLVEs to what NAME with LOCATIVE resolves to:
```common-lisp
(resolve (dref 'xxx '(go (print function))))
==> #<FUNCTION PRINT>
```
- The DOCSTRING of a GO reference is NIL.
- SOURCE-LOCATION (thus `M-.`) returns the source location of the
embedded reference:
```common-lisp
(equal (source-location (dref 'xxx '(go (print function))))
(source-location (dref 'print 'function)))
=> T
```
- [locative] CLHS &OPTIONAL NESTED-LOCATIVE
Refers to sections or definitions in the Common Lisp Hyperspec.
These have no source location so `M-.` will not work. What works
is linking in documentation, including @BROWSING-LIVE-DOCUMENTATION.
The generated links are relative to *DOCUMENT-HYPERSPEC-ROOT* and
work even if *DOCUMENT-LINK-TO-HYPERSPEC* is NIL.
- *definitions*: These are typically unnecessary as DOCUMENT will
produce the same link for e.g. `PPRINT`, `[PPRINT][function]`,
or `[PPRINT][]` if *DOCUMENT-LINK-TO-HYPERSPEC* is non-NIL and the
PPRINT function in the running Lisp is not being DOCUMENTed. When
@BROWSING-LIVE-DOCUMENTATION, a slight difference is that
everything is being DOCUMENTed, so using the CLHS link bypasses
the page with the definition in the running Lisp.
- *unambiguous*: `[pprint][clhs]` (pprint)
- *ambiguous*: `[function][clhs]` (function)
- *explicit*: `[function][(clhs class)]` (function)
- *glossary terms* (case-insensitive):
- `[lambda list][(clhs glossary-term)]`
(lambda list)
- *issues*:
- `[ISSUE:AREF-1D][clhs]` (ISSUE:AREF-1D)
- `[ISSUE:AREF-1D][(clhs section)]` (ISSUE:AREF-1D)
- *issue summaries*: These render
as (SUMMARY:CHARACTER-PROPOSAL:2-6-5):
- `[SUMMARY:CHARACTER-PROPOSAL:2-6-5][clhs]`
- `[SUMMARY:CHARACTER-PROPOSAL:2-6-5][(clhs section)]`
Since these summary ids are not particularly reader friendly,
the alternative form of the @SPECIFIED-LOCATIVE may be used:
- `[see this][SUMMARY:CHARACTER-PROPOSAL:2-6-5 (clhs
section)]` (see this)
- *sections*:
- *by section number*: `[3.4][clhs]` or `[3.4][(clhs
section)]` (3.4)
- *by section title* (case-insensitive, substring match):
`[lambda lists][clhs]` or `[lambda lists][(clhs
section)]` (lambda lists)
- *by filename*: `[03_d][clhs]` or `[03_d][(clhs
section)]` (03\_d)
As the above examples show, the NESTED-LOCATIVE argument of the CLHS
locative may be omitted. In that case, definitions, glossary terms,
issues, issue summaries, and sections are considered in that order.
Sections are considered last because a substring of a section title
can be matched by chance easily.
All examples so far used explicit
links. Autolinking also works if the @NAME is marked up as code or
is codified (e.g. in `COS clhs` (COS clhs).
As mentioned above, `M-.` does not do anything over CLHS
references. Slightly more usefully, the live documentation
browser understands CLHS links so one
can enter inputs like `3.4 clhs`, `"lambda list" clhs` or `error (clhs
function)`.
CLHS references do not RESOLVE.
## Navigating Sources in Emacs
Integration into @SLIME's @M-. (`slime-edit-definition`) allows
one to visit the SOURCE-LOCATION of a definition.
The definition is either determined from the buffer content at point
or is prompted. If prompted, then the format is `<NAME> <LOCATIVE>`,
where the locative may be omitted to recover stock Slime behaviour.
When determining the definition from the buffer contents,
`slime-symbol-at-point` is parsed as a @WORD, then candidate
locatives are looked for before and after that word. Thus, if a
locative is the previous or the next expression around the symbol of
interest, then `M-.` will go straight to the definition which
corresponds to the locative. If that fails, `M-.` will try to find
the definitions in the normal way, which may involve popping up an
xref buffer and letting the user interactively select one of
possible definitions.
In the following examples, when the cursor is on one of the
characters of `FOO` or just after `FOO`, pressing `M-.` will visit
the definition of function `FOO`:
function foo
foo function
(function foo)
(foo function)
In particular, DREF::@REFERENCEs in a DEFSECTION form are in (NAME
LOCATIVE) format so `M-.` will work just fine there.
Just like vanilla `M-.`, this works in comments and docstrings. In
the next example, pressing `M-.` on `FOO` will visit `FOO`'s
default method:
```
;; See RESOLVE* (method () (dref)) for how this all works.
```
With a prefix argument (`C-u M-.`), one can enter a symbol plus a
locative separated by whitespace to preselect one of the
possibilities.
The `M-.` extensions can be enabled by loading `src/mgl-pax.el`.
See @EMACS-SETUP. In addition, the Elisp command
`mgl-pax-edit-parent-section` visits the source location of the
section containing the definition with `point` in it. See
@BROWSING-LIVE-DOCUMENTATION.
### The mgl-pax/navigate ASDF System
- Description: Slime `M-.` support for MGL-PAX.
- Long Description: Autoloaded by Slime's `M-.` when `src/pax.el` is
loaded. See MGL-PAX::@NAVIGATING-IN-EMACS.
- Licence: MIT, see COPYING.
- Author: Gábor Melis
- Mailto: [mega@retes.hu](mailto:mega@retes.hu)
## Generating Documentation
### The DOCUMENT Function
- [function] DOCUMENT DOCUMENTABLE &KEY (STREAM T) PAGES (FORMAT :PLAIN)
Write DOCUMENTABLE in FORMAT to STREAM diverting some output to PAGES.
FORMAT is a 3BMD output format (currently one of :MARKDOWN,
:HTML and :PLAIN). STREAM may be a STREAM object, T or NIL
as with CL:FORMAT.
To look up the documentation of the DOCUMENT function itself:
(document #'document)
The same with fancy markup:
(document #'document :format :markdown)
To document a SECTION:
(document @pax-manual)
To generate the documentation for separate libraries with automatic
cross-links:
(document (list pax::@pax-manual dref::@dref-manual) :format :markdown)
See @DOCUMENTATION-UTILITIES for more.
Definitions that do not define a first-class object are supported
via DRef:
(document (dref:locate 'foo 'type))
There are quite a few special variables that affect how output is
generated, see @CODIFICATION, @LINKING-TO-CODE,
@LINKING-TO-SECTIONS, and
@MISCELLANEOUS-DOCUMENTATION-PRINTER-VARIABLES.
For the details, see the following sections, starting with
@DOCUMENTABLES. Also see @EXTENSION-API and DOCUMENT-OBJECT\*.
#### Documentables
- The DOCUMENTABLE argument may be a DREF or anything else
that is LOCATEable. This includes non-DREF XREFs and
first-class objects such as FUNCTIONs.
- If DOCUMENTABLE is a string, then it is processed like a docstring
in DEFSECTION. That is, with docstring sanitization, @CODIFICATION, and linking (see
@LINKING-TO-CODE, @LINKING-TO-THE-HYPERSPEC).
- Finally, DOCUMENTABLE may be a nested list of LOCATEable objects
and docstrings. The structure of the list is unimportant. The
objects in it are documented in depth-first order.
#### Return Values
If PAGES are NIL, then DOCUMENT - like CL:FORMAT - returns a
string (when STREAM is NIL) else NIL.
If PAGES, then a list of output designators are returned, one for
each non-empty page (to which some output has been written), which
are determined as follows.
- The string itself if the output was to a string.
- The stream if the output was to a stream.
- The pathname of the file if the output was to a file.
If the default page given by the STREAM argument of DOCUMENT was
written to, then its output designator is the first element of the
returned list. The rest of the designators correspond to the
non-empty pages in the PAGES argument of DOCUMENT in that order.
#### Pages
The PAGES argument of DOCUMENT is to create multi-page documents
by routing some of the generated output to files, strings or
streams. PAGES is a list of page specification elements. A page spec
is a property list with keys :OBJECTS, :OUTPUT,
:URI-FRAGMENT, :SOURCE-URI-FN, :HEADER-FN and :FOOTER-FN. OBJECTS is
a list of objects (references are allowed but not required) whose
documentation is to be sent to :OUTPUT.
Documentation is initially sent to a default stream (the STREAM
argument of DOCUMENT), but output is redirected if the thing being
currently documented is the :OBJECT of a PAGE-SPEC.
:OUTPUT can be a number things:
- If it's NIL, then output will be collected in a string.
- If it's T, then output will be sent to *STANDARD-OUTPUT*.
- If it's a stream, then output will be sent to that stream.
- If it's a list whose first element is a string or a pathname, then
output will be sent to the file denoted by that and the rest of
the elements of the list are passed on to CL:OPEN. One extra
keyword argument is :ENSURE-DIRECTORIES-EXIST. If it's true,
ENSURE-DIRECTORIES-EXIST will be called on the pathname before
it's opened.
Note that even if PAGES is specified, STREAM acts as a catch all,
absorbing the generated documentation for references not claimed by
any pages.
:HEADER-FN, if not NIL, is a function of a single stream argument,
which is called just before the first write to the page. Since
:FORMAT :HTML only generates HTML fragments, this makes it possible
to print arbitrary headers, typically setting the title, CSS
stylesheet, or charset.
:FOOTER-FN is similar to :HEADER-FN, but it's called after the last
write to the page. For HTML, it typically just closes the body.
:URI-FRAGMENT is a string such as `"doc/manual.html"` that specifies
where the page will be deployed on a webserver. It defines how links
between pages will look. If it's not specified and :OUTPUT refers to
a file, then it defaults to the name of the file. If :URI-FRAGMENT
is NIL, then no links will be made to or from that page.
Finally, :SOURCE-URI-FN is a function of a single, REFERENCE
argument. If it returns a value other than NIL, then it must be a
string representing an URI. If FORMAT is :HTML and
*DOCUMENT-MARK-UP-SIGNATURES* is true, then the locative as
displayed in the signature will be a link to this URI. See
MAKE-GIT-SOURCE-URI-FN.
PAGES may look something like this:
```
`((;; The section about SECTIONs and everything below it ...
:objects (, @sections)
;; ... is so boring that it's not worth the disk space, so
;; send it to a string.
:output (nil)
;; Explicitly tell other pages not to link to these guys.
:uri-fragment nil)
;; Send the @EXTENSION-API section and everything reachable
;; from it ...
(:objects (, @extension-api)
;; ... to build/tmp/pax-extension-api.html.
:output "build/tmp/pax-extension-api.html"
;; However, on the web server html files will be at this
;; location relative to some common root, so override the
;; default:
:uri-fragment "doc/dev/pax-extension-api.html"
;; Set html page title, stylesheet, charset.
:header-fn 'write-html-header
;; Just close the body.
:footer-fn 'write-html-footer)
;; Catch references that were not reachable from the above. It
;; is important for this page spec to be last.
(:objects (, @pax-manual)
:output "build/tmp/manual.html"
;; Links from the extension api page to the manual page will
;; be to ../user/pax-manual#<anchor>, while links going to
;; the opposite direction will be to
;; ../dev/pax-extension-api.html#<anchor>.
:uri-fragment "doc/user/pax-manual.html"
:header-fn 'write-html-header
:footer-fn 'write-html-footer))
```
#### Package and Readtable
While generating documentation, symbols may be read (e.g. from
docstrings) and printed. What values of *PACKAGE* and *READTABLE*
are used is determined separately for each definition being
documented.
- If the values of *PACKAGE* and *READTABLE* in effect at the time
of definition were captured (e.g. by DEFINE-LOCATIVE-TYPE and
DEFSECTION), then they are used.
- Else, if the definition has a @HOME-SECTION (see below), then the
home section's SECTION-PACKAGE and SECTION-READTABLE are used.
- Else, if the definition has an argument list, then the package of
the first argument that's not external in any package is used.
- Else, if the definition is DREF::@NAMEd by a symbol, then its
SYMBOL-PACKAGE is used, and *READTABLE* is set to the standard
readtable `(NAMED-READTABLES:FIND-READTABLE :COMMON-LISP)`.
- Else, *PACKAGE* is set to the `CL-USER` package and *READTABLE* to
the standard readtable.
The values thus determined come into effect after the name itself is
printed, for printing of the arglist and the docstring.
CL-USER> (pax:document #'foo)
- [function] FOO <!> X Y &KEY (ERRORP T)
Do something with X and Y.
In the above, the `<!>` marks the place where *PACKAGE* and
*READTABLE* are bound.
##### Home Section
The home section of an object is a SECTION that contains the
object's definition in its SECTION-ENTRIES or NIL. In the
overwhelming majority of cases there should be at most one
containing section.
If there are multiple containing sections, the following apply.
- If the DREF::@NAME of the definition is a non-keyword symbol, only
those containing sections are considered whose package is closest
to the SYMBOL-PACKAGE of the name, where closest is defined as
having the longest common prefix between the two PACKAGE-NAMEs.