Add auto_identifiers support to Man Reader (#11675)

Add support for the `auto_identifiers`, `gfm_auto_identifiers`, and
`ascii_identifiers` extensions in the man reader. Section headings
parsed from .SH and .SS macros now receive auto-generated id
attributes when the extension is enabled, enabling `--toc` to
produce working anchor links.

- Add `autoIdExtensions` to default man extensions [behavior change]
- Add `HasReaderOptions`, `HasLogMessages` and `HasIdentifierList` to
  `ManState` to run `registerHeader`

Closes #8852.
This commit is contained in:
Meher Chaitanya
2026-05-30 19:11:14 +02:00
committed by GitHub
parent c6ba4d9040
commit 1ffeb856ee
7 changed files with 89 additions and 21 deletions
+2 -2
View File
@@ -3668,13 +3668,13 @@ automatically assigned a unique identifier based on the heading text.
This extension can be enabled/disabled for the following formats:
input formats
: `markdown`, `latex`, `rst`, `mediawiki`, `textile`
: `markdown`, `latex`, `rst`, `mediawiki`, `textile`, `man`
output formats
: `markdown`, `muse`
enabled by default in
: `markdown`, `muse`
: `markdown`, `muse`, `man`
The default algorithm used to derive the identifier from the
heading text is:
+1
View File
@@ -664,4 +664,5 @@ getAllExtensions f = universalExtensions <> getAll f
[ Ext_smart ]
getAll "typst" = extensionsFromList [Ext_citations, Ext_smart]
getAll "djot" = extensionsFromList [Ext_sourcepos]
getAll "man" = autoIdExtensions
getAll _ = mempty
+21 -1
View File
@@ -26,23 +26,40 @@ import Text.Pandoc.Builder as B
import Text.Pandoc.Class.PandocMonad (PandocMonad(..), report)
import Text.Pandoc.Logging (LogMessage(..))
import Text.Pandoc.Options
import Text.Pandoc.Parsing.Capabilities
import Text.Pandoc.Parsing
import Text.Pandoc.Walk (query)
import Text.Pandoc.Readers.Roff -- TODO explicit imports
import qualified Text.Pandoc.Parsing as P
import qualified Data.Foldable as Foldable
import qualified Data.Set as Set
import Text.Pandoc.Shared (extractSpaces)
data ManState = ManState { readerOptions :: ReaderOptions
, manLogMessages :: []LogMessage
, manIdentifiers :: Set.Set T.Text
, metadata :: Meta
, tableCellsPlain :: Bool
} deriving Show
instance Default ManState where
def = ManState { readerOptions = def
, manLogMessages = []
, manIdentifiers = Set.empty
, metadata = nullMeta
, tableCellsPlain = True }
instance HasReaderOptions ManState where
extractReaderOptions = readerOptions
instance HasLogMessages ManState where
addLogMessage msg st = st{ manLogMessages = msg : manLogMessages st }
getLogMessages st = reverse $ manLogMessages st
instance HasIdentifierList ManState where
extractIdentifierList = manIdentifiers
updateIdentifierList f st = st{ manIdentifiers = f $ manIdentifiers st }
type ManParser m = P.ParsecT [RoffToken] ManState m
@@ -74,6 +91,7 @@ parseMan = do
bs <- many parseBlock <* eof
meta <- metadata <$> getState
let (Pandoc _ blocks) = doc $ mconcat bs
reportLogMessages
return $ Pandoc meta blocks
parseBlock :: PandocMonad m => ManParser m Blocks
@@ -417,7 +435,9 @@ parseHeader = do
else return $ mconcat $ intersperse B.space
$ map linePartsToInlines args
let lvl = if name == "SH" then 1 else 2
return $ header lvl contents
attr <- registerHeader nullAttr contents
return $ B.headerWith attr lvl contents
parseBlockQuote :: PandocMonad m => ManParser m Blocks
parseBlockQuote = blockQuote <$>
+1 -1
View File
@@ -11,7 +11,7 @@ another \
one;123456
.TE
^D
<h1>HEADING</h1>
<h1 id="heading">HEADING</h1>
<table>
<tbody>
<tr>
+1 -1
View File
@@ -16,7 +16,7 @@ This should still be indented, until some other macro is called to change it.
Like this.
^D
<p>TH "TEST" "1" "2026-05-25" "test v1.0.0" "test manual"</p>
<h1>HEADING</h1>
<h1 id="heading">HEADING</h1>
<dl>
<dt>This is the unindented tag.</dt>
<dd>
+43
View File
@@ -0,0 +1,43 @@
Github Formatted Markdown Identifiers
```
% pandoc -f man+gfm_auto_identifiers -t html
.TH "TEST" "1" "2026-05-08" "test v1.0.0" "test manual"
.SH 1st HEADING
.SH C++ & Rust
.SH HEADING
.SH HEADING
^D
<h1 id="1st-heading">1st HEADING</h1>
<h1 id="c--rust">C++ &amp; Rust</h1>
<h1 id="heading">HEADING</h1>
<h1 id="heading-1">HEADING</h1>
```
Ascii Identifiers test
```
% pandoc -f man+ascii_identifiers -t html
.TH "TEST" "1" "2026-05-08" "test v1.0.0" "test manual"
.SH Über den Flüssen
^D
<h1 id="uber-den-flussen">Über den Flüssen</h1>
```
Headers without Auto Identifiers test
```
% pandoc -f man-auto_identifiers -t native
.TH "TEST" "1" "2026-05-08" "test v1.0.0" "test manual"
.SS Level 2
.SS different styles:
.SS Ordered
.SS Ordered
^D
[ Header
2 ( "" , [] , [] ) [ Str "Level" , Space , Str "2" ]
, Header
2
( "" , [] , [] )
[ Str "different" , Space , Str "styles:" ]
, Header 2 ( "" , [] , [] ) [ Str "Ordered" ]
, Header 2 ( "" , [] , [] ) [ Str "Ordered" ]
]
```
+20 -16
View File
@@ -42,11 +42,11 @@ Pandoc
, Space
, Str "*"
]
, Header 1 ( "" , [] , [] ) [ Str "Headers" ]
, Header 1 ( "headers" , [] , [] ) [ Str "Headers" ]
, Header
1 ( "" , [] , [] ) [ Str "Level" , Space , Str "1" ]
1 ( "level-1" , [] , [] ) [ Str "Level" , Space , Str "1" ]
, Header
2 ( "" , [] , [] ) [ Str "Level" , Space , Str "2" ]
2 ( "level-2" , [] , [] ) [ Str "Level" , Space , Str "2" ]
, Para
[ Str "*"
, Space
@@ -58,7 +58,7 @@ Pandoc
, Space
, Str "*"
]
, Header 1 ( "" , [] , [] ) [ Str "Paragraphs" ]
, Header 1 ( "paragraphs" , [] , [] ) [ Str "Paragraphs" ]
, Para
[ Str "Here's"
, Space
@@ -159,7 +159,9 @@ Pandoc
, Str "*"
]
, Header
1 ( "" , [] , [] ) [ Str "Block" , Space , Str "Quotes" ]
1
( "block-quotes" , [] , [] )
[ Str "Block" , Space , Str "Quotes" ]
, Para
[ Str "Code"
, Space
@@ -182,7 +184,9 @@ Pandoc
, [ Para [ Str "item" , Space , Str "two" ] ]
]
, Header
1 ( "" , [] , [] ) [ Str "Code" , Space , Str "Blocks" ]
1
( "code-blocks" , [] , [] )
[ Str "Code" , Space , Str "Blocks" ]
, Para [ Str "Code:" ]
, CodeBlock
( "" , [] , [] )
@@ -201,22 +205,22 @@ Pandoc
, Space
, Str "*"
]
, Header 1 ( "" , [] , [] ) [ Str "Lists" ]
, Header 2 ( "" , [] , [] ) [ Str "Unordered" ]
, Header 1 ( "lists" , [] , [] ) [ Str "Lists" ]
, Header 2 ( "unordered" , [] , [] ) [ Str "Unordered" ]
, Para [ Str "Asterisks:" ]
, BulletList
[ [ Para [ Str "asterisk" , Space , Str "1" ] ]
, [ Para [ Str "asterisk" , Space , Str "2" ] ]
, [ Para [ Str "asterisk" , Space , Str "3" ] ]
]
, Header 2 ( "" , [] , [] ) [ Str "Ordered" ]
, Header 2 ( "ordered" , [] , [] ) [ Str "Ordered" ]
, OrderedList
( 1 , Decimal , Period )
[ [ Para [ Str "First" ] ]
, [ Para [ Str "Second" ] ]
, [ Para [ Str "Third" ] ]
]
, Header 2 ( "" , [] , [] ) [ Str "Nested" ]
, Header 2 ( "nested" , [] , [] ) [ Str "Nested" ]
, BulletList
[ [ Para [ Str "Tab" ]
, BulletList
@@ -254,7 +258,7 @@ Pandoc
]
, Header
2
( "" , [] , [] )
( "different-styles" , [] , [] )
[ Str "different" , Space , Str "styles:" ]
, OrderedList
( 1 , UpperAlpha , Period )
@@ -292,7 +296,7 @@ Pandoc
]
]
]
, Header 2 ( "" , [] , [] ) [ Str "Ordered" ]
, Header 2 ( "ordered-1" , [] , [] ) [ Str "Ordered" ]
, Para [ Str "Definition" , Space , Str "lists" ]
, DefinitionList
[ ( [ Strong [ Str "term1" ] ]
@@ -323,7 +327,7 @@ Pandoc
]
, Header
1
( "" , [] , [] )
( "special-characters" , [] , [] )
[ Str "Special" , Space , Str "Characters" ]
, Para
[ Str "AT&T"
@@ -364,7 +368,7 @@ Pandoc
, Para [ Str "Bang:" , Space , Str "!" ]
, Para [ Str "Plus:" , Space , Str "+" ]
, Para [ Str "Minus:" , Space , Str "-" ]
, Header 1 ( "" , [] , [] ) [ Str "Links" ]
, Header 1 ( "links" , [] , [] ) [ Str "Links" ]
, Para
[ Link
( "" , [] , [] )
@@ -379,7 +383,7 @@ Pandoc
( "mailto:me@example.com" , "" )
, Str "."
]
, Header 1 ( "" , [] , [] ) [ Str "Macros" ]
, Header 1 ( "macros" , [] , [] ) [ Str "Macros" ]
, Para
[ Strong [ Str "Me" , Space , Str "Myself" ]
, Space
@@ -406,7 +410,7 @@ Pandoc
, Strong [ Str "Author" ]
, Str "."
]
, Header 1 ( "" , [] , [] ) [ Str "Tables" ]
, Header 1 ( "tables" , [] , [] ) [ Str "Tables" ]
, Table
( "" , [] , [] )
(Caption Nothing [])