Skip to content

Improve BibTeX parsing and bibliography rendering - #573

Merged
mflatt merged 44 commits into
racket:masterfrom
fare-patches:doi-dot
Sep 29, 2026
Merged

mflatt merged 44 commits into
racket:masterfrom
fare-patches:doi-dot

Conversation

@fare

@fare fare commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Improve bibliography rendering and BibTeX support

Improve Scribble's support for rich bibliographies, particularly annotated bibliographies with long, formatted, multi-paragraph notes. The immediate motivation is the bibliography of my book Lambda: the Ultimate Object, but the improvements apply to ordinary academic papers as well.

Bibliography rendering

  • Remove the old LaTeX \parbox layout, which prevented page breaks within bibliography entries, with needspace, allowing long annotations to span pages.
  • Use needspace when available instead of \parbox to still try to keep short entries together.
  • Allow opt-in LaTeX adjustments in entries through \AutobibEntrySetup for e.g. line-breaking settings.
  • Improve numbered bibliography layout using CSS and LaTeX environments, with hanging indentation and aligned citation numbers.
  • Improve formatting across bibliography fields.
  • Add a period after a DOI only when a note follows it, preserving the existing formatting of ordinary entries without notes. Avoid appending punctuation directly to URLs.
  • Render numeric book chapters as “chapter 3”, with appropriate capitalization when the chapter starts the location.
  • Add an optional #:accessed field to make-bib, displayed
    immediately after the URL, when one is displayed.
    BibTeX online and webpage entries now use this field
    instead of putting access dates in their location.
    This places access dates after publication dates and
    next to the URLs they qualify, without changing the
    generic ordering of bibliography fields.
    The webpage-location API from 1.61 is removed.

The improvements primarily target HTML and LaTeX. Typst receives minimal compatibility support rather than a new rendering implementation.

BibTeX parsing

  • Add a small LaTeX reader supporting common formatting commands, accents, special characters, protected groups and mathematical expressions.
  • Preserve protected groups when parsing author names and other fields.
  • Support LaTeX escapes in URLs and DOIs, generating correct hyperlinks in HTML and LaTeX.
  • Improve parsing of BibTeX string references, including references adjacent to delimiters.
  • Support formatted content and multiple paragraphs in bibliography notes.
  • Check required fields of standard BibTeX entry types more precisely.

The reader deliberately supports a useful subset of LaTeX rather than attempting to implement a complete TeX interpreter. Unknown commands are preserved rather than silently discarded.

API, documentation and tests

  • Add #:accessed to make-bib; access dates are displayed only when the corresponding URL is displayed. DOI still takes precedence over URL.
  • Some location helpers now compose Scribble can return #f when they contain no information. This lets callers omit empty components entirely rather than retaining opaque empty elements that can cause stray separators and punctuation.
  • Update the manuals to document the new behavior and configuration options.
  • Bump scribble-lib to version 1.68.
  • Add unit tests, expected-output tests and rendering tests, including regression tests for accented names, protected groups, escaped hyperlinks, access dates, BibTeX string references and multi-paragraph notes.

The changes have been exercised against my book's heavily annotated bibliography and reviewed through several rounds of automated and manual testing.

Compatibility notes

  • webpage-location is removed. It was a recent addition from 1.61, I'm not sure anyone uses it directly (as opposed to through bibtex.rkt), but if they do they will have to migrate to #:accessed instead.
  • bibtex-parse now keeps inner braces in raw field values
    (e.g. "The {ACM} Paper") so that protected groups survive until
    rendering; rendered output is unchanged, but code that reads
    bibdb-raw directly will now see the braces.
  • BibTeX titles are no longer passed through verbatim to LaTeX;
    they go through the same reader as other fields. Math and unknown
    commands are still emitted verbatim in LaTeX output.
  • Notes are now decoded like other Scribble text, so -- becomes
    an en dash and straight quotes become curly quotes.
  • A purely numeric #:chapter now renders as "chapter N".
  • In LaTeX output, entries may now break across pages (subject to
    the five-line minimum), and numbered bibliographies use hanging
    indentation instead of a table.
  • In text output, numbered entries are no longer aligned as a table.
  • Various minor bugfixes, in handling inbook, proceedings, or braces in author names.

The implementation was substantially assisted by GPT-5.6 Sol and Claude Sonnet 5, with additional review by Claude Opus 5.5.

@fare

fare commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor Author

PS: I'm tempted to have a clanker improve the parsing of bibtex to support (a) emphasis, in notes, (b) {} in titles to prevent lowercasification when using LaTeX.

Also, maybe to improve autobib so multi-paragraph notes are a thing, and maybe crossing page boundaries within a bibliography entry.

These two would also much improve LtUO.

PPS: I'm still thinking about (a), but at least the basics of (b) was apparently done by #571.

PPPS: The clankers did it!

@fare

fare commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Weird: the CI failed on Racket 9.3.0.8, but at home it just worked on v9.3.0.8-2026-09-14-06fd59e02c [cs].

PS: I had forgotten to update a test.

@mflatt

mflatt commented Sep 19, 2026

Copy link
Copy Markdown
Member

The change to add . after a DOI would cause papers written with Scribble+autobib to render differently than Latex+bibtex (in the "acmart" style). Would it work to add . only when there's a note? Or maybe it should be configurable?

@fare

fare commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor Author

Yes, adding a "." only if there's a note makes a lot sense, especially for backwards compatibility. Thanks for the suggestion.

PS: also rebasing to the latest master.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 1 file in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 2 files in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 3 files in this pull request and found no issues.

@fare fare changed the title autobib: include "." after doi, to clearly separate from notes. [WIP] bibliography improvements Sep 21, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 3 files in this pull request and found no issues.

Use CSS and LaTeX environments for autobib number-style.
Much nicer output in HTML and PDF. In number-style, text output
won't align as a table anymore, but will have a space after the [number].

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 4 files in this pull request and found no issues.

@fare fare changed the title Bibliography improvements Improve BibTeX parsing and bibliography rendering Sep 26, 2026
@fare

fare commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor Author

The ability to return #f is so that we can eliminate fields that contain no information, and in turn not have separators between empty fields, which would otherwise happen if there were an opaque element: . , . . , .

Returning content instead of element also seemed more practical to me, considering that the output has a loose structure and is meant to be further aggregated into bigger lists. It seemed to me that at that point, if we really wanted an element, we could better add one in the caller when the content is not #f. But I'm not sure I understand the invariants of Scribble with respect to element vs content vs decoded-content vs blocks vs passes, etc., so I admit I don't really know.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and found no issues.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and has added suggestions.

Comment thread scribble-lib/scriblib/private/read-latex.rkt Outdated
@mflatt

mflatt commented Sep 27, 2026

Copy link
Copy Markdown
Member

The ability to return #f is so that we can eliminate fields that contain no information, and in turn not have separators between empty fields, which would otherwise happen if there were an opaque element

I can appreciate why make-bib needs to accept #f for location, but I'm not seeing why a location-generating function like proceedings-location would be called if there was not information about a proceedings to return. What would be an example where that happens?

Returning content instead of element also seemed more practical to me, considering that the output has a loose structure and is meant to be further aggregated into bigger lists.

There shouldn't be a difference between content c and the element (element #f c). If there is, then that's worrying, and I'd like to understand more. If there's not, then I think it may be worthwhile for backward compatibility to add element wrappers on the results — but I'm also not sure it really matters, since content is generally accepted where are element is accepted.

fare and others added 2 commits September 28, 2026 06:33
mflatt wants the *-location functions to keep returning elements
rather than generic content, for backward compatibility. Wrap each
non-#f result in (elem ...); the split between functions that may
return #f (booklet-location, manual-location, misc-location,
book-location, and now also proceedings-location, since bibtex may
call it with nothing at all) and those that always return a non-#f
element? (journal-location, techrpt-location, dissertation-location,
book-chapter-location, since each has a genuinely required argument)
now matches origin/master exactly, confirmed by diffing against it.

Drop the stray docs claiming location helpers "now return Scribble
content, potentially #f" -- that phase never shipped outside this
branch, so there's nothing to document as a change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Enforce, as hard parse-time errors, the fields Patashnik's BIBTEXing
§3.1 marks required for each of the 14 standard entry types,
including the author-or-editor and chapter-and/or-pages disjunctions
(new require-one-of helper). Also require title and url on
online/webpage, by our own choice since neither is a standard type.
This is intentionally stricter than real BibTeX, which only warns on
a missing required field; document why.

Fix a latent bug found along the way: author-attr silently turned a
genuinely missing field into the literal author name "#f" instead of
most entry types, author on booklet/manual/misc/online/webpage).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@fare

fare commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

bibtex.rkt always calls the functions, even when all the arguments are missing. I suppose I could make it avoid to do so, but I think it's better to have the function itself deal with it. booklet-location, manual-location, misc-location, and proceedings-location can be legitimately contentless (based on BIBTEXing as a spec). I am now allowing #f only from those functions. Then again, a lot of bibliography databases do NOT fill the mandatory fields from that "specification", and bibtex is quite lenient in practice, so I'm not sure tightening the screw is the right thing (though tightening did lead me to fix a few entries in my own database).

If you want bibtex.rkt to instead avoid calling the location functions when it has no data for them, I can do that.

I added back element wrappers for backward compatibility.

Docs updated.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and has added suggestions.

Comment thread scribble-lib/scriblib/private/read-latex.rkt Outdated
fare and others added 2 commits September 28, 2026 07:20
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and has added suggestions.

Comment thread scribble-lib/scriblib/private/read-latex.rkt

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and found no issues.

fare and others added 2 commits September 28, 2026 07:57
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and found no issues.

@mflatt

mflatt commented Sep 28, 2026

Copy link
Copy Markdown
Member

bibtex.rkt always calls the functions, even when all the arguments are missing. I suppose I could make it avoid to do so, but I think it's better to have the function itself deal with it.

Ok, that seems reasonable. Maybe the most useful thing would be to improve the specification to say more specifically when the result is #f. One history note says "when there's nothing to return", but I imagine the documentation for each function should say something like "Returns #f when all arguments are #f or empty content", and this history note could be just "Added #f as a possible result."

I added back element wrappers for backward compatibility.

Thanks!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and found no issues.

@fare

fare commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

Clarified the documentation, made the code more systematic about what is optional or required and normalizing content, fixed a few edge cases.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resyntax analyzed 7 files in this pull request and found no issues.

@mflatt

mflatt commented Sep 29, 2026

Copy link
Copy Markdown
Member

This seems ready to me. I would adjust the history notes slightly as in mflatt@785dbcc, but I can make those adjustments after.

Ok to merge?

@fare

fare commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

Eager to merge! Thanks a lot for your gracious time and welcome.

@fare

fare commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

I suggest a squash with the PR description—I don't think the sausage of intermediate commits is worth preserving.

@mflatt
mflatt merged commit 96e13ca into racket:master Sep 29, 2026
2 checks passed
@fare
fare deleted the doi-dot branch September 29, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants