From ad0f3e21f97f4654c9801dcafbbcdbf177774ddd Mon Sep 17 00:00:00 2001 From: Greg Price Date: Thu, 25 Sep 2025 19:25:00 -0700 Subject: [PATCH] tools/format-changelog: Upgrade line-unwrapping to handle nested lists The `fmt` tool from GNU coreutils is very simple, and doesn't have the needed configuration knobs to be able to handle the nested lists that we now routinely use in changelog entries; it ends up mangling them. As a result, for many recent releases I've been doing the reformatting semi-manually, in Emacs: M-q to unwrap lines (after setting the text width to 999), and then a regexp find-and-replace to turn references `#1234` into `#F1234`. It seems to be somewhat annoying to get Emacs to operate within a shell pipeline. But it's less annoying for Vim; and Vim's `gq` works just as well as Emacs's M-q, given the right config. So use that. --- tools/format-changelog | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tools/format-changelog b/tools/format-changelog index 820440b05b..d0b566dab8 100755 --- a/tools/format-changelog +++ b/tools/format-changelog @@ -30,8 +30,45 @@ extract_highlights() { } # Undo line-wrapping. +_do_unwrap() { + # Implemented by rewrapping paragraphs in Vim. + # (Emacs works equally well, interactively; but seems more annoying + # to integrate into a CLI pipeline.) + + # The Vim "filetype" plugin for Markdown, relative to + # the Vim runtime path (typically "/usr/share/vim/vim$version"). + # The file's upstream source is here: + # https://github.com/tpope/vim-markdown/blob/f9f845f28/ftplugin/markdown.vim + # The parts we actually use are the variables `comments`, + # `formatoptions`, and `formatlistpat`. + local vim_markdown_settings=ftplugin/markdown.vim + + # The Vim command "gq" rewraps paragraphs; "G" makes it do so + # from the current point to the end, and "gg" first goes to the start. + vim -es /dev/stdin \ + "+runtime! ${vim_markdown_settings}" \ + '+set textwidth=2000' \ + '+normal gggqG' '+%print' '+:q!' +} + +# Undo line-wrapping; print an error if missing needed dependencies. unwrap() { - fmt --tagged-paragraph --width=2000 + # A test string which gets rewrapped differently as plain text vs Markdown. + local test_markdown=$'* a\n * b' + if [ "$(_do_unwrap <<<"${test_markdown}")" != "${test_markdown}" ]; then + # As plain text, the test string wraps to "* a * b". + # But as Markdown, it's already wrapped, so shouldn't have changed. + cat >&2 <