mdoc-0.1.0.0: src/Mdoc/Detect.hs
-- |
--
-- Module : Mdoc.Detect
-- Copyright : (c) 2026 Patrick Brisbin
-- License : AGPL-3
-- Maintainer : pbrisbin@gmail.com
-- Stability : experimental
-- Portability : POSIX
module Mdoc.Detect
( Unparsable (..)
, detectParsable
, prettyUnparsable
) where
import Mdoc.Prelude
import Data.List.NonEmpty qualified as NE
import Data.Text qualified as T
import Mdoc.Pretty (Ann (..))
import Prettyprinter
data Unparsable
= KnownBug
| NotMdoc Text
prettyUnparsable :: Unparsable -> Doc Ann
prettyUnparsable = \case
NotMdoc m ->
"first macro is not"
<+> annotate AnnKeyword ".Dd"
<+> "or"
<+> annotate AnnKeyword ".Dt"
<+> " (saw "
<> annotate AnnKeyword (pretty m)
<> ")"
KnownBug -> "known bug in this mdoc source"
detectParsable :: String -> Text -> Maybe Unparsable
detectParsable name txt =
knownBug name <|> notMdoc (mapMaybe toMacro $ T.lines txt)
knownBug :: String -> Maybe Unparsable
knownBug name = KnownBug <$ guard (name `elem` knownBad)
knownBad :: [String]
knownBad =
[ "/usr/share/man/man1/xkbcli-how-to-type.1.gz" -- https://github.com/xkbcommon/libxkbcommon/pull/863
, "/usr/share/man/man3/archive_entry_paths.3.gz" -- https://github.com/libarchive/libarchive/pull/2746
, "/usr/share/man/man5/crypt.5.gz" -- .if in .de macros
]
notMdoc :: [Text] -> Maybe Unparsable
notMdoc ms = do
m <- NE.head <$> nonEmpty ms
NotMdoc m <$ guard (m `notElem` [".Dd", ".Dt"])
toMacro :: Text -> Maybe Text
toMacro t
| ".\\\"" `T.isPrefixOf` t = Nothing -- comment
| "." == t = Nothing -- standalone dot
| "." `T.isPrefixOf` t = NE.head <$> nonEmpty (T.words t)
| otherwise = Nothing