packages feed

mdoc-0.1.0.0: src/Mdoc/Parse/TroffMacro.hs

-- |
--
-- Module      : Mdoc.Parse.TroffMacro
-- Copyright   : (c) 2026 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Mdoc.Parse.TroffMacro
  ( parseTroffMacro
  ) where

import Mdoc.Prelude

import Control.Monad.State.Strict (get, modify)
import Data.Monoid (Last (..))
import Data.Set qualified as Set
import Data.Text qualified as T
import Mdoc.Parse
import Mdoc.TroffMacro

parseTroffMacro :: Parser TroffMacro
parseTroffMacro =
  choice
    [ try troffMacroDefine
    , try troffMacroDefineS
    , try troffMacroCall
    , try troffMacroEnd
    ]

troffMacroDefine :: Parser TroffMacro
troffMacroDefine = do
  void $ string ".de" >> hspace1
  name <- restOfWord
  mClose <- optional $ hspace1 *> restOfWord
  lift
    $ modify (<> mempty {defined = Set.singleton name, nextClose = Last mClose})
  pure $ TroffMacroDefine name mClose

troffMacroDefineS :: Parser TroffMacro
troffMacroDefineS = do
  void $ string ".ds" >> hspace1
  name <- restOfWord
  value <- optional $ hspace1 *> restOfLine
  lift $ modify (<> mempty {defined = Set.singleton name})
  pure $ TroffMacroDefineS name value

troffMacroCall :: Parser TroffMacro
troffMacroCall = do
  s <- lift get
  let
    names = toList s.defined
    pName =
      choice (map string names)
        <?> "custom macro "
        <> unpack (T.intercalate "|" names)
  macroCall TroffMacroCall pName restOfWord

troffMacroEnd :: Parser TroffMacro
troffMacroEnd = do
  s <- lift get
  t <- case getLast s.nextClose of
    Nothing -> string ".."
    Just cl -> char '.' *> string cl
  TroffMacroEnd t <$ peek (hspace >> eol)