-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathREADME
3620 lines (2590 loc) · 125 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 names in 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"
The following transcript shows the raw Markdown for
the previous example.
```
(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
Here is a quick recipe for setting up PAX for use via @SLIME to
take advantage of the conveniences on offer.
Conversely, there is no need to do any of this just to use
DEFSECTION, write docstrings and for @GENERATING-DOCUMENTATION.
If PAX was installed from @QUICKLISP, then evaluate this in CL to
copy the Elisp code to a stable location:
(mgl-pax:install-pax-elisp "~/quicklisp/")
Assuming the Elisp file is in the `~/quicklisp/` directory, add
something like this to your `.emacs`:
```elisp
(add-to-list 'load-path "~/quicklisp/")
(require 'mgl-pax)
(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)
```
### Functionality Provided
- For @NAVIGATING-IN-EMACS, loading `mgl-pax` extends
`slime-edit-definitions` (@M-.) by adding
`mgl-pax-edit-definitions` to `slime-edit-definition-hooks`. There
are no related variables to customize.
- For @BROWSING-LIVE-DOCUMENTATION, `mgl-pax-browser-function` and
`mgl-pax-web-server-port` can be customized in Elisp. To browse
within Emacs, choose `w3m-browse-url` (see @W3M), 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 @TRANSCRIBING-WITH-EMACS for how to use the transcription
features. There are no related variables to customize.
### Installing from Quicklisp
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 by evaluating this in
CL:
(mgl-pax:install-pax-elisp "~/quicklisp/")
If working from, say, a git checkout, there is no need for this
step.
- [function] INSTALL-PAX-ELISP TARGET-DIR
Copy `mgl-pax.el` distributed with this package to TARGET-DIR.
### Loading PAX
Assuming the Elisp file is in the `~/quicklisp/` directory, add
something like this to your `.emacs`:
```elisp
(add-to-list 'load-path "~/quicklisp/")
(require 'mgl-pax)
```
If the Lisp variable `mgl-pax-autoload` is true (the default), then
MGL-PAX will be loaded in the connected Lisp on-demand via @SLIME.
If loading fails, `mgl-pax` will be unloaded from Emacs and any
overridden Slime key bindings restored.
### Setting up Keys
The recommended key bindings are this:
```
(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)
```
The global key bindings above are global because their commands work
in any mode. If that's not desired, one may bind `C-.` locally in
all Slime related modes like this:
```elisp
(slime-bind-keys slime-parent-map nil '(("C-." mgl-pax-document)))
```
If the customizable variable `mgl-pax-hijack-slime-doc-keys` is
true, then upon loading `mgl-pax', the following changes are made to
`slime-doc-map`(assuming it's bound to`C-c C-d\`):
- `C-c C-d a`: replaces `slime-apropos` with `mgl-pax-apropos`
- `C-c C-d z`: replaces `slime-apropos-all` with `mgl-pax-apropos-all`
- `C-c C-d p`: replaces `slime-apropos-package` with `mgl-pax-apropos-package`
- `C-c C-d d`: replaces `slime-describe-symbol` with `mgl-pax-document`
- `C-c C-d f`: replaces `slime-describe-function` with `mgl-pax-document`
- `C-c C-d c`: installs `mgl-pax-current-definition-toggle-view`
- `C-c C-d u`: installs `mgl-pax-edit-parent-section`
Calling `mgl-pax-unhijack-slime-doc-keys` reverts these changes.
## 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)
- [system] "mgl-pax"
- Version: 0.4.0
- Description: Documentation system, browser, generator. See the
MGL-PAX::@PAX-MANUAL.
- 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: [[email protected]](mailto:[email protected])
- 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)
- Depends on: dref, mgl-pax-bootstrap, named-readtables, pythonic-string-reader
- Defsystem depends on: mgl-pax.asdf
- [system] "mgl-pax/full"
- Description: The `mgl-pax` system with all features
preloaded except `mgl-pax/web`.
- Long Description: Do not declare a dependency on this system. It
is for interactive use.
- Licence: MIT, see COPYING.
- Author: Gábor Melis
- Mailto: [[email protected]](mailto:[email protected])
- Depends on: mgl-pax/document, mgl-pax/navigate, mgl-pax/transcribe
## 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\*)) &BODY 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 encountering a @WORD such as `CLASSes`, PAX needs to find the
@NAME in it that makes sense in the context. @CODIFICATION, for
example, looks for @INTERESTING names, @NAVIGATING-IN-EMACS for
names with Lisp DEFINITIONS, and
@LINKING for names with any kind of definition.
This is not as straightforward as it sounds because it needs to
handle cases like nonREADable, CLASSES, all the various forms of
@LINKING in docstrings as well as in comments, and the `(NAME
LOCATIVE)` syntax in DEFSECTION.
- [glossary-term] word
A *word* is a string from which we want to extract a @NAME. When
Navigating, the word is
`slime-sexp-at-point` or the label of a @MARKDOWN/REFLINK if point
is over one. Similarly, when @GENERATING-DOCUMENTATION, it is a
non-empty string between whitespace characters in a docstring or the
label of a @MARKDOWN/REFLINK.
- [glossary-term] raw name
A *raw name* is a string from which a @NAME may be read. Raw names
correspond to an intermediate parsing step between @WORDs an @NAMEs.
See @NAMES-IN-RAW-NAMES.
- [glossary-term] name
A *name* is a DRef name. That is, a symbol or a
string associated with a definition, whose kind is given by a
DREF::@LOCATIVE.
Depending on the context, trimming and depluralization may be
enabled (see @RAW-NAMES-IN-WORDS), while the possible names may be
restricted to symbols (see @NAMES-IN-RAW-NAMES).
- *Trimming:* Enabled for @NAVIGATING-IN-EMACS and @CODIFICATION.
- *Depluralization:* Enabled when the @WORD is part of the normal
flow of text (i.e. not for @SPECIFIC-REFLINK-WITH-TEXT,
@UNSPECIFIC-REFLINK-WITH-TEXT and various Elisp functions such as
`mgl-pax-apropos` unless they determine their argument from buffer
contents).
- *Symbols only:* This is the case for @CODIFICATION and
@UNSPECIFIC-AUTOLINK to prevent string-based definitions from
littering the documentation with links without the control
provided by explicitly IMPORTing symbols.
For a word, a number of @RAW-NAMEs is generated by trimming
delimiter characters and plural markers, and for each raw name a
number of names are considered until one is found suitable in the
context. The following subsections describe the details of the
parsing algorithm.
### Raw Names in Words
From @WORDs, @RAW-NAMEs are parsed by trimming some
prefixes and suffixes. For a given word, multiple raw 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., 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 `SES` (e.g. `GASSES`),
`ES` (e.g. `BUSES`), `S` (e.g. `CARS`), `ZES` (e.g. `FEZZES`), and
`REN` (e.g. `CHILDREN`).
6. From the result of 4., removing the prefix before the first, and the suffix after the last
uppercase character if it contains at least one lowercase character.
### Names in Raw Names
For each @RAW-NAME from @RAW-NAMES-IN-WORDS, various @NAMEs
may be considered until one is found suitable in the context.
The following examples list the names considered for a given raw
name, assuming that READTABLE-CASE is :UPCASE as well as that `FOO`
and `|Foo|` are interned.
- `"foo"`: `FOO`, `"foo"`, `"FOO"` (rules 1, 2, 3)
- `"FOO"`: `FOO`, `"FOO"` (rules 1, 2)
- `"Foo"`: `"Foo"`, `"FOO"` (rules 2, 3)
- `"|Foo|"`: `|Foo|` (rule 4)
- `"\"foo\""`: `"foo"` (rule 5)
The rules are:
1. If the raw name is not mixed case (i.e. it doesn't have both
upper- and lowercase characters) and it names an interned
symbol (subject to the current @PACKAGE-AND-READTABLE), then that
symbol is considered as a name.
2. The raw name itself (a string) is considered a name.
3. The raw name upcased or downcased according to
READTABLE-CASE (subject to the current
readtable) but still as a string. This
is to allow `[dref][package]` to refer to the `"DREF"`
package regardless of whether the symbol `DREF` is interned in
the current package.
4. If the raw name is explicitly a symbol (it starts with `#\|`),
and it names an interned symbol (subject to the current
@PACKAGE-AND-READTABLE), then that symbol is considered as a name
and nothing else.
5. If the raw name has an embedded string (it starts with `#\"`) and
READ-FROM-STRING can read the embedded string from it, then that
string is considered as a name and nothing else.
<br/>
For example, when `M-.` is pressed while point is over
`nonREADable.`, the last word of the sentence `It may be
nonREADable.`, the following @RAW-NAMEs are considered until one is
found with a definition:
1. The entire word, `"nonREADable."`.
2. Trimming left does not produce a new raw name.
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 names an interned symbol which has a
definition, so `M-.` will visit it.
When @GENERATING-DOCUMENTATION, @AUTOLINKing behaves similarly.
## PAX Locatives
To the DREF::@BASIC-LOCATIVE-TYPES defined by DRef,
PAX adds a few of its own.
- [locative] SECTION
- Direct locative supertypes: [VARIABLE][6c83]
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
- Direct locative supertypes: [VARIABLE][6c83]
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
suppressing @UNSPECIFIC-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 @ESCAPING-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 PSEUDO locative 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.
- 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 PSEUDO locative 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 PSEUDO locative 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>
=> T
```
- 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 definitions, glossary entries, sections, issues and
issue summaries 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. All matching is
case-insensitive.
- *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 @LINKABLE. When
@BROWSING-LIVE-DOCUMENTATION, a slight difference is that
everything is linkable, so using the CLHS link bypasses the page
with the definition in the running Lisp.
- *unambiguous definition*: `[pprint][clhs]` (pprint)
- *disambiguation page*: `[function][clhs]` (function)
- *specific*: `[function][(clhs class)]` (function)
- *glossary terms*:
- `[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 anchor text a @SPECIFIC-REFLINK-WITH-TEXT 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* (substring match): `[lambda lists][clhs]`
or `[lambda lists][(clhs section)]` (lambda lists)
- *by filename*: `[03_d][clhs]` or `[03_d][(clhs
section)]` (03\_d)
- *by alias*: Format directives are
aliases of the sections describing them. Thus, `[~c][clhs]`
is equivalent to `[22.3.1.1][clhs]` and `[Tilde C:
Character][clhs]`. The full list is
~C ~% ~\& ~|
~~ ~R ~D ~B
~O ~X ~F ~E
~G ~$ ~A ~S
~W ~\_ ~\< ~:>
~I ~/ ~T ~\< Justification
~> ~\* ~\[ ~\]
~{ ~} ~? ~(
~) ~P ~; ~^
~Newline.
Similarly, reader macro characters are aliases of
the sections describing them. The full list is
( ) ' ;
" \` , #
\#\\ #' #( #\*
\#: #. #B #O
\#X #R #C #A
\#S #P #= ##
\#+ #- #| #\<
\#).
Finally, loop keywords have aliases
to the sections describing them. For example, the strings
`loop:for`, `for` and `:for` are aliases of CLHS `6.1.2.1`.
The `loop:*` aliases are convenient for completion at the
prompt when @BROWSING-LIVE-DOCUMENTATION, while the other
aliases are for defaulting to buffer contents.
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 @REFLINKs. @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 DREF::@DEFINITION. PAX extends
standard Slime functionality by
- adding support for all kinds of definitions (see e.g.
ASDF:SYSTEM, READTABLE in
DREF::@BASIC-LOCATIVE-TYPES), not just the ones Slime knows about,
- providing a portable way to refer to even standard definitions,
- disambiguating the definition based on buffer content, and
- adding more powerful completions.
The definition is either determined from the buffer content at point
or is prompted for. At the prompt, TAB-completion is available for
both names and locatives. With a prefix argument (`C-u M-.`), the
buffer contents are not consulted, and `M-.` always prompts.
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.
A close relative of `M-.` is `C-.` for @BROWSING-LIVE-DOCUMENTATION.
- [system] "mgl-pax/navigate"
- Description: Support for MGL-PAX::@NAVIGATING-IN-EMACS via Slime's
`MGL-PAX::@M-.` in MGL-PAX.
- Long Description: Do not declare a dependency on this system. It is
autoloaded by Elisp or by accessing the functionality provided if the
`mgl-pax` system is loaded.
- Licence: MIT, see COPYING.
- Author: Gábor Melis
- Mailto: [[email protected]](mailto:[email protected])
- Depends on: alexandria, dref/full, mgl-pax, swank(?)
- Defsystem depends on: mgl-pax.asdf
### `M-.` Defaulting
When `@M-.` is invoked, it first tries to find a @NAME in the
current buffer at point. If no name is found, then it
prompts.
First, `(slime-sexp-at-point)` is taken as a @WORD, from which the
@NAME will be parsed. Then, candidate locatives are
looked for before and after the @WORD. Thus, if a locative is the
previous or the next expression, 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.
`M-.` works on parenthesized references, such as those in
DEFSECTION:
```
(defsection @foo ()
(cos function))
```
Here, when the cursor is on one of the characters of `COS` or just
after `COS`, pressing `M-.` will visit the definition of the
function `COS`.
To play nice with @GENERATING-DOCUMENTATION, forms suitable for
@AUTOLINKing are recognized:
function cos
cos function
... as well as @REFLINKs:
[cos][function]
[see this][cos function]