scriblib/autobib: first cut at configurable style

Adds `number-style' as an alternative to `author+date-style'.

original commit: 48e154e3cb3eae280a82116933ddf0b03a7dd4d1
This commit is contained in:
Matthew Flatt 2012-07-10 00:20:49 -06:00
parent 83e4a20c8e
commit 570f682b23
5 changed files with 202 additions and 41 deletions

View File

@ -2,6 +2,7 @@
(require scribble/manual (require scribble/manual
racket/list racket/list
racket/date racket/date
racket/class
scribble/core scribble/core
scribble/decode scribble/decode
scribble/html-properties scribble/html-properties
@ -12,6 +13,7 @@
setup/main-collects) setup/main-collects)
(provide define-cite (provide define-cite
author+date-style number-style
make-bib in-bib (rename-out [auto-bib? bib?]) make-bib in-bib (rename-out [auto-bib? bib?])
proceedings-location journal-location book-location proceedings-location journal-location book-location
techrpt-location dissertation-location techrpt-location dissertation-location
@ -25,8 +27,12 @@
(make-css-addition (abs "autobib.css")) (make-css-addition (abs "autobib.css"))
(make-tex-addition (abs "autobib.tex"))))) (make-tex-addition (abs "autobib.tex")))))
(define bib-table-style (make-style "AutoBibliography" autobib-style-extras)) (define bib-single-style (make-style "AutoBibliography" autobib-style-extras))
(define bib-columns-style (make-style #f autobib-style-extras))
(define bibentry-style (make-style "Autobibentry" autobib-style-extras)) (define bibentry-style (make-style "Autobibentry" autobib-style-extras))
(define colbibnumber-style (make-style "Autocolbibnumber" autobib-style-extras))
(define colbibentry-style (make-style "Autocolbibentry" autobib-style-extras))
(define-struct auto-bib (author date title location url is-book? key specific)) (define-struct auto-bib (author date title location url is-book? key specific))
(define-struct bib-group (ht)) (define-struct bib-group (ht))
@ -38,7 +44,7 @@
(and x (author-element-names x))) (and x (author-element-names x)))
;; render the use of a citation. ;; render the use of a citation.
(define (add-cite group bib-entry which with-specific? disambiguation) (define (add-cite group bib-entry which with-specific? disambiguation style)
(let ([key (auto-bib-key bib-entry)]) (let ([key (auto-bib-key bib-entry)])
(when disambiguation (when disambiguation
(for ([bib disambiguation]) (for ([bib disambiguation])
@ -50,7 +56,8 @@
(define s (resolve-get part ri `(,which ,key))) (define s (resolve-get part ri `(,which ,key)))
(make-link-element #f (make-link-element #f
(list (or s "???") (list (or s "???")
(cond [disambiguation ;; should be a list of bib-entries with same author/date (cond [(not (send style disambiguate-date?)) '()]
[disambiguation ;; should be a list of bib-entries with same author/date
(define disambiguation* (define disambiguation*
(add-between (for/list ([bib (in-list disambiguation)]) (add-between (for/list ([bib (in-list disambiguation)])
(define key (auto-bib-key bib)) (define key (auto-bib-key bib))
@ -70,17 +77,20 @@
(lambda () "(???)") (lambda () "(???)")
(lambda () "(???)")))) (lambda () "(???)"))))
(define (add-date-cites group bib-entries delimiter maybe-date<? maybe-date=?) (define (add-date-cites group bib-entries delimiter style sort? maybe-date<? maybe-date=?)
(define date<? (or maybe-date<? default-date<?)) (define date<? (or maybe-date<? default-date<?))
(define date=? (or maybe-date=? default-date=?)) (define date=? (or maybe-date=? default-date=?))
(define sorted-by-date (sort bib-entries date<?)) (define sorted-by-date (if sort?
(sort bib-entries date<?)
bib-entries))
(define partitioned-by-ambiguity (define partitioned-by-ambiguity
(let-values ([(last last-ambiguous-list partition) (let-values ([(last last-ambiguous-list partition)
(for/fold ([last #f] (for/fold ([last #f]
[currently-ambiguous '()] [currently-ambiguous '()]
[partition '()]) [partition '()])
([bib (reverse sorted-by-date)]) ([bib (reverse sorted-by-date)])
(cond [(and last (date=? last bib) (cond [(and (send style collapse-for-date?)
last (date=? last bib)
(equal? (auto-bib-specific bib) "") (equal? (auto-bib-specific bib) "")
(equal? (auto-bib-specific last) "")) (equal? (auto-bib-specific last) ""))
;; can group ;; can group
@ -94,7 +104,7 @@
[else [else
(add-between (add-between
(for/list ([part (in-list partitioned-by-ambiguity)]) (for/list ([part (in-list partitioned-by-ambiguity)])
(add-cite group (car part) 'autobib-date #t part)) (add-cite group (car part) 'autobib-date #t part style))
delimiter)])) delimiter)]))
(define all-equal? (define all-equal?
@ -103,7 +113,7 @@
[(a b) (equal? a b)] [(a b) (equal? a b)]
[(a . bs) (andmap (lambda (v) (equal? a v)) bs)])) [(a . bs) (andmap (lambda (v) (equal? a v)) bs)]))
(define (add-inline-cite group bib-entries bib-date<? bib-date=?) (define (add-inline-cite group bib-entries style bib-date<? bib-date=?)
(for ([i bib-entries]) (for ([i bib-entries])
(hash-set! (bib-group-ht group) (auto-bib-key i) i)) (hash-set! (bib-group-ht group) (auto-bib-key i) i))
(when (and (pair? (cdr bib-entries)) (when (and (pair? (cdr bib-entries))
@ -112,12 +122,16 @@
(map (compose author-element-names* auto-bib-author) bib-entries))) (map (compose author-element-names* auto-bib-author) bib-entries)))
(make-element (make-element
#f #f
(list (add-cite group (car bib-entries) 'autobib-author #f #f) (list (add-cite group (car bib-entries) 'autobib-author #f #f style)
'nbsp 'nbsp
"(" (add-date-cites group bib-entries "; " bib-date<? bib-date=?) ")"))) (send style get-cite-open)
(add-date-cites group bib-entries
(send style get-group-sep)
style #t bib-date<? bib-date=?)
(send style get-cite-close))))
;; This allows citing multiple sources in one @cite. Groups of citations are separated by semicolons. ;; This allows citing multiple sources in one @cite. Groups of citations are separated by semicolons.
(define (add-cites group bib-entries sort? bib-date<? bib-date=?) (define (add-cites group bib-entries sort? style bib-date<? bib-date=?)
(define-values (groups keys) (define-values (groups keys)
(for/fold ([h (hash)] [ks null]) ([b (reverse bib-entries)]) (for/fold ([h (hash)] [ks null]) ([b (reverse bib-entries)])
(let ([k (author-element-names* (auto-bib-author b))]) (let ([k (author-element-names* (auto-bib-author b))])
@ -126,17 +140,18 @@
(make-element (make-element
#f #f
(append (append
(list 'nbsp "(") (list 'nbsp (send style get-cite-open))
(add-between (add-between
(for/list ([k (if sort? (sort keys string-ci<?) keys)]) (for/list ([k (if sort? (sort keys string-ci<?) keys)])
(let ([v (hash-ref groups k)]) (let ([v (hash-ref groups k)])
(make-element (make-element
#f #f
(list* (send style
(add-cite group (car v) 'autobib-author #f #f) render-author+dates
" " (add-date-cites group v ", " bib-date<? bib-date=?))))) (add-cite group (car v) 'autobib-author #f #f style)
"; ") (add-date-cites group v (send style get-item-sep) style sort? bib-date<? bib-date=?)))))
(list ")")))) (send style get-group-sep))
(list (send style get-cite-close)))))
(define (extract-bib-author b) (define (extract-bib-author b)
(or (auto-bib-author b) (or (auto-bib-author b)
@ -163,7 +178,45 @@
(error 'default-disambiguation "Citations too ambiguous for default disambiguation scheme.")) (error 'default-disambiguation "Citations too ambiguous for default disambiguation scheme."))
(make-element #f (list (format "~a" (integer->char (+ 97 n)))))) (make-element #f (list (format "~a" (integer->char (+ 97 n))))))
(define (gen-bib tag group sec-title maybe-disambiguator maybe-render-date-bib maybe-render-date-cite maybe-date<? maybe-date=?) (define author+date-style
(new
(class object%
(define/public (bibliography-table-style) bib-single-style)
(define/public (entry-style) bibentry-style)
(define/public (disambiguate-date?) #t)
(define/public (collapse-for-date?) #t)
(define/public (get-cite-open) "(")
(define/public (get-cite-close) ")")
(define/public (get-group-sep) "; ")
(define/public (get-item-sep) ", ")
(define/public (render-citation date-cite i) date-cite)
(define/public (render-author+dates author dates) (list* author " " dates))
(define/public (bibliography-line i e) (list e))
(super-new))))
(define number-style
(new
(class object%
(define/public (bibliography-table-style) bib-columns-style)
(define/public (entry-style) colbibentry-style)
(define/public (disambiguate-date?) #f)
(define/public (collapse-for-date?) #f)
(define/public (get-cite-open) "[")
(define/public (get-cite-close) "]")
(define/public (get-group-sep) ", ")
(define/public (get-item-sep) ", ")
(define/public (render-citation date-cite i) (number->string i))
(define/public (render-author+dates author dates) dates)
(define/public (bibliography-line i e)
(list (make-paragraph plain
(make-element colbibnumber-style (list "[" (number->string i) "]")))
e))
(super-new))))
(define (gen-bib tag group sec-title
style maybe-disambiguator
maybe-render-date-bib maybe-render-date-cite
maybe-date<? maybe-date=?)
(define disambiguator (or maybe-disambiguator default-disambiguation)) (define disambiguator (or maybe-disambiguator default-disambiguation))
(define date<? (or maybe-date<? default-date<?)) (define date<? (or maybe-date<? default-date<?))
(define date=? (or maybe-date=? default-date=?)) (define date=? (or maybe-date=? default-date=?))
@ -191,11 +244,11 @@
author/date<?)) author/date<?))
(define disambiguated (define disambiguated
(let () (let ()
(define (bib->para bib [disambiguation #f]) (define (bib->para bib disambiguation i)
(define collect-target (define collect-target
(list (make-target-element (list (make-target-element
#f #f
(list (bib->entry bib disambiguation render-date-bib)) (bib->entry bib style disambiguation render-date-bib i)
`(autobib ,(auto-bib-key bib))))) `(autobib ,(auto-bib-key bib)))))
;; Communicate to scribble's resolve step. ;; Communicate to scribble's resolve step.
(define (collect ci) (define (collect ci)
@ -209,18 +262,27 @@
(when (auto-bib-date bib) (when (auto-bib-date bib)
(collect-put! ci (collect-put! ci
`(autobib-date ,(auto-bib-key bib)) ;; (list which key) `(autobib-date ,(auto-bib-key bib)) ;; (list which key)
(make-element #f (list (render-date-cite (auto-bib-date bib)))))) (make-element #f (list
(send style
render-citation
(render-date-cite (auto-bib-date bib))
i)))))
;; store how to disambiguate it from other like citations. ;; store how to disambiguate it from other like citations.
(collect-put! ci (collect-put! ci
`(autobib-disambiguation ,(auto-bib-key bib)) `(autobib-disambiguation ,(auto-bib-key bib))
(or disambiguation 'unambiguous))) (or disambiguation 'unambiguous)))
(list (send style
bibliography-line
i
(make-paragraph plain (make-paragraph plain
(list (make-collect-element #f collect-target collect))))) (list (make-collect-element #f collect-target collect)))))
;; create the bibliography with disambiguations added. ;; create the bibliography with disambiguations added.
(define-values (last num-ambiguous rev-disambiguated*) (define-values (last num-ambiguous rev-disambiguated*)
(for/fold ([last #f] [num-ambiguous 0] [rev-disambiguated '()]) ([bib (in-list bibs)]) (for/fold ([last #f] [num-ambiguous 0] [rev-disambiguated '()]) ([bib (in-list bibs)]
(define ambiguous?? (and last (ambiguous? last bib))) [i (in-naturals 1)])
(define ambiguous?? (and (send style disambiguate-date?)
last
(ambiguous? last bib)))
(define num-ambiguous* (define num-ambiguous*
(cond [ambiguous?? (add1 num-ambiguous)] (cond [ambiguous?? (add1 num-ambiguous)]
[else 0])) [else 0]))
@ -228,11 +290,11 @@
;; to have the first disambiguation. ;; to have the first disambiguation.
(define rev-disambiguated* (define rev-disambiguated*
(cond [(and ambiguous?? (= 0 num-ambiguous)) (cond [(and ambiguous?? (= 0 num-ambiguous))
(cons (bib->para last (disambiguator num-ambiguous)) (cons (bib->para last (disambiguator num-ambiguous) i)
(cdr rev-disambiguated))] (cdr rev-disambiguated))]
[else rev-disambiguated])) [else rev-disambiguated]))
(define para* (define para*
(bib->para bib (and ambiguous?? (disambiguator num-ambiguous*)))) (bib->para bib (and ambiguous?? (disambiguator num-ambiguous*)) i))
(values bib num-ambiguous* (cons para* rev-disambiguated*)))) (values bib num-ambiguous* (cons para* rev-disambiguated*))))
(reverse rev-disambiguated*))) (reverse rev-disambiguated*)))
(make-part #f (make-part #f
@ -240,10 +302,10 @@
(list sec-title) (list sec-title)
(make-style #f '(unnumbered)) (make-style #f '(unnumbered))
null null
(list (make-table bib-table-style disambiguated)) (list (make-table (send style bibliography-table-style) disambiguated))
null)) null))
(define (bib->entry bib disambiguation render-date-bib) (define (bib->entry bib style disambiguation render-date-bib i)
(define-values (author date title location url is-book?) (define-values (author date title location url is-book?)
(values (auto-bib-author bib) (values (auto-bib-author bib)
(auto-bib-date bib) (auto-bib-date bib)
@ -251,7 +313,7 @@
(auto-bib-location bib) (auto-bib-location bib)
(auto-bib-url bib) (auto-bib-url bib)
(auto-bib-is-book? bib))) (auto-bib-is-book? bib)))
(make-element bibentry-style (make-element (send style entry-style)
(append (append
(if author (if author
`(,author `(,author
@ -281,7 +343,8 @@
(define-syntax (define-cite stx) (define-syntax (define-cite stx)
(syntax-parse stx (syntax-parse stx
[(_ (~var ~cite) citet generate-bibliography [(_ (~var ~cite) citet generate-bibliography
(~or (~optional (~seq #:disambiguate fn) #:defaults ([fn #'#f])) (~or (~optional (~seq #:style style) #:defaults ([style #'author+date-style]))
(~optional (~seq #:disambiguate fn) #:defaults ([fn #'#f]))
(~optional (~seq #:render-date-in-bib render-date-bib) #:defaults ([render-date-bib #'#f])) (~optional (~seq #:render-date-in-bib render-date-bib) #:defaults ([render-date-bib #'#f]))
(~optional (~seq #:render-date-in-cite render-date-cite) #:defaults ([render-date-cite #'#f])) (~optional (~seq #:render-date-in-cite render-date-cite) #:defaults ([render-date-cite #'#f]))
(~optional (~seq #:date<? date<?) #:defaults ([date<? #'#f])) (~optional (~seq #:date<? date<?) #:defaults ([date<? #'#f]))
@ -289,12 +352,13 @@
(syntax/loc stx (syntax/loc stx
(begin (begin
(define group (make-bib-group (make-hasheq))) (define group (make-bib-group (make-hasheq)))
(define the-style style)
(define (~cite #:sort? [sort? #t] bib-entry . bib-entries) (define (~cite #:sort? [sort? #t] bib-entry . bib-entries)
(add-cites group (cons bib-entry bib-entries) sort? date<? date=?)) (add-cites group (cons bib-entry bib-entries) sort? the-style date<? date=?))
(define (citet bib-entry . bib-entries) (define (citet bib-entry . bib-entries)
(add-inline-cite group (cons bib-entry bib-entries) date<? date=?)) (add-inline-cite group (cons bib-entry bib-entries) the-style date<? date=?))
(define (generate-bibliography #:tag [tag "doc-bibliography"] #:sec-title [sec-title "Bibliography"]) (define (generate-bibliography #:tag [tag "doc-bibliography"] #:sec-title [sec-title "Bibliography"])
(gen-bib tag group sec-title fn render-date-bib render-date-cite date<? date=?))))])) (gen-bib tag group sec-title the-style fn render-date-bib render-date-cite date<? date=?))))]))
(define (ends-in-punc? e) (define (ends-in-punc? e)
(regexp-match? #rx"[.!?,]$" (content->string e))) (regexp-match? #rx"[.!?,]$" (content->string e)))
@ -329,7 +393,7 @@
(define parsed-date (understand-date date)) (define parsed-date (understand-date date))
(make-auto-bib author* parsed-date title location url is-book? (make-auto-bib author* parsed-date title location url is-book?
(content->string (content->string
(make-element bibentry-style (make-element #f
(append (append
(if author* (list author*) null) (if author* (list author*) null)
(list title) (list title)

View File

@ -1,3 +1,8 @@
\newenvironment{AutoBibliography}{\begin{small}}{\end{small}} \newenvironment{AutoBibliography}{\begin{small}}{\end{small}}
\newcommand{\Autobibentry}[1]{\hspace{0.05\linewidth}\parbox[t]{0.95\linewidth}{\parindent=-0.05\linewidth#1\vspace{1.0ex}}} \newcommand{\Autobibentry}[1]{\hspace{0.05\linewidth}\parbox[t]{0.95\linewidth}{\parindent=-0.05\linewidth#1\vspace{1.0ex}}}
\usepackage{calc}
\newlength{\ABcollength}
\newcommand{\Autocolbibnumber}[1]{\parbox[t]{5ex}{\hfill#1~~\vspace{1.0ex}}}
\newcommand{\Autocolbibentry}[1]{\setlength{\ABcollength}{\linewidth-5ex}\parbox[t]{\ABcollength}{#1\vspace{1.0ex}}}

View File

@ -39,14 +39,16 @@ function. See below for an example.
@defform/subs[(define-cite ~cite-id citet-id generate-bibliography-id @defform/subs[(define-cite ~cite-id citet-id generate-bibliography-id
option ...) option ...)
([option (code:line #:disambiguate disambiguator-expr) ([option (code:line #:style style-expr)
(code:line #:disambiguate disambiguator-expr)
(code:line #:render-date-bib render-date-expr) (code:line #:render-date-bib render-date-expr)
(code:line #:render-date-cite render-date-expr) (code:line #:render-date-cite render-date-expr)
(code:line #:date<? date-compare-expr) (code:line #:date<? date-compare-expr)
(code:line #:date=? date-compare-expr)]) (code:line #:date=? date-compare-expr)])
#:contracts ([disambiguator-expr (-> exact-nonnegative-integer? element?)] #:contracts ([style-expr (or/c author+date-style number-style)]
[render-date-expr (-> date? element?)] [disambiguator-expr (or/c #f (-> exact-nonnegative-integer? element?))]
[date-compare-expr (-> date? date? boolean?)])]{ [render-date-expr (or/c #f (-> date? element?))]
[date-compare-expr (or/c #f (-> date? date? boolean?))])]{
Binds @racket[~cite-id], @racket[citet-id], and Binds @racket[~cite-id], @racket[citet-id], and
@racket[generate-bibliography-id], which share state to accumulate and @racket[generate-bibliography-id], which share state to accumulate and
@ -79,7 +81,13 @@ section for the bibliography. It has the contract
The default value for the @racket[#:tag] argument is @racket["doc-bibliography"] The default value for the @racket[#:tag] argument is @racket["doc-bibliography"]
and for @racket[#:sec-title] is @racket["Bibliography"]. and for @racket[#:sec-title] is @racket["Bibliography"].
If two citations' references would render the same (as judged by equal The optional @racket[style-expr] determines the way that citations and
the bibliography are rendered.@margin-note*{Programmer-defined styles
may be supported in the future.} Currently, two built-in style are
provided, and @racket[author+date-style] is the default.
For @racket[author+date-style],
if two citations' references would render the same (as judged by equal
authors and dates that are considered the same) but are different, the authors and dates that are considered the same) but are different, the
optionally provided function from @racket[disambiguator-expr] is used optionally provided function from @racket[disambiguator-expr] is used
to add an extra element after the date; the default disambiguator adds to add an extra element after the date; the default disambiguator adds
@ -89,6 +97,13 @@ ambiguous raises an exception. Date comparison is controlled by
bibliography may be rendered differently, as specified by the bibliography may be rendered differently, as specified by the
optionally given @racket[render-date-expr] functions.} optionally given @racket[render-date-expr] functions.}
@deftogether[(
@defthing[author+date-style any/c]
@defthing[number-style any/c]
)]{
Styles for use with @racket[define-cite].}
@defproc[(bib? [v any/c]) boolean?]{ @defproc[(bib? [v any/c]) boolean?]{

View File

@ -0,0 +1,57 @@
#lang scribble/manual
@(require scriblib/autobib)
@(define-cite ~cite citet generate-bibliography
#:style number-style)
@(define a1
(make-bib
#:title "One"
#:author "A"
#:date "2012"
#:location "There"))
@(define a2
(make-bib
#:title "Two"
#:author "A"
#:date "2012"
#:location "Here"))
@(define a2x
(make-bib
#:title "Twoish"
#:author "A"
#:date "2012"
#:location "HereX"))
@(define a3
(make-bib
#:title "Three"
#:author "A"
#:date "2013"
#:location "Where?"))
@(define b1
(make-bib
#:title "Uno"
#:author "B"
#:date "2012"
#:location "Ici"))
A1@~cite[a1 a2 b1].
A1@~cite[a1 a2 a3].
@citet[a1 a2 a3].
In A2@~cite[(in-bib a2 " p. 17")]
In A2 and A3@~cite[(in-bib a2 " p. 17") a3]
In A1 and more@~cite[a1 (in-bib a2 " p. 17") a3]
B&B@~cite[b1 a1].
@generate-bibliography[]

View File

@ -0,0 +1,20 @@
A1 [1, 2, 4].
A1 [1, 2, 3].
A [1, 2, 3].
In A2 [2 p. 17]
In A2 and A3 [2 p. 17, 3]
In A1 and more [1, 2 p. 17, 3]
B&B [1, 4].
Bibliography
[1]A. One. There, 2012.
[2]A. Two. Here, 2012.
[3]A. Three. Where?, 2013.
[4]B. Uno. Ici, 2012.