├── .readthedocs.yml ├── README.md ├── cl-rtd.asd ├── docs ├── alexandria.md ├── asdf.md ├── bordeaux-threads.md ├── cl-ppcre.md ├── cl-who.md ├── extra.css ├── fiveam.md ├── hunchentoot.md ├── index.md ├── iterate.md ├── local-time.md ├── numcl.md ├── postmodern.md ├── quicklisp.md ├── unix-opts.md ├── usocket.md └── utilities.md ├── emacs-utils.el ├── mkdocs.yml ├── requirements.txt ├── scratch └── postmodern.lisp └── src ├── .gitignore ├── functions.lisp ├── md-file.lisp ├── package.lisp ├── types.lisp ├── utilities.lisp └── variables.lisp /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | # sphinx: 10 | # configuration: docs/conf.py 11 | 12 | # Build documentation with MkDocs 13 | mkdocs: 14 | configuration: mkdocs.yml 15 | fail_on_warning: false 16 | 17 | # Optionally build your docs in additional formats such as PDF 18 | formats: 19 | - pdf 20 | 21 | # Optionally set the version of Python and requirements required to build your docs 22 | python: 23 | version: 3.7 24 | install: 25 | - requirements: requirements.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | docs/index.md -------------------------------------------------------------------------------- /cl-rtd.asd: -------------------------------------------------------------------------------- 1 | (asdf:defsystem "cl-rtd" 2 | :depends-on ("alexandria" 3 | "arrows" 4 | "cl-interpol" 5 | "closer-mop" 6 | "introspect-environment" 7 | "iterate" 8 | "str" 9 | "reader+swank" 10 | "trivial-types" 11 | #-swank "swank" 12 | "trivial-package-local-nicknames") 13 | :pathname #P"src/" 14 | :serial t 15 | :components ((:file "package") 16 | (:file "utilities") 17 | (:file "variables") 18 | (:file "functions") ; functions, macros, generic functions 19 | (:file "types") ; tested on SBCL 20 | (:file "md-file"))) 21 | 22 | ;;; Why didn't I use docparser or declt? 23 | ;;; I tried declt. But found modifying the output format to suit my needs not 24 | ;;; worth the time investment, at least for bordeaux-threads. 25 | ;;; I found docparser leaving behind some details. I liked it for generating a 26 | ;;; output independent documentation-tree, but it seems not very complete. 27 | 28 | -------------------------------------------------------------------------------- /docs/bordeaux-threads.md: -------------------------------------------------------------------------------- 1 | # bordeaux-threads - Threading 2 | 3 | Version: 0.8.7 4 |
5 | Licence: MIT 6 |
7 | Repository: [sionescu/bordeaux-threads - Github](https://github.com/sionescu/bordeaux-threads/) 8 |
9 | See also: [awesome-cl#parallelism-and-concurrency](https://github.com/CodyReichert/awesome-cl#parallelism-and-concurrency) 10 | 11 | *This page was possible due to the [official documentation](https://trac.common-lisp.net/bordeaux-threads/wiki/ApiDocumentation), albeit its a bit outdated.* 12 | 13 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 14 | 15 | *** 16 | 17 | 18 | BORDEAUX-THREADS is a proposed standard for a minimal 19 | MP/threading interface. It is similar to the CLIM-SYS threading and 20 | lock support, but for the following broad differences: 21 | 22 | 1. Some behaviours are defined in additional detail: attention has 23 | been given to special variable interaction, whether and when 24 | cleanup forms are run. Some behaviours are defined in less 25 | detail: an implementation that does not support multiple 26 | threads is not required to use a new list (nil) for a lock, for 27 | example. 28 | 29 | 2. Many functions which would be difficult, dangerous or inefficient 30 | to provide on some implementations have been removed. Chiefly 31 | these are functions such as thread-wait which expect for 32 | efficiency that the thread scheduler is written in Lisp and 33 | 'hookable', which can't sensibly be done if the scheduler is 34 | external to the Lisp image, or the system has more than one CPU. 35 | 36 | 3. Unbalanced ACQUIRE-LOCK and RELEASE-LOCK functions have been 37 | added. 38 | 39 | 4. Posix-style condition variables have been added, as it's not 40 | otherwise possible to implement them correctly using the other 41 | operations that are specified. 42 | 43 | Threads may be implemented using whatever applicable techniques are 44 | provided by the operating system: user-space scheduling, 45 | kernel-based LWPs or anything else that does the job. 46 | 47 | Some parts of this specification can also be implemented in a Lisp 48 | that does not support multiple threads. Thread creation and some 49 | thread inspection operations will not work, but the locking 50 | functions are still present (though they may do nothing) so that 51 | thread-safe code can be compiled on both multithread and 52 | single-thread implementations without need of conditionals. 53 | 54 | To avoid conflict with existing MP/threading interfaces in 55 | implementations, these symbols live in the BORDEAUX-THREADS package. 56 | Implementations and/or users may also make them visible or exported 57 | in other more traditionally named packages. 58 | 59 | ### \*default-special-bindings\* 60 | 61 | ```lisp 62 | Variable 63 | ``` 64 | 65 | This variable holds an alist associating special variable symbols 66 | to forms to evaluate. Special variables named in this list will 67 | be locally bound in the new thread before it begins executing user code. 68 | 69 | This variable may be rebound around calls to [make-thread](#make-thread) to 70 | add/alter default bindings. The effect of mutating this list is 71 | undefined, but earlier forms take precedence over later forms for 72 | the same symbol, so defaults may be overridden by consing to the 73 | head of the list. 74 | 75 | ### \*standard-io-bindings\* 76 | 77 | ```lisp 78 | Variable 79 | ``` 80 | 81 | Standard bindings of printer/reader control variables as per CL:WITH-STANDARD-IO-SYNTAX. 82 | 83 | ### \*supports-threads-p\* 84 | 85 | ```lisp 86 | Variable 87 | ``` 88 | 89 | This should be set to T if the running instance has thread support. 90 | 91 | ### acquire-lock 92 | 93 | ```lisp 94 | Function: (acquire-lock lock &optional (wait-p t)) 95 | ``` 96 | Acquire the lock `lock` for the calling thread. 97 | `wait-p` governs what happens if the lock is not available: if `wait-p` 98 | is true, the calling thread will wait until the lock is available 99 | and then acquire it; if `wait-p` is NIL, `acquire-lock` will return 100 | immediately. `acquire-lock` returns true if the lock was acquired and 101 | NIL otherwise. 102 | 103 | This specification does not define what happens if a thread 104 | attempts to acquire a lock that it already holds. For applications 105 | that require locks to be safe when acquired recursively, see instead 106 | [make-recursive-lock](#make-recursive-lock) and friends. 107 | 108 | ### acquire-recursive-lock 109 | 110 | ```lisp 111 | Function: (acquire-recursive-lock lock) 112 | ``` 113 | As for [acquire-lock](#acquire-lock), but for recursive locks. 114 | 115 | ### all-threads 116 | 117 | ```lisp 118 | Function: (all-threads) 119 | ``` 120 | Returns a sequence of all of the threads. This may not 121 | be freshly-allocated, so the caller should not modify it. 122 | 123 | ### condition-notify 124 | 125 | ```lisp 126 | Function: (condition-notify condition-variable) 127 | ``` 128 | Notify at least one of the threads waiting for 129 | `condition-variable`. It is implementation-dependent whether one or 130 | more than one (and possibly all) threads are woken, but if the 131 | implementation is capable of waking only a single thread (not all 132 | are) this is probably preferable for efficiency reasons. The order 133 | of wakeup is unspecified and does not necessarily relate to the 134 | order that the threads went to sleep in. 135 | 136 | `condition-notify` has no useful return value. In an implementation 137 | that does not support multiple threads, it has no effect. 138 | 139 | ### condition-wait 140 | 141 | ```lisp 142 | Function: (condition-wait condition-variable lock &key timeout) 143 | ``` 144 | Atomically release `lock` and enqueue the calling 145 | thread waiting for `condition-variable`. The thread will resume when 146 | another thread has notified it using [condition-notify](#condition-notify); it may also 147 | resume if interrupted by some external event or in other 148 | implementation-dependent circumstances: the caller must always test 149 | on waking that there is threading to be done, instead of assuming 150 | that it can go ahead. 151 | 152 | It is an error to call function this unless from the thread that 153 | holds `lock`. 154 | 155 | If `timeout` is nil or not provided, the system always reacquires `lock` 156 | before returning to the caller. In this case T is returned. 157 | 158 | If `timeout` is non-nil, the call will return after at most `timeout` 159 | seconds (approximately), whether or not a notification has occurred. 160 | Either NIL or T will be returned. A return of NIL indicates that the 161 | lock is no longer held and that the timeout has expired. A return of 162 | T indicates that the lock is held, in which case the timeout may or 163 | may not have expired. 164 | 165 | **NOTE**: The behavior of `condition-wait` with `timeout` diverges from 166 | the POSIX function pthread_cond_timedwait. The former may return 167 | without the lock being held while the latter always returns with the 168 | lock held. 169 | 170 | In an implementation that does not support multiple threads, this 171 | function signals an error. 172 | 173 | ### current-thread 174 | 175 | ```lisp 176 | Function: (current-thread) 177 | ``` 178 | Returns the thread object for the calling 179 | thread. This is the same kind of object as would be returned by 180 | [make-thread](#make-thread). 181 | 182 | ### destroy-thread 183 | 184 | ```lisp 185 | Function: (destroy-thread thread) 186 | ``` 187 | Terminates the thread `thread`, which is an object 188 | as returned by [make-thread](#make-thread). This should be used with caution: it is 189 | implementation-defined whether the thread runs cleanup forms or 190 | releases its locks first. 191 | 192 | Destroying the calling thread is an error. 193 | 194 | ### interrupt-thread 195 | 196 | ```lisp 197 | Function: (interrupt-thread thread function &rest args) 198 | ``` 199 | Interrupt `thread` and cause it to evaluate `function` 200 | before continuing with the interrupted path of execution. This may 201 | not be a good idea if `thread` is holding locks or doing anything 202 | important. On systems that do not support multiple threads, this 203 | function signals an error. 204 | 205 | ### join-thread 206 | 207 | ```lisp 208 | Function: (join-thread thread) 209 | ``` 210 | Wait until `thread` terminates. If `thread` has already terminated, 211 | return immediately. The return values of the thread function are 212 | returned. 213 | 214 | ### lock 215 | 216 | ### lock-p 217 | 218 | ```lisp 219 | Function: (lock-p object) 220 | ``` 221 | Returns T if `object` is a lock; returns NIL otherwise. 222 | 223 | ### make-condition-variable 224 | 225 | ```lisp 226 | Function: (make-condition-variable &key name) 227 | ``` 228 | Returns a new condition-variable object for use 229 | with [condition-wait](#condition-wait) and [condition-notify](#condition-notify). 230 | 231 | ### make-lock 232 | 233 | ```lisp 234 | Function: (make-lock &optional name) 235 | ``` 236 | Creates a lock (a mutex) whose name is `name`. If the system does not 237 | support multiple threads this will still return some object, but it 238 | may not be used for very much. 239 | 240 | ### make-recursive-lock 241 | 242 | ```lisp 243 | Function: (make-recursive-lock &optional name) 244 | ``` 245 | Create and return a recursive lock whose name is `name`. A recursive 246 | lock differs from an ordinary lock in that a thread that already 247 | holds the recursive lock can acquire it again without blocking. The 248 | thread must then release the lock twice before it becomes available 249 | for another thread. 250 | 251 | ### make-semaphore 252 | 253 | ```lisp 254 | Function: (make-semaphore &key name (count 0)) 255 | ``` 256 | Create a semaphore with the supplied `name` and initial counter value `count`. 257 | 258 | ### make-thread 259 | 260 | ```lisp 261 | Function: (make-thread function &key name (initial-bindings 262 | *default-special-bindings*)) 263 | ``` 264 | Creates and returns a thread named `name`, which will call the 265 | function `function` with no arguments: when `function` returns, the 266 | thread terminates. `name` defaults to "Anonymous thread" if unsupplied. 267 | 268 | On systems that do not support multi-threading, `make-thread` will 269 | signal an error. 270 | 271 | The interaction between threads and dynamic variables is in some 272 | cases complex, and depends on whether the variable has only a global 273 | binding (as established by e.g. DEFVAR/DEFPARAMETER/top-level SETQ) 274 | or has been bound locally (e.g. with LET or LET*) in the calling 275 | thread. 276 | 277 | - Global bindings are shared between threads: the initial value of a 278 | global variable in the new thread will be the same as in the 279 | parent, and an assignment to such a variable in any thread will be 280 | visible to all threads in which the global binding is visible. 281 | 282 | - Local bindings, such as the ones introduced by `initial-bindings`, 283 | are local to the thread they are introduced in, except that 284 | 285 | - Local bindings in the the caller of `make-thread` may or may not be 286 | shared with the new thread that it creates: this is 287 | implementation-defined. Portable code should not depend on 288 | particular behaviour in this case, nor should it assign to such 289 | variables without first rebinding them in the new thread. 290 | 291 | ### recursive-lock 292 | 293 | ### recursive-lock-p 294 | 295 | ```lisp 296 | Function: (recursive-lock-p object) 297 | ``` 298 | Returns T if `object` is a recursive lock; returns NIL otherwise. 299 | 300 | ### release-lock 301 | 302 | ```lisp 303 | Function: (release-lock lock) 304 | ``` 305 | Release `lock`. It is an error to call this unless 306 | the lock has previously been acquired (and not released) by the same 307 | thread. If other threads are waiting for the lock, the 308 | [acquire-lock](#acquire-lock) call in one of them will now be able to continue. 309 | 310 | This function has no interesting return value. 311 | 312 | ### release-recursive-lock 313 | 314 | ```lisp 315 | Function: (release-recursive-lock lock) 316 | ``` 317 | Release the recursive `lock`. The lock will only 318 | become free after as many Release operations as there have been 319 | Acquire operations. See [release-lock](#release-lock) for other information. 320 | 321 | ### semaphore 322 | 323 | ### semaphore-p 324 | 325 | ```lisp 326 | Function: (semaphore-p object) 327 | ``` 328 | Returns T if `object` is a semaphore; returns NIL otherwise. 329 | 330 | ### signal-semaphore 331 | 332 | ```lisp 333 | Function: (signal-semaphore semaphore &key (count 1)) 334 | ``` 335 | Increment `semaphore` by `count`. If there are threads waiting on this 336 | semaphore, then `count` of them are woken up. 337 | 338 | ### start-multiprocessing 339 | 340 | ```lisp 341 | Function: (start-multiprocessing) 342 | ``` 343 | If the host implementation uses user-level threads, start the 344 | scheduler and multiprocessing, otherwise do nothing. 345 | It is safe to call repeatedly. 346 | 347 | ### thread 348 | 349 | ### thread-alive-p 350 | 351 | ```lisp 352 | Function: (thread-alive-p thread) 353 | ``` 354 | Returns true if `thread` is alive, that is, if 355 | [destroy-thread](#destroy-thread) has not been called on it. 356 | 357 | ### thread-name 358 | 359 | ```lisp 360 | Function: (thread-name thread) 361 | ``` 362 | Returns the name of the thread, as supplied to [make-thread](#make-thread). 363 | 364 | ### thread-yield 365 | 366 | ```lisp 367 | Function: (thread-yield) 368 | ``` 369 | Allows other threads to run. It may be necessary or desirable to 370 | call this periodically in some implementations; others may schedule 371 | threads automatically. On systems that do not support 372 | multi-threading, this does nothing. 373 | 374 | ### threadp 375 | 376 | ```lisp 377 | Function: (threadp object) 378 | ``` 379 | Returns true if object is a thread, otherwise NIL. 380 | 381 | ### timeout 382 | 383 | ### wait-on-semaphore 384 | 385 | ```lisp 386 | Function: (wait-on-semaphore semaphore &key timeout) 387 | ``` 388 | Decrement the count of `semaphore` by 1 if the count would not be negative. 389 | 390 | Else blocks until the semaphore can be decremented. Returns generalized boolean 391 | T on success. 392 | 393 | If `timeout` is given, it is the maximum number of seconds to wait. If the count 394 | cannot be decremented in that time, returns NIL without decrementing the count. 395 | 396 | ### with-lock-held 397 | 398 | ```lisp 399 | Macro: (with-lock-held (place) &body body) 400 | ``` 401 | Evaluates `body` with the lock named by `place`, the value of which 402 | is a lock created by [make-lock](#make-lock). Before the forms in `body` are 403 | evaluated, the lock is acquired as if by using [acquire-lock](#acquire-lock). After the 404 | forms in `body` have been evaluated, or if a non-local control transfer 405 | is caused (e.g. by THROW or SIGNAL), the lock is released as if by 406 | [release-lock](#release-lock). 407 | 408 | Note that if the debugger is entered, it is unspecified whether the 409 | lock is released at debugger entry or at debugger exit when execution 410 | is restarted. 411 | 412 | ### with-recursive-lock-held 413 | 414 | ```lisp 415 | Macro: (with-recursive-lock-held (place) &body body) 416 | ``` 417 | Evaluates `body` with the recursive lock named by `place`, which is a 418 | reference to a recursive lock created by [make-recursive-lock](#make-recursive-lock). See 419 | [with-lock-held](#with-lock-held) etc etc 420 | 421 | ### with-timeout 422 | 423 | ```lisp 424 | Macro: (with-timeout (timeout) &body body) 425 | ``` 426 | -------------------------------------------------------------------------------- /docs/cl-ppcre.md: -------------------------------------------------------------------------------- 1 | # cl-ppcre - Regular Expressions 2 | 3 | Version: 2.1.1 4 |
5 | Licence: BSD 6 |
7 | Nickname: ppcre 8 |
9 | Repository: [edicl/cl-ppcre - Github](https://github.com/edicl/cl-ppcre) 10 |
11 | See also: [awesome-cl/#regex](https://github.com/CodyReichert/awesome-cl#regex) 12 | 13 | *This documentation is possible the [excellent official documentation](https://edicl.github.io/cl-ppcre) as of 4th May 2020.* 14 | 15 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 16 | 17 | *** 18 | 19 | CL-PPCRE is a Portable Perl-Compatible Regular Expressions library for Common Lisp. 20 | This is also thread-safe, and allows specifying [regular expressions using 21 | S-expressions](#using-s-expressions). 22 | 23 | 24 | ## GETTING STARTED 25 | 26 | ### Using perl regex 27 | 28 | Per the name, `cl-ppcre` is more or less compatible with perl 5.8 including 29 | extended features like non-greedy repetitions, positive and negative 30 | look-ahead and look-behind assertions, "standalone" subexpressions, 31 | and conditional subpatterns. The following Perl features are 32 | (currently) **not** supported: 33 | 34 | - `(?{ code })` and `(??{ code })` because they obviously don't make 35 | sense in Lisp. 36 | - `\N{name}` (named characters), `\x{263a}` (wide hex characters), 37 | `\l`, `\u`, `\L`, and `\U` because they're actually not part of 38 | Perl's *regex* syntax - but see 39 | [CL-INTERPOL](https://github.com/edicl/cl-interpol/). 40 | - `\X` (extended Unicode), and `\C` (single character). But you can 41 | of course use all characters supported by your CL implementation. 42 | - Posix character classes like `[[:alpha]]`. Load `(asdf:load-system :cl-ppcre-unicode)` 43 | to install [unicode-preperty-resolver](#unicode-property-resolver) as your 44 | [property-resolver](#property-resolver). See [cl-unicode](https://edicl.github.io/cl-unicode/) 45 | for the supported unicode properties and their naming conventions. 46 | - `\G` for Perl's `pos()` because we don't have it. 47 | 48 | Note, however, that `\t`, `\n`, `\r`, `\f`, `\a`, `\e`, `\033` (octal 49 | character codes), `\x1B` (hexadecimal character codes), `\c[` (control 50 | characters), `\w`, `\W`, `\s`, `\S`, `\d`, `\D`, `\b`, `\B`, `\A`, 51 | `\Z`, and `\z` **are** supported. 52 | 53 | Users can straightaway start with: 54 | 55 | - [scan](#scan) 56 | - [scan-to-strings](#scan-to-strings) 57 | - [split](#split) 58 | - [quote-meta-chars](#quote-meta-chars) 59 | - [register-groups-bind](#register-groups-bind) 60 | - [regex-replace](#regex-replace) 61 | 62 | Register groups simply refer to the captured groups. For instance: 63 | 64 | ```lisp 65 | CL-USER> (register-groups-bind (a b) ("([^ ]+) ([^ ]+)" "hello world") 66 | (list a b)) 67 | ("hello" "world") 68 | ``` 69 | 70 | See the [other macros](#do-matches) for iterative versions of these. 71 | 72 | Those wanting to get into perl regular expressions, might find [their official 73 | documentation](https://perldoc.perl.org/perlre.html) useful. 74 | 75 | Users comfortable with regular expressions might also want to try 76 | [cl-interpol](https://github.com/edicl/cl-interpol/) - which provides string 77 | interpolation facilities to the lisp reader. (Yes, it's defacto!) 78 | 79 | ### Using s-expressions 80 | 81 | The basics: 82 | 83 | ``` 84 | +------- Common Lisp Equivalent -------+----------- Perl Equivalent -----------+ 85 | | String / Character | Literal treatment | 86 | | :void | Empty string | 87 | | :everything | Dot | 88 | | :(non-)word-boundary | \b, \B (non) | 89 | | :(non-)digit-class | \d, \D (non) | 90 | | :(non-)word-char-class | \w, \W (non) | 91 | | :(non-)whitespace-char-class | \s, \S (non) | 92 | | :start/end-anchor | ^ [start], $ [end | 93 | | :modeless-start/end-anchor | \A [start], \Z [end] | 94 | | :modeless-end-anchor-no-newline | \z | 95 | | :case-(in)sensitive-p | (?i), (?-i) [insensitive] | 96 | | :(not)-multi-line-mode-p | (?m), (?-m) [not] | 97 | | :(not)-single-line-mode-p | (?s), (?-s) [not] | 98 | | (anything else) | Syntax Error | 99 | +--------------------------------------+---------------------------------------+ 100 | ``` 101 | 102 | Simple combinations include `:sequence`, `:group`, `:flags`, `:register`, 103 | `:greedy-repetition`, `:non-greedy-repetition`. You could play around with 104 | [parse-string](#parse-string) to learn more about the equivalence. 105 | 106 | For instance: 107 | 108 | ```lisp 109 | * (parse-string "(ab)*") 110 | (:GREEDY-REPETITION 0 `NIL` (:REGISTER "ab")) 111 | 112 | * (parse-string "(a(b))") 113 | (:REGISTER (:SEQUENCE #\a (:REGISTER #\b))) 114 | 115 | * (parse-string "(?:abc){3,5}") 116 | (:GREEDY-REPETITION 3 5 (:GROUP "abc")) 117 | ;; (:GREEDY-REPETITION 3 5 "abc") would also be OK 118 | 119 | * (parse-string "a(?i)b(?-i)c") 120 | (:SEQUENCE #\a 121 | (:SEQUENCE (:FLAGS :CASE-INSENSITIVE-P) 122 | (:SEQUENCE #\b (:SEQUENCE (:FLAGS :CASE-SENSITIVE-P) #\c)))) 123 | ;; same as (:SEQUENCE #\a :CASE-INSENSITIVE-P #\b :CASE-SENSITIVE-P #\c) 124 | 125 | * (parse-string "(?=a)b") 126 | (:SEQUENCE (:POSITIVE-LOOKAHEAD #\a) #\b) 127 | 128 | * (parse-string "aa|aaa") 129 | (:ALTERNATION "aa" "aaa") 130 | ``` 131 | 132 | See the [manual](https://edicl.github.io/cl-ppcre/#create-scanner2) for the 133 | more detailed equivalence. 134 | 135 | Thus, you could equivalently use parse-trees for the functions and macros that 136 | expect regex. 137 | 138 | ```lisp 139 | * (all-matches-as-strings '(:greedy-repetition 1 nil #\a) "aaaa") 140 | ("aaaa") 141 | ``` 142 | 143 | ### Performance Aspects 144 | 145 | `cl-ppcre` was intended to be fast. Indeed, [when it first appeared, 146 | it was perhaps the fastest](http://web.archive.org/web/20080624164217/http://weitz.de/cl-ppcre/#bench). 147 | 148 | However, in 2020, it can be five times as slow as Perl: 149 | 150 | ```sh 151 | time perl -e '"@{['x' x 50000000]}" =~ /([xy])*/' 152 | 153 | real 0m0.245s 154 | user 0m0.161s 155 | sys 0m0.084s 156 | ``` 157 | 158 | 159 | ```lisp 160 | CL-USER> (time (progn 161 | (scan "([xy])*" 162 | (make-string 50000000 :element-type 'base-char 163 | :initial-element #\x)) 164 | nil)) 165 | Evaluation took: 166 | 1.116 seconds of real time 167 | 1.115901 seconds of total run time (1.111972 user, 0.003929 system) 168 | 100.00% CPU 169 | 2,463,959,814 processor cycles 170 | 50,000,032 bytes consed 171 | ``` 172 | 173 | But still (more than) 5 times faster than python: 174 | 175 | ```sh 176 | time python3 -c 'import re; x = re.search("([xy])*", "x"*50000000)' 177 | 178 | real 0m7.458s 179 | user 0m4.563s 180 | sys 0m2.892s 181 | ``` 182 | 183 | Or slower as well: 184 | 185 | ```sh 186 | $ ~ time python3 -c 'import re; x = re.search("x*", "x"*50000000)' 187 | 188 | real 0m0.146s 189 | user 0m0.109s 190 | sys 0m0.036s 191 | ``` 192 | 193 | Honestly, though, it should be possible to use implementation specific means to speed things up 194 | - or copying the developments in the perl and/or python world. 195 | 196 | Perhaps, see the [manual](https://edicl.github.io/cl-ppcre/#blabla) for hints on speeding things 197 | up. 198 | 199 | ## FUNCTIONS AND MACROS 200 | 201 | ### all-matches 202 | 203 | ```lisp 204 | Function: (all-matches regex target-string 205 | &key (start 0) (end (length target-string))) 206 | ``` 207 | Returns a list containing the start and end positions of all 208 | matches of `regex` against `target-string`, i.e. if there are N matches 209 | the list contains (* 2 N) elements. If `regex` matches an empty string 210 | the scan is continued one position behind this match. 211 | 212 | ### all-matches-as-strings 213 | 214 | ```lisp 215 | Function: (all-matches-as-strings regex target-string 216 | &key (start 0) (end (length target-string)) sharedp) 217 | ``` 218 | Returns a list containing all substrings of `target-string` which 219 | match `regex`. If `regex` matches an empty string the scan is continued 220 | one position behind this match. If `sharedp` is true, the substrings may 221 | share structure with `target-string`. 222 | 223 | ### create-optimized-test-function 224 | 225 | ```lisp 226 | Function: (create-optimized-test-function test-function 227 | &key (start 0) (end *regex-char-code-limit*) 228 | (kind *optimize-char-classes*)) 229 | ``` 230 | Given a unary test function which is applicable to characters 231 | returns a function which yields the same boolean results for all 232 | characters with character codes from `start` to (excluding) `end`. If 233 | `kind` is `nil`, `test-function` will simply be returned. Otherwise, `kind` 234 | should be one of: 235 | 236 | * `:hash-table` - builds a hash table representing all characters which 237 | satisfy the test and returns a closure which checks if 238 | a character is in that hash table 239 | 240 | * `:charset` - instead of a hash table uses a "charset" which is a 241 | data structure using non-linear hashing and optimized to 242 | represent (sparse) sets of characters in a fast and 243 | space-efficient way (contributed by Nikodemus Siivola) 244 | 245 | * `:charmap` - instead of a hash table uses a bit vector to represent 246 | the set of characters 247 | 248 | You can also use `:hash-table*` or `:charset*` which are like `:hash-table` 249 | and `:charset` but use the complement of the set if the set contains 250 | more than half of all characters between `start` and `end`. This saves 251 | space but needs an additional pass across all characters to create the 252 | data structure. There is no corresponding `:charmap*` kind as the bit 253 | vectors are already created to cover the smallest possible interval 254 | which contains either the set or its complement. 255 | 256 | ### create-scanner 257 | 258 | ```lisp 259 | Function: (create-scanner regex 260 | &key case-insensitive-mode multi-line-mode 261 | single-line-mode extended-mode destructive) 262 | ``` 263 | Accepts a regular expression - either as a 264 | parse-tree or as a string - and returns a scan closure which will scan 265 | strings for this regular expression and a list mapping registers to 266 | their names (`nil` stands for unnamed ones). The "mode" keyword 267 | arguments are equivalent to the imsx modifiers in Perl. If 268 | `destructive` is not `nil`, the function is allowed to destructively 269 | modify its first argument (but only if it's a parse tree). 270 | 271 | (More in the manual!) 272 | 273 | ### define-parse-tree-synonym 274 | 275 | ```lisp 276 | Macro: (define-parse-tree-synonym name parse-tree) 277 | ``` 278 | Defines the symbol `name` to be a synonym for the parse tree 279 | `parse-tree`. Both arguments are quoted. 280 | 281 | ### do-matches 282 | 283 | ```lisp 284 | Macro: (do-matches (match-start match-end regex target-string 285 | &optional result-form &key start end) 286 | &body body) 287 | ``` 288 | Iterates over `target-string` and tries to match `regex` as often as 289 | possible evaluating `body` with `match-start` and `match-end` bound to the 290 | start/end positions of each match in turn. After the last match, 291 | returns `result-form` if provided or `nil` otherwise. An implicit block 292 | named `nil` surrounds `do-matches`; `return` may be used to terminate the 293 | loop immediately. If `regex` matches an empty string the scan is 294 | continued one position behind this match. `body` may start with 295 | declarations. 296 | 297 | ### do-matches-as-strings 298 | 299 | ```lisp 300 | Macro: (do-matches-as-strings 301 | (match-var regex target-string 302 | &optional result-form &key start end sharedp) 303 | &body body) 304 | ``` 305 | Iterates over `target-string` and tries to match `regex` as often as 306 | possible evaluating `body` with `match-var` bound to the substring of 307 | `target-string` corresponding to each match in turn. After the last 308 | match, returns `result-form` if provided or `nil` otherwise. An implicit 309 | block named `nil` surrounds `do-matches-as-strings`; `return` may be used to 310 | terminate the loop immediately. If `regex` matches an empty string the 311 | scan is continued one position behind this match. If `sharedp` is true, 312 | the substrings may share structure with `target-string`. `body` may start 313 | with declarations. 314 | 315 | ### do-register-groups 316 | 317 | ```lisp 318 | Macro: (do-register-groups 319 | var-list 320 | (regex target-string 321 | &optional result-form &key start end sharedp) 322 | &body body) 323 | ``` 324 | Iterates over `target-string` and tries to match `regex` as often as 325 | possible evaluating `body` with the variables in `var-list` bound to the 326 | corresponding register groups for each match in turn, i.e. each 327 | variable is either bound to a string or to `nil`. For each element of 328 | `var-list` which is `nil` there's no binding to the corresponding register 329 | group. The number of variables in `var-list` must not be greater than 330 | the number of register groups. After the last match, returns 331 | `result-form` if provided or `nil` otherwise. An implicit block named `nil` 332 | surrounds `do-register-groups`; `return` may be used to terminate the loop 333 | immediately. If `regex` matches an empty string the scan is continued 334 | one position behind this match. If `sharedp` is true, the substrings 335 | may share structure with `target-string`. `body` may start with 336 | declarations. 337 | 338 | ### do-scans 339 | 340 | ```lisp 341 | Macro: (do-scans (match-start match-end reg-starts reg-ends regex target-string 342 | &optional result-form &key start end) 343 | &body body) 344 | ``` 345 | Iterates over `target-string` and tries to match `regex` as often as 346 | possible evaluating BODY with `match-start`, `match-end`, `reg-starts`, and 347 | `reg-ends` bound to the four return values of each match in turn. After 348 | the last match, returns `result-form` if provided or `nil` otherwise. An 349 | implicit block named `nil` surrounds `do-scans`; `return` may be used to 350 | terminate the loop immediately. If `regex` matches an empty string the 351 | scan is continued one position behind this match. `body` may start with 352 | declarations. 353 | 354 | ### parse-string 355 | 356 | ```lisp 357 | Function: (parse-string string) 358 | ``` 359 | Translate the regex string `string` into a parse tree. 360 | 361 | ### parse-tree-synonym 362 | 363 | ```lisp 364 | Function: (parse-tree-synonym symbol) 365 | ``` 366 | Returns the parse tree the `symbol` symbol is a synonym for. Returns 367 | `nil` is `symbol` wasn't yet defined to be a synonym. 368 | 369 | ### ppcre-error 370 | 371 | Every error signaled by CL-PPCRE is of type `ppcre-error`. This is a direct subtype of 372 | [simple-error](http://www.lispworks.com/documentation/HyperSpec/Body/e_smp_er.htm) 373 | without any additional slots or options. 374 | 375 | ### ppcre-invocation-error 376 | 377 | Errors of type `ppcre-invocation-error` are signaled if one of the exported functions of CL-PPCRE is called with wrong or inconsistent arguments. This is a direct subtype of `ppcre-error` without any additional slots or options. 378 | 379 | ### ppcre-syntax-error 380 | 381 | An error of type `ppcre-syntax-error` is signaled if CL-PPCRE's parser encounters an error when trying to parse a regex string or to convert a parse tree into its internal representation. This is a direct subtype of `ppcre-error` with two additional slots. These denote the regex string which HTML-PPCRE was parsing and the position within the string where the error occurred. If the error happens while CL-PPCRE is converting a parse tree, both of these slots contain NIL. (See the next two entries on how to access these slots.) 382 | 383 | ### ppcre-syntax-error-pos 384 | 385 | ```lisp 386 | Function: (ppcre-syntax-error-pos condition) 387 | ``` 388 | Returns the position within the string where the error occurred 389 | (or `nil` if the error happened while trying to convert a parse tree 390 | 391 | ### ppcre-syntax-error-string 392 | 393 | ```lisp 394 | Function: (ppcre-syntax-error-string condition) 395 | ``` 396 | Returns the string the parser was parsing when the error was 397 | encountered (or `nil` if the error happened while trying to convert a 398 | parse tree). 399 | 400 | 401 | ### quote-meta-chars 402 | 403 | ```lisp 404 | Function: (quote-meta-chars string &key (start 0) (end (length string))) 405 | ``` 406 | Quote, i.e. prefix all non-word characters in `string` with `#\\`. 407 | 408 | ### regex-apropos 409 | 410 | ```lisp 411 | Function: (regex-apropos regex &optional packages &key (case-insensitive t)) 412 | ``` 413 | Similar to the standard function `apropos` but returns a list of all 414 | symbols which match the regular expression REGEX. If `case-insensitive` 415 | is true and `regex` isn't already a scanner, a case-insensitive scanner 416 | is used. 417 | 418 | ### regex-apropos-list 419 | 420 | ```lisp 421 | Function: (regex-apropos-list regex &optional packages &key (case-insensitive t)) 422 | ``` 423 | Similar to the standard function `apropos-list` but returns a list of 424 | all symbols which match the regular expression `regex`. If 425 | `case-insensitive` is true and `regex` isn't already a scanner, a 426 | case-insensitive scanner is used. 427 | 428 | ### regex-replace 429 | 430 | ```lisp 431 | Function: (regex-replace regex target-string replacement 432 | &key (start 0) (end (length target-string)) 433 | preserve-case simple-calls 434 | (element-type 'character)) 435 | ``` 436 | Try to match `target-string` between `start` and `end` against `regex` and 437 | replace the first match with `replacement`. Two values are returned; 438 | the modified string, and `t` if `regex` matched or `nil` otherwise. 439 | 440 | `replacement` can be a string which may contain the special substrings 441 | "\&" for the whole match, "\`" for the part of `target-string` 442 | before the match, "\'" for the part of `target-string` after the 443 | match, "\N" or "\{N}" for the Nth register where N is a positive 444 | integer. 445 | 446 | `replacement` can also be a function designator in which case the 447 | match will be replaced with the result of calling the function 448 | designated by `replacement` with the arguments `target-string`, `start`, 449 | `end`, `match-start`, `match-end`, `reg-starts`, and `reg-ends`. (`reg-starts` and 450 | `reg-ends` are arrays holding the start and end positions of matched 451 | registers or `nil` - the meaning of the other arguments should be 452 | obvious.) 453 | 454 | Finally, `replacement` can be a list where each element is a string, 455 | one of the symbols `:match`, `:before-match`, or `:after-match` - 456 | corresponding to "\&", "\`", and "\'" above -, an integer N - 457 | representing register (1+ N) -, or a function designator. 458 | 459 | If `preserve-case` is true, the replacement will try to preserve the 460 | case (all upper case, all lower case, or capitalized) of the 461 | match. The result will always be a fresh string, even if `regex` doesn't 462 | match. 463 | 464 | `element-type` is the element type of the resulting string. 465 | 466 | ### regex-replace-all 467 | 468 | ```lisp 469 | Function: (regex-replace-all regex target-string replacement 470 | &key (start 0) (end (length target-string)) 471 | preserve-case simple-calls 472 | (element-type 'character)) 473 | ``` 474 | Try to match `target-string` between `start` and `end` against `regex` and 475 | replace all matches with `replacement`. Two values are returned; the 476 | modified string, and T if `regex` matched or `nil` otherwise. 477 | 478 | `replacement` can be a string which may contain the special substrings 479 | "\&" for the whole match, "\`" for the part of `target-string` 480 | before the match, "\'" for the part of `target-string` after the 481 | match, "\N" or "\{N}" for the Nth register where N is a positive 482 | integer. 483 | 484 | `replacement` can also be a function designator in which case the 485 | match will be replaced with the result of calling the function 486 | designated by `replacement` with the arguments `target-string`, `start`, 487 | `end`, `match-start`, `match-end`, `reg-starts`, and `reg-ends`. (`reg-starts` and 488 | `reg-ends` are arrays holding the start and end positions of matched 489 | registers or `nil` - the meaning of the other arguments should be 490 | obvious.) 491 | 492 | Finally, `replacement` can be a list where each element is a string, 493 | one of the symbols `:match`, `:before-match`, or `:after-match` - 494 | corresponding to "\&", "\`", and "\'" above -, an integer N - 495 | representing register (1+ N) -, or a function designator. 496 | 497 | If `preserve-case` is true, the replacement will try to preserve the 498 | case (all upper case, all lower case, or capitalized) of the 499 | match. The result will always be a fresh string, even if `regex` doesn't 500 | match. 501 | 502 | `element-type` is the element type of the resulting string. 503 | 504 | ### register-groups-bind 505 | 506 | ```lisp 507 | Macro: (register-groups-bind var-list 508 | (regex target-string &key start end sharedp) 509 | &body body) 510 | ``` 511 | Executes `body` with the variables in `var-list` bound to the 512 | corresponding register groups after `target-string` has been matched 513 | against `regex`, i.e. each variable is either bound to a string or to 514 | `nil`. If there is no match, `body` is _not_ executed. For each element 515 | of `var-list` which is `nil` there's no binding to the corresponding 516 | register group. The number of variables in `var-list` must not be 517 | greater than the number of register groups. If `sharedp` is true, the 518 | substrings may share structure with `target-string`. 519 | 520 | ### scan 521 | 522 | ```lisp 523 | Function: (scan regex target-string &key start end real-start-pos) 524 | ``` 525 | Searches `target-string` from `start` to `end` and tries 526 | to match `regex`. On success returns four values - the start of the 527 | match, the end of the match, and two arrays denoting the beginnings 528 | and ends of register matches. On failure returns `nil`. `regex` can be a 529 | string which will be parsed according to Perl syntax, a parse tree, or 530 | a pre-compiled scanner created by [create-scanner](#create-scanner). `target-string` will 531 | be coerced to a simple string if it isn't one already. The 532 | `real-start-pos` parameter should be ignored - it exists only for 533 | internal purposes. 534 | 535 | 536 | ### scan-to-strings 537 | 538 | ```lisp 539 | Function: (scan-to-strings regex target-string 540 | &key (start 0) (end (length target-string)) sharedp) 541 | ``` 542 | Like `scan` but returns substrings of `target-string` instead of 543 | positions, i.e. this function returns two values on success: the whole 544 | match as a string plus an array of substrings (or `nil`s) corresponding 545 | to the matched registers. If `sharedp` is true, the substrings may 546 | share structure with `target-string`. 547 | 548 | ### split 549 | 550 | ```lisp 551 | Function: (split regex target-string 552 | &key (start 0) (end (length target-string)) 553 | limit with-registers-p omit-unmatched-p sharedp) 554 | ``` 555 | Matches `regex` against `target-string` as often as possible and 556 | returns a list of the substrings between the matches. If 557 | `with-registers-p` is true, substrings corresponding to matched 558 | registers are inserted into the list as well. If `omit-unmatched-p` is 559 | true, unmatched registers will simply be left out, otherwise they will 560 | show up as `nil`. `limit` limits the number of elements returned - 561 | registers aren't counted. If `limit` is `nil` (or 0 which is 562 | equivalent), trailing empty strings are removed from the result list. 563 | If `regex` matches an empty string the scan is continued one position 564 | behind this match. If `sharedp` is true, the substrings may share 565 | structure with `target-string`. 566 | 567 | 568 | ## CONFIGURATION VARIABLES 569 | 570 | ### \*allow-named-registers\* 571 | 572 | Whether the parser should support AllegroCL's named registers 573 | `(?"")` and back-reference \k syntax. 574 | 575 | ### \*allow-quoting\* 576 | 577 | Whether the parser should support Perl's \Q and \E. 578 | 579 | ### \*look-ahead-for-suffix\* 580 | 581 | Controls whether scanners will optimistically look ahead for a 582 | constant suffix of a regular expression, if there is one. 583 | 584 | ### \*optimize-char-classes\* 585 | 586 | Whether character classes should be compiled into look-ups into 587 | O(1) data structures. This is usually fast but will be costly in 588 | terms of scanner creation time and might be costly in terms of size if 589 | `*regex-char-code-limit*` is high. This value will be used as the `:kind` 590 | keyword argument to `create-optimized-test-function` - see there for the 591 | possible non-`NIL` values. 592 | 593 | ### \*property-resolver\* 594 | 595 | Should be `NIL` or a designator for a function which accepts strings 596 | and returns unary character test functions or `NIL`. This 'resolver' is 597 | intended to handle character properties' like \p{IsAlpha}. If 598 | `*property-resolver*` is `NIL`, then the parser will simply treat \p and 599 | \P as #\p and #\P as in older versions of CL-PPCRE. 600 | 601 | ### \*regex-char-code-limit\* 602 | 603 | The upper exclusive bound on the char-codes of characters which can 604 | occur in character classes. Change this value BEFORE creating 605 | scanners if you don't need the (full) Unicode support of 606 | implementations like AllegroCL, CLISP, LispWorks, or SBCL. 607 | 608 | ### \*use-bmh-matchers\* 609 | 610 | Whether the scanners created by [create-scanner](#create-scanner) should use the (fast 611 | but large) Boyer-Moore-Horspool matchers. 612 | 613 | 614 | 615 | ## SUPPORT 616 | 617 | The development version of cl-ppcre can be found [on 618 | github](https://github.com/edicl/cl-ppcre). Please use the github issue 619 | tracking system to submit bug reports. Patches are welcome, please use 620 | [GitHub pull requests](https://github.com/edicl/cl-ppcre/pulls). If you 621 | want to make a change, please [read this 622 | first](http://weitz.de/patches.html). 623 | -------------------------------------------------------------------------------- /docs/cl-who.md: -------------------------------------------------------------------------------- 1 | # cl-who - DSL for Markup 2 | 3 | Version: 1.1.4 4 |
5 | Nickname: who 6 |
7 | Licence: BSD 8 |
9 | Repository: [edicl/cl-who - Github](https://github.com/edicl/cl-who) 10 |
11 | See also: [awesome-cl#html-generators-and-templates](https://github.com/CodyReichert/awesome-cl#html-generators-and-templates) 12 | 13 | *This documentation is possible due to the [excellent official documentation](https://edicl.github.io/cl-who) as of 5th May 2020.* 14 | 15 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 16 | 17 | *** 18 | 19 | CL-WHO primarily provides a single macro [with-html-output](#with-html-output) to convert S-expressions intermingled with code into 20 | (X)HTML, XML and the likes. 21 | 22 | ## GETTING STARTED 23 | 24 | [with-html-output](#with-html-output) and [with-html-output-to-string](#with-html-output-to-string) 25 | are the basic macros to get going: 26 | 27 | ```lisp 28 | CL-USER> (defparameter *site-alist* 29 | '(("http://zappa.com/" . "Frank Zappa") 30 | ("http://marcusmiller.com/" . "Marcus Miller") 31 | ("http://www.milesdavis.com/" . "Miles Davis"))) 32 | *SITE-ALIST* 33 | 34 | CL-USER> (format t 35 | (with-html-output-to-string (s nil :indent t) 36 | (loop for (link . title) in *site-alist* 37 | do (htm (:a :href link 38 | (:b (str title))) ; <- note the str! 39 | :br)))) 40 | 41 | 42 | Frank Zappa 43 | 44 | 45 |
46 | 47 | Marcus Miller 48 | 49 | 50 |
51 | 52 | Miles Davis 53 | 54 | 55 |
56 | NIL 57 | 58 | CL-USER> (format t 59 | (with-output-to-string (s) 60 | (with-html-output (s s :indent t) 61 | (loop for (link . title) in *site-alist* 62 | do (htm (:a :href link 63 | (:b (str title))) ; <- note the str! 64 | :br))))) 65 | 66 | 67 | Frank Zappa 68 | 69 | 70 |
71 | 72 | Marcus Miller 73 | 74 | 75 |
76 | 77 | Miles Davis 78 | 79 | 80 |
81 | ``` 82 | 83 | Inside these macros, there exist the lexically scoped macros: 84 | 85 | - **esc** as short-hand for [escape-string](#escape-string) 86 | - **fmt** as short-hand for [cl:format](http://www.lispworks.com/documentation/lw50/CLHS/Body/f_format.htm) 87 | - **htm** as short-hand for (another) `with-html-output`. 88 | - **str** as short-hand for, well, writing to the "inner html" rather than attributes; 89 | basically the difference between these two: 90 | 91 | ```lisp 92 | CL-USER> (let ((string "hello") 93 | (class "world")) 94 | (with-html-output-to-string (s nil :indent t) 95 | (htm (:div :class class string)))) 96 | " 97 |
98 |
" 99 | CL-USER> (let ((string "hello") 100 | (class "world")) 101 | (with-html-output-to-string (s nil :indent t) 102 | (htm (:div :class class (str string))))) 103 | " 104 |
hello 105 |
" 106 | ``` 107 | 108 | In this case, `str` could equivalently be replaced by `fmt` or `esc`. 109 | 110 | Also see [html-mode](#html-mode). Detailed transformation rules are available in 111 | the [official documentation](https://edicl.github.io/cl-who/#syntax). 112 | 113 | 114 | 115 | ## CONFIGURATION VARIABLES 116 | 117 | ### \*attribute-quote-char\* 118 | 119 | ```lisp 120 | Variable 121 | ``` 122 | 123 | Quote character for attributes. 124 | 125 | ### \*downcase-tokens-p\* 126 | 127 | ```lisp 128 | Variable 129 | ``` 130 | 131 | If NIL, a keyword symbol representing a tag or attribute name will 132 | not be automatically converted to lowercase. If T, the tag and 133 | attribute name will be converted to lowercase only if it is in the 134 | same case. This is useful when one needs to output case sensitive 135 | XML. 136 | 137 | ### \*empty-attribute-syntax\* 138 | 139 | ```lisp 140 | Variable 141 | ``` 142 | 143 | Set this to `t` to enable attribute minimization (also called 144 | "boolean attributes", or "empty attribute syntax" according to the [w3 145 | html standard](https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#syntax-attr-empty)). In XHTML attribute minimization is forbidden, and all 146 | attributes must have a value. Thus in XHTML boolean attributes must be 147 | defined as . In HTML5 boolean attributes 148 | can be defined as 149 | 150 | If it is NIL the attribute will be left out completely. 151 | 152 | ``` 153 | (:td :nowrap nil) => "" 154 | ``` 155 | 156 | ### \*escape-char-p\* 157 | 158 | ```lisp 159 | Variable 160 | ``` 161 | 162 | Used by [escape-string](#escape-string) to test whether a character should be escaped. 163 | 164 | ### \*html-empty-tag-aware-p\* 165 | 166 | ```lisp 167 | Variable 168 | ``` 169 | 170 | Set this to NIL to if you want to use CL-WHO as a strict XML 171 | generator. Otherwise, CL-WHO will only write empty tags listed 172 | in [\*html-empty-tags\*](#html-empty-tags) as (XHTML mode) or (SGML 173 | mode and HTML5 mode). For all other tags, it will always generate 174 | . 175 | 176 | ### \*html-empty-tags\* 177 | 178 | ```lisp 179 | Variable 180 | ``` 181 | 182 | The list of HTML tags that should be output as empty tags. 183 | See [\*html-empty-tag-aware-p\*](#html-empty-tag-aware-p). 184 | 185 | ### \*html-no-indent-tags\* 186 | 187 | ```lisp 188 | Variable 189 | ``` 190 | 191 | The list of HTML tags that should disable indentation inside them. The initial 192 | value is a list containing only `:pre` and `:textarea`. 193 | 194 | ### \*prologue\* 195 | 196 | ```lisp 197 | Variable 198 | ``` 199 | 200 | This is the first line that'll be printed if the `:prologue` keyword 201 | argument is T 202 | 203 | ## FUNCTIONS AND MACROS 204 | 205 | ### conc 206 | 207 | ```lisp 208 | Function: (conc &rest string-list) 209 | ``` 210 | Concatenates all arguments which should be string into one string. 211 | 212 | ### convert-attributes 213 | 214 | ```lisp 215 | Function: (convert-attributes attr-list) 216 | ``` 217 | Helper function for [convert-tag-to-string-list](#convert-tag-to-string-list) which converts the 218 | alist `attr-list` of attributes into a list of strings and/or Lisp 219 | forms. 220 | 221 | ### convert-tag-to-string-list 222 | 223 | ```lisp 224 | Generic Function: (convert-tag-to-string-list tag attr-list body body-fn) 225 | ``` 226 | Used by `cl-who::process-tag` to convert `HTML` into a list 227 | of strings. `tag` is a keyword symbol naming the outer tag, `attr-list` 228 | is an alist of its attributes (the car is the attribute's name as a 229 | keyword, the cdr is its value), `body` is the tag's body, and `body-fn` is 230 | a function which should be applied to `body`. The function must return 231 | a list of strings or Lisp forms. 232 | 233 | ### esc 234 | 235 | ### escape-char 236 | 237 | ```lisp 238 | Function: (escape-char char &key (test *escape-char-p*)) 239 | ``` 240 | Returns an escaped version of the character `char` if `char` satisfies 241 | the predicate `test`. Always returns a string. 242 | 243 | ### escape-char-all 244 | 245 | ```lisp 246 | Function: (escape-char-all char) 247 | ``` 248 | Escapes characters which aren't in the 7-bit ASCII character set. 249 | 250 | ### escape-char-iso-8859-1 251 | 252 | ```lisp 253 | Function: (escape-char-iso-8859-1 char) 254 | ``` 255 | Escapes characters that aren't defined in ISO-8859-9. 256 | 257 | ### escape-char-minimal 258 | 259 | ```lisp 260 | Function: (escape-char-minimal char) 261 | ``` 262 | Escapes only #<, #>, and #& characters. 263 | 264 | ### escape-char-minimal-plus-quotes 265 | 266 | ```lisp 267 | Function: (escape-char-minimal-plus-quotes char) 268 | ``` 269 | Like [escape-char-minimal](#escape-char-minimal) but also escapes quotes. 270 | 271 | ### escape-string 272 | 273 | ```lisp 274 | Function: (escape-string string &key (test *escape-char-p*)) 275 | ``` 276 | Escape all characters in `string` which pass `test`. This function is 277 | not guaranteed to return a fresh string. Note that you can pass NIL 278 | for `string` which'll just be returned. 279 | 280 | ### escape-string-all 281 | 282 | ```lisp 283 | Function: (escape-string-all string) 284 | ``` 285 | Escapes all characters in `string` which aren't in the 7-bit ASCII 286 | character set. 287 | 288 | ### escape-string-iso-8859-1 289 | 290 | ```lisp 291 | Function: (escape-string-iso-8859-1 string) 292 | ``` 293 | Escapes all characters in `string` which aren't defined in ISO-8859-1. 294 | 295 | ### escape-string-minimal 296 | 297 | ```lisp 298 | Function: (escape-string-minimal string) 299 | ``` 300 | Escapes only #<, #>, and #& in `string`. 301 | 302 | ### escape-string-minimal-plus-quotes 303 | 304 | ```lisp 305 | Function: (escape-string-minimal-plus-quotes string) 306 | ``` 307 | Like [escape-string-minimal](#escape-string-minimal) but also escapes quotes. 308 | 309 | ### fmt 310 | 311 | ### htm 312 | 313 | ### html-mode 314 | 315 | ```lisp 316 | Function: (html-mode) 317 | ``` 318 | Returns the current HTML mode. :SGML for (SGML-)HTML, :XML for 319 | XHTML and :HTML5 for HTML5 (HTML syntax). 320 | 321 | ```lisp 322 | Function: (setf (html-mode) mode) 323 | ``` 324 | 325 | Sets the output mode to XHTML or (SGML-)HTML. MODE can be 326 | :SGML for HTML, :XML for XHTML or :HTML5 for HTML5 (HTML syntax). 327 | 328 | 329 | ### str 330 | 331 | ### with-html-output 332 | 333 | ```lisp 334 | Macro: (with-html-output (var &optional stream &rest rest &key prologue indent) &body body) 335 | ``` 336 | Transform the enclosed `body` consisting of HTML as s-expressions 337 | into Lisp code to write the corresponding HTML as strings to `var` - 338 | which should either hold a stream or which'll be bound to STREAM if 339 | supplied. 340 | 341 | ### with-html-output-to-string 342 | 343 | ```lisp 344 | Macro: (with-html-output-to-string (var &optional string-form &key prologue 345 | indent) &body body) 346 | ``` 347 | Transform the enclosed `body` consisting of HTML as s-expressions 348 | into Lisp code which creates the corresponding HTML as a string. 349 | 350 | 351 | 352 | 353 | -------------------------------------------------------------------------------- /docs/extra.css: -------------------------------------------------------------------------------- 1 | .wy-side-scroll { 2 | /* background-color:#b3d9ff; */ 3 | background:white; 4 | } 5 | 6 | .wy-menu-vertical a{ 7 | color:black; 8 | } 9 | 10 | 11 | 12 | /* .toctree-l1 .current > a.reference.internal.current{ */ 13 | /* background:#2980B9; */ 14 | /* } */ 15 | 16 | .rst-versions .rst-current-version{ 17 | background-color:#2980B9; 18 | } 19 | -------------------------------------------------------------------------------- /docs/fiveam.md: -------------------------------------------------------------------------------- 1 | # fiveam - Regression Testing Framework 2 | 3 | Version: 1.4.1 4 |
5 | Nickname: 5am 6 |
7 | Licence: BSD 8 |
9 | Repository: [sionescu/fiveam - Github](https://github.com/sionescu/fiveam) 10 |
11 | See also: [awesome-cl#unit-testing](https://github.com/CodyReichert/awesome-cl#unit-testing) 12 | 13 | *This documentation was possible due to [Tomek Kurez's tutorial on fiveam](http://turtleware.eu/posts/Tutorial-Working-with-FiveAM.html) and the [excellent official documentation](https://common-lisp.net/project/fiveam/docs/).* 14 | 15 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 16 | 17 | *** 18 | 19 | ## GETTING STARTED 20 | 21 | ### Checks and Tests 22 | 23 | A check, defined using the macro [is](#is), is a line of code that makes sure something is indeed true. A basic check definition is of the form `(is test &rest reason-args)`. 24 | 25 | However, checks can only be defined in the context of tests: 26 | 27 | ```lisp 28 | (test test-demo 29 | "This demonstrates the basic use of test and check." 30 | (is (listp (list 1 2))) 31 | (is (= 5 (+ 2 3)) "This should pass.") ; &rest reason-args 32 | (is (= 4 4.1) "~D and ~D are not = to each other." 4 4.1)) 33 | ``` 34 | 35 | To run the test, simply, call [run!](#run_1): 36 | 37 | ```lisp 38 | (run! 'test-demo) 39 | ;; Running test TEST-DEMO ..f 40 | ;; Did 3 checks. 41 | ;; Pass: 2 (66%) 42 | ;; Skip: 0 ( 0%) 43 | ;; Fail: 1 (33%) 44 | ;; 45 | ;; Failure Details: 46 | ;; -------------------------------- 47 | ;; TEST-DEMO [This demonstrates the basic use of test and check.]: 48 | ;; 4 and 4.1 are not = to each other. 49 | ;; 50 | ;; (= 4 4.1) 51 | ;; 52 | ;; was NIL.. 53 | ;; -------------------------------- 54 | ``` 55 | 56 | Tests can automatically be run on (re)compilation by setting [\*run-test-when-defined\*](#run-test-when-defined) to `t`. So, simply compiling 57 | 58 | ```lisp 59 | (test another-test (is (eq t t))) 60 | ;; 61 | ;; Running test ANOTHER-TEST . 62 | ;; Did 1 check. 63 | ;; Pass: 1 (100%) 64 | ;; Skip: 0 ( 0%) 65 | ;; Fail: 0 ( 0%) 66 | ``` 67 | 68 | runs the test. (Also see other [Configuration Variables](#configuration-variables).) 69 | 70 | `(run!)` can be called without arguments to run all the tests. 71 | 72 | ### Suites 73 | 74 | Tests can be grouped into suites. In fact, suites can also parent other suites. 75 | 76 | Suites can be defined using [def-suite](#def-suite), and similar to* `in-package`, the current 77 | suite can be specified using [in-suite](#in-suite). 78 | 79 | ```lisp 80 | (def-suite suite-one) 81 | (def-suite suite-two) 82 | 83 | (in-suite suite-one) 84 | 85 | (test first-test (is (= 1 1))) 86 | (test (second-test :suite suite-two) ; perhaps, not recommended 87 | (is (null nil))) 88 | 89 | (in-suite suite-two) 90 | 91 | (test third-test (is (eq 'done 'done))) 92 | ``` 93 | 94 | All tests can be run with [run-all-tests](#run-all-tests). Also see the arguments to [run!](#run_1). 95 | 96 | ```lisp 97 | (run-all-tests) 98 | ;; Running test suite NIL 99 | ;; Running test FIRST-TEST . 100 | ;; Running test THIRD-TEST . 101 | ;; Running test suite SUITE-TWO 102 | ;; Running test SECOND-TEST . 103 | ;; Did 3 checks. 104 | ;; Pass: 3 (100%) 105 | ;; Skip: 0 ( 0%) 106 | ;; Fail: 0 ( 0%) 107 | ``` 108 | 109 | ### More Things 110 | 111 | - Tests can be removed using [rem-test](#rem-test). 112 | - See [generators](#gen-buffer) for utilities for generating random data. These are to be used in 113 | conjunction with the [for-all](#for-all) macro. Generators are merely closures and you can 114 | define your own. 115 | - fiveam also provides the ability to [def-fixture](#def-fixture) and 116 | [with-fixture](#with-fixture); however, (as of 2016) it is [recommended to just use macros 117 | instead](https://github.com/sionescu/fiveam/issues/31). 118 | - The [signals](#signals) macro can be used to check if conditions are signalled appropriately. 119 | 120 | 121 | 122 | ## CONFIGURATION VARIABLES 123 | 124 | ### \*debug-on-error\* 125 | 126 | T if we should drop into the debugger on error, NIL otherwise. 127 | OBSOLETE: superseded by \*ON-ERROR\* 128 | 129 | ### \*debug-on-failure\* 130 | 131 | T if we should drop into the debugger on a failing check, NIL otherwise. 132 | OBSOLETE: superseded by \*ON-FAILURE\* 133 | 134 | ### \*default-test-compilation-time\* 135 | 136 | ### \*max-trials\* 137 | 138 | Number of total times we attempt to run the body of the 139 | FOR-ALL test including when the body is skipped due to failed 140 | guard conditions. 141 | 142 | Since we have guard conditions we may get into infinite loops 143 | where the test code is never run due to the guards never 144 | returning true. This second run limit prevents that. 145 | 146 | ### \*num-trials\* 147 | 148 | Number of times we attempt to run the body of the FOR-ALL test. 149 | 150 | ### \*on-error\* 151 | 152 | The action to perform on error: 153 | - :DEBUG if we should drop into the debugger 154 | - :BACKTRACE to print a backtrace 155 | - NIL to simply continue 156 | 157 | ### \*on-failure\* 158 | 159 | The action to perform on check failure: 160 | - :DEBUG if we should drop into the debugger 161 | - :BACKTRACE to print a backtrace 162 | - NIL to simply continue 163 | 164 | ### \*print-names\* 165 | 166 | T if we should print test running progress, NIL otherwise. 167 | 168 | ### \*run-test-when-defined\* 169 | 170 | When non-NIL tests are run as soon as they are defined. 171 | 172 | ### \*test-dribble\* 173 | 174 | ### \*verbose-failures\* 175 | 176 | T if we should print the expression failing, NIL otherwise. 177 | 178 | 179 | ## FUNCTIONS AND MACROS 180 | 181 | 182 | 183 | ### ! 184 | 185 | ```lisp 186 | Function: (!) 187 | ``` 188 | Rerun the most recently run test and explain the results. 189 | 190 | ### !! 191 | 192 | ```lisp 193 | Function: (!!) 194 | ``` 195 | Rerun the second most recently run test and explain the results. 196 | 197 | ### !!! 198 | 199 | ```lisp 200 | Function: (!!!) 201 | ``` 202 | Rerun the third most recently run test and explain the results. 203 | 204 | ### debug! 205 | 206 | ```lisp 207 | Function: (debug! &optional (test-spec *suite*)) 208 | ``` 209 | Calls (run! test-spec) but enters the debugger if any kind of error happens. 210 | 211 | ### def-fixture 212 | 213 | ```lisp 214 | Macro: (def-fixture name (&rest args) &body body) 215 | ``` 216 | Defines a fixture named NAME. A fixture is very much like a 217 | macro but is used only for simple templating. A fixture created 218 | with DEF-FIXTURE is a macro which can use the special macrolet 219 | &BODY to specify where the body should go. 220 | 221 | See Also: [WITH-FIXTURE](#with-fixture). 222 | 223 | 224 | ### def-suite 225 | 226 | ```lisp 227 | Macro: (def-suite name &key description in) 228 | ``` 229 | Define a new test-suite named NAME. 230 | 231 | IN (a symbol), if provided, causes this suite te be nested in the 232 | suite named by IN. NB: This macro is built on top of make-suite, 233 | as such it, like make-suite, will overrwrite any existing suite 234 | named NAME. 235 | 236 | ### def-suite\* 237 | 238 | ```lisp 239 | Macro: (def-suite* name &rest def-suite-args) 240 | ``` 241 | 242 | ### def-test 243 | 244 | ```lisp 245 | Macro: (def-test name (&key depends-on (suite) fixture (compile-at) profile) &body body) 246 | ``` 247 | Create a test named NAME. 248 | 249 | NAME is the symbol which names the test. 250 | 251 | DEPENDS-ON is a list of the form: 252 | 253 | (AND . test-names) - This test is run only if all of the tests 254 | in TEST-NAMES have passed, otherwise a single test-skipped 255 | result is generated. 256 | 257 | (OR . test-names) - If any of TEST-NAMES has passed this test is 258 | run, otherwise a test-skipped result is generated. 259 | 260 | (NOT test-name) - This is test is run only if TEST-NAME failed. 261 | 262 | AND, OR and NOT can be combined to produce complex dependencies. 263 | 264 | If DEPENDS-ON is a symbol it is interpreted as `(AND 265 | ,depends-on), this is accomadate the common case of one test 266 | depending on another. 267 | 268 | FIXTURE specifies a fixture to wrap the body in. 269 | 270 | If PROFILE is T profiling information will be collected as well. 271 | 272 | ### explain! 273 | 274 | ```lisp 275 | Function: (explain! result-list) 276 | ``` 277 | Explain the results of RESULT-LIST using a 278 | detailed-text-explainer with output going to *test-dribble*. 279 | Return a boolean indicating whether no tests failed. 280 | 281 | ### fail 282 | 283 | ```lisp 284 | Macro: (fail &rest message-args) 285 | ``` 286 | Simply generate a FAIL. 287 | 288 | ### finishes 289 | 290 | ```lisp 291 | Macro: (finishes &body body) 292 | ``` 293 | Generates a pass if BODY executes to normal completion. In 294 | other words if body does signal, return-from or throw this test 295 | fails. 296 | 297 | ### for-all 298 | 299 | ```lisp 300 | Macro: (for-all bindings &body body) 301 | ``` 302 | Bind `BINDINGS` to random variables and test `BODY` *num-trials* times. 303 | 304 | `BINDINGS` is a list of binding forms, each element is a list 305 | of `(BINDING VALUE &optional GUARD)`. Value, which is evaluated 306 | once when the for-all is evaluated, must return a generator which 307 | be called each time `BODY` is evaluated. `BINDING` is either a symbol 308 | or a list which will be passed to destructuring-bind. `GUARD` is a 309 | form which, if present, stops `BODY` from executing when `IT` returns 310 | NIL. The GUARDS are evaluated after all the random data has been 311 | generated and they can refer to the current value of any 312 | binding. NB: Generator forms, unlike guard forms, can not contain 313 | references to the bound variables. 314 | 315 | Examples: 316 | 317 | ```lisp 318 | (for-all ((a (gen-integer))) 319 | (is (integerp a))) 320 | 321 | (for-all ((a (gen-integer) (plusp a))) 322 | (is (integerp a)) 323 | (is (plusp a))) 324 | 325 | (for-all ((less (gen-integer)) 326 | (more (gen-integer) (< less more))) 327 | (is (<= less more))) 328 | 329 | (for-all (((a b) (gen-two-integers))) 330 | (is (integerp a)) 331 | (is (integerp b))) 332 | ``` 333 | 334 | ### gen-buffer 335 | 336 | ```lisp 337 | Function: (gen-buffer &key 338 | (length (gen-integer min 0 max 50)) 339 | (element-type '(unsigned-byte 8)) 340 | (elements (gen-integer :min 0 :max (1- (expt 2 8))))) 341 | ``` 342 | 343 | ### gen-character 344 | 345 | ```lisp 346 | Function: (gen-character &key 347 | (code-limit char-code-limit) 348 | (code (gen-integer :min 0 :max (1- code-limit))) 349 | (alphanumericp nil)) 350 | ``` 351 | Returns a generator of characters. 352 | 353 | CODE must be a generator of random integers. ALPHANUMERICP, if 354 | non-NIL, limits the returned chars to those which pass 355 | alphanumericp. 356 | 357 | ### gen-float 358 | 359 | ```lisp 360 | Function: (gen-float &key bound (type 'short-float)) 361 | ``` 362 | Returns a generator which produces floats of type TYPE. BOUND, 363 | if specified, constrains the results to be in the range (-BOUND, 364 | BOUND). 365 | 366 | ### gen-integer 367 | 368 | ```lisp 369 | Function: (gen-integer &key 370 | (max (1+ most-positive-fixnum)) 371 | (min (1- most-negative-fixnum))) 372 | ``` 373 | Returns a generator which produces random integers greater 374 | than or equal to MIN and less than or equal to MAX. 375 | 376 | ### gen-list 377 | 378 | ```lisp 379 | Function: (gen-list &key 380 | (length (gen-integer :min 0 :max 10)) 381 | (elements (gen-integer :min -10 :max 10))) 382 | ``` 383 | Returns a generator which produces random lists. LENGTH must be 384 | an integer generator and ELEMENTS must be a generator which 385 | produces objects. 386 | 387 | ### gen-one-element 388 | 389 | ```lisp 390 | Function: (gen-one-element &rest elements) 391 | ``` 392 | 393 | ### gen-string 394 | 395 | ```lisp 396 | 397 | Function: (gen-string &key 398 | (length (gen-integer :min 0 :max 80)) 399 | (elements (gen-character)) 400 | (element-type 'character)) 401 | ``` 402 | Returns a generator which produces random strings. LENGTH must 403 | be a generator which produces integers, ELEMENTS must be a 404 | generator which produces characters of type ELEMENT-TYPE. 405 | 406 | ### gen-tree 407 | 408 | ```lisp 409 | Function: (gen-tree &key (size 20) (elements (gen-integer :min -10 :max 10))) 410 | ``` 411 | Returns a generator which produces random trees. SIZE controls 412 | the approximate size of the tree, but don't try anything above 413 | 30, you have been warned. ELEMENTS must be a generator which 414 | will produce the elements. 415 | 416 | ### get-fixture 417 | 418 | ```lisp 419 | Function: (get-fixture key &optional default) 420 | ``` 421 | 422 | ### get-test 423 | 424 | ```lisp 425 | Function: (get-test key &optional default) 426 | ``` 427 | 428 | ### in-suite 429 | 430 | ```lisp 431 | Macro: (in-suite suite-name) 432 | ``` 433 | Set the *suite* special variable so that all tests defined 434 | after the execution of this form are, unless specified otherwise, 435 | in the test-suite named SUITE-NAME. 436 | 437 | See also: DEF-SUITE *SUITE* 438 | 439 | ### in-suite\* 440 | 441 | ```lisp 442 | Macro: (in-suite* suite-name &key in) 443 | ``` 444 | Just like in-suite, but silently creates missing suites. 445 | 446 | ### is 447 | 448 | ```lisp 449 | Macro: (is test &rest reason-args) 450 | ``` 451 | The DWIM checking operator. 452 | 453 | If TEST returns a true value a test-passed result is generated, 454 | otherwise a test-failure result is generated. The reason, unless 455 | REASON-ARGS is provided, is generated based on the form of TEST: 456 | 457 | (predicate expected actual) - Means that we want to check 458 | whether, according to PREDICATE, the ACTUAL value is 459 | in fact what we EXPECTED. 460 | 461 | (predicate value) - Means that we want to ensure that VALUE 462 | satisfies PREDICATE. 463 | 464 | Wrapping the TEST form in a NOT simply produces a negated reason 465 | string. 466 | 467 | ### is-every 468 | 469 | ```lisp 470 | Macro: (is-every predicate &body clauses) 471 | ``` 472 | The input is either a list of lists, or a list of pairs. Generates (is (,predicate ,expr ,value)) 473 | for each pair of elements or (is (,predicate ,expr ,value) ,@reason) for each list. 474 | 475 | ### is-false 476 | 477 | ```lisp 478 | Macro: (is-false condition &rest reason-args) 479 | ``` 480 | Generates a pass if CONDITION returns false, generates a 481 | failure otherwise. Like IS-TRUE, and unlike IS, IS-FALSE does 482 | not inspect CONDITION to determine what reason to give it case 483 | of test failure 484 | 485 | ### is-true 486 | 487 | ```lisp 488 | Macro: (is-true condition &rest reason-args) 489 | ``` 490 | Like IS this check generates a pass if CONDITION returns true 491 | and a failure if CONDITION returns false. Unlike IS this check 492 | does not inspect CONDITION to determine how to report the 493 | failure. 494 | 495 | ### make-fixture 496 | 497 | ### make-suite 498 | 499 | ```lisp 500 | Function: (make-suite name &key description ((in parent-suite))) 501 | ``` 502 | Create a new test suite object. 503 | 504 | Overrides any existing suite named NAME. 505 | 506 | ### make-test 507 | 508 | ### pass 509 | 510 | ```lisp 511 | Macro: (pass &rest message-args) 512 | ``` 513 | Simply generate a PASS. 514 | 515 | ### rem-fixture 516 | 517 | ```lisp 518 | Function: (rem-fixture key) 519 | ``` 520 | 521 | ### rem-test 522 | 523 | ```lisp 524 | Function: (rem-test key) 525 | ``` 526 | 527 | ### results-status 528 | 529 | ```lisp 530 | Function: (results-status result-list) 531 | ``` 532 | Given a list of test results (generated while running a test) 533 | return true if no results are of type TEST-FAILURE. Returns second 534 | and third values, which are the set of failed tests and skipped 535 | tests respectively. 536 | 537 | ### run 538 | 539 | ```lisp 540 | Function: (run test-spec &key (print-names *print-names*)) 541 | ``` 542 | Run the test specified by TEST-SPEC. 543 | 544 | TEST-SPEC can be either a symbol naming a test or test suite, or 545 | a testable-object object. This function changes the operations 546 | performed by the !, !! and !!! functions. 547 | 548 | ### run! 549 | 550 | ```lisp 551 | Function: (run! &optional (test-spec *suite*) 552 | &key (print-names *print-names*)) 553 | ``` 554 | 555 | Equivalent to (explain! (run TEST-SPEC)). 556 | 557 | ### run-all-tests 558 | 559 | ```lisp 560 | Function: (run-all-tests &key (summary :end)) 561 | ``` 562 | Runs all defined test suites, T if all tests passed and NIL otherwise. 563 | SUMMARY can be :END to print a summary at the end, :SUITE to print it 564 | after each suite or NIL to skip explanations. 565 | 566 | ### signals 567 | 568 | ```lisp 569 | Macro: (signals condition-spec &body body) 570 | ``` 571 | Generates a pass if BODY signals a condition of type 572 | CONDITION. BODY is evaluated in a block named NIL, CONDITION is 573 | not evaluated. 574 | 575 | ### skip 576 | 577 | ```lisp 578 | Macro: (skip &rest reason) 579 | ``` 580 | Generates a TEST-SKIPPED result. 581 | 582 | ### test 583 | 584 | ```lisp 585 | Macro: (test name &body body) 586 | ``` 587 | Create a test named NAME. If NAME is a list it must be of the 588 | form: 589 | 590 | ```lisp 591 | (name &key depends-on suite fixture compile-at profile) 592 | ``` 593 | 594 | NAME is the symbol which names the test. 595 | 596 | DEPENDS-ON is a list of the form: 597 | 598 | - (AND . test-names) - This test is run only if all of the tests 599 | in TEST-NAMES have passed, otherwise a single test-skipped 600 | result is generated. 601 | 602 | - (OR . test-names) - If any of TEST-NAMES has passed this test is 603 | run, otherwise a test-skipped result is generated. 604 | 605 | - (NOT test-name) - This is test is run only if TEST-NAME failed. 606 | 607 | AND, OR and NOT can be combined to produce complex dependencies. 608 | 609 | If DEPENDS-ON is a symbol it is interpreted as `(AND 610 | ,depends-on), this is accomadate the common case of one test 611 | depending on another. 612 | 613 | FIXTURE specifies a fixture to wrap the body in. 614 | 615 | If PROFILE is T profiling information will be collected as well. 616 | 617 | ### test-names 618 | 619 | ```lisp 620 | Function: (test-names) 621 | ``` 622 | 623 | ### with-fixture 624 | 625 | ```lisp 626 | Macro: (with-fixture fixture-name (&rest args) &body body) 627 | ``` 628 | Insert BODY into the fixture named FIXTURE-NAME. 629 | 630 | See Also: [DEF-FIXTURE](#def-fixture). 631 | 632 | 633 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # common-lisp-libraries.readthedocs.io 2 | 3 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 4 | 5 | *See the [html version of this page](https://common-lisp-libraries.readthedocs.io), rather than the markdown version for the working links below.* 6 | 7 | --- 8 | 9 | ## Introduction 10 | 11 | Common Lisp documentation - libraries or the HyperSpec - isn't known to be particularly "modern" or "attractive". While those terms are subjective, ease of introduction to a technology does seem to have *some* objective component to it. 12 | 13 | 14 | ## Libraries 15 | 16 | ### Installation 17 | 18 | Each of the below libraries (except asdf and quicklisp) can be installed using quicklisp: 19 | 20 | ```lisp 21 | (ql:quickload "alexandria") ; for example 22 | ``` 23 | See [quicklisp - Getting Started](./quicklisp/#getting-started) for instructions on 24 | installing quicklisp. 25 | 26 | You may want to use a local nickname when importing a package which is possible in ASDF/UIOP since version 3.3.4.3. 27 | You can either check `uiop:*uiop-version*` or `(uiop:featurep :package-local-nicknames)`. 28 | See [adding package local nicknames](https://lispcookbook.github.io/cl-cookbook/packages.html#package-local-nicknames-pln) for details. 29 | 30 | ```lisp 31 | (uiop:add-package-local-nickname #:a #:alexandria) 32 | ; OR 33 | (defpackage my-package 34 | (:use #:cl) 35 | (:local-nicknames (#:a #:alexandria))) 36 | ``` 37 | 38 | ### Libraries documented so far 39 | 40 | The below list of libraries is not even the *complete list of defacto libraries*. Many more awesome Common Lisp libraries are available at [awesome-cl](https://github.com/CodyReichert/awesome-cl). 41 | 42 | #### Defacto libraries 43 | 44 | - [asdf](./asdf/) - build system for softwares (packages*) 45 | - [alexandria](./alexandria/) - a utility library 46 | - [bordeaux-threads](./bordeaux-threads/) - library for threading 47 | - [cl-ppcre](./cl-ppcre/) - regular expressions 48 | - [cl-who](./cl-who/) - DSL for Markup 49 | - [hunchentoot](./hunchentoot/) - web server 50 | - [fiveam](./fiveam/) - regression testing framework 51 | - [iterate](./iterate/) - a lispy extensible alternative to `loop` 52 | - [local-time](./local-time/) - date and time manipulation 53 | - [postmodern](./postmodern/) - PostgreSQL programming interace 54 | - [quicklisp](./quicklisp/) - library manager 55 | - [usocket](./usocket) - universal socket library 56 | - [utilities](./utilities/) - a collection of utility libraries 57 | 58 | #### Not yet defacto 59 | 60 | - [numcl](./numcl/) - lispy clone of numpy 61 | - [unix-opts](./unix-opts/) - minimalistic command line options parser 62 | 63 | 64 | \*What one might call packages in other languages are called systems in Common Lisp parlance. Instead, the word `package` in Common Lisp refers to a data structure providing namespacing 65 | for symbols. By contrast, a system is a tool to organize a bunch of files, in accordance with dependencies, and specifying how to perform certain actions on the system. A single system may contain multiple packages. See [this StackOverFlow answer](https://stackoverflow.com/questions/45642330/why-do-many-common-lisp-systems-use-a-single-packages-lisp-file/45643829#45643829) for a detailed discussion. 66 | 67 | ## Previous Efforts 68 | 69 | Documentation efforts have been made at: 70 | 71 | - [Quickdocs](http://quickdocs.org/): While it was up, I didn't particularly like the layout. I want the API at a glance! This can improve! But don't look at me. I'm also not very at ease with full automation without human intervention. As of December 2020, this is down though. 72 | 73 | - [Quickref](http://quickref.common-lisp.net/): Frankly, this is just too much. As a user, all I want to know is "What can this library do? And, how do I do it? (What functions, macros or anything is available?)" Therefore, for a user, the only good place I found was the Packages section here. It is, after all, a Reference Manual. Another excuse is, again, that I do want human intervention in documentation. 74 | 75 | - [common-lisp.net](http://common-lisp.net/): Ultimately, this is the place for most everything Common Lisp. And indeed, most of the work here is based on the official documentation. An attempt is made to "simplify" wherever need is felt. 76 | 77 | - [CLiki](http://cliki.net/): Again, layout and "at a glance"! 78 | 79 | - [UltraSpec]: I liked this. The only trouble? It isn't "quick" to build upon. 80 | 81 | - [MiniSpec](https://lamberta.github.io/minispec/): This looks like a work-in-progress-but-active perhaps-smaller version of UltraSpec. And for the parts that are done, I find this vastly better than CLHS in terms of looks and accessibility. 82 | 83 | ## UltraSpec 84 | 85 | I liked (the theme of) [UltraSpec]. I also liked [mkdocs](https://www.mkdocs.org/) - I am using mkdocs with the pre-provided [readthedocs](https://readthedocs.org/) theme. What UltraSpec seems to be good for is larger websites than what is currently here, in that it isn't as straightforward as mkdocs for library-documenters to use it. 86 | 87 | Additionally, `markdown` files and `dokuwiki` files (the format UltraSpec requires) are interconvertible (but the compatibility is untested) using [pandoc](https://pandoc.org/). (pandoc is indeed useful for a ton of other file formats!) 88 | 89 | ## mkdocs 90 | 91 | As a marketing for mkdocs: [mkdocs](https://www.mkdocs.org/#getting-started) is as simple as 92 | 93 | - `pip install mkdocs # or conda` 94 | - create a .yml configuration file (or copy and edit!) 95 | - put your markdown files inside docs/ directory (or as mentioned in the .yml file) 96 | - `mkdocs gh-deploy`# to deploy on github-pages 97 | 98 | Done! 99 | 100 | *PS: Regardless of the justifications, all I wanted was a documentation site with a "sidebar" that, both, tells the page at glance, and is easy to navigate.* 101 | 102 | 103 | [ultraspec]: https://phoe.tymoon.eu/clus/doku.php 104 | -------------------------------------------------------------------------------- /docs/iterate.md: -------------------------------------------------------------------------------- 1 | # iterate - Psuedocodic Iteration 2 | 3 | Version: 1.5 4 |
5 | Licence: MIT 6 |
7 | Repository: [iterate/iterate - Gitlab](https://gitlab.common-lisp.net/iterate/iterate) 8 |
9 | See also: [awesome-cl#iteration](https://github.com/CodyReichert/awesome-cl#iteration) 10 | 11 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/digikar99/common-lisp.readthedocs/issues).* 12 | 13 | *** 14 | 15 | `iterate` is a powerful iteration facility for Common Lisp, and a alternative to `loop`. As opposed to `loop`, `iterate` is more lispy, extensible, besides being more powerful. 16 | 17 | See [The Iterate Manual] for a more detailed explanation of the various facilities. 18 | 19 | For a tutorial on looping in Common Lisp, check out [Loops, Iterate and Mapping - The Common Lisp Cookbook](http://lispcookbook.github.io/cl-cookbook/iteration.html). 20 | 21 | ## HIGHLIGHTS 22 | 23 | - [def*](#defclause-sequence): extensibility 24 | - [display-iterate-clauses](#display-iterate-clauses): quick help for clauses 25 | - [dsetq](#dsetq): for use outside the `iter` form 26 | - [finally-protected](#finally-protected): for protecting against unwindings 27 | - [finding-maximizing](#finding): `loop` equivalent can be quite verbose 28 | - [for](#for): lots of variants! 29 | - [generate](#generate) 30 | - [in](#in): `loop` equivalent can be quite verbose 31 | - there's no support for "true" parallel assignment - see [with](#with) 32 | 33 | ## OTHER POINTS 34 | 35 | - `iterate` does not declare variables unless asked to. See [Types and Declarations]. 36 | - `into `*`var`* stores the value into *`var`* instead of returning it. 37 | - There, probably, are some idiosyncrasies involved with running the epilogue code - it is not run "always": `always`, `finding`, `finish`, `thereis`. 38 | 39 | 40 | ### Notes for myself - indications of incomplete documentation 41 | 42 | - Documentation for `finding` is incomplete here. 43 | - Documentation for `def*`, `for` has been omitted here. 44 | - When are the variable values for prologue defined? 45 | - Will there be future versions of iterate? What is the compatibility relation between `terminate` and `finish` for `for-next` [Generalized Drivers]? 46 | 47 | ### Installation 48 | 49 | If `quicklisp` is set-up, simply `(ql:quickload 'iterate)`. 50 | 51 | Otherwise [head over here](https://common-lisp.net/project/iterate/index.html). 52 | 53 | ### Accumulation vs Reduction 54 | 55 | The differences between accumulate and reducing are slight. One difference is that the functions take their arguments in a different order. Another is that in the absence of init-val, accumulate will use nil, whereas reducing will generate different code that avoids any dependence on the initial value. The reason for having both clauses is that one usually thinks of reductions (like sum) and accumulations (like collect) as different beasts. 56 | 57 | 58 | ## API (CLAUSE) REFERENCE 59 | 60 | ### accumulate 61 | `accumulate `*`expr`*` by `*`func`*` &optional initial-value `*`init-val`*` into `*`var`* 62 | 63 | This is a general-purpose accumulation clause. func should be a function of two arguments, the value of expr and the value accumulated so far in the iteration, and it should return the updated value. If no initial value is supplied, nil is used. 64 | 65 | 66 | ```lisp 67 | CL-USER> (iter (for i in '(1 2 3)) 68 | (accumulate i by 69 | (lambda (i values-so-far) 70 | (cons i values-so-far)))) 71 | (3 2 1) 72 | CL-USER> (iter (for i in '(1 2 3)) 73 | (accumulate i by 74 | (lambda (i values-so-far) 75 | (cons i values-so-far)) 76 | initial-value '(init))) 77 | (3 2 1 INIT) 78 | CL-USER> (iter (for i in '(1 2 3)) 79 | (accumulate i by 80 | (lambda (i values-so-far) 81 | (cons i values-so-far)) 82 | initial-value '(init) into var)) 83 | NIL 84 | ``` 85 | 86 | 87 | See [Accumulations], [Accumulation vs Reduction](#accumulation-vs-reduction) and [reducing](#reducing). 88 | 89 | 90 | ### accumulating 91 | An alias for [accumulate](#accumulate). 92 | 93 | ### adjoining 94 | `adjoining `*`exptr`*` &optional into `*`var`*` test `*`test`*` at `*`place`*` result-type `*`type`* 95 | 96 | Like [collect], but only adds the value of exptr if it is not already present. test, which defaults to #'eql, is the test to be used with member. 97 | 98 | ### after-each 99 | `after-each &rest `*`forms`* 100 | 101 | Executes forms at the end of the loop body, after each iteration. Forms may contain iterate clauses. 102 | ```lisp 103 | CL-USER> (iter (for i below 4) 104 | (after-each (print var)) 105 | (if (oddp i) 106 | (collect i into var) 107 | (collect (* 2 i) into var))) 108 | 109 | ; (0) 110 | ; (0 1) 111 | ; (0 1 4) 112 | ; (0 1 4 3) 113 | NIL 114 | ``` 115 | See [Code Placement] and [Problems with Code Movement]. 116 | 117 | ### always 118 | `always `*`expr`* 119 | ```lisp 120 | CL-USER> (iter (for i below 4) (always (evenp i))) 121 | NIL 122 | ``` 123 | - If expr ever evaluates to nil, then nil is immediately returned; the epilogue code is not executed. 124 | - If expr never evaluates to nil, the epilogue code is executed and the last value of expr (or t if expr was never evaluated) is returned (whereas loop would constantly return t). 125 | 126 | See [Aggregated Boolean Tests]. 127 | 128 | ### appending 129 | `appending `*`exptr`*` &optional into `*`var`*` at `*`place`* 130 | Like [collect], but behaves like the Common Lisp `append`, and works only on lists. 131 | ```lisp 132 | CL-USER> (iter (for i in '((1) (2 3) (4 5 6))) 133 | (appending i)) 134 | (1 2 3 4 5 6) 135 | CL-USER> (iter (for i in '((1) (2 3) (4 5 6))) 136 | (appending i into var)) 137 | NIL 138 | ``` 139 | See [Accumulations]. 140 | 141 | ### as 142 | An alias for [for](#for). 143 | 144 | ### collect 145 | `collect `*`exptr`*` &optional into `*`var`*` test `*`test`*` at `*`place`*` result-type `*`type`* 146 | ```lisp 147 | CL-USER> (iter (for i from 1 to 5) 148 | (collect i)) 149 | (1 2 3 4 5) 150 | CL-USER> (iter (for i from 1 to 5) 151 | (collect i at start)) ;; likely to be faster 152 | (5 4 3 2 1) 153 | ``` 154 | - `place` can be either `beginning`/`start` or `end`: default value is `end`. 155 | - `type` should be a subtype of `sequence` - default is `list`; however, the type of sequence being constructed inside the loop is undefined when a non-list type is specified. 156 | 157 | ```lisp 158 | CL-USER> (iter (for i from 1 to 3) 159 | (collect i into vec result-type 'vector) 160 | (print vec) 161 | (finally (return vec))) 162 | 163 | ; (1) 164 | ; (1 2) 165 | ; (1 2 3) 166 | #(1 2 3) 167 | ``` 168 | - `type` or `place` may be optionally quoted. 169 | 170 | See [Accumulations]. 171 | 172 | ### collecting 173 | Alias for [collect]. 174 | 175 | ### count 176 | Alias for [counting](#counting). 177 | 178 | This, probably, overrides the CL `count` when used in top-level inside an iterate loop. 179 | ```lisp 180 | CL-USER> (iter (for i in '(1 2 3)) 181 | (finally (return (count 1 '(1 2 1))))) 182 | 2 183 | ``` 184 | 185 | ### counting 186 | `counting `*`expr`*` &optional into `*`var`* 187 | 188 | See [Reductions] and [accumulate]. 189 | 190 | ### declare-variables 191 | `(declare (declare-variables))` 192 | 193 | - iterate does not declare variable types unless asked to. 194 | - Declaration of types of user introduced symbols can be done by either the usual Common Lisp `declare`, but this declaration should be inside the iter form. 195 | - Declaration of internal variables or use of `the` requires one to use `declare-variables`, or set `iterate:::*always-declare-variables* to `t`. 196 | 197 | ```lisp 198 | CL-USER> (macroexpand-1 '(iter (for (the fixnum el) in '(1 2 3)) 199 | (declare (DECLARE-VARIABLES)) 200 | (count (oddp el)))) 201 | ;; note that this produces a type declaration for el. 202 | CL-USER> (macroexpand-1 '(iter (for el in '(1 2 3)) 203 | (declare (DECLARE-VARIABLES)) 204 | (count (oddp el)))) 205 | ;; this does not produce a type declaration for el. 206 | CL-USER> (macroexpand-1 '(iter (for (the fixnum el) in '(1 2 3)) 207 | (count (oddp el)))) 208 | ;; this does not produce any declarations. 209 | ``` 210 | See [Types and Declarations]. 211 | 212 | ### defclause-sequence 213 | [Undocumented here.] 214 | 215 | See [Extensibility Aids]. 216 | 217 | ### defmacro-clause 218 | [Undocumented here] 219 | 220 | See [Rolling Your Own]. 221 | 222 | ### defmacro-driver 223 | [Undocumented here.] 224 | 225 | See [Writing Drivers]. 226 | 227 | ### defsynonym 228 | [Undocumented here.] 229 | 230 | See [Extensibility Aids]. 231 | 232 | ### display-iterate-clauses 233 | `display-iterate-clauses &optional `*`clause-spec`* 234 | 235 | ```lisp 236 | CL-USER> (display-iterate-clauses 'repeat) 237 | ; REPEAT Repeat the loop some number of times 238 | T 239 | CL-USER> (display-iterate-clauses '(for in-vector)) 240 | ; FOR IN-VECTOR &OPTIONAL FROM UPFROM DOWNFROM TO DOWNTO ABOVE BELOW BY 241 | ; WITH-INDEX Elements of a vector 242 | T 243 | ``` 244 | 245 | See [On-line help]. 246 | 247 | ### dsetq 248 | `dsetq`*` template expr`* 249 | 250 | Can be used outside iter. 251 | ```lisp 252 | CL-USER> (foo) 253 | FIRST 254 | SECOND 255 | CL-USER> (progn 256 | (dsetq (values a b) (foo)) 257 | (list a b)) ;; undeclared variables warning 258 | (FIRST SECOND) 259 | ``` 260 | See [Destructuring]. 261 | 262 | ### else 263 | `else &rest `*`forms`* 264 | 265 | Forms are executed if loop is never entered, but is terminated normally. 266 | ```lisp 267 | CL-USER> (iter (for i in '(1 2 3)) (while nil) 268 | (else (write 'else))) 269 | ; ELSE 270 | NIL 271 | ``` 272 | See [Code Placement] and [Problems with Code Movement]. 273 | 274 | ### finally 275 | `finally &rest `*`forms`* 276 | 277 | Forms are executed after a normal termination of the loop. 278 | ```lisp 279 | CL-USER> (iter (for i in '(1 2 3)) (finally (write 'end))) 280 | ; END 281 | NIL 282 | ``` 283 | See [Code Placement] and [Problems with Code Movement]. 284 | 285 | ### finally-protected 286 | `finally-protected &rest `*`forms`* 287 | 288 | Forms are executed "always" - regardless of whether the termination was notmal 289 | ```lisp 290 | CL-USER> (iter (for i in-vector '(1 2 3)) 291 | (finally-protected (write 'error))) 292 | ;; warnings 293 | ERROR ; Evaluation aborted on #. 294 | CL-USER> (iter (for i in '(1 2 3)) 295 | (finally-protected (write 'no-error))) 296 | ; NO-ERROR 297 | NIL 298 | ``` 299 | See [Code Placement] and [Problems with Code Movement]. 300 | 301 | ### finding 302 | `finding `*`expr`*` such-that `*`test`*` &optionally into `*`var`*` on-failure `*`failure-value`* 303 | 304 | - The loop terminates (with epilogue code) whenever *`test`* evaluates to non-`nil`. 305 | - *`expr`* that satifies the *`test`*, or *`failure-value`*, or `nil` is returned (unless modified by epilogue). 306 | - *`failure-value`* is always evaluated. 307 | 308 | ```lisp 309 | CL-USER> (iter (for x in '(1 2 3)) 310 | (finding x such-that #'evenp on-failure 'not-found)) 311 | 2 312 | CL-USER> (iter (for x in '(1 2 3)) 313 | (finding x such-that #'evenp on-failure (error "not found"))) 314 | ; Evaluation aborted on #. 315 | CL-USER> (iter (for x in '(1 2 3)) 316 | (if (evenp x) (leave x)) 317 | (finally (error "not found"))) 318 | 2 319 | ``` 320 | 321 | `finding `*`expr`*` maximizing `*`m-expr`*` &optionally into `*`var`* 322 | 323 | `finding `*`expr`*` minimizing `*`m-expr`*` &optionally into `*`var`* 324 | 325 | - Returns *`expr`* corresponding to the maximum value of *`m-expr`*. 326 | - If *`m-expr`* is never evaluated (how?), the return value is `nil` or `0` depending on the type (or its absence) of *`expr`* (or *`var`* if supplied.) 327 | - Here, *`m-expr`* can also be a list of two symbols. 328 | 329 | ```lisp 330 | CL-USER> CL-USER> (iter (for list in '((1) (2 3) nil)) 331 | (finding list maximizing (length list))) 332 | (2 3) 333 | CL-USER> (iter (for i in '(1 2 3)) 334 | (finding (* 2 i) maximizing (- i) into (twice neg)) 335 | (finally (return (values twice neg)))) 336 | 2 337 | -1 338 | ``` 339 | [Example required for the case when *`m-expr`* is not evaluated.] 340 | 341 | See [Finders]. 342 | 343 | 344 | ### finish 345 | `finish` 346 | 347 | Stop the loop (and run the epilogue code). 348 | ```lisp 349 | CL-USER> (iter (for i in '(1 2 3)) (if (evenp i) (finish))) 350 | NIL 351 | ``` 352 | 353 | See [Control Flow]. 354 | 355 | ### first-iteration-p 356 | `first-iteration-p` 357 | 358 | `t` in the first cycle of the loop, otherwise `nil`. 359 | ```lisp 360 | CL-USER> (iter (for el in '(nil 1 2 nil 3)) 361 | (when el 362 | (unless (first-iteration-p) 363 | (princ ", ")) 364 | (princ el))) 365 | ; , 1, 2, 3 366 | NIL 367 | ``` 368 | See [Boolean Tests]. 369 | 370 | ### first-time-p 371 | `first-iteration-p` 372 | 373 | `t` only when the expression is evaluated for the first time. 374 | ```lisp 375 | CL-USER> (iter (for el in '(nil 1 2 nil 3)) 376 | (when el 377 | (unless (first-time-p) 378 | (princ ", ")) 379 | (princ el))) 380 | ; 1, 2, 3 381 | NIL 382 | ``` 383 | See [Boolean Tests]. 384 | 385 | ### for 386 | [Undocumented here.] 387 | 388 | See 389 | 390 | - [Numeric Iteration] 391 | - [Sequence Iteration] 392 | - [Variable Binding and Setting] 393 | - [Generalized Drivers] 394 | - [Previous Values of Driver Variables] 395 | 396 | ### generate 397 | See [Generators] and [for]. 398 | ```lisp 399 | CL-USER> (iter (for el in '(a b nil c)) 400 | (generate i upfrom 1) 401 | (if el (collect (cons el (next i))))) 402 | ((A . 1) (B . 2) (C . 3)) 403 | ``` 404 | `for` can be replaced by `generate` to achieve the desired result, except in the case of [Variable Binding and Setting]. 405 | 406 | ### generating 407 | Alias for [generate](#generate) 408 | 409 | ### if-first-time 410 | `if-first-time `*`then`*` &optional `*`else`* 411 | ```lisp 412 | CL-USER> (iter (for i in '(1 2 3)) 413 | (if-first-time 414 | (princ 'first) 415 | (print 'not-first))) 416 | ; FIRST 417 | ; NOT-FIRST 418 | ; NOT-FIRST 419 | NIL 420 | ``` 421 | See [Control Flow]. 422 | 423 | ### in 424 | `in`*`name`*` &rest `*`forms`* 425 | ```lisp 426 | CL-USER> (defvar ar #2A((1 2 3) (4 5 6))) 427 | AR 428 | CL-USER> (iter outer 429 | (for i below (array-dimension ar 0)) 430 | (iter (for j below (array-dimension ar 1)) 431 | (in outer 432 | (collect (aref ar i j))))) 433 | (1 2 3 4 5 6) 434 | ``` 435 | 436 | See [Named Blocks]. 437 | 438 | ### initially 439 | `in &rest `*`forms`* 440 | Place the forms in the prologue of the loop. 441 | ```lisp 442 | CL-USER> (iter (initially (princ 'hi)) 443 | (for i below 3) 444 | (print i)) 445 | ; HI 446 | ; 0 447 | ; 1 448 | ; 2 449 | NIL 450 | CL-USER> (iter (for i below 3) 451 | (initially (princ i))) 452 | ; -1 ;; this is probably an undefined behaviour. 453 | NIL 454 | ``` 455 | See [Code Placement] and [Problems with Code Movement]. 456 | 457 | ### leave 458 | `leave &optional `*`value`* 459 | 460 | Returns from the current iterate form with *`value`* or `nil`. 461 | ```lisp 462 | CL-USER> (iter (for i below 3) 463 | (leave 464 | (iter (for j below 2) 465 | (if (oddp j) (leave j))))) 466 | 1 467 | ``` 468 | 469 | See [Control Flow]. 470 | 471 | ### maximize 472 | `maximize `*`expr`*` &optional into `*`var`* 473 | ```lisp 474 | CL-USER> (iter (for list in '((1) (1 2) nil)) 475 | (maximize (length list))) 476 | 2 477 | ``` 478 | See [Reductions] and [finding](#finding). 479 | 480 | ### maximizing 481 | Alias for [maximize](#maximize). 482 | 483 | ### minimize 484 | `minimize `*`expr`*` &optional into `*`var`* 485 | ```lisp 486 | CL-USER> (iter (for list in '((1) (1 2) nil)) 487 | (minimize (length list))) 488 | 0 489 | ``` 490 | See [Reductions] and [finding](#finding). 491 | 492 | ### minimizing 493 | Alias for [minimize](#minimize). 494 | 495 | ### multiply 496 | `multiply `*`expr`*` &optional into `*`var`* 497 | ```lisp 498 | CL-USER> (iter (for i from 1 to 5) 499 | (multiply i)) 500 | 120 501 | ``` 502 | Initial value of `*`var`* is 1. 503 | 504 | See [Reductions]. 505 | 506 | ### multiplying 507 | Alias for [multiply](# 508 | 509 | ### nconcing 510 | `nconcing `*`exptr`*` &optional into `*`var`*` test `*`test`*` at `*`place`*` result-type `*`type`* 511 | 512 | See [Accumulations] and [collect]. 513 | 514 | ### never 515 | `never `*`expr`* 516 | 517 | Effectively `(always (not expr))`, but does not influence the last value returned by a possible other `always` clause. 518 | ```lisp 519 | CL-USER> (iter (repeat 2) 520 | (always 2) 521 | (never nil)) 522 | 2 523 | ``` 524 | 525 | See [Aggregated Boolean Tests] 526 | 527 | ### next 528 | See [generate](#generate). 529 | 530 | ### next-iteration 531 | `next-iteration` 532 | ```lisp 533 | CL-USER> (iter (for i below 3) 534 | (if (oddp i) 535 | (next-iteration) 536 | (collect i))) 537 | (0 2) 538 | ``` 539 | ### nunioning 540 | `nunioning `*`exptr`*` &optional into `*`var`*` test `*`test`*` at `*`place`*` result-type `*`type`* 541 | 542 | See [Accumulations] and [collect]. 543 | 544 | ### reducing 545 | `reducing `*`expr`*` by `*`func`*` &optional initial-value `*`init-val`*` into `*`var`* 546 | ```lisp 547 | CL-USER> (iter (for i in '(1 2 3)) 548 | (reducing i by 549 | (lambda (value-so-far i) 550 | (cons i value-so-far)) 551 | initial-value ())) 552 | (3 2 1) 553 | ``` 554 | 555 | See [Reductions], [Accumulation vs Reduction](#accumulation-vs-reduction) and [accumulate](#accumulate). 556 | 557 | ### repeat 558 | `repeat `*`n`* 559 | 560 | Repeat the loop n times. 561 | 562 | See [Drivers]. 563 | ```lisp 564 | CL-USER> (iter (repeat 3) (print 'doing)) 565 | 566 | ; DOING 567 | ; DOING 568 | ; DOING 569 | NIL 570 | ``` 571 | 572 | ### sum 573 | `sum `*`expr`*` &optional into `*`var`* 574 | ```lisp 575 | CL-USER> (iter (for i from 1 to 5) 576 | (sum i)) 577 | 15 578 | ``` 579 | ### summing 580 | Alias for [sum](#sum). 581 | 582 | ### terminate 583 | `terminate 584 | 585 | Use to terminate `for-next` clause. Effectively an alias for `finish` - but use with `for-next` to maintain compatibility with future versions of `iterate`(!). 586 | 587 | ```lisp 588 | CL-USER> (iter (for i upfrom 0) 589 | (if (> i 5) (terminate) (collect i))) 590 | (0 1 2 3 4 5) 591 | CL-USER> (iter (initially (setq i 0)) 592 | (for i next 593 | (if (> i 10) 594 | (terminate) 595 | (incf i)))) 596 | NIL 597 | 598 | ``` 599 | 600 | See [Generalized Drivers]. 601 | 602 | ### thereis 603 | `thereis `*`expr`* 604 | 605 | - If *`expr`* is ever non-`nil`, its value is returned without running the epilogue code. 606 | - Otherwise epilogue code is run, and `nil` is returned. 607 | - Cannot be used with `always` or `never`. 608 | 609 | See [Aggregated Boolean Tests]. 610 | 611 | ### unioning 612 | `unioning `*`exptr`*` &optional into `*`var`*` test `*`test`*` at `*`place`*` result-type `*`type`* 613 | 614 | See [Accumulations] and [collect]. 615 | 616 | ### until 617 | `until `*`expr`* 618 | ```lisp 619 | CL-USER> (iter (for i in '(1 2 3 4 5)) 620 | (until (> i 5)) 621 | (collect i)) 622 | (1 2 3 4 5) 623 | ``` 624 | Equivalent to `(if expr (finish))`. 625 | 626 | See [finish](#finish) and [Control Flow]. 627 | 628 | ### while 629 | `repeat `*`n`* 630 | `until `*`expr`* 631 | 632 | Equivalent to `(if (not expr) (finish))`. 633 | ```lisp 634 | CL-USER> (iter (for i below 10) 635 | (while (= 0 (rem i 5))) 636 | (collect i)) 637 | (0) 638 | ``` 639 | See [finish](#finish) and [Control Flow]. 640 | 641 | ### with 642 | `with `*`var`*` &optional = `*`value`* 643 | 644 | *`var`* is bound to *`value`* before the loop is entered. Binding happens sequentially, as while using a `let*`, and not in parallel as with `let`. 645 | ```lisp 646 | CL-USER> (iter (with i = 0) 647 | (while (< i 3)) 648 | (collect (incf i))) 649 | (1 2 3) 650 | CL-USER> (iter (with i = 1) 651 | (for i below 3) 652 | (collect (incf i))) 653 | ; Evaluation aborted on #. 654 | ``` 655 | 656 | See [Variable Binding and Setting] and [Parallel Binding and Stepping]. 657 | 658 | ## OTHER RESOURCES ON ITERATE 659 | 660 | - [The Iterate Manual] 661 | - [Comparing LOOP and ITERATE](https://items.sjbach.com/211/comparing-loop-and-iterate) 662 | - [Loop v Iterate - SabraOnTheHill](https://sites.google.com/site/sabraonthehill/loop-v-iter) 663 | 664 | --- 665 | 666 | [The Iterate Manual]: https://common-lisp.net/project/iterate/index.html 667 | [tCLC]: https://github.com/LispCookbook/cl-cookbook 668 | [DLI]: appendix/Don't Loop, Iterate 669 | [Accumulations]: https://common-lisp.net/project/iterate/doc/Accumulations.html 670 | [Code Placement]: https://common-lisp.net/project/iterate/doc/Code-Placement.html#index-after_002deach-103 671 | [Problems with Code Movement]: https://common-lisp.net/project/iterate/doc/Problems-with-Code-Movement.html#Problems-with-Code-Movement 672 | [Aggregated Boolean Tests]: https://common-lisp.net/project/iterate/doc/Aggregated-Boolean-Tests.html 673 | [collect]: #collect 674 | [Reductions]: https://common-lisp.net/project/iterate/doc/Reductions.html 675 | [Types and Declarations]: https://common-lisp.net/project/iterate/doc/Types-and-Declarations.html 676 | [Extensibility Aids]: https://common-lisp.net/project/iterate/doc/Extensibility-Aids.html 677 | [Rolling Your Own]: https://common-lisp.net/project/iterate/doc/Rolling-Your-Own.html 678 | [Writing Drivers]: https://common-lisp.net/project/iterate/doc/Writing-Drivers.html 679 | [On-line help]: https://common-lisp.net/project/iterate/doc/On_002dline-Help.html 680 | [Destructuring]: https://common-lisp.net/project/iterate/doc/Destructuring.html 681 | [Finders]: https://common-lisp.net/project/iterate/doc/Finders.html 682 | [Control Flow]: https://common-lisp.net/project/iterate/doc/Control-Flow.html 683 | [Boolean Tests]: https://common-lisp.net/project/iterate/doc/Boolean-Tests.html 684 | [Numeric Iteration]: https://common-lisp.net/project/iterate/doc/Numerical-Iteration.html 685 | [Sequence Iteration]: https://common-lisp.net/project/iterate/doc/Sequence-Iteration.html 686 | [Variable Binding and Setting]: https://common-lisp.net/project/iterate/doc/Variable-Binding-and-Setting.html 687 | [Generalized Drivers]: https://common-lisp.net/project/iterate/doc/Generalized-Drivers.html 688 | [Previous Values of Driver Variables]: https://common-lisp.net/project/iterate/doc/Previous-Values-of-Driver-Variables.html 689 | [Generators]: https://common-lisp.net/project/iterate/doc/Generators.html 690 | [for]: #for 691 | [Named Blocks]: https://common-lisp.net/project/iterate/doc/Named-Blocks.html 692 | [Drivers]: https://common-lisp.net/project/iterate/doc/Drivers.html 693 | [accumulate]: #accumulate 694 | [Parallel Binding and Stepping]: https://common-lisp.net/project/iterate/doc/Parallel-Binding-and-Stepping.html#Parallel-Binding-and-Stepping 695 | -------------------------------------------------------------------------------- /docs/local-time.md: -------------------------------------------------------------------------------- 1 | # local-time - Date and Time Manipulation 2 | 3 | Version: 1.0.6 4 |
5 | Licence: 3-clause BSD 6 |
7 | Repository: [dlowe-net/local-time](https://github.com/dlowe-net/local-time) 8 |
9 | See also: [awesome-cl#date-and-time](https://github.com/CodyReichert/awesome-cl#date-and-time) 10 | 11 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 12 | 13 | *Great thanks to the excellent [official documentation](https://common-lisp.net/project/local-time/manual.html).* 14 | 15 | `local-time` library is a Common Lisp library for the manipulation 16 | of dates, times and intervals. It was originally based almost entirely 17 | upon Erik Naggum's paper [The Long Painful History of Time](http://naggum.no/lugm-time.html). Many of the core concepts originated from this paper, 18 | such as the seperation of days and seconds, the choice of 2000-03-01 as 19 | the standard epoch, and the timestring format. 20 | 21 | 22 | ## GETTING STARTED 23 | 24 | ### timestamps and timezones 25 | 26 | `local-time` deals with time in the form of [timestamp](#timestamp) and [timezone](#timezone). 27 | 28 | The following constructs deal with timezones: 29 | 30 | - [\*default-timezone\*](#default-timezone) 31 | - [+utc-zone+](#utc-zone) 32 | - [define-timezone](#define-timezone) 33 | - [find-timezone-by-location-name](#find-timezone-by-location-name) 34 | - [reread-timezone-repository](#reread-timezone-repository) 35 | 36 | 37 | **Examples** 38 | 39 | ```lisp 40 | CL-USER> (add-package-local-nickname :lt :local-time) 41 | # 42 | 43 | CL-USER> (lt:now) 44 | @2020-12-16T13:44:22.493573Z 45 | 46 | CL-USER> lt:+asctime-format+ 47 | (:SHORT-WEEKDAY #\ :SHORT-MONTH #\ (:DAY 2 #\ ) #\ (:HOUR 2) #\: (:MIN 2) 48 | #\: (:SEC 2) #\ (:YEAR 4)) 49 | 50 | CL-USER> (lt:format-timestring nil (lt:now) 51 | :format lt:+asctime-format+) 52 | "Wed Dec 16 13:45:24 2020" 53 | 54 | CL-USER> (lt:reread-timezone-repository) 55 | NIL 56 | 57 | CL-USER> lt::*default-timezone-repository-path* 58 | #P"/home/user/quicklisp/local-projects/local-time/zoneinfo/" 59 | 60 | CL-USER> (lt:find-timezone-by-location-name "US/Eastern") 61 | # 62 | T 63 | 64 | CL-USER> (lt:format-timestring nil (lt:now) 65 | :format lt:+asctime-format+ 66 | :timezone *) 67 | "Wed Dec 16 09:00:57 2020" 68 | ``` 69 | 70 | See [the cookbook](https://lispcookbook.github.io/cl-cookbook/dates_and_times.html) for more examples. 71 | 72 | ### Dealing with timestamps 73 | 74 | **Conversion: to and fro** 75 | 76 | - [now](#now) 77 | - [today](#today) 78 |
79 |
80 | - [days-in-month](#days-in-month) 81 |
82 |
83 | - [universal-to-timestamp](#universal-to-timestamp) 84 | - [unix-to-timestamp](#unix-to-timestamp) 85 | - [timestamp-to-universal](#timestamp-to-universal) 86 | - [timestamp-to-unix](#timestamp-to-unix) 87 |
88 |
89 | - [make-timestamp](#make-timestamp) 90 | - [clone-timestamp](#clone-timestamp) 91 |
92 |
93 | - [encode-timestamp](#encode-timestamp) 94 | - [decode-timestamp](#decode-timestamp) 95 | - [with-decoded-timestamp](#with-decoded-timestamp) 96 | 97 | **Querying and Manipulation** 98 | 99 | - [day-of](#day-of) 100 | - [sec-of](#sec-of) 101 | - [nsec-of](#nsec-of) 102 |
103 |
104 | - [timestamp<](#timestamp<) 105 | - [timestamp<=](#timestamp<=) 106 | - [timestamp>](#timestamp>) 107 | - [timestamp>=](#timestamp>=) 108 | - [timestamp=](#timestamp=) 109 | - [timestamp/=](#timestamp/=) 110 | - [timestamp-minimum](#timestamp-minimum) 111 | - [timestamp-maximum](#timestamp-maximum) 112 | - [timestamp-whole-year-difference](#timestamp-whole-year-difference) 113 |
114 |
115 | - [timestamp+](#timestamp+) 116 | - [timestamp-](#timestamp-) 117 | - [timestamp-maximize-part](#timestamp-maximize-part) 118 | - [timestamp-minimize-part](#timestamp-minimize-part) 119 |
120 |
121 | - [adjust-timestamp](#adjust-timestamp) 122 | - [adjust-timestamp!](#adjust-timestamp!) 123 |
124 |
125 | - [timestamp-subtimezone](#timestamp-subtimezone) 126 | - [timestamp-day-of-week](#timestamp-day-of-week) 127 | - [timestamp-millennium](#timestamp-millennium) 128 | - [timestamp-century](#timestamp-century) 129 | - [timestamp-decade](#timestamp-decade) 130 | - [timestamp-year](#timestamp-year) 131 | - [timestamp-month](#timestamp-month) 132 | - [timestamp-day](#timestamp-day) 133 | - [timestamp-hour](#timestamp-hour) 134 | - [timestamp-minute](#timestamp-minute) 135 | - [timestamp-second](#timestamp-second) 136 | - [timestamp-millisecond](#timestamp-millisecond) 137 | - [tiemstamp-microsecond](#tiemstamp-microsecond) 138 | 139 | **Parsing and Formatting** 140 | 141 | - [+iso-8601-format+](#iso-8601-format) 142 | - [+asctime-format+](#asctime-format) 143 | - [+rfc-1123-format+](#rfc-1123-format) 144 | - [+iso-week-date-format+](#iso-week-date-format) 145 | - [parse-timestring](#parse-timestring) 146 | - [format-timestring](#format-timestring) 147 | - [format-rfc3339-timestring](#format-rfc3339-timestring) 148 | 149 | **Reader Macros** 150 | 151 | - [enable-read-macros](#enable-read-macros) 152 | 153 | ### Clocks 154 | 155 | The [\*clock\*](#clock) special variable and the generic functions [clock-now](#clock-now) and [clock-today](#clock-today) are exposed so that applications may re-define the current time or date as required. This can be used for testing or to support alternate clocks. 156 | 157 | The currently supported values are: 158 | 159 | - `t` - Use the standard system clock with no adjustments 160 | - `leap-second-adjusted` - The system clock, adjusted for leap seconds using the information in [\*default-timezone\*](#default-timezone). 161 | 162 | 163 | ### Non-Gregorian Calendars 164 | 165 | Support for julian calendars is provided by the following functions: 166 | 167 | - [astronomical-julian-date](#astronomical-modified-julian-date) 168 | - [astronomical-modified-julian-date](#astronomical-modified-julian-date) 169 | 170 | ### A note on Portability 171 | 172 | This implementation assumes that time zone information is stored in the 173 | tzfile format. The default timezone is loaded from /etc/localtime. On 174 | non-POSIX systems, this will certainly give different results than the 175 | system time handling. 176 | 177 | local-time currently supports subsecond precision clocks with allegro, 178 | cmucl, sbcl, abcl, and non-Windows ccl. All others will be able to 179 | retrieve the time with second precision using `get-universal-time`. You 180 | may add support for your own implementation by implementing the clock 181 | generic protocol documented here. 182 | 183 | ## API REFERENCE 184 | 185 | ### \*clock\* 186 | 187 | ```lisp 188 | Variable 189 | Default Value: T 190 | ``` 191 | 192 | Use this special variable if you need to define your own idea of the current time. 193 | 194 | The value of this variable should have the methods [clock-now](#clock-now), and 195 | [clock-today](#clock-today). The currently supported values in `local-time` are: 196 | 197 | - `t` - use the standard clock 198 | - [leap-second-adjusted](#leap-second-adjusted) - use a clock which adjusts for leap seconds using the information in [\*default-timezone\*](#default-timezone). 199 | 200 | TODO: Add / Point to a concrete example of dealing with clocks. 201 | 202 | ### \*default-timezone\* 203 | 204 | ```lisp 205 | Variable 206 | Default Value: # 207 | ``` 208 | 209 | This variable contains the timezone that will be used by default if none 210 | is specified. It is loaded from `/etc/localtime` when the library is loaded. 211 | If `/etc/localtime` is not present, it will default to UTC. 212 | 213 | ### +asctime-format+ 214 | 215 | ```lisp 216 | Variable 217 | Default Value: (:SHORT-WEEKDAY #\ :SHORT-MONTH #\ (:DAY 2 #\ ) #\ (:HOUR 2) 218 | #\: (:MIN 2) #\: (:SEC 2) #\ (:YEAR 4)) 219 | ``` 220 | 221 | This constant is bound to a format mirroring the output of the POSIX 222 | asctime() function. An output with this format will look like this: 223 | `Sat Mar 1 19:42:34 2008`. 224 | 225 | ### +day-names+ 226 | 227 | ```lisp 228 | Variable 229 | Default Value: #("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" 230 | "Saturday") 231 | ``` 232 | 233 | ### +days-per-week+ 234 | 235 | ```lisp 236 | Constant: 7 237 | ``` 238 | 239 | ### +gmt-zone+ 240 | 241 | ```lisp 242 | Variable 243 | Default Value: # 244 | ``` 245 | 246 | ### +hours-per-day+ 247 | 248 | ```lisp 249 | Constant: 24 250 | ``` 251 | 252 | ### +iso-8601-date-format+ 253 | 254 | ```lisp 255 | Variable 256 | Default Value: ((:YEAR 4) #\- (:MONTH 2) #\- (:DAY 2)) 257 | ``` 258 | 259 | See [+iso-8601-format+](#iso-8601-format). 260 | 261 | ### +iso-8601-format+ 262 | 263 | ```lisp 264 | Variable 265 | Default Value: ((:YEAR 4) #\- (:MONTH 2) #\- (:DAY 2) #\T (:HOUR 2) #\: 266 | (:MIN 2) #\: (:SEC 2) #\. (:USEC 6) :GMT-OFFSET-OR-Z) 267 | ``` 268 | 269 | This constant is bound to a description of the ISO 8601 format. An output 270 | with this format will look like this: `2008-03-01T19:42:34.608506+01:00`. 271 | This is the default format for the [format-timestring](#format-timestring) function. 272 | 273 | ### +iso-8601-time-format+ 274 | 275 | ```lisp 276 | Variable 277 | Default Value: ((:HOUR 2) #\: (:MIN 2) #\: (:SEC 2) #\. (:USEC 6)) 278 | ``` 279 | 280 | See [+iso-8601-format+](#iso-8601-format). 281 | 282 | ### +iso-week-date-format+ 283 | 284 | ```lisp 285 | Variable 286 | Default Value: ((:ISO-WEEK-YEAR 4) #\- #\W (:ISO-WEEK-NUMBER 2) #\- 287 | (:ISO-WEEK-DAY 1)) 288 | ``` 289 | 290 | This constant is bound to a description of the ISO 8601 Week Date format. 291 | An output with this format will look like this: `2009-W53-5`. 292 | 293 | ### +minutes-per-day+ 294 | 295 | ```lisp 296 | Constant: 1440 297 | ``` 298 | 299 | ### +minutes-per-hour+ 300 | 301 | ```lisp 302 | Constant: 60 303 | ``` 304 | 305 | ### +month-names+ 306 | 307 | ```lisp 308 | Variable 309 | Default Value: #("" "January" "February" "March" "April" "May" "June" "July" 310 | "August" "September" "October" "November" "December") 311 | ``` 312 | 313 | ### +months-per-year+ 314 | 315 | ```lisp 316 | Constant: 12 317 | ``` 318 | 319 | ### +rfc-1123-format+ 320 | 321 | ```lisp 322 | Variable 323 | Default Value: (:SHORT-WEEKDAY ", " (:DAY 2) #\ :SHORT-MONTH #\ (:YEAR 4) #\ 324 | (:HOUR 2) #\: (:MIN 2) #\: (:SEC 2) #\ :GMT-OFFSET-HHMM) 325 | ``` 326 | 327 | This constant is bound to a description of the format defined in RFC 1123 328 | for Internet timestamps. An output with this format will look like this: 329 | `Sat, 01 Mar 2008 19:42:34 -0500`. See the [RFC 1123](https://tools.ietf.org/html/rfc1123) 330 | for the details about the possible values of the timezone field. 331 | 332 | ### +rfc3339-format+ 333 | 334 | ```lisp 335 | Variable 336 | Default Value: ((:YEAR 4) #\- (:MONTH 2) #\- (:DAY 2) #\T (:HOUR 2) #\: 337 | (:MIN 2) #\: (:SEC 2) #\. (:USEC 6) :GMT-OFFSET-OR-Z) 338 | ``` 339 | 340 | ### +rfc3339-format/date-only+ 341 | 342 | ```lisp 343 | Variable 344 | Default Value: ((:YEAR 4) #\- (:MONTH 2) #\- (:DAY 2)) 345 | ``` 346 | 347 | ### +seconds-per-day+ 348 | 349 | ```lisp 350 | Constant: 86400 351 | ``` 352 | 353 | ### +seconds-per-hour+ 354 | 355 | ```lisp 356 | Constant: 3600 357 | ``` 358 | 359 | ### +seconds-per-minute+ 360 | 361 | ```lisp 362 | Constant: 60 363 | ``` 364 | 365 | ### +short-day-names+ 366 | 367 | ```lisp 368 | Variable 369 | Default Value: #("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat") 370 | ``` 371 | 372 | ### +short-month-names+ 373 | 374 | ```lisp 375 | Variable 376 | Default Value: #("" "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" 377 | "Nov" "Dec") 378 | ``` 379 | 380 | ### +utc-zone+ 381 | 382 | ```lisp 383 | Variable 384 | Default Value: # 385 | ``` 386 | 387 | A timezone corresponding to UTC. 388 | 389 | ### adjust-timestamp 390 | 391 | ```lisp 392 | Macro: (adjust-timestamp timestamp &body changes) 393 | ``` 394 | 395 | Alters various parts of [timestamp](#timestamp), given a list of 396 | changes. The changes are in the format `(offset part value)` and 397 | `(set part value)`. 398 | 399 | ``` {.lisp} 400 | ;; Return a new timestamp value that points to the previous Monday 401 | (adjust-timestamp (today) (offset :day-of-week :monday)) 402 | 403 | ;; Return a new timestamp value that points three days ahead from now 404 | (adjust-timestamp (today) (offset :day 3)) 405 | ``` 406 | 407 | Keep in mind that adjust-timestamp is not a mere setter for fields 408 | but instead it handles overflows and timezone conversions as 409 | expected. Also note that it's possible to specify multiple commands. 410 | 411 | The list of possible places to manipulate are: `:nsec` `:sec` 412 | `:sec-of-day` `:minute` `:hour` `:day` `:day-of-month` `:month` 413 | `:year`. 414 | 415 | 416 | ### adjust-timestamp! 417 | 418 | ```lisp 419 | Macro: (adjust-timestamp! timestamp &body changes) 420 | ``` 421 | 422 | Just like [adjust-timestamp](#adjust-timestamp), but instead of returning a freshly constructed 423 | value, it alters the provided [timestamp](#timestamp) value (and returns it). 424 | 425 | ### all-timezones-matching-subzone 426 | 427 | ```lisp 428 | Function: (all-timezones-matching-subzone abbreviated-name) 429 | ``` 430 | 431 | Returns list of lists of timezone, matched subzone and last transition time 432 | for timezones that have subzone matching specified abbreviated-name. Includes both active and historical timezones. 433 | 434 | ### astronomical-julian-date 435 | 436 | ```lisp 437 | Function: (astronomical-julian-date timestamp) 438 | ``` 439 | 440 | Returns the astronomical julian date referred to by the timestamp. 441 | 442 | ### astronomical-modified-julian-date 443 | 444 | No documentation found for `astronomical-modified-julian-date` 445 | 446 | ### clock-now 447 | 448 | ```lisp 449 | Generic Function: (clock-now clock) 450 | ``` 451 | 452 | Returns a timestamp for the current time given a clock. 453 | Specialize this generic function to re-define the present moment 454 | 455 | ### clock-today 456 | 457 | ```lisp 458 | Generic Function: (clock-today clock) 459 | ``` 460 | 461 | Returns a timestamp for the current date given a 462 | clock. The date is encoded by convention as a timestamp with the 463 | time set to 00:00:00UTC. 464 | 465 | Specialize this generic function to re-define the present day. 466 | 467 | ### clone-timestamp 468 | 469 | ```lisp 470 | Function: (clone-timestamp timestamp) 471 | ``` 472 | 473 | Returns a copy of [timestamp](#timestamp) that is `timestamp=` to it. 474 | 475 | ### date 476 | 477 | ```lisp 478 | Type 479 | ``` 480 | 481 | A [timestamp](#timestamp) referring to a UTC timezone. The `sec` slot must be the first 482 | second of a day; in other words, the time elements of the `timestamp` value must 483 | have their least possible values 0. 484 | 485 | 486 | ### day-of 487 | 488 | ```lisp 489 | Generic Function: (day-of object) 490 | ``` 491 | 492 | Returns the day component of [timestamp](#timestamp). Although 493 | Naggum's paper specifies that the day should be a signed fixnum, it 494 | is left unbounded for flexibility reasons. 495 | 496 | 497 | ### days-in-month 498 | 499 | ```lisp 500 | Function: (days-in-month month year) 501 | ``` 502 | 503 | Returns the number of days in the given month of the specified year. 504 | 505 | ### decode-timestamp 506 | 507 | ```lisp 508 | Function: (decode-timestamp timestamp &key (timezone *default-timezone*) offset) 509 | ``` 510 | 511 | Returns the decoded time as multiple values: 512 | 513 | (values ns ss mm hh day month year day-of-week daylight-saving-time-p timezone-offset timezone-abbreviation) 514 | 515 | ### define-timezone 516 | 517 | ```lisp 518 | Macro: (define-timezone zone-name zone-file &key (load NIL)) 519 | ``` 520 | 521 | Define [zone-name](#zone-name) (a symbol or a string) as a new timezone, lazy-loaded from zone-file (a pathname designator relative to the zoneinfo directory on this system. If load is true, load immediately. 522 | 523 | ### enable-read-macros 524 | 525 | ```lisp 526 | Function: (enable-read-macros) 527 | ``` 528 | 529 | Enables the local-time reader macros for literal timestamps and universal time. 530 | 531 | ### encode-timestamp 532 | 533 | ```lisp 534 | Function: (encode-timestamp nsec sec minute hour day month year &key 535 | (timezone *default-timezone*) offset into) 536 | ``` 537 | 538 | Returns a new [timestamp](#timestamp) instance corresponding to the specified 539 | time elements. offset is the number of seconds offset from UTC of the locale. 540 | If offset is not specified, the offset will be guessed from the timezone. 541 | 542 | If a [timestamp](#timestamp) is passed as the into argument, its value will be set and that 543 | [timestamp](#timestamp) will be returned. Otherwise, a new [timestamp](#timestamp) is created. 544 | 545 | ### find-timezone-by-location-name 546 | 547 | ```lisp 548 | Function: (find-timezone-by-location-name name) 549 | ``` 550 | 551 | Returns the timezone found at the location name (such as `US/Eastern`). 552 | [reread-timezone-repository](#reread-timezone-repository) must be called before this function is used. 553 | 554 | ### format-rfc1123-timestring 555 | 556 | ```lisp 557 | Function: (format-rfc1123-timestring destination timestamp &key 558 | (timezone *default-timezone*)) 559 | ``` 560 | 561 | See [+rfc-1123-format+](#rfc-1123-format) and [format-timestring](#format-timestring). 562 | 563 | 564 | ### format-rfc3339-timestring 565 | 566 | ```lisp 567 | Function: (format-rfc3339-timestring destination timestamp &key omit-date-part 568 | omit-time-part (omit-timezone-part omit-time-part) (use-zulu t) 569 | (timezone *default-timezone*)) 570 | ``` 571 | 572 | Formats a timestring in the RFC 3339 format, a restricted form of the ISO-8601 timestring specification for Internet timestamps. 573 | 574 | See [+rfc3339-format+](#rfc3339-format) and [format-timestring](#format-timestring). 575 | 576 | ### format-timestring 577 | 578 | ```lisp 579 | Function: (format-timestring destination timestamp &key 580 | (format +iso-8601-format+) (timezone *default-timezone*)) 581 | ``` 582 | 583 | Constructs a string representation of [timestamp](#timestamp) according 584 | to format and returns it. 585 | If `destination` is T, the string is written to *STANDARD-OUTPUT*. 586 | If `destination` is a stream, the string is written to the stream. 587 | 588 | `format` is a list containing one or more of strings, characters, 589 | and keywords. Strings and characters are output literally, 590 | while keywords are replaced by the values here: 591 | 592 | :YEAR *year 593 | :MONTH *numeric month 594 | :DAY *day of month 595 | :HOUR *hour 596 | :MIN *minutes 597 | :SEC *seconds 598 | :WEEKDAY *numeric day of week starting from index 0, which means Sunday 599 | :MSEC *milliseconds 600 | :USEC *microseconds 601 | :NSEC *nanoseconds 602 | :ISO-WEEK-YEAR *year for ISO week date (can be different from regular calendar year) 603 | :ISO-WEEK-NUMBER *ISO week number (i.e. 1 through 53) 604 | :ISO-WEEK-DAY *ISO compatible weekday number (monday=1, sunday=7) 605 | :LONG-WEEKDAY long form of weekday (e.g. Sunday, Monday) 606 | :SHORT-WEEKDAY short form of weekday (e.g. Sun, Mon) 607 | :MINIMAL-WEEKDAY minimal form of weekday (e.g. Su, Mo) 608 | :SHORT-YEAR short form of year (last 2 digits, e.g. 41, 42 instead of 2041, 2042) 609 | :LONG-MONTH long form of month (e.g. January, February) 610 | :SHORT-MONTH short form of month (e.g. Jan, Feb) 611 | :HOUR12 *hour on a 12-hour clock 612 | :AMPM am/pm marker in lowercase 613 | :GMT-OFFSET the gmt-offset of the time, in +00:00 form 614 | :GMT-OFFSET-OR-Z like :GMT-OFFSET, but is Z when UTC 615 | :GMT-OFFSET-HHMM like :GMT-OFFSET, but in +0000 form 616 | :TIMEZONE timezone abbrevation for the time 617 | 618 | Elements marked by `*` can be placed in a list in the form 619 | 620 | (:keyword padding &optional (padchar #\0)) 621 | 622 | The string representation of the value will be padded with the padchar. 623 | 624 | You can see examples in [+ISO-8601-FORMAT+](#iso-8601-format), [+ASCTIME-FORMAT+](#asctime-format), and [+RFC-1123-FORMAT+](#rfc-1123-format). 625 | 626 | ### invalid-timestring 627 | 628 | ```lisp 629 | Condition 630 | ``` 631 | 632 | 633 | ### leap-second-adjusted 634 | 635 | No documentation found for `leap-second-adjusted` 636 | 637 | ### make-timestamp 638 | 639 | ```lisp 640 | Macro: (make-timestamp &rest args) 641 | ``` 642 | 643 | Expands to an expression that creates an instance of a [timestamp](#timestamp) 644 | exactly as specified. 645 | 646 | ### modified-julian-date 647 | 648 | ```lisp 649 | Function: (modified-julian-date timestamp) 650 | ``` 651 | 652 | Returns the modified julian date referred to by the timestamp. 653 | 654 | ### now 655 | 656 | ```lisp 657 | Function: (now) 658 | ``` 659 | 660 | Produces a [timestamp](#timestamp) instance with the current time. Under sbcl, the new timestamp will be precise to the microsecond. Otherwise, the precision is limited to the second. 661 | 662 | ### nsec-of 663 | 664 | ```lisp 665 | Generic Function: (nsec-of object) 666 | ``` 667 | Returns the `microseconds` component of the [timestamp](#timestamp). Valid values for 668 | the nanoseconds range from 0 to 999999999. 669 | 670 | 671 | 672 | ### parse-rfc3339-timestring 673 | 674 | ```lisp 675 | Function: (parse-rfc3339-timestring timestring &key (fail-on-error t) 676 | (allow-missing-time-part NIL)) 677 | ``` 678 | 679 | ### parse-timestring 680 | 681 | ```lisp 682 | Function: (parse-timestring timestring &key start end (fail-on-error t) 683 | (time-separator :) (date-separator -) (date-time-separator t) 684 | (fract-time-separators (quote (. ,))) (allow-missing-elements t) 685 | (allow-missing-date-part allow-missing-elements) 686 | (allow-missing-time-part allow-missing-elements) 687 | (allow-missing-timezone-part allow-missing-elements) (offset 0)) 688 | ``` 689 | 690 | Parses a timestring and returns the corresponding `timestamp`. 691 | Parsing begins at `start` and stops at the 692 | `end` position. If there are invalid characters within 693 | `timestring` and `fail-on-error` is `T`, then an 694 | `invalid-timestring` error is signaled, otherwise `NIL` is returned. 695 | 696 | If there is no timezone specified in `timestring` then 697 | `offset` is used as the default timezone offset (in 698 | seconds). 699 | 700 | See `local-time::split-timestring` for details. Unspecified fields in the 701 | timestring are initialized to their lowest possible value, 702 | and timezone offset is 0 (UTC) unless explicitly specified 703 | in the input string. 704 | 705 | ### reread-timezone-repository 706 | 707 | ```lisp 708 | Function: (reread-timezone-repository &key 709 | (timezone-repository *default-timezone-repository-path*)) 710 | ``` 711 | 712 | Walks the current repository, reading all tzinfo files updating indexes. 713 | The default timezone repository is set to the zoneinfo/ directory of the local-time system. 714 | 715 | ### sec-of 716 | 717 | ```lisp 718 | Generic Function: (sec-of object) 719 | ``` 720 | 721 | Returns the `seconds` component of the [timestamp](#timestamp). Valid values for the 722 | seconds range from 0 to 86399. 723 | 724 | 725 | ### time-of-day 726 | 727 | ```lisp 728 | Type 729 | ``` 730 | 731 | A [timestamp](#timestamp) with `day` slot having the value 0. 732 | 733 | 734 | ### timestamp 735 | 736 | ```lisp 737 | Class 738 | ``` 739 | 740 | `timestamp` values are basically instances of 741 | 742 | ```lisp 743 | (defclass timestamp () 744 | ((day :type integer) 745 | (sec :type integer) 746 | (nsec :type (integer 0 999999999)))) 747 | ``` 748 | 749 | These can represent either a [date](#date), a `daytime` or a 750 | [time-of-day](#time-of-day) value, depending on the values of its slots. 751 | 752 | 753 | ### timestamp+ 754 | 755 | ```lisp 756 | Function: (timestamp+ time amount unit &optional (timezone *default-timezone*) 757 | offset) 758 | ``` 759 | 760 | Add the `amount` to the `time` 761 | using the specified `unit`. 762 | 763 | - `unit` may be one of ( `:nsec` `:sec` `:minute` `:hour` `:day` `:month` `:year`). 764 | 765 | The value of the parts of the timestamp of higher resolution than the 766 | `unit` will never be touched. If you want a precise number of seconds 767 | from a time, you should specify the offset in seconds. 768 | 769 | ### timestamp- 770 | 771 | ```lisp 772 | Function: (timestamp- time amount unit &optional (timezone *default-timezone*) 773 | offset) 774 | ``` 775 | 776 | Subtract the `amount` from the `time` 777 | using the specified `unit`. 778 | 779 | - `unit` may be one of ( `:nsec` `:sec` `:minute` `:hour` `:day` `:month` `:year`). 780 | 781 | The value of the parts of the timestamp of higher resolution than the 782 | `unit` will never be touched. If you want a precise number of seconds 783 | from a time, you should specify the offset in seconds. 784 | 785 | ### timestamp-century 786 | 787 | ```lisp 788 | Function: (timestamp-century timestamp &key (timezone *default-timezone*)) 789 | ``` 790 | 791 | Returns the ordinal century upon which the timestamp falls. Ordinal time values start at 1, so the `(timestamp-century (now))` will return 21. 792 | 793 | ### timestamp-day 794 | 795 | ```lisp 796 | Function: (timestamp-day timestamp &key (timezone *default-timezone*)) 797 | ``` 798 | 799 | Returns the day of the month upon which the timestamp falls. 800 | 801 | ### timestamp-day-of-week 802 | 803 | ```lisp 804 | Function: (timestamp-day-of-week timestamp &key (timezone *default-timezone*) 805 | offset) 806 | ``` 807 | 808 | This returns the index of the day of the week, starting at 0 which 809 | means Sunday. 810 | 811 | **Note:** "Day of the week" is ambigous and locale dependent. 812 | 813 | ### timestamp-decade 814 | 815 | ```lisp 816 | Function: (timestamp-decade timestamp &key (timezone *default-timezone*)) 817 | ``` 818 | 819 | Returns the cardinal decade upon which the timestamp falls. Ordinal time values start at 1. 820 | 821 | ### timestamp-difference 822 | 823 | ```lisp 824 | Function: (timestamp-difference time-a time-b) 825 | ``` 826 | 827 | Returns the difference between time-a and time-b in seconds 828 | 829 | ### timestamp-hour 830 | 831 | ```lisp 832 | Function: (timestamp-hour timestamp &key (timezone *default-timezone*)) 833 | ``` 834 | 835 | ### timestamp-maximize-part 836 | 837 | ```lisp 838 | Function: (timestamp-maximize-part timestamp part &key 839 | (timezone *default-timezone*) into) 840 | ``` 841 | 842 | Returns a timestamp with its parts maximized up to 843 | `part`. `part` can be any of (:nsec :sec :min 844 | :hour :day :month). If `into` is specified, it will be 845 | modified and returned, otherwise a new timestamp will be created. 846 | 847 | ### timestamp-maximum 848 | 849 | ```lisp 850 | Function: (timestamp-maximum time &rest times) 851 | ``` 852 | 853 | Returns the latest timestamp 854 | 855 | ### timestamp-microsecond 856 | 857 | ```lisp 858 | Function: (timestamp-microsecond timestamp) 859 | ``` 860 | 861 | ### timestamp-millennium 862 | 863 | ```lisp 864 | Function: (timestamp-millennium timestamp &key (timezone *default-timezone*)) 865 | ``` 866 | 867 | Returns the ordinal millennium upon which the timestamp falls. These start from 1, so the `(timestamp-millennium (now))` will return 3. 868 | 869 | ### timestamp-millisecond 870 | 871 | ```lisp 872 | Function: (timestamp-millisecond timestamp) 873 | ``` 874 | 875 | ### timestamp-minimize-part 876 | 877 | ```lisp 878 | Function: (timestamp-minimize-part timestamp part &key 879 | (timezone *default-timezone*) into) 880 | ``` 881 | 882 | Returns a timestamp with its parts minimized up to 883 | `part`. `part` can be any of (:nsec :sec :min 884 | :hour :day :month). If `into` is specified, it will be 885 | modified and returned, otherwise a new timestamp will be created. 886 | 887 | 888 | ### timestamp-minimum 889 | 890 | ```lisp 891 | Function: (timestamp-minimum time &rest times) 892 | ``` 893 | 894 | Returns the earliest timestamp 895 | 896 | ### timestamp-minute 897 | 898 | ```lisp 899 | Function: (timestamp-minute timestamp &key (timezone *default-timezone*)) 900 | ``` 901 | 902 | ### timestamp-month 903 | 904 | ```lisp 905 | Function: (timestamp-month timestamp &key (timezone *default-timezone*)) 906 | ``` 907 | 908 | Returns the month upon which the timestamp falls. 909 | 910 | ### timestamp-second 911 | 912 | ```lisp 913 | Function: (timestamp-second timestamp &key (timezone *default-timezone*)) 914 | ``` 915 | 916 | ### timestamp-subtimezone 917 | 918 | ```lisp 919 | Function: (timestamp-subtimezone timestamp timezone) 920 | ``` 921 | 922 | Return as multiple values the time zone as the number of seconds east of UTC, a boolean daylight-saving-p, and the customary abbreviation of the timezone. 923 | 924 | ### timestamp-to-universal 925 | 926 | ```lisp 927 | Function: (timestamp-to-universal timestamp) 928 | ``` 929 | 930 | Return the UNIVERSAL-TIME corresponding to the [timestamp](#timestamp). 931 | This is the date/time specified in `timestamp` 932 | encoded as the number of seconds since January 1st, 1900 12:00am 933 | UTC. 934 | 935 | ### timestamp-to-unix 936 | 937 | ```lisp 938 | Function: (timestamp-to-unix timestamp) 939 | ``` 940 | 941 | Return the Unix time corresponding to the [timestamp](#timestamp). 942 | This returns the date/time specified in `timestamp` 943 | encoded as the number of seconds since January 1st, 1970 12:00am 944 | UTC. It corresponds with the time received from the POSIX call 945 | `time()`. 946 | 947 | 948 | ### timestamp-week 949 | 950 | No documentation found for `timestamp-week` 951 | 952 | ### timestamp-whole-year-difference 953 | 954 | ```lisp 955 | Function: (timestamp-whole-year-difference time-a time-b) 956 | ``` 957 | 958 | Returns the number of whole years elapsed between time-a and time-b. 959 | 960 | **Note:** This is useful for calculating anniversaries and birthdays. 961 | 962 | ### timestamp-year 963 | 964 | ```lisp 965 | Function: (timestamp-year timestamp &key (timezone *default-timezone*)) 966 | ``` 967 | 968 | Returns the cardinal year upon which the timestamp falls. 969 | 970 | ### timestamp/= 971 | 972 | ```lisp 973 | Function: (timestamp/= &rest timestamps) 974 | ``` 975 | 976 | Returns T if no pair of timestamps is equal. Otherwise return NIL. 977 | 978 | ### timestamp< 979 | 980 | ```lisp 981 | Function: (timestamp< &rest times) 982 | ``` 983 | 984 | ### timestamp<= 985 | 986 | ```lisp 987 | Function: (timestamp<= &rest times) 988 | ``` 989 | 990 | ### timestamp= 991 | 992 | ```lisp 993 | Function: (timestamp= &rest times) 994 | ``` 995 | 996 | ### timestamp> 997 | 998 | ```lisp 999 | Function: (timestamp> &rest times) 1000 | ``` 1001 | 1002 | ### timestamp>= 1003 | 1004 | ```lisp 1005 | Function: (timestamp>= &rest times) 1006 | ``` 1007 | 1008 | ### timezones-matching-subzone 1009 | 1010 | ```lisp 1011 | Function: (timezones-matching-subzone abbreviated-name timestamp) 1012 | ``` 1013 | 1014 | Returns list of lists of active timezone, matched subzone and last transition time 1015 | for timezones that have subzone matching specified abbreviated-name as of [timestamp](#timestamp) moment if provided. 1016 | 1017 | ### to-rfc1123-timestring 1018 | 1019 | ```lisp 1020 | Function: (to-rfc1123-timestring timestamp) 1021 | ``` 1022 | 1023 | ### to-rfc3339-timestring 1024 | 1025 | ```lisp 1026 | Function: (to-rfc3339-timestring timestamp) 1027 | ``` 1028 | 1029 | ### today 1030 | 1031 | ```lisp 1032 | Function: (today) 1033 | ``` 1034 | 1035 | Produces a [timestamp](#timestamp) instance that corresponds to today's date, 1036 | which is the midnight of the current day in the UTC zone. 1037 | 1038 | ### universal-to-timestamp 1039 | 1040 | ```lisp 1041 | Function: (universal-to-timestamp universal &key (nsec 0)) 1042 | ``` 1043 | 1044 | Produces a [timestamp](#timestamp) instance from the provided universal time 1045 | universal. Universal time is defined in the Common Lisp 1046 | Specification as the number of seconds since 1900-01-01T00:00:00Z. 1047 | 1048 | **Note:** Subsecond precision is not preserved. 1049 | 1050 | ### unix-to-timestamp 1051 | 1052 | ```lisp 1053 | Function: (unix-to-timestamp unix &key (nsec 0)) 1054 | ``` 1055 | 1056 | Produces a [timestamp](#timestamp) instance from the provided unix time unix. Unix time 1057 | is defined by POSIX as the number of seconds since 1970-01-01T00:00:00Z. 1058 | 1059 | ### with-decoded-timestamp 1060 | 1061 | ```lisp 1062 | Macro: (with-decoded-timestamp 1063 | (&key nsec sec minute hour day month year day-of-week daylight-p 1064 | timezone offset) 1065 | timestamp &body forms) 1066 | ``` 1067 | 1068 | This macro binds variables to the decoded elements of [timestamp](#timestamp). The timezone argument is used for decoding the timestamp, and is not bound by the macro. The value of day-of-week starts from 0 which means Sunday. 1069 | 1070 | ### zone-name 1071 | 1072 | ```lisp 1073 | Function: (zone-name zone) 1074 | ``` 1075 | -------------------------------------------------------------------------------- /docs/quicklisp.md: -------------------------------------------------------------------------------- 1 | # quicklisp - Library Manager 2 | 3 | Version: 2020-01-04 4 |
5 | Licence: BSD-style 6 |
7 | Repository: [quicklisp/quicklisp-client - Github](https://github.com/quicklisp/quicklisp-client) 8 | 9 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/digikar99/common-lisp.readthedocs/issues).* 10 | 11 | 12 | ## GETTING STARTED 13 | 14 | ### Installation 15 | 16 | 17 | **Download** 18 | 19 | Do the equivalent steps on Windows and Mac OS: 20 | 21 | ```sh 22 | curl -O https://beta.quicklisp.org/quicklisp.lisp # download quicklisp.lisp 23 | curl -O https://beta.quicklisp.org/quicklisp.lisp.asc # download the PGP signature file 24 | gpg --verify quicklisp.lisp.asc quicklisp.lisp # verify it against the signing key 25 | ``` 26 | 27 | As of 07 June 2020, Quicklisp release signing key has a fingerprint of `D7A3 489D DEFE 32B7 D0E7 CC61 3079 65AB 028B 5FF7`, an id of `028B5FF7`, and an email of `release@quicklisp.org`. See [here](https://www.quicklisp.org/beta/#installation) for the more recent details. 28 | 29 | **Installation** 30 | 31 | Load quicklisp.lisp: `sbcl --load quicklisp.lisp # or an equivalent command for your implementation` (optionally, you may want to `rlwrap sbcl --load quicklisp.lisp` for a better 32 | repl experience): 33 | 34 | ```lisp 35 | (quicklisp-quickstart:install) 36 | (ql:add-to-init-file) ; to automatically load quicklisp at implementation startup 37 | ;;; Note that ql acts as a nickname for the quicklisp-client package. 38 | ``` 39 | 40 | `quicklisp-quickstart:install` also takes a couple keyword arguments (see `(describe 'quicklisp-quickstart:install)` - but unless you know what 41 | you are doing, it is recommended to leave them as they are. 42 | 43 | ### Loading after installation 44 | 45 | `(ql:add-to-init-file)` adds instructions to your implementations init-file (`.sbclrc` or 46 | equivalent) to load quicklisp on implementation startup. 47 | 48 | However, some runtime options of the implementation may disable loading the init-file - 49 | `sbcl --script` for instance. For these cases, you might want to `alias` (or equivalent) 50 | `alias sbcl-ql='rlwrap sbcl --noinform --load $HOME/quicklisp/setup.lisp'` in your `.bashrc` 51 | (or equivalent). 52 | 53 | ### A few useful functions and variables 54 | 55 | - [quickload](#quickload): `(ql:quickload '("alexandria" "bordeaux-threads"))` or `(ql:quickload "alexandria")`. 56 | - [system-apropos](#system-apropos): `(ql:system-apropos "postgres")` 57 | - [where-is-system](#where-is-system) 58 | - [\*local-project-directories\*](#local-project-directories): you may either want to have this variable modified from implementation init-file, or symlink `~/quicklisp/local-projects` to wherever your projects directory is. This is the location - as the name suggests - where quicklisp searches for local projects. 59 | - [uninstall](#uninstall) 60 | - [update-client](#update-client) 61 | 62 | You may also need to run `(asdf:clear-configuration)` to have [ASDF](https://common-lisp.net/project/asdf/asdf.html) reprocess its configuration files while loading a newer library. There is also the [ql:register-local-projects](#register-local-projects) that can help with the same. 63 | 64 | ### A note on quicklisp dists 65 | 66 | Besides being an ASDF system, quicklisp is also the name of a [dist](#dist). This distribution 67 | is released about once per month, with the guarantee that all systems in the distribution build together - note that this does not still imply that they *work* together. For these cases, 68 | you may want to [go back in dist time](http://blog.quicklisp.org/2011/08/going-back-in-dist-time.html). You might, additionally, want to learn about [qlot](https://github.com/fukamachi/qlot) that helps with version pinning - however, given the stability of Common Lisp, that translates to the stability for its (old but gold) libraries, it may be an overkill. But, YMMV. 69 | 70 | Also worth a read is [getting libraries into quicklisp](http://blog.quicklisp.org/2015/01/getting-library-into-quicklisp.html). (Hope you took note of the blog!) 71 | 72 | The once-per-month release nature of quicklisp can be an issue if you need to work with 73 | bleeding edge packages - for these cases, there exists [Ultralisp](https://ultralisp.org/) - which updates every 5 minutes! This is yet another distribution. Some useful functions for working with distributions include: 74 | 75 | - [install-dist](#install-dist) 76 | - [uninstall-dist](#uninstall-dist) 77 | - [update-dist](#update-dist): `(ql:update-dist "quicklisp")` 78 | - [find-dist](#find-dist) 79 | - [enabled-dists](#enabled-dists) 80 | - [enable](#enable) 81 | - [disable](#disable) 82 | 83 | ### More reading 84 | 85 | More reading about quicklisp is available on its [official page](https://www.quicklisp.org/beta/index.html). 86 | 87 | 88 | ## quicklisp-client: API REFERENCE 89 | 90 | Nickname: ql 91 |
92 | 93 | The Quicklisp client package, intended for end-user Quicklisp 94 | commands and configuration parameters. 95 | 96 | 97 | ### \*local-project-directories\* 98 | 99 | ```lisp 100 | Variable 101 | ``` 102 | 103 | The default local projects directory. 104 | 105 | 106 | ### \*quickload-prompt\* 107 | 108 | ```lisp 109 | Variable 110 | ``` 111 | 112 | When NIL, quickload systems without prompting for enter to 113 | continue, otherwise proceed directly without user intervention. 114 | 115 | 116 | ### \*quickload-verbose\* 117 | 118 | ```lisp 119 | Variable 120 | ``` 121 | 122 | When NIL, show terse output when quickloading a system. Otherwise, 123 | show normal compile and load output. 124 | 125 | 126 | ### add-to-init-file 127 | 128 | ```lisp 129 | Function: (add-to-init-file &optional implementation-or-file) 130 | ``` 131 | 132 | Add forms to the Lisp implementation's init file that will load 133 | quicklisp at CL startup. 134 | 135 | ### available-client-versions 136 | 137 | ```lisp 138 | Function: (available-client-versions) 139 | ``` 140 | 141 | 142 | 143 | ### available-dist-versions 144 | 145 | ```lisp 146 | Function: (available-dist-versions name) 147 | ``` 148 | 149 | 150 | 151 | ### bundle-systems 152 | 153 | ```lisp 154 | Function: (bundle-systems system-names &key include-local-projects to 155 | (overwrite t)) 156 | ``` 157 | 158 | In the directory `to`, construct a self-contained bundle of libraries 159 | based on `system-names`. For each system named, and its recursive 160 | required systems, unpack its release archive in TO/software/, and 161 | write a system index, compatible with the output of 162 | QL:[write-asdf-manifest-file](#write-asdf-manifest-file), to TO/system-index.txt. Write a loader 163 | script to TO/bundle.lisp that, when loaded via CL:LOAD, configures 164 | ASDF to load systems from the bundle before any other system. 165 | 166 | `system-names` must name systems provided directly by Quicklisp. 167 | 168 | If `include-local-projects` is true, each directory in 169 | QL:*LOCAL-PROJECT-DIRECTORIES* is copied into the bundle and loaded 170 | before any of the other bundled systems. 171 | 172 | ### client-url 173 | 174 | ```lisp 175 | Function: (client-url) 176 | ``` 177 | 178 | Return an URL suitable for passing as the :URL argument to 179 | [install-client](#install-client) for the current local client installation. 180 | 181 | ### client-version 182 | 183 | ```lisp 184 | Function: (client-version) 185 | ``` 186 | 187 | Return the version for the current local client installation. May 188 | or may not be suitable for passing as the :VERSION argument to 189 | [install-client](#install-client), depending on if it's a standard Quicklisp-provided 190 | client. 191 | 192 | ### config-value 193 | 194 | ```lisp 195 | Function: (config-value path) 196 | ``` 197 | 198 | 199 | 200 | ### dist-url 201 | 202 | ```lisp 203 | Function: (dist-url name) 204 | ``` 205 | 206 | 207 | 208 | ### dist-version 209 | 210 | ```lisp 211 | Function: (dist-version name) 212 | ``` 213 | 214 | 215 | 216 | ### help 217 | 218 | ```lisp 219 | Function: (help) 220 | ``` 221 | 222 | 223 | 224 | ### install-client 225 | 226 | ```lisp 227 | Function: (install-client &key url version) 228 | ``` 229 | 230 | 231 | 232 | ### list-local-projects 233 | 234 | ```lisp 235 | Function: (list-local-projects) 236 | ``` 237 | 238 | Return a list of pathnames to local project system files. 239 | 240 | ### list-local-systems 241 | 242 | ```lisp 243 | Function: (list-local-systems) 244 | ``` 245 | 246 | Return a list of local project system names. 247 | 248 | ### local-projects-searcher 249 | 250 | ```lisp 251 | Function: (local-projects-searcher system-name) 252 | ``` 253 | 254 | This function is added to ASDF:*SYSTEM-DEFINITION-SEARCH-FUNCTIONS* 255 | to use the local project directory and cache to find systems. 256 | 257 | ### provided-systems 258 | 259 | ```lisp 260 | Generic Function: (provided-systems object) 261 | ``` 262 | 263 | Return a list of systems provided by `object`. 264 | 265 | ### qmerge 266 | 267 | ```lisp 268 | Function: (qmerge pathname) 269 | ``` 270 | 271 | Return `pathname` merged with the base Quicklisp directory. 272 | 273 | ### quickload 274 | 275 | ```lisp 276 | Generic Function: (quickload systems &key verbose silent prompt explain 277 | &allow-other-keys) 278 | ``` 279 | 280 | Load `systems` the quicklisp way. `systems` is a designator for a list 281 | of things to be loaded. 282 | 283 | ### register-local-projects 284 | 285 | ```lisp 286 | Function: (register-local-projects) 287 | ``` 288 | 289 | Force a scan of the local projects directory to create the system 290 | file index. 291 | 292 | ### setup 293 | 294 | ```lisp 295 | Function: (setup) 296 | ``` 297 | 298 | 299 | 300 | ### system-apropos 301 | 302 | ```lisp 303 | Generic Function: (system-apropos term) 304 | ``` 305 | 306 | 307 | 308 | ### system-apropos-list 309 | 310 | ```lisp 311 | Generic Function: (system-apropos-list term) 312 | ``` 313 | 314 | 315 | 316 | ### system-list 317 | 318 | ```lisp 319 | Function: (system-list) 320 | ``` 321 | 322 | 323 | 324 | ### system-not-found 325 | 326 | ```lisp 327 | Condition 328 | ``` 329 | 330 | This condition is signaled by QUICKLOAD when a 331 | system given to load is not available via ASDF or a Quicklisp 332 | dist. 333 | 334 | **Direct Slots** 335 | 336 | **ql-dist:name** 337 | ```lisp 338 | Initargs: :NAME 339 | Readers: SYSTEM-NOT-FOUND-NAME 340 | ``` 341 | 342 | ### system-not-found-name 343 | 344 | ```lisp 345 | Generic Function: (system-not-found-name condition) 346 | ``` 347 | 348 | 349 | 350 | ### uninstall 351 | 352 | ```lisp 353 | Function: (uninstall system-name) 354 | ``` 355 | 356 | 357 | 358 | ### uninstall-dist 359 | 360 | ```lisp 361 | Function: (uninstall-dist name) 362 | ``` 363 | 364 | 365 | 366 | ### update-all-dists 367 | 368 | ```lisp 369 | Function: (update-all-dists &key (prompt t)) 370 | ``` 371 | 372 | 373 | 374 | ### update-client 375 | 376 | ```lisp 377 | Function: (update-client &key (prompt t)) 378 | ``` 379 | 380 | 381 | 382 | ### update-dist 383 | 384 | ```lisp 385 | Function: (update-dist dist &key (prompt t)) 386 | ``` 387 | 388 | 389 | 390 | ### use-only-quicklisp-systems 391 | 392 | ```lisp 393 | Function: (use-only-quicklisp-systems) 394 | ``` 395 | 396 | 397 | 398 | ### where-is-system 399 | 400 | ```lisp 401 | Function: (where-is-system name) 402 | ``` 403 | 404 | Return the pathname to the source directory of ASDF system with the 405 | given `name`, or NIL if no system by that name can be found known. 406 | 407 | ### who-depends-on 408 | 409 | ```lisp 410 | Function: (who-depends-on system-name) 411 | ``` 412 | 413 | Return a list of names of systems that depend on `system-name`. 414 | 415 | ### write-asdf-manifest-file 416 | 417 | ```lisp 418 | Function: (write-asdf-manifest-file output-file &key 419 | (if-exists :rename-and-delete) exclude-local-projects) 420 | ``` 421 | 422 | Write a list of system file pathnames to `output-file`, one per line, 423 | in order of descending QL-DIST:PREFERENCE. 424 | 425 | 426 | ## ql-dist: API Reference 427 | 428 | Generic functions, variables, and classes for interacting with the 429 | dist system. Documented, exported symbols are intended for public 430 | use. 431 | 432 | 433 | ### \*dist-enumeration-functions\* 434 | 435 | ```lisp 436 | Variable 437 | ``` 438 | 439 | [all-dists](#all-dists) calls each function in this list with no arguments, and 440 | appends the results into a list of dist objects, removing 441 | duplicates. Functions might be called just once for a batch of 442 | related operations; see [with-consistent-dists](#with-consistent-dists). 443 | 444 | 445 | ### all-dists 446 | 447 | ```lisp 448 | Function: (all-dists) 449 | ``` 450 | 451 | Return a list of all known dists. 452 | 453 | ### archive-content-sha1 454 | 455 | ```lisp 456 | Generic Function: (archive-content-sha1 object) 457 | ``` 458 | 459 | 460 | 461 | ### archive-md5 462 | 463 | ```lisp 464 | Generic Function: (archive-md5 object) 465 | ``` 466 | 467 | 468 | 469 | ### archive-size 470 | 471 | ```lisp 472 | Generic Function: (archive-size object) 473 | ``` 474 | 475 | 476 | 477 | ### archive-url 478 | 479 | ```lisp 480 | Generic Function: (archive-url release) 481 | ``` 482 | 483 | Return the full URL for fetching the archive file of `release`. 484 | 485 | ### available-update 486 | 487 | ```lisp 488 | Generic Function: (available-update dist) 489 | ``` 490 | 491 | If an update is available for `dist`, return the 492 | update as an uninstalled dist object. Otherwise, return NIL. 493 | 494 | ### available-versions 495 | 496 | ```lisp 497 | Generic Function: (available-versions object) 498 | ``` 499 | 500 | Return a list of version information for `object`. 501 | 502 | ### available-versions-url 503 | 504 | ```lisp 505 | Generic Function: (available-versions-url object) 506 | ``` 507 | 508 | Return the URL for the available versions data file of `object`. 509 | 510 | ### badly-sized-local-archive 511 | 512 | ```lisp 513 | Condition 514 | ``` 515 | 516 | 517 | ### base-directory 518 | 519 | ```lisp 520 | Generic Function: (base-directory object) 521 | ``` 522 | 523 | Return the base directory pathname of `object`. 524 | 525 | ### canonical-distinfo-url 526 | 527 | ```lisp 528 | Generic Function: (canonical-distinfo-url object) 529 | ``` 530 | 531 | 532 | 533 | ### check-local-archive-file 534 | 535 | ```lisp 536 | Generic Function: (check-local-archive-file release) 537 | ``` 538 | 539 | Check the local archive file of `release` for validity, including 540 | size and signature checks. Signals errors in the case of invalid files. 541 | 542 | ### clean 543 | 544 | ```lisp 545 | Generic Function: (clean object) 546 | ``` 547 | 548 | Remove any unneeded files or directories related to 549 | `object`. 550 | 551 | ### dependency-tree 552 | 553 | ```lisp 554 | Generic Function: (dependency-tree system) 555 | ``` 556 | 557 | 558 | 559 | ### disable 560 | 561 | ```lisp 562 | Generic Function: (disable object) 563 | ``` 564 | 565 | Disable `object`. 566 | 567 | ### dist 568 | 569 | ```lisp 570 | Generic Function: (dist object) 571 | ``` 572 | 573 | Return the dist of `object`. 574 | 575 | ```lisp 576 | Class 577 | ``` 578 | 579 | **Direct Slots** 580 | 581 | **base-directory** 582 | ```lisp 583 | Initargs: :BASE-DIRECTORY 584 | Readers: BASE-DIRECTORY 585 | Writers: (SETF BASE-DIRECTORY) 586 | ``` 587 | **name** 588 | ```lisp 589 | Initargs: :NAME 590 | Readers: NAME 591 | Writers: (SETF NAME) 592 | ``` 593 | **version** 594 | ```lisp 595 | Initargs: :VERSION 596 | Readers: VERSION 597 | Writers: (SETF VERSION) 598 | ``` 599 | **system-index-url** 600 | ```lisp 601 | Initargs: :SYSTEM-INDEX-URL 602 | Readers: SYSTEM-INDEX-URL 603 | Writers: (SETF SYSTEM-INDEX-URL) 604 | ``` 605 | **release-index-url** 606 | ```lisp 607 | Initargs: :RELEASE-INDEX-URL 608 | Readers: RELEASE-INDEX-URL 609 | Writers: (SETF RELEASE-INDEX-URL) 610 | ``` 611 | **available-versions-url** 612 | ```lisp 613 | Initargs: :AVAILABLE-VERSIONS-URL 614 | Readers: AVAILABLE-VERSIONS-URL 615 | Writers: (SETF AVAILABLE-VERSIONS-URL) 616 | ``` 617 | **canonical-distinfo-url** 618 | ```lisp 619 | Initargs: :CANONICAL-DISTINFO-URL 620 | Readers: CANONICAL-DISTINFO-URL 621 | Writers: (SETF CANONICAL-DISTINFO-URL) 622 | ``` 623 | **provided-systems** 624 | ```lisp 625 | Initargs: :PROVIDED-SYSTEMS 626 | Readers: PROVIDED-SYSTEMS 627 | Writers: (SETF PROVIDED-SYSTEMS) 628 | ``` 629 | **provided-releases** 630 | ```lisp 631 | Initargs: :PROVIDED-RELEASES 632 | Readers: PROVIDED-RELEASES 633 | Writers: (SETF PROVIDED-RELEASES) 634 | ``` 635 | 636 | ### enable 637 | 638 | ```lisp 639 | Generic Function: (enable object) 640 | ``` 641 | 642 | Enable `object`. 643 | 644 | ### enabled-dists 645 | 646 | ```lisp 647 | Function: (enabled-dists) 648 | ``` 649 | 650 | Return a list of all known dists for which [enabledp](#enabledp) returns true. 651 | 652 | ### enabledp 653 | 654 | ```lisp 655 | Generic Function: (enabledp object) 656 | ``` 657 | 658 | Return true if `object` is enabled. 659 | 660 | ### ensure-installed 661 | 662 | ```lisp 663 | Generic Function: (ensure-installed object) 664 | ``` 665 | 666 | Ensure that `object` is installed. 667 | 668 | ### ensure-local-archive-file 669 | 670 | ```lisp 671 | Generic Function: (ensure-local-archive-file release) 672 | ``` 673 | 674 | If the archive file for `release` is not available locally, fetch it 675 | and return the pathname to it. 676 | 677 | ### find-asdf-system-file 678 | 679 | ```lisp 680 | Function: (find-asdf-system-file name) 681 | ``` 682 | 683 | Return the ASDF system file in which the system named `name` is defined. 684 | 685 | ### find-dist 686 | 687 | ```lisp 688 | Function: (find-dist name) 689 | ``` 690 | 691 | 692 | 693 | ### find-dist-or-lose 694 | 695 | ```lisp 696 | Function: (find-dist-or-lose name) 697 | ``` 698 | 699 | 700 | 701 | ### find-release 702 | 703 | ```lisp 704 | Generic Function: (find-release name) 705 | ``` 706 | 707 | Return a release with the given `name`, or NIL if no system is 708 | found. If multiple releases have the same name, the one with the 709 | highest preference is returned. 710 | 711 | ### find-release-in-dist 712 | 713 | ```lisp 714 | Generic Function: (find-release-in-dist release-name dist) 715 | ``` 716 | 717 | Return a release with the given [name](#name) in `dist`, or NIL if no release 718 | is found. 719 | 720 | ### find-system 721 | 722 | ```lisp 723 | Generic Function: (find-system name) 724 | ``` 725 | 726 | Return a system with the given `name`, or NIL if no system is 727 | found. If multiple systems have the same name, the one with the 728 | highest preference is returned. 729 | 730 | ### find-system-in-dist 731 | 732 | ```lisp 733 | Generic Function: (find-system-in-dist system-name dist) 734 | ``` 735 | 736 | Return a system with the given [name](#name) in `dist`, or NIL if no system 737 | is found. 738 | 739 | ### forget-preference 740 | 741 | ```lisp 742 | Generic Function: (forget-preference object) 743 | ``` 744 | 745 | Remove specific preference information for `object`. 746 | 747 | ### inhibit-subscription 748 | 749 | ```lisp 750 | Generic Function: (inhibit-subscription object) 751 | ``` 752 | 753 | Inhibit subscription for `object`. 754 | 755 | ### initialize-release-index 756 | 757 | ```lisp 758 | Generic Function: (initialize-release-index dist) 759 | ``` 760 | 761 | Initialize the release index of `dist`. 762 | 763 | ### initialize-system-index 764 | 765 | ```lisp 766 | Generic Function: (initialize-system-index dist) 767 | ``` 768 | 769 | Initialize the system index of `dist`. 770 | 771 | ### install 772 | 773 | ```lisp 774 | Generic Function: (install object) 775 | ``` 776 | 777 | Install `object`. 778 | 779 | ### install-dist 780 | 781 | ```lisp 782 | Function: (install-dist url &key (prompt t) replace) 783 | ``` 784 | 785 | 786 | 787 | ### install-metadata-file 788 | 789 | ```lisp 790 | Generic Function: (install-metadata-file object) 791 | ``` 792 | 793 | The pathname to a file describing the installation status of 794 | `object`. 795 | 796 | ### installed-releases 797 | 798 | ```lisp 799 | Generic Function: (installed-releases dist) 800 | ``` 801 | 802 | Return a list of all releases installed for `dist`. 803 | 804 | ### installed-systems 805 | 806 | ```lisp 807 | Generic Function: (installed-systems dist) 808 | ``` 809 | 810 | Return a list of all systems installed for `dist`. 811 | 812 | ### installedp 813 | 814 | ```lisp 815 | Generic Function: (installedp object) 816 | ``` 817 | 818 | Return true if `object` is installed. 819 | 820 | ### invalid-local-archive 821 | 822 | ```lisp 823 | Condition 824 | ``` 825 | 826 | **Direct Slots** 827 | 828 | **release** 829 | ```lisp 830 | Initargs: :RELEASE 831 | Readers: INVALID-LOCAL-ARCHIVE-RELEASE 832 | ``` 833 | 834 | ### invalid-local-archive-file 835 | 836 | ```lisp 837 | Generic Function: (invalid-local-archive-file condition) 838 | ``` 839 | 840 | 841 | 842 | ### invalid-local-archive-release 843 | 844 | ```lisp 845 | Generic Function: (invalid-local-archive-release condition) 846 | ``` 847 | 848 | 849 | 850 | ### local-archive-file 851 | 852 | ```lisp 853 | Generic Function: (local-archive-file release) 854 | ``` 855 | 856 | Return the pathname to where the archive file of `release` should be 857 | stored. 858 | 859 | ### metadata-name 860 | 861 | ```lisp 862 | Generic Function: (metadata-name object) 863 | ``` 864 | 865 | The metadata-name of an object is used to form the pathname for a 866 | few different object metadata files. 867 | 868 | ### missing-local-archive 869 | 870 | ```lisp 871 | Condition 872 | ``` 873 | 874 | 875 | ### name 876 | 877 | ```lisp 878 | Generic Function: (name object) 879 | ``` 880 | 881 | Return the name of `object`. 882 | 883 | ### new-version-available-p 884 | 885 | ```lisp 886 | Generic Function: (new-version-available-p dist) 887 | ``` 888 | 889 | Return true if a new version of `dist` is available. 890 | 891 | ### preference 892 | 893 | ```lisp 894 | Generic Function: (preference object) 895 | ``` 896 | 897 | Returns a value used when comparing multiple systems or releases 898 | with the same name. Objects with higher preference are returned by 899 | [find-system](#find-system) and [find-release](#find-release). 900 | 901 | ### preference-file 902 | 903 | ```lisp 904 | Generic Function: (preference-file object) 905 | ``` 906 | 907 | Return the file from which preference information is loaded for 908 | `object`. 909 | 910 | ### preference-parent 911 | 912 | ```lisp 913 | Generic Function: (preference-parent object) 914 | ``` 915 | 916 | Return a value suitable for checking if `object` has no specific 917 | preference set. 918 | 919 | ### prefix 920 | 921 | ```lisp 922 | Generic Function: (prefix object) 923 | ``` 924 | 925 | 926 | 927 | ### project-name 928 | 929 | ```lisp 930 | Generic Function: (project-name object) 931 | ``` 932 | 933 | 934 | 935 | ### provided-releases 936 | 937 | ```lisp 938 | Generic Function: (provided-releases object) 939 | ``` 940 | 941 | Return a list of releases provided by `object`. 942 | 943 | ### provided-systems 944 | 945 | ```lisp 946 | Generic Function: (provided-systems object) 947 | ``` 948 | 949 | Return a list of systems provided by `object`. 950 | 951 | ### relative-to 952 | 953 | ```lisp 954 | Generic Function: (relative-to object pathname) 955 | ``` 956 | 957 | Merge `pathname` with the base-directory of `object`. 958 | 959 | ### release 960 | 961 | ```lisp 962 | Generic Function: (release object) 963 | ``` 964 | 965 | Return the release of `object`. 966 | 967 | ```lisp 968 | Class 969 | ``` 970 | 971 | Instances of this class represent a snapshot of a project at some 972 | point in time, which might be from version control, or from an 973 | official release, or from some other source. 974 | 975 | **Direct Slots** 976 | 977 | **project-name** 978 | ```lisp 979 | Initargs: :PROJECT-NAME 980 | ``` 981 | **dist** 982 | ```lisp 983 | Initargs: :DIST 984 | ``` 985 | **provided-systems** 986 | ```lisp 987 | Initargs: :PROVIDED-SYSTEMS 988 | Readers: PROVIDED-SYSTEMS 989 | Writers: (SETF PROVIDED-SYSTEMS) 990 | ``` 991 | **archive-url** 992 | ```lisp 993 | Initargs: :ARCHIVE-URL 994 | Readers: ARCHIVE-URL 995 | Writers: (SETF ARCHIVE-URL) 996 | ``` 997 | **archive-size** 998 | ```lisp 999 | Initargs: :ARCHIVE-SIZE 1000 | Readers: ARCHIVE-SIZE 1001 | Writers: (SETF ARCHIVE-SIZE) 1002 | ``` 1003 | **archive-md5** 1004 | ```lisp 1005 | Initargs: :ARCHIVE-MD5 1006 | Readers: ARCHIVE-MD5 1007 | Writers: (SETF ARCHIVE-MD5) 1008 | ``` 1009 | **archive-content-sha1** 1010 | ```lisp 1011 | Initargs: :ARCHIVE-CONTENT-SHA1 1012 | Readers: ARCHIVE-CONTENT-SHA1 1013 | Writers: (SETF ARCHIVE-CONTENT-SHA1) 1014 | ``` 1015 | **prefix** 1016 | ```lisp 1017 | Initargs: :PREFIX 1018 | ``` 1019 | **system-files** 1020 | ```lisp 1021 | Initargs: :SYSTEM-FILES 1022 | Readers: SYSTEM-FILES 1023 | Writers: (SETF SYSTEM-FILES) 1024 | ``` 1025 | **metadata-name** 1026 | ```lisp 1027 | Initargs: :METADATA-NAME 1028 | Readers: METADATA-NAME 1029 | Writers: (SETF METADATA-NAME) 1030 | ``` 1031 | 1032 | ### release-index-url 1033 | 1034 | ```lisp 1035 | Generic Function: (release-index-url object) 1036 | ``` 1037 | 1038 | Return the URL for the release index of `object`. 1039 | 1040 | ### required-systems 1041 | 1042 | ```lisp 1043 | Generic Function: (required-systems object) 1044 | ``` 1045 | 1046 | 1047 | 1048 | ### short-description 1049 | 1050 | ```lisp 1051 | Generic Function: (short-description object) 1052 | ``` 1053 | 1054 | Return a short string describing `object`. 1055 | 1056 | ### show-update-report 1057 | 1058 | ```lisp 1059 | Generic Function: (show-update-report old-dist new-dist) 1060 | ``` 1061 | 1062 | Display a description of the update from `old-dist` 1063 | to `new-dist`. 1064 | 1065 | ### standard-dist-enumeration-function 1066 | 1067 | ```lisp 1068 | Function: (standard-dist-enumeration-function) 1069 | ``` 1070 | 1071 | The default function used for producing a list of dist objects. 1072 | 1073 | ### subscribe 1074 | 1075 | ```lisp 1076 | Generic Function: (subscribe object) 1077 | ``` 1078 | 1079 | Subscribe to updates of `object`, if possible. If no 1080 | updates are available, a condition of type [subscription-unavailable](#subscription-unavailable) 1081 | is raised. 1082 | 1083 | ### subscribedp 1084 | 1085 | ```lisp 1086 | Generic Function: (subscribedp object) 1087 | ``` 1088 | 1089 | Return true if `object` is subscribed to updates. 1090 | 1091 | ### subscription-inhibited-p 1092 | 1093 | ```lisp 1094 | Generic Function: (subscription-inhibited-p object) 1095 | ``` 1096 | 1097 | Return T if subscription to `object` is inhibited. 1098 | 1099 | ### subscription-inhibition-file 1100 | 1101 | ```lisp 1102 | Generic Function: (subscription-inhibition-file object) 1103 | ``` 1104 | 1105 | The file whose presence indicates the inhibited 1106 | subscription status of `object`. 1107 | 1108 | ### subscription-unavailable 1109 | 1110 | ```lisp 1111 | Condition 1112 | ``` 1113 | 1114 | 1115 | ### subscription-url 1116 | 1117 | ```lisp 1118 | Generic Function: (subscription-url object) 1119 | ``` 1120 | 1121 | 1122 | 1123 | ### system 1124 | 1125 | ```lisp 1126 | Generic Function: (system object) 1127 | ``` 1128 | 1129 | Return the system of `object`. 1130 | 1131 | ```lisp 1132 | Class 1133 | ``` 1134 | 1135 | **Direct Slots** 1136 | 1137 | **name** 1138 | ```lisp 1139 | Initargs: :NAME 1140 | ``` 1141 | **system-file-name** 1142 | ```lisp 1143 | Initargs: :SYSTEM-FILE-NAME 1144 | Readers: SYSTEM-FILE-NAME 1145 | Writers: (SETF SYSTEM-FILE-NAME) 1146 | ``` 1147 | **release** 1148 | ```lisp 1149 | Initargs: :RELEASE 1150 | ``` 1151 | **dist** 1152 | ```lisp 1153 | Initargs: :DIST 1154 | Readers: DIST 1155 | Writers: (SETF DIST) 1156 | ``` 1157 | **required-systems** 1158 | ```lisp 1159 | Initargs: :REQUIRED-SYSTEMS 1160 | Readers: REQUIRED-SYSTEMS 1161 | Writers: (SETF REQUIRED-SYSTEMS) 1162 | ``` 1163 | **metadata-name** 1164 | ```lisp 1165 | Initargs: :METADATA-NAME 1166 | Readers: METADATA-NAME 1167 | Writers: (SETF METADATA-NAME) 1168 | ``` 1169 | 1170 | ### system-apropos 1171 | 1172 | ```lisp 1173 | Generic Function: (system-apropos term) 1174 | ``` 1175 | 1176 | 1177 | 1178 | ### system-apropos-list 1179 | 1180 | ```lisp 1181 | Generic Function: (system-apropos-list term) 1182 | ``` 1183 | 1184 | 1185 | 1186 | ### system-definition-searcher 1187 | 1188 | ```lisp 1189 | Function: (system-definition-searcher name) 1190 | ``` 1191 | 1192 | Like [find-asdf-system-file](#find-asdf-system-file), but this function can be used in 1193 | ASDF:*SYSTEM-DEFINITION-SEARCH-FUNCTIONS*; it will only return system 1194 | file names if they match `name`. 1195 | 1196 | ### system-file-name 1197 | 1198 | ```lisp 1199 | Generic Function: (system-file-name object) 1200 | ``` 1201 | 1202 | 1203 | 1204 | ### system-files 1205 | 1206 | ```lisp 1207 | Generic Function: (system-files object) 1208 | ``` 1209 | 1210 | 1211 | 1212 | ### system-index-url 1213 | 1214 | ```lisp 1215 | Generic Function: (system-index-url object) 1216 | ``` 1217 | 1218 | Return the URL for the system index of `object`. 1219 | 1220 | ### uninhibit-subscription 1221 | 1222 | ```lisp 1223 | Generic Function: (uninhibit-subscription object) 1224 | ``` 1225 | 1226 | Remove inhibition of subscription for `object`. 1227 | 1228 | ### uninstall 1229 | 1230 | ```lisp 1231 | Generic Function: (uninstall object) 1232 | ``` 1233 | 1234 | Uninstall `object`. 1235 | 1236 | ### unknown-dist 1237 | 1238 | ```lisp 1239 | Condition 1240 | ``` 1241 | 1242 | **Direct Slots** 1243 | 1244 | **name** 1245 | ```lisp 1246 | Initargs: :NAME 1247 | Readers: :UNKNOWN-DIST-NAME 1248 | ``` 1249 | 1250 | ### unsubscribe 1251 | 1252 | ```lisp 1253 | Generic Function: (unsubscribe object) 1254 | ``` 1255 | 1256 | Unsubscribe from updates to `object`. 1257 | 1258 | ### update-in-place 1259 | 1260 | ```lisp 1261 | Generic Function: (update-in-place old-dist new-dist) 1262 | ``` 1263 | 1264 | Update `old-dist` to `new-dist` in place. 1265 | 1266 | ### update-release-differences 1267 | 1268 | ```lisp 1269 | Generic Function: (update-release-differences old-dist new-dist) 1270 | ``` 1271 | 1272 | Compare `old-dist` to `new-dist` and return three lists 1273 | as multiple values: new releases (present in `new-dist` but not 1274 | `old-dist`), changed releases (present in both dists but different in 1275 | some way), and removed releases (present in `old-dist` but not 1276 | `new-dist`). The list of changed releases is a list of two-element 1277 | lists, with each two-element list having first the old release 1278 | object and then the new release object. 1279 | 1280 | ### version 1281 | 1282 | ```lisp 1283 | Generic Function: (version object) 1284 | ``` 1285 | 1286 | 1287 | 1288 | ### with-consistent-dists 1289 | 1290 | ```lisp 1291 | Macro: (with-consistent-dists &body body) 1292 | ``` 1293 | 1294 | See CALL-WITH-CONSISTENT-DISTS. 1295 | -------------------------------------------------------------------------------- /docs/unix-opts.md: -------------------------------------------------------------------------------- 1 | # unix-opts - cmd line argument parser 2 | 3 | Version: 0.1.7 4 |
5 | Licence: MIT 6 |
7 | Nickname: opts 8 |
9 | Repository: [libre-man/unix-opts](https://github.com/libre-man/unix-opts) 10 |
11 | See also: [awesome-cl#command-line-options-parsers](https://github.com/CodyReichert/awesome-cl#command-line-options-parsers) 12 | 13 | *This documentation was possible due to the excellent [official documentation and 14 | example](https://github.com/libre-man/unix-opts).* 15 | 16 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/digikar99/common-lisp.readthedocs/issues).* 17 | 18 | *** 19 | 20 | ## GETTING STARTED 21 | 22 | Consider the following command line options defined using [define-opts](#define-opts): 23 | 24 | ```lisp 25 | (opts:define-opts 26 | (:name :help 27 | :description "print this help text" 28 | :short #\h 29 | :long "help") 30 | (:name :verbose 31 | :description "verbose output" 32 | :short #\v 33 | :long "verbose") 34 | (:name :level 35 | :description "the program will run on LEVEL level" 36 | :short #\l 37 | :long "level" 38 | :required t 39 | :arg-parser #'parse-integer ; <- takes an argument, which we want to parse into integer 40 | :meta-var "LEVEL") 41 | (:name :output 42 | :description "redirect output to file FILE" 43 | :short #\o 44 | :long "output" 45 | :arg-parser #'identity ; <- takes an argument, but we keep it as the string 46 | :meta-var "FILE")) 47 | ``` 48 | 49 | [describe](#describe) gets us the required "help text" (see the documentation for other 50 | options): 51 | 52 | ```lisp 53 | CL-USER> (opts:describe :prefix "Demonstrating REPL") 54 | Demonstrating REPL 55 | 56 | Available options: 57 | -h, --help print this help text 58 | -v, --verbose verbose output 59 | -l, --level LEVEL (Required) the program will run on LEVEL level 60 | -o, --output FILE redirect output to file FILE 61 | NIL 62 | ``` 63 | 64 | Command line arguments can be processed with a call to [get-opts](#get-opts). 65 | For demonstration purposes, we use the REPL. See [this example 66 | directory](https://github.com/libre-man/unix-opts/tree/master/example) 67 | to see how this might be done in a script. 68 | 69 | ```lisp 70 | CL-USER> (opts:get-opts '()) 71 | ; Evaluation aborted on #. 72 | CL-USER> (opts:get-opts '("--level" "2")) 73 | (:LEVEL 2) 74 | NIL 75 | CL-USER> (opts:get-opts '("--level" "2" "--help")) 76 | (:LEVEL 2 :HELP T) 77 | NIL 78 | ``` 79 | 80 | `get-opts` can throw several conditions: 81 | 82 | - [unknown-option](#unknown-option) 83 | - [missing-arg](#missing-arg) 84 | - [arg-parser-failed](#arg-parser-failed) 85 | - [missing-required-option](#missing-required-option) 86 | 87 | Each of these has several restarts: 88 | 89 | - [use-value](#use-value) 90 | - [skip-option](#skip-option) 91 | - [reparse-arg](#reparse-arg) 92 | 93 | (See the documentation for [get-opts](#get-opts) for the details about each of these restarts. 94 | The Cookbook chapter on [Error and Exception 95 | Handling](https://lispcookbook.github.io/cl-cookbook/error_handling.html) should be helpful 96 | if you want to learn about them.) 97 | 98 | Thus, a typical way to use `get-opts` would be simply wrap the error in [handler-case](): 99 | 100 | ```lisp 101 | CL-USER> (handler-case (opts:get-opts '()) 102 | (error (condition) 103 | (format t "~A" condition) 104 | (opts:describe))) 105 | missing required options: "--level" 106 | Available options: 107 | -h, --help print this help text 108 | -v, --verbose verbose output 109 | -l, --level LEVEL (Required) the program will run on LEVEL level 110 | -o, --output FILE redirect output to file FILE 111 | 112 | NIL 113 | ``` 114 | 115 | You could use [getf](http://www.lispworks.com/documentation/lw50/CLHS/Body/f_getf.htm#getf) 116 | or [destructuring-bind](http://www.lispworks.com/documentation/HyperSpec/Body/m_destru.htm#destructuring-bind) 117 | to obtain the arguments you need: 118 | 119 | ```lisp 120 | CL-USER> (defun process-options (&rest options) 121 | (handler-case (opts:get-opts options) 122 | (error (condition) ; or you could case down on the various conditions above! 123 | (format t "~A" condition) 124 | (opts:describe)))) 125 | PROCESS-OPTIONS 126 | CL-USER> (destructuring-bind (&key level help) (process-options "--level" "2" "--help") 127 | (if help 128 | (opts:describe) 129 | (format t "I see you've supplied level option, you want ~a level!~%" level))) 130 | 131 | Available options: 132 | -h, --help print this help text 133 | -v, --verbose verbose output 134 | -l, --level LEVEL (Required) the program will run on LEVEL level 135 | -o, --output FILE redirect output to file FILE 136 | 137 | NIL 138 | CL-USER> (destructuring-bind (&key level help) (process-options "--level" "2") 139 | (if help 140 | (opts:describe) 141 | (format t "I see you've supplied level option, you want ~a level!~%" level))) 142 | I see you've supplied level option, you want 2 level! 143 | NIL 144 | ``` 145 | 146 | You could also [iterate:dsetq](../iterate/#dsetq) to bring the options to global space. 147 | 148 | ```lisp 149 | CL-USER> (destructuring-bind (&key verbose level help) 150 | (process-options "--level" "2" "--verbose") 151 | (if help 152 | (opts:describe) ; assume we have defined *level* and *verbose* previously 153 | (dsetq (*verbose* *level*) (list verbose level)))) 154 | (T 2) 155 | CL-USER> *verbose* 156 | T 157 | CL-USER> *level* 158 | 2 159 | ``` 160 | 161 | ## API REFERENCE 162 | 163 | ### arg-parser-failed 164 | 165 | 166 | ```lisp 167 | Condition 168 | ``` 169 | 170 | This condition is thrown when some option OPTION wants 171 | an argument, it's given but cannot be parsed by argument parser. 172 | 173 | **Direct Slots** 174 | 175 | **raw-arg** 176 | ```lisp 177 | Initargs: :RAW-ARG 178 | Readers: RAW-ARG 179 | ``` 180 | ### argv 181 | 182 | ```lisp 183 | Function: (argv) 184 | ``` 185 | Return a list of program's arguments, including command used to execute 186 | the program as first elements of the list. Portable across implementations. 187 | 188 | ### define-opts 189 | 190 | ```lisp 191 | Macro: (define-opts &body descriptions) 192 | ``` 193 | Define command line options. Arguments of this macro must be plists 194 | containing various parameters. Here we enumerate all allowed parameters: 195 | 196 | - **:name** - keyword that will be included in list returned by [get-opts](#get-opts) function if 197 | actual option is supplied by user. 198 | 199 | - **:description** - description of the option (it will be used in [describe](#describe) 200 | function). This argument is optional, but it's recommended to supply it. 201 | 202 | - **:short** - single character, short variant of the option. You may omit this 203 | argument if you supply `:long` variant of option. 204 | 205 | - **:long** - string, long variant of option. You may omit this argument if you 206 | supply `:short` variant of option. 207 | 208 | - **:arg-parser** - if actual option must take an argument, supply this argument, it 209 | must be a function that takes a string and parses it. 210 | 211 | - **:meta-var** - if actual option requires an argument, this is how it will be 212 | printed in option description. 213 | 214 | ### describe 215 | 216 | ```lisp 217 | Function: (describe &key prefix suffix usage-of args (stream *standard-output*)) 218 | ``` 219 | Return string describing options of the program that were defined with 220 | `define-opts` macro previously. You can supply `prefix` and `suffix` arguments 221 | that will be printed before and after options respectively. If `usage-of` is 222 | supplied, it should be a string, name of the program for "Usage: " 223 | section. This section is only printed if this name is given. If your program 224 | takes arguments (apart from options), you can specify how to print them in 225 | "Usage: " section with `args` option (should be a string designator). Output 226 | goes to `stream`. 227 | 228 | ### exit 229 | 230 | ```lisp 231 | Function: (exit &optional (status 0)) 232 | ``` 233 | Exit the program returning `status`. 234 | 235 | ### get-opts 236 | 237 | ```lisp 238 | Function: (get-opts &optional options) 239 | ``` 240 | Parse command line options. If `options` is given, it should be a list to 241 | parse. If it's not given, the function will use `argv` function to get list 242 | of command line arguments. 243 | 244 | Return two values: 245 | 246 | * a list that contains keywords associated with command line options with 247 | `define-opts` macro, and 248 | * a list of free arguments. 249 | 250 | If some option requires an argument, you can use `getf` to 251 | test presence of the option and get its argument if the option is present. 252 | 253 | The parser may signal various conditions. Let's list them all specifying 254 | which restarts are available for every condition, and what kind of 255 | information the programmer can extract from the conditions. 256 | 257 | - [unknown-option](#unknown-option) is thrown when parser encounters unknown (not previously 258 | defined with `define-opts`) option. Use the `option` reader to get name of 259 | the option (string). Available restarts: 260 | - [use-value](#use-value): substitute the option and try again, 261 | - [skip-option](#skip-option): ignore the option. 262 | 263 | - [missing-arg](#missing-arg) is thrown when some option wants an argument, but there is no 264 | such argument given. Use the `option` reader to get name of the 265 | option (string). Available restarts: 266 | - [use-value](#use-value): supplied value will be used, 267 | - [skip-option](#skip-option): ignore the option. 268 | 269 | - [arg-parser-failed](#arg-parser-failed) is thrown when some option wants an argument, it's given 270 | but cannot be parsed by argument parser. Use the `option` reader to get name 271 | of the option (string) and `raw-arg` to get raw string representing the 272 | argument before parsing. Available restarts: 273 | - [use-value](#use-value): supplied value will be used, 274 | - [skip-option](#skip-option): ignore the option, 275 | - [reparse-arg](#reparse-arg): supplied string will be parsed instead. 276 | 277 | - [missing-required-option](#missing-required-option) is thrown when some option was required but was 278 | not given. Use the `missing-options` reader to get the list of options that 279 | are missing. Available restarts: 280 | - [use-value](#use-value): supplied list of values will be used, 281 | - [skip-option](#skip-option): ignore all these options, effectively binding them 282 | to `nil` 283 | 284 | ### missing-arg 285 | 286 | 287 | ```lisp 288 | Condition 289 | ``` 290 | 291 | This condition is thrown when some option OPTION wants 292 | an argument, but there is no such argument given. 293 | 294 | ### missing-options 295 | 296 | ```lisp 297 | Generic Function: (missing-options condition) 298 | ``` 299 | 300 | 301 | ### missing-required-option 302 | 303 | 304 | ```lisp 305 | Condition 306 | ``` 307 | 308 | This condition is thrown when required options are missing. 309 | 310 | **Direct Slots** 311 | 312 | **missing-options** 313 | ```lisp 314 | Initargs: :MISSING-OPTIONS 315 | Readers: MISSING-OPTIONS 316 | ``` 317 | ### option 318 | 319 | ```lisp 320 | Generic Function: (option condition) 321 | ``` 322 | 323 | 324 | 325 | ```lisp 326 | Class 327 | ``` 328 | 329 | representation of an option 330 | 331 | ### raw-arg 332 | 333 | ```lisp 334 | Generic Function: (raw-arg condition) 335 | ``` 336 | 337 | 338 | ### reparse-arg 339 | 340 | ### skip-option 341 | 342 | ### unknown-option 343 | 344 | 345 | ```lisp 346 | Condition 347 | ``` 348 | 349 | This condition is thrown when parser encounters 350 | unknown (not previously defined with `define-opts`) option. 351 | 352 | ### use-value 353 | 354 | ```lisp 355 | Function: (use-value value &optional condition) 356 | ``` 357 | Transfer control and `value` to a restart named USE-VALUE, or 358 | return NIL if none exists. 359 | -------------------------------------------------------------------------------- /docs/utilities.md: -------------------------------------------------------------------------------- 1 | # utilities - A collection of utility libraries 2 | 3 | A collection of smallish utility libraries. 4 | 5 | *In case of any inaccuracies, ambiguities or suggestions, please [create an issue here](https://github.com/cl-library-docs/common-lisp-libraries/issues).* 6 | 7 | *** 8 | 9 | 10 | 11 | ## PARSE-NUMBER 12 | 13 | Version: 1.7 14 |
15 | Licence: BSD 3-Clause 16 |
17 | Repository: [sharplispers/parse-number - Github](https://github.com/sharplispers/parse-number) 18 | 19 | PARSE-NUMBER is a library of functions which accept an arbitrary 20 | string and attempt to parse it, if possible into one of the standard 21 | Common Lisp number types without using the reader, or else signal an 22 | error of type `invalid-number`. 23 | 24 | ### invalid-number 25 | 26 | ```lisp 27 | Condition 28 | ``` 29 | 30 | ### invalid-number-reason 31 | 32 | ```lisp 33 | Generic Function: (invalid-number-reason condition) 34 | ``` 35 | 36 | ### invalid-number-value 37 | 38 | ```lisp 39 | Generic Function: (invalid-number-value condition) 40 | ``` 41 | 42 | ### parse-number 43 | 44 | ```lisp 45 | Function: (parse-number string &key (start 0) (end NIL) (radix 10) 46 | ((:float-format *read-default-float-format*) 47 | *read-default-float-format*)) 48 | ``` 49 | 50 | ### parse-positive-real-number 51 | 52 | ```lisp 53 | Function: (parse-positive-real-number string &key (start 0) (end NIL) 54 | (radix 10) 55 | ((float-format *read-default-float-format*) 56 | *read-default-float-format*)) 57 | ``` 58 | 59 | ### parse-real-number 60 | 61 | ```lisp 62 | Function: (parse-real-number string &key (start 0) (end NIL) (radix 10) 63 | ((float-format *read-default-float-format*) 64 | *read-default-float-format*)) 65 | ``` 66 | 67 | ## SPLIT-SEQUENCE 68 | 69 | Version: 2.0.0 70 |
71 | Licence: MIT 72 |
73 | Repository: [sharplispers/split-sequence](https://github.com/sharplispers/split-sequence) 74 | 75 | ### split-sequence 76 | 77 | ```lisp 78 | Function: (split-sequence delimiter sequence &key (start 0) (end NIL) 79 | (from-end NIL) (count NIL) (remove-empty-subseqs NIL) 80 | (test (function eql) test-p) (test-not NIL test-not-p) 81 | (key (function identity))) 82 | ``` 83 | 84 | Return a list of subsequences in seq delimited by delimiter. 85 | If `:remove-empty-subseqs` is NIL, empty subsequences will be included 86 | in the result; otherwise they will be discarded. All other keywords 87 | work analogously to those for [cl:substitute](http://www.lispworks.com/documentation/HyperSpec/Body/f_sbs_s.htm). In particular, the 88 | behaviour of `:from-end` is possibly different from other versions of 89 | this function; `:from-end` values of NIL and T are equivalent unless 90 | `:count` is supplied. `:count` limits the number of subseqs in the main 91 | resulting list. The second return value is an index suitable as an 92 | argument to [cl:subseq](http://www.lispworks.com/documentation/HyperSpec/Body/f_subseq.htm) into the sequence indicating where processing 93 | stopped. 94 | 95 | ### split-sequence-if 96 | 97 | ```lisp 98 | Function: (split-sequence-if predicate sequence &key (start 0) (end NIL) 99 | (from-end NIL) (count NIL) (remove-empty-subseqs NIL) 100 | (key (function identity))) 101 | ``` 102 | 103 | Return a list of subsequences in seq delimited by items satisfying 104 | predicate. 105 | If `:remove-empty-subseqs` is NIL, empty subsequences will be included 106 | in the result; otherwise they will be discarded. All other keywords 107 | work analogously to those for [cl:substitute-if](http://www.lispworks.com/documentation/HyperSpec/Body/f_sbs_s.htm). In particular, the 108 | behaviour of `:from-end` is possibly different from other versions of 109 | this function; `:from-end` values of NIL and T are equivalent unless 110 | `:count` is supplied. `:count` limits the number of subseqs in the main 111 | resulting list. The second return value is an index suitable as an 112 | argument to [cl:subseq](http://www.lispworks.com/documentation/HyperSpec/Body/f_subseq.htm) into the sequence indicating where processing 113 | stopped. 114 | 115 | ### split-sequence-if-not 116 | 117 | ```lisp 118 | Function: (split-sequence-if-not predicate sequence &key (start 0) (end NIL) 119 | (from-end NIL) (count NIL) (remove-empty-subseqs NIL) 120 | (key (function identity))) 121 | ``` 122 | 123 | Return a list of subsequences in seq delimited by items satisfying 124 | ([cl:complement](http://www.lispworks.com/documentation/HyperSpec/Body/f_comple.htm) predicate). 125 | If `:remove-empty-subseqs` is NIL, empty subsequences will be included 126 | in the result; otherwise they will be discarded. All other keywords 127 | work analogously to those for [cl:substitute-if-not](http://www.lispworks.com/documentation/HyperSpec/Body/f_sbs_s.htm). In particular, 128 | the behaviour of `:from-end` is possibly different from other versions 129 | of this function; `:from-end` values of NIL and T are equivalent unless 130 | `:count` is supplied. `:count` limits the number of subseqs in the main 131 | resulting list. The second return value is an index suitable as an 132 | argument to [cl:subseq](http://www.lispworks.com/documentation/HyperSpec/Body/f_subseq.htm) into the sequence indicating where processing 133 | stopped. 134 | 135 | ## TRIVIAL-TYPES 136 | 137 | Version: 0.1 138 |
139 | Licence: LLGPL 140 |
141 | Repository: [m2ym/trivial-types - Github](https://github.com/m2ym/trivial-types) 142 |
143 | 144 | TODO: This repository is archived; quickdocs points to this; a [branch of a fork](https://github.com/christophejunke/trivial-types/tree/patch-1) is ahead of this. 145 | 146 | TRIVIAL-TYPES provides missing but important type 147 | definitions such as `proper-list`, `association-list`, `property-list` and 148 | `tuple`. 149 | 150 | By using these types, you can keep type declarations more 151 | accurate. For example, you may write a class definition like: 152 | 153 | ```lisp 154 | (defclass person () 155 | ((name :type string)) 156 | ((age :type fixnum)) 157 | ((friends :type list))) 158 | ``` 159 | 160 | However, it is not obvious for anyone except you that FRIENDS slot has 161 | only a list of person. If you want declare `friends` slot more 162 | accurately,` proper-list` is the best for that: 163 | 164 | ```lisp 165 | (defclass person () 166 | ((name :type string)) 167 | ((age :type fixnum)) 168 | ((friends :type (proper-list person)))) 169 | ``` 170 | 171 | In addition, TRIVIAL-TYPES also provides standard designators defined 172 | in ANSI standard such as `package-designator`. They are useful when you 173 | write a function that takes a package-oid argument like: 174 | 175 | ```lisp 176 | (defun list-external-symbols (package) 177 | (declare (package-designator package)) 178 | (loop for symbol being the external-symbol of package 179 | collect symbol)) 180 | ``` 181 | 182 | An exhaustive list of provided types includes: 183 | 184 | - [association-list](#association-list-p) 185 | - character-designator 186 | - [file-associated-stream](#file-associated-stream-p) 187 | - file-position-designator 188 | - function-designator 189 | - list-designator 190 | - non-nil 191 | - package-designator 192 | - pathname-designator 193 | - [proper-list](#proper-list-p) 194 | - [property-list](#property-list-p) 195 | - stream-designator 196 | - string-designator 197 | 198 | ### association-list-p 199 | 200 | ```lisp 201 | Function: (association-list-p var) 202 | ``` 203 | 204 | Returns true if OBJECT is an association list. 205 | 206 | Examples: 207 | 208 | ```lisp 209 | (association-list-p 1) => NIL 210 | (association-list-p '(1 2 3)) => NIL 211 | (association-list-p nil) => T 212 | (association-list-p '((foo))) => T 213 | (association-list-p '((:a . 1) (:b . 2))) => T 214 | ``` 215 | 216 | ### file-associated-stream-p 217 | 218 | ```lisp 219 | Function: (file-associated-stream-p stream) 220 | ``` 221 | 222 | Returns true if `stream` is a stream associated to a file. 223 | 224 | ### proper-list-p 225 | 226 | ```lisp 227 | Function: (proper-list-p object) 228 | ``` 229 | 230 | Returns true if `object` is a proper list. 231 | 232 | Examples: 233 | 234 | ```lisp 235 | (proper-list-p 1) => NIL 236 | (proper-list-p '(1 . 2)) => NIL 237 | (proper-list-p nil) => T 238 | (proper-list-p '(1 2 3)) => T 239 | ``` 240 | 241 | ### property-list-p 242 | 243 | ```lisp 244 | Function: (property-list-p object) 245 | ``` 246 | 247 | Returns true if `object` is a property list. 248 | 249 | Examples: 250 | 251 | ```lisp 252 | (property-list-p 1) => NIL 253 | (property-list-p '(1 2 3)) => NIL 254 | (property-list-p '(foo)) => NIL 255 | (property-list-p nil) => T 256 | (property-list-p '(foo 1)) => T 257 | (property-list-p '(:a 1 :b 2)) => T 258 | ``` 259 | 260 | ### tuple 261 | 262 | ```lisp 263 | Function: (tuple &rest args) 264 | ``` 265 | 266 | Exactly same as LIST. 267 | 268 | ### tuplep 269 | 270 | ```lisp 271 | Function: (tuplep object) 272 | ``` 273 | 274 | Returns true if `object` is a tuple, meaning a proper list. 275 | 276 | Examples: 277 | 278 | ```lisp 279 | (tuplep 1) => NIL 280 | (tuplep '(1 . 2)) => NIL 281 | (tuplep nil) => T 282 | (tuplep '(1 2 3)) => T 283 | ``` 284 | 285 | ### type-expand 286 | 287 | ```lisp 288 | Function: (type-expand type-specifier &optional env) 289 | ``` 290 | 291 | Expand `type-specifier` in the lexical environment `env`. 292 | 293 | ### type-specifier-p 294 | 295 | ```lisp 296 | Function: (type-specifier-p type-specifier) 297 | ``` 298 | 299 | Returns true if `type-specifier` is a valid type specfiier. 300 | 301 | 302 | ## TRIVIAL-PACKAGE-LOCAL-NICKNAMES 303 | 304 | Version: 0.2 305 |
306 | Licence: Public Domain 307 |
308 | Repository: [phoe/trivial-package-local-nicknames](https://github.com/phoe/trivial-package-local-nicknames) 309 | 310 | A portability layer for package local nicknames. 311 | 312 | ### add-package-local-nickname 313 | 314 | ```lisp 315 | Function: (add-package-local-nickname local-nickname actual-package &optional 316 | (package-designator (sane-package))) 317 | ``` 318 | 319 | Adds `local-nickname` for `actual-package` in the designated package, defaulting 320 | to current package. `local-nickname` must be a string designator, and 321 | `actual-package` must be a package designator. 322 | 323 | Returns the designated package. 324 | 325 | Signals a continuable error if `local-nickname` is already a package local 326 | nickname for a different package, or if `local-nickname` is one of "CL", 327 | "COMMON-LISP", or, "KEYWORD", or if `local-nickname` is a global name or 328 | nickname for the package to which the nickname would be added. 329 | 330 | When in the designated package, calls to FIND-PACKAGE with the `local-nickname` 331 | will return the package the designated `actual-package` instead. This also 332 | affects all implied calls to FIND-PACKAGE, including those performed by the 333 | reader. 334 | 335 | When printing a package prefix for a symbol with a package local nickname, 336 | local nickname is used instead of the real name in order to preserve 337 | print-read consistency. 338 | 339 | See also: [package-local-nicknames](#package-local-nicknames), [package-locally-nicknamed-by-list](#package-locally-nicknamed-by-list), 340 | [remove-package-local-nickname](#remove-package-local-nickname), and the DEFPACKAGE option :LOCAL-NICKNAMES. 341 | 342 | Experimental: interface subject to change. 343 | 344 | ### package-local-nicknames 345 | 346 | ```lisp 347 | Function: (package-local-nicknames package-designator) 348 | ``` 349 | 350 | Returns an alist of (local-nickname . actual-package) describing the 351 | nicknames local to the designated package. 352 | 353 | When in the designated package, calls to FIND-PACKAGE with the any of the 354 | local-nicknames will return the corresponding actual-package instead. This 355 | also affects all implied calls to FIND-PACKAGE, including those performed by 356 | the reader. 357 | 358 | When printing a package prefix for a symbol with a package local nickname, the 359 | local nickname is used instead of the real name in order to preserve 360 | print-read consistency. 361 | 362 | See also: [add-package-local-nickname](#add-package-local-nickname), [package-locally-nicknamed-by-list](#package-locally-nicknamed-by-list), 363 | [remove-package-local-nickname](#remove-package-local-nickname), and the DEFPACKAGE option :LOCAL-NICKNAMES. 364 | 365 | Experimental: interface subject to change. 366 | 367 | ### package-locally-nicknamed-by-list 368 | 369 | ```lisp 370 | Function: (package-locally-nicknamed-by-list package-designator) 371 | ``` 372 | 373 | Returns a list of packages which have a local nickname for the designated 374 | package. 375 | 376 | See also: [add-package-local-nickname](#add-package-local-nickname), [package-local-nicknames](#package-local-nicknames), 377 | [remove-package-local-nickname](#remove-package-local-nickname), and the DEFPACKAGE option :LOCAL-NICKNAMES. 378 | 379 | Experimental: interface subject to change. 380 | 381 | ### remove-package-local-nickname 382 | 383 | ```lisp 384 | Function: (remove-package-local-nickname old-nickname &optional 385 | (package-designator (sane-package))) 386 | ``` 387 | 388 | If the designated package had `old-nickname` as a local nickname for 389 | another package, it is removed. Returns true if the nickname existed and was 390 | removed, and NIL otherwise. 391 | 392 | See also: [add-package-local-nickname](#add-package-local-nickname), [package-local-nicknames](#package-local-nicknames), 393 | [package-locally-nicknamed-by-list](#package-locally-nicknamed-by-list), and the DEFPACKAGE option :LOCAL-NICKNAMES. 394 | 395 | Experimental: interface subject to change. 396 | 397 | -------------------------------------------------------------------------------- /emacs-utils.el: -------------------------------------------------------------------------------- 1 | 2 | 3 | ;; https://www.emacswiki.org/emacs/RegularExpression 4 | 5 | (defun quote-symbol-at-point () 6 | (interactive) 7 | (beginning-of-thing 'symbol) 8 | (insert ?\`) 9 | (end-of-thing 'symbol) 10 | (insert ?`)) 11 | 12 | (defun quote-keyword-at-point () 13 | (interactive) 14 | (beginning-of-thing 'symbol) 15 | (backward-char) 16 | (insert ?\`) 17 | (forward-char) 18 | (end-of-thing 'symbol) 19 | (insert ?`)) 20 | 21 | (global-set-key (kbd "") 'quote-keyword-at-point) 22 | (global-set-key (kbd "") 'quote-symbol-at-point) 23 | 24 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: common-lisp-libraries 2 | theme: 3 | name: readthedocs 4 | collapse_by_default: false 5 | highlightjs: true 6 | hljs_languages: 7 | - lisp 8 | navigation_depth: 4 9 | sticky_navigation: false 10 | prev_next_buttons_location: none 11 | include_search_page: true 12 | nav: 13 | - index: index.md 14 | - Defacto libraries: 15 | - asdf.md 16 | - alexandria.md 17 | - bordeaux-threads.md 18 | - cl-ppcre.md 19 | - cl-who.md 20 | - fiveam.md 21 | - hunchentoot.md 22 | - iterate.md 23 | - local-time.md 24 | - postmodern.md 25 | - quicklisp.md 26 | - usocket.md 27 | - utilities.md 28 | - Not yet defacto: 29 | - numcl.md 30 | - unix-opts.md 31 | plugins: 32 | - search 33 | extra_css: [extra.css] -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs>=1.1 2 | -------------------------------------------------------------------------------- /scratch/postmodern.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-rtd) 2 | 3 | (reader:enable-reader-syntax 'get-val 'lambda) 4 | 5 | (defparameter md-file "~/ram-disk/postmodern.md") 6 | 7 | (defparameter file-contents (with-output-to-string (s) 8 | (iter (for line in-file md-file using 'read-line) 9 | (write-line line s)))) 10 | 11 | (defun parse (file-contents) 12 | (let* ((body-list (cdr 13 | (ppcre:split 14 | `(:sequence (:flags :single-line-mode-p) 15 | #\newline 16 | (:register (:sequence 17 | (:non-greedy-repetition 18 | 0 nil (:inverted-char-class #\newline)))) 19 | #\newline 20 | (:greedy-repetition 2 nil #\-) 21 | #\newline 22 | #\newline) 23 | file-contents))) 24 | (symbol-doc-ht (make-hash-table :test 'equal))) 25 | (ppcre:do-register-groups (title) 26 | (`(:sequence (:flags :single-line-mode-p) 27 | #\newline 28 | (:register (:sequence 29 | (:non-greedy-repetition 30 | 0 nil (:inverted-char-class #\newline)))) 31 | #\newline 32 | (:greedy-repetition 2 nil #\-) 33 | #\newline 34 | #\newline) 35 | file-contents) 36 | (let ((symbol (str:replace-all "**" "*" [(str:split " " title) 1]))) 37 | ;; (print symbol) 38 | ;; (print (car body-list)) 39 | ;; (if (= (decf a) 0) (return-from parse nil)) 40 | (if-let (doc [symbol-doc-ht symbol]) 41 | (setf [symbol-doc-ht symbol] (str:concat doc (car body-list))) 42 | (setf [symbol-doc-ht symbol] (car body-list))) 43 | (setq body-list (cdr body-list)))) 44 | symbol-doc-ht)) 45 | 46 | 47 | 48 | (with-open-file (f "~/ram-disk/postmodern-md.md" 49 | :direction :output :if-exists :supersede :if-does-not-exist :create) 50 | (let ((symbol-doc-ht (parse file-contents))) 51 | (iter (for (key . val) in 52 | (sort (hash-table-alist symbol-doc-ht) λ(string< (car -) (car --)))) 53 | (for symbol = (find-symbol (string-upcase key) 54 | :postmodern)) 55 | (unless symbol (format t "~&~D was not found in package~%" 56 | (string-upcase key))) 57 | (for signature = (ignore-errors (swank/backend:arglist symbol))) 58 | (write-string 59 | (conc "### " (str:replace-all "*" "\\*" key) 60 | (when (fboundp symbol) 61 | (conc #\newline #\newline "```lisp" #\newline 62 | (cond ((macro-function symbol) "Macro") 63 | ((typep (fdefinition symbol) 64 | (find-class 'standard-generic-function)) 65 | "Generic Function") 66 | (t "Function")) 67 | ": " (string-downcase (format nil "~D" (cons key signature))) 68 | #\newline "```" #\newline)) 69 | #\newline 70 | val (string #\newline)) 71 | f)))) 72 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.fasl -------------------------------------------------------------------------------- /src/functions.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-rtd) 2 | 3 | ;; This file gets the documentation of Functions, Macros and Generic Functions 4 | (reader:enable-reader-syntax 'get-val) 5 | 6 | (defun arglist-symbols (arg-list) 7 | (let ((special-symbols '(&optional &key))) 8 | (iter 9 | (for elt in arg-list) 10 | (for linear 11 | initially nil 12 | then (or linear (member elt special-symbols))) 13 | (cond ((member elt special-symbols) nil) 14 | (linear 15 | (collect (etypecase elt 16 | (symbol elt) 17 | (list (car elt))))) 18 | ((listp elt) (appending (arglist-symbols elt))) 19 | (t (collect elt)))))) 20 | 21 | (defparameter *classes-are-significant* nil 22 | "If T, generic functions are not documented separately.") 23 | ;;; TODO: This should only disable listing accessors separately 24 | 25 | (defmethod format-documentation ((slot (eql 'function)) symbol 26 | &optional (docstring (documentation symbol slot))) 27 | (when (fboundp symbol) 28 | (let* ((arg-list (swank/backend:arglist symbol)) 29 | (arg-symbols (arglist-symbols arg-list))) 30 | (ppcre-flet ((quote-args 31 | (let ((symbol-name (subseq target-string [reg-starts 0] [reg-ends 0]))) 32 | (if (and (string-upcase-p symbol-name) 33 | (member (string-upcase symbol-name) arg-symbols 34 | :test 'string=)) 35 | (conc "`" (string-downcase symbol-name) "`") 36 | symbol-name)))) 37 | (apply #'conc 38 | (format nil "~%```lisp~%~A: ~A~%```~%" 39 | (cond ((macro-function symbol) "Macro") 40 | ((typep (fdefinition symbol) 41 | (find-class 'standard-generic-function)) 42 | "Generic Function") 43 | (t "Function")) 44 | (map-tree (lm elt (typecase elt 45 | (keyword (string-downcase (format nil "~S" elt))) 46 | (string-designator (string-downcase elt)) 47 | (t (write-to-string elt)))) 48 | (cons symbol arg-list))) 49 | (when docstring 50 | (list #\newline 51 | (restart-case 52 | (-<> (ppcre:regex-replace-all "([^\\s^\(^\)^\.^\,^\;]*)" 53 | docstring #'quote-args) 54 | ;; Usually, docstring contain symbols in upcase formats. However, 55 | ;; quoted-and-downcased symbols "look nicer". 56 | ;; A docstring-ed symbol cannot contain a space and '(', ')' characters. 57 | ;; Also assume, full-stops and commas are due to english. 58 | (requote-with-backquote <>) 59 | ;; Some also contain symbols in `format'. We want them to be in `format`. 60 | ;; Ideally they should be hyperlinked elsewhere around the world! 61 | (hyperlink-samedoc-symbols <> symbol) 62 | ;; Too many links? Control using *blacklist-samedoc-symbols* 63 | ;; These functions should be separated 64 | (quote-self <> symbol)) 65 | (continue-ignoring-errors () (format t "Errors on ~D~%" symbol))) 66 | #\newline))))))) 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/md-file.lisp: -------------------------------------------------------------------------------- 1 | ;; (handler-bind ((asdf/find-system:load-system-definition-error 2 | ;; (lambda (c) 3 | ;; (declare (ignore c)) 4 | ;; (invoke-restart 'sb-impl::drop-them))) 5 | ;; (sb-int:package-at-variance-error 6 | ;; (lambda (c) 7 | ;; (declare (ignore c)) 8 | ;; (invoke-restart 'sb-impl::drop-them)))) 9 | ;; (ql:quickload '(:alexandria :str :iterate :reader :arrows :swank :closer-mop))) 10 | 11 | ;; (ql:quickload '(:alexandria :str :iterate :reader :simple-arrows :closer-mop)) 12 | 13 | (in-package :cl-rtd) 14 | 15 | ;;; Our main function is the md-file function below. 16 | ;; Typical usage of the below function includes 17 | ;; (let ((*blacklist-samedoc-symbols* '(thread lock timeout))) 18 | ;; (md-file :bordeaux-threads "~/ram-disk/bordeaux-threads.md")) 19 | 20 | (defparameter *slots* '(function variable type)) 21 | 22 | (defun documentation-exists-p (symbol) 23 | (or (some #'identity 24 | (mapcar (lm doc-slot (documentation symbol doc-slot)) 25 | *slots*)) 26 | (trivial-types:type-specifier-p symbol) 27 | (fboundp symbol) 28 | (boundp symbol))) 29 | 30 | (defun generate-package-documentation (&optional prologue-exists-p) 31 | (apply #'conc 32 | (unless prologue-exists-p 33 | (format nil "~%# ~a~%" (string-downcase *package-name*))) 34 | ;; Refer: http://www.lispworks.com/documentation/HyperSpec/Body/f_docume.htm 35 | ;; T for documentation merely specifies to get the documentation of the package 36 | (when-let (doc (documentation (find-package *package-name*) t)) 37 | (format nil "~a~%~%" doc)) 38 | (iter outer 39 | (for symbol in *samedoc-symbols*) 40 | ;; (for i below 5) 41 | (collect (format nil "~%### ~a~%" (let ((sym-name (string-downcase symbol))) 42 | (if (str:containsp "*" sym-name) 43 | (str:replace-all "*" "\\\*" sym-name) 44 | sym-name)))) 45 | (if (not (documentation-exists-p symbol)) 46 | (collect (format nil "~%No documentation found for `~a`~%" 47 | (string-downcase symbol))) 48 | (iter (for slot in *slots*) 49 | (for docstring = (documentation symbol slot)) 50 | (when (and (eq slot 'function) 51 | (fboundp symbol) 52 | (typep (fdefinition symbol) 'generic-function) 53 | *classes-are-significant*) 54 | ;; If it's a generic function, we don't even reach the next lines. 55 | (next-iteration)) 56 | ;; (print (list symbol slot)) 57 | ;; (print (list 'documenting symbol slot)); 58 | ;; Some classes may have no docstrings, but may have doc. 59 | ;; We do want to write the heading for such classes. 60 | (when-let (doc (format-documentation slot symbol docstring)) 61 | (setq doc (if (ppcre:scan "(?s)^\\n*$" doc) 62 | "" doc)) ; remove spurious new lines 63 | (in outer (collect doc)))))))) 64 | 65 | (defun prologue-file-path () 66 | (let ((prologue-file-path (merge-pathnames (pathname (conc "../prologue/" 67 | (string-downcase *package-name*) 68 | ".md")) 69 | (asdf:component-pathname 70 | (asdf:find-system "cl-rtd"))))) 71 | (if (uiop:file-exists-p prologue-file-path) 72 | prologue-file-path 73 | nil))) 74 | 75 | (defun md-file (package-keyword &optional (output-file (format nil "~A.md" package-keyword)) 76 | &key classes-are-significant) 77 | "If CLASSES-ARE-SIGNIFICANT is T, generic functions are not documented separately." 78 | 79 | (let* ((symbols (iter (for symbol in-package package-keyword 80 | external-only t) 81 | (collect symbol))) 82 | (sorted-symbols (sort symbols #'string<)) 83 | (*samedoc-symbols* (set-difference sorted-symbols *blacklist-samedoc-symbols* 84 | :test #'string=)) 85 | (*package-name* (package-name package-keyword)) 86 | (*classes-are-significant* classes-are-significant) 87 | (*print-length* nil) 88 | (prologue-file-path (prologue-file-path))) 89 | (when prologue-file-path 90 | (uiop:copy-file prologue-file-path output-file)) 91 | (write-string-into-file (generate-package-documentation prologue-file-path) 92 | (string-downcase output-file) 93 | :if-exists (if prologue-file-path :append :supersede) 94 | :if-does-not-exist :create) 95 | t)) 96 | -------------------------------------------------------------------------------- /src/package.lisp: -------------------------------------------------------------------------------- 1 | (cl:in-package :cl-user) 2 | 3 | (defpackage :cl-rtd 4 | (:use :cl :alexandria :iterate :arrows) 5 | (:local-nicknames (:mop :closer-mop)) 6 | (:export #:md-file)) 7 | 8 | (in-package :cl-rtd) 9 | 10 | (defgeneric format-documentation (slot symbol &optional docstring)) 11 | 12 | (defvar *samedoc-symbols* () 13 | "List of symbols used for hyperlinking on the same page. This is bound in md-file.") 14 | (defvar *blacklist-samedoc-symbols* () 15 | "List of symbols users may want to exclude for hyperlinking. This list is subtracted 16 | from *SAMEDOC-SYMBOLS* to obtain the final list.") 17 | (defvar *package-name* "") 18 | 19 | (reader+swank:enable-package-local-reader-syntax 'get-val) 20 | -------------------------------------------------------------------------------- /src/types.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-rtd) 2 | 3 | (defun split-and-clean-slots (slots-doc) 4 | (-<> (str:replace-all " " "4SPACES" slots-doc) 5 | (str:split " " <> :omit-nulls t) 6 | (mapcar (lm - (str:replace-all "4SPACES" " " -)) 7 | <>) 8 | (remove-if (lm - (str:starts-with-p (conc *package-name* "::") -)) 9 | <>))) 10 | 11 | (defun class-documentation (class) 12 | ;; Only slots are documented currently. 13 | (flet 14 | ((quote-slots (slots) 15 | (conc "**Direct Slots**" #\newline #\newline 16 | (with-output-to-string (s) 17 | (ppcre:do-register-groups (slot-name initarg reader writer) 18 | (*slot-splitting-regex* 19 | (ppcre:regex-replace-all (conc "(?-i)" *package-keyword* #\:) 20 | slots 21 | "")) 22 | (when (and slot-name (string/= "" slot-name)) 23 | (write-string (conc "**" (string-downcase slot-name) "**" 24 | #\newline 25 | "```lisp" #\newline 26 | (or initarg "") 27 | (or reader "") 28 | (or writer "") 29 | "```" #\newline) 30 | s))))))) 31 | (let ((full-doc (with-output-to-string (*standard-output*) (describe class)))) 32 | (if-let 33 | (return-value 34 | (ppcre:register-groups-bind (prologue direct-slots end) 35 | (`(:sequence (:flags :single-line-mode-p) 36 | (:register (:sequence (:greedy-repetition 0 nil :everything) 37 | "Direct slots:" #\newline)) 38 | (:register (:sequence (:non-greedy-repetition 39 | 0 nil :everything) 40 | #\newline)) 41 | (:register (:sequence #\newline 42 | (:greedy-repetition 0 nil :everything)))) 43 | full-doc) 44 | (declare (ignore prologue end)) 45 | (quote-slots direct-slots))) 46 | return-value 47 | "")))) 48 | 49 | (defun slot-splitting-regex () 50 | `(:sequence 51 | (:flags :single-line-mode-p) 52 | (:register (:greedy-repetition 0 nil 53 | :non-whitespace-char-class)) 54 | (:greedy-repetition 55 | 0 1 (:sequence #\newline " " 56 | (:register (:sequence "Initargs: " 57 | (:greedy-repetition 58 | 0 nil 59 | :non-whitespace-char-class) 60 | #\newline)))) 61 | (:greedy-repetition 62 | 0 1 (:sequence " " 63 | (:register (:sequence "Readers: " 64 | (:greedy-repetition 65 | 0 nil 66 | :non-whitespace-char-class) 67 | #\newline)))) 68 | (:greedy-repetition 69 | 0 1 (:sequence " " 70 | (:register (:sequence 71 | "Writers: " 72 | (:greedy-repetition 73 | 0 nil 74 | (:inverted-char-class #\newline)) 75 | #\newline)))) 76 | (:greedy-repetition 77 | 0 1 (:sequence " " 78 | (:register (:sequence 79 | "Documentation:" 80 | (:greedy-repetition 81 | 0 nil 82 | :everything) 83 | #\newline)))) 84 | (:alternation :void (:sequence " " ,*package-name*)))) 85 | 86 | (defun format-slot-documentation (slot-doc-list) 87 | (if-let (processed-doc-list 88 | (mapcar (lambda (slot-doc) 89 | ;; (write-string slot-doc) 90 | (with-output-to-string (s) 91 | (ppcre:register-groups-bind (slot-name initarg reader writer) 92 | ((slot-splitting-regex) 93 | (ppcre:regex-replace-all (conc "(?-i)" *package-name* #\:) 94 | slot-doc 95 | "")) 96 | (when (and slot-name (string/= "" slot-name)) 97 | (write-string (conc "**" (string-downcase slot-name) "**" 98 | #\newline 99 | "```lisp" #\newline 100 | (or initarg "") 101 | (or reader "") 102 | (or writer "") 103 | "```" #\newline) 104 | s))))) 105 | slot-doc-list)) 106 | (apply 'conc "**Direct Slots**" #\newline #\newline processed-doc-list) 107 | "")) 108 | 109 | (defun direct-slots-documentation (class) 110 | (declare (type class class)) 111 | (let ((full-doc (with-output-to-string (*standard-output*) (describe class)))) 112 | (ppcre:register-groups-bind (prologue direct-slots end) 113 | (`(:sequence (:flags :single-line-mode-p) 114 | (:register (:sequence (:greedy-repetition 0 nil :everything) 115 | "Direct slots:" #\newline)) 116 | (:register (:sequence (:non-greedy-repetition 117 | 0 nil :everything) 118 | #\newline)) 119 | (:register (:sequence #\newline 120 | (:greedy-repetition 0 nil :everything)))) 121 | full-doc) 122 | (declare (ignore prologue end)) 123 | direct-slots))) 124 | 125 | (defmethod format-documentation ((slot (eql 'type)) symbol 126 | &optional (docstring (documentation symbol slot))) 127 | (let ((class (ignore-errors (find-class symbol)))) 128 | (when (trivial-types:type-specifier-p symbol) 129 | (funcall 'conc 130 | (format nil "~%```lisp~%~A~%```~%~%" 131 | (cond ((null class) 132 | "Type") 133 | ((typep class (find-class 'structure-class)) 134 | "Structure") 135 | ((typep class (find-class 'standard-class)) 136 | "Class") 137 | ((subtypep class (find-class 'condition)) 138 | "Condition") 139 | ((typep class 140 | (find-class 'closer-mop:funcallable-standard-class)) 141 | "Function") 142 | #+sbcl 143 | ((typep class (find-class 'sb-pcl:system-class)) 144 | "System Class (SBCL)") 145 | (t (error "Non-exhaustive cases: ~D" class)))) 146 | (when docstring 147 | (conc (requote-with-backquote docstring) 148 | #\newline 149 | #\newline)) 150 | (when class 151 | (-> class 152 | direct-slots-documentation 153 | split-and-clean-slots 154 | format-slot-documentation 155 | (hyperlink-samedoc-symbols symbol))))))) 156 | -------------------------------------------------------------------------------- /src/utilities.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-rtd) 2 | 3 | (reader:enable-reader-syntax 'get-val) 4 | 5 | (defun map-tree (function tree) 6 | (cond ((null tree) ()) 7 | ((listp tree) 8 | (cons (map-tree function (car tree)) 9 | (map-tree function (cdr tree)))) 10 | (t (funcall function tree)))) 11 | 12 | (defun string-upcase-p (string) 13 | (every (lambda (char) 14 | (or (not (alpha-char-p char)) 15 | (char= (char-upcase char) char))) 16 | string)) 17 | 18 | (defmacro ppcre-flet (bindings &body body) 19 | `(flet (,@(loop for binding in bindings 20 | collect (destructuring-bind (name &body body) binding 21 | `(,name (target-string start end match-start match-end 22 | reg-starts reg-ends) 23 | (declare (ignorable target-string start end match-start match-end 24 | reg-starts reg-ends)) 25 | ,@body)))) 26 | ,@body)) 27 | 28 | (defun conc (&rest strings/chars) 29 | (apply #'concatenate 30 | 'string 31 | (mapcar (lambda (elt) 32 | (etypecase elt 33 | (string elt) 34 | (character (string elt)) 35 | (null ""))) 36 | strings/chars))) 37 | 38 | (defmacro lm (&rest body-vars) 39 | `(lambda ,(butlast body-vars) 40 | ,@(last body-vars))) 41 | 42 | (define-constant +lisp-symbol-regex+ 43 | `(:sequence (:register 44 | (:greedy-repetition 1 nil 45 | (:alternation (:char-class (:range #\A #\Z)) 46 | #\- 47 | #\: 48 | #\* 49 | (:char-class (:range #\0 #\9)))))) 50 | :test 'equal) 51 | 52 | (define-constant +quoted-lisp-symbol-regex+ 53 | `(:sequence #\` 54 | (:register 55 | (:greedy-repetition 1 nil 56 | (:alternation (:char-class (:range #\A #\Z)) 57 | #\- 58 | #\: 59 | #\* 60 | (:char-class (:range #\0 #\9))))) 61 | #\`) 62 | :test 'equal) 63 | 64 | (defun requote-with-backquote (string) 65 | "Converts quoted of `format' to `format`." 66 | (ppcre-flet ((%requote-with-backquote 67 | (conc (subseq target-string [reg-starts 0] (1- [reg-ends 0])) "`"))) 68 | (ppcre:regex-replace-all "(\\`[^\\s^\(^\)]*')" string #'%requote-with-backquote))) 69 | 70 | (defun hyperlink-samedoc-symbols (string current-symbol) 71 | "Converts SYMBOL or `symbol` to [symbol](#symbol) if SYMBOL is in *SAMEDOC-SYMBOLS*." 72 | (ppcre-flet ((%hyperlink-samedoc-symbols 73 | (let* ((potential-symbol-name (subseq target-string [reg-starts 0] [reg-ends 0])) 74 | (potential-symbol (ignore-errors (read-from-string 75 | (string-upcase potential-symbol-name)))) 76 | (downcased (string-downcase potential-symbol-name))) 77 | (if (and (symbolp potential-symbol) 78 | (member potential-symbol *samedoc-symbols* 79 | :test #'string=) 80 | ;; avoid hyperlinking to the same function 81 | (string/= potential-symbol current-symbol)) 82 | (format nil "[~A](#~A)" 83 | (str:replace-all "*" "\\*" 84 | (str:replace-all "\\*" "*" downcased)) 85 | (string-trim '(#\*) 86 | (string-downcase (symbol-name potential-symbol)))) 87 | potential-symbol-name)))) 88 | (-<> (ppcre:regex-replace-all +lisp-symbol-regex+ string 89 | #'%hyperlink-samedoc-symbols) 90 | (ppcre:regex-replace-all +quoted-lisp-symbol-regex+ <> 91 | #'%hyperlink-samedoc-symbols)))) 92 | 93 | (defun quote-self (string current-symbol) 94 | (ppcre-flet ((%quote-self 95 | (let* ((symbol-name (subseq target-string [reg-starts 0] [reg-ends 0])) 96 | (downcased (string-downcase symbol-name))) 97 | (if (string= (string-upcase symbol-name) current-symbol) 98 | (format nil "`~A`" downcased) 99 | symbol-name)))) 100 | (ppcre:regex-replace-all +lisp-symbol-regex+ string 101 | #'%quote-self))) 102 | 103 | -------------------------------------------------------------------------------- /src/variables.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-rtd) 2 | 3 | (defmethod format-documentation ((slot (eql 'variable)) symbol 4 | &optional (docstring (documentation symbol slot))) 5 | (apply #'conc 6 | (ecase (introspect-environment:variable-information symbol) 7 | (:constant 8 | (format nil "~%```lisp~%Constant: ~A~%```~%" (symbol-value symbol))) 9 | (:special 10 | (if (boundp symbol) 11 | (format nil "~%```lisp~%Variable~%Default Value: ~S~%```~%" 12 | (symbol-value symbol)) 13 | (format nil "~%```lisp~%Variable~%Default Unbound~%```~%"))) 14 | (:symbol-macro 15 | (format nil "~%```lisp~%Symbol Macro~%Expansion: ~S~%```~%" 16 | (macroexpand-1 symbol))) 17 | ((nil))) 18 | (when docstring 19 | (list #\newline 20 | (hyperlink-samedoc-symbols docstring symbol) 21 | #\newline)))) 22 | --------------------------------------------------------------------------------