packages feed

mdoc 0.4.1.4 → 0.5.0.0

raw patch · 47 files changed

+461/−416 lines, 47 filesdep −file-embedPVP ok

version bump matches the API change (PVP)

Dependencies removed: file-embed

API changes (from Hackage documentation)

- Mdoc.Data.Page: addCommand :: Command -> Page -> Page
- Mdoc.Data.Page: setEpilogue :: Mdoc -> Page -> Page
- Mdoc.Data.Page: setPrologue :: Mdoc -> Page -> Page
- Mdoc.Data.Page: setSynopsis :: Mdoc -> Page -> Page
- Mdoc.Data.Synopsis: custom :: Mdoc -> Synopsis
+ Mdoc.Data.Synopsis: command :: Synopsis
+ Mdoc.Examples.MdocDump: mdocDump1 :: Named
+ Mdoc.Syntax.Mdoc: textToMdocPp :: Text -> Maybe Mdoc

Files

README.lhs view
@@ -41,30 +41,24 @@  import Prelude -import Data.Function ((&)) import Env.Mdoc qualified as Env import Mdoc-import Mdoc.Data.Page (setEpilogue)+import Mdoc.Template qualified as Template import Mdoc.Dump.Env (envParser) import Mdoc.Dump.Options (optionsInfo, optionsParser) import Options.Applicative.Mdoc qualified as Opt -mdocDump1 :: Named-mdocDump1 =-  mempty-    & (<> Opt.getPage optionsParser)-    & (<> Env.getPage envParser)-    & setEpilogue-      ( Mdoc-        [ MacroLine Sh ["SEE ALSO"]-        , MacroLine Xr ["mdoc", "7"]-        ]-      )-    & name "mdoc-dump" optionsInfo- main :: IO () main = do-  mdoc <- renderTemplateThrow man1 mdocDump1+  -- Use a custom template so we can add "SEE ALSO"+  t <- Template.custom "templates/mdoc-dump.1.mustache"++  -- Render template with options and environment from our parsers+  mdoc <- renderTemplateThrow t+    $ name "mdoc-dump" optionsInfo+    $ Opt.getPage optionsParser <> Env.getPage envParser++  -- Update the Mdocdate and pretty-print   putMdoc =<< updateMdocdate mdoc ``` 
README.md view
@@ -41,30 +41,24 @@  import Prelude -import Data.Function ((&)) import Env.Mdoc qualified as Env import Mdoc-import Mdoc.Data.Page (setEpilogue)+import Mdoc.Template qualified as Template import Mdoc.Dump.Env (envParser) import Mdoc.Dump.Options (optionsInfo, optionsParser) import Options.Applicative.Mdoc qualified as Opt -mdocDump1 :: Named-mdocDump1 =-  mempty-    & (<> Opt.getPage optionsParser)-    & (<> Env.getPage envParser)-    & setEpilogue-      ( Mdoc-        [ MacroLine Sh ["SEE ALSO"]-        , MacroLine Xr ["mdoc", "7"]-        ]-      )-    & name "mdoc-dump" optionsInfo- main :: IO () main = do-  mdoc <- renderTemplateThrow man1 mdocDump1+  -- Use a custom template so we can add "SEE ALSO"+  t <- Template.custom "templates/mdoc-dump.1.mustache"++  -- Render template with options and environment from our parsers+  mdoc <- renderTemplateThrow t+    $ name "mdoc-dump" optionsInfo+    $ Opt.getPage optionsParser <> Env.getPage envParser++  -- Update the Mdocdate and pretty-print   putMdoc =<< updateMdocdate mdoc ``` 
+ data/commands.mustache view
@@ -0,0 +1,8 @@+.Bl -tag -width {{{width}}}+{{#items}}+.It Cm {{{name}}}+{{#description}}+{{{description}}}+{{/description}}+{{/items}}+.El
+ data/configs.mustache view
@@ -0,0 +1,26 @@+.Bl -tag -width {{{width}}}+{{#items}}+.It {{{item}}}+{{#help}}+{{{help}}}+{{/help}}+{{#optionality.required}}+(required)+{{/optionality.required}}+{{^optionality.required}}+{{#optionality.default}}+(optional, default: {{{.}}})+{{/optionality.default}}+{{^optionality.default}}+(optional)+{{/optionality.default}}+{{/optionality.required}}+{{#example}}+.Pp+Example:+.Bd -literal -offset indent+{{{.}}}+.Ed+{{/example}}+{{/items}}+.El
+ data/environment.mustache view
@@ -0,0 +1,3 @@+The following environment variables affect the execution of+.Nm :+{{>tag-list}}
+ data/man1.mustache view
@@ -0,0 +1,31 @@+{{>title1}}+{{>name}}+.Sh SYNOPSIS+.Nm+{{#page.synopsis}}+{{{page.synopsis}}}+{{/page.synopsis}}+{{#page.commands}}+{{#items}}+.Pp+.Nm+.Cm {{{name}}}+{{#synopsis}}+{{{.}}}+{{/synopsis}}+{{/items}}+{{/page.commands}}+.Sh DESCRIPTION+{{#page.options}}+{{>options}}+{{/page.options}}+{{#page.commands}}+.Ss COMMANDS+{{>commands}}+{{/page.commands}}+{{#page.environment}}+.Sh ENVIRONMENT+{{>environment}}+{{/page.environment}}+.Sh EXIT STATUS+.Ex -std
− data/man1.template
@@ -1,80 +0,0 @@-.\" vim: ft=nroff.mustache-.Dd $Mdocdate$-.Dt {{{title}}} 1-.Os-.Sh NAME-{{#name.init}}-.Nm {{{.}}} ,-{{/name.init}}-.Nm {{{name.last}}}-.Nd {{{name.description}}}-.Sh SYNOPSIS-.Nm-.Bk -words-{{#page.synopsis}}-{{{page.synopsis}}}-{{/page.synopsis}}-{{^page.commands}}-.Ek-{{/page.commands}}-{{#page.commands}}-.Ar command-.Ek-{{#page.commands.items}}-.Pp-.Nm-.Cm {{{name}}}-{{#synopsis}}-.Bk -words-{{{.}}}-.Ek-{{/synopsis}}-{{/page.commands.items}}-{{/page.commands}}-.Sh DESCRIPTION-{{#page.prologue}}-{{{.}}}-{{/page.prologue}}-{{#page.options}}-The options are as follows:-.Bl -tag -width {{{page.options.width}}}-{{#page.options.items}}-.It {{{item}}}-{{#help}}-{{{help}}}-{{#optionality.default}}-(default: {{{.}}})-{{/optionality.default}}-{{/help}}-{{/page.options.items}}-.El-{{/page.options}}-{{#page.commands}}-.Ss COMMANDS-.Bl -tag -width {{{page.commands.width}}}-{{#page.commands.items}}-.It Cm {{{name}}}-{{#description}}-{{{description}}}-{{/description}}-{{/page.commands.items}}-.El-{{/page.commands}}-{{#page.environment}}-.Sh ENVIRONMENT-The following environment variables affect the execution of-.Nm :-.Bl -tag -width {{{page.environment.width}}}-{{#page.environment.items}}-.It {{{item}}}-{{#help}}-{{{help}}}-{{/help}}-{{/page.environment.items}}-.El-{{/page.environment}}-.Sh EXIT STATUS-.Ex -std-{{#page.epilogue}}-{{{.}}}-{{/page.epilogue}}
+ data/man5.mustache view
@@ -0,0 +1,6 @@+{{>title5}}+{{>name}}+.Sh DESCRIPTION+{{#page.configs}}+{{>configs}}+{{/page.configs}}
− data/man5.template
@@ -1,47 +0,0 @@-.\" vim: ft=nroff.mustache-.Dd $Mdocdate$-.Dt {{{title}}} 5-.Os-.Sh NAME-{{#name.init}}-.Nm {{{.}}} ,-{{/name.init}}-.Nm {{{name.last}}}-.Nd {{{name.description}}}-{{#page.synopsis}}-.Sh SYNOPSIS-{{{.}}}-{{/page.synopsis}}-.Sh DESCRIPTION-{{#page.prologue}}-{{{.}}}-{{/page.prologue}}-.Bl -tag -width {{{page.configs.width}}}-{{#page.configs.items}}-.It {{{item}}}-{{#help}}-{{{help}}}-{{/help}}-{{#optionality.required}}-(required)-{{/optionality.required}}-{{^optionality.required}}-{{#optionality.default}}-(optional, default: {{{.}}})-{{/optionality.default}}-{{^optionality.default}}-(optional)-{{/optionality.default}}-{{/optionality.required}}-{{#example}}-.Pp-Example:-.Bd -literal -offset indent-{{{.}}}-.Ed-{{/example}}-{{/page.configs.items}}-.El-{{#page.epilogue}}-{{{.}}}-{{/page.epilogue}}
+ data/name.mustache view
@@ -0,0 +1,6 @@+.Sh NAME+{{#name.init}}+.Nm {{{.}}} ,+{{/name.init}}+.Nm {{{name.last}}}+.Nd {{{name.description}}}
+ data/options.mustache view
@@ -0,0 +1,12 @@+The options are as follows:+.Bl -tag -width {{{page.options.width}}}+{{#page.options.items}}+.It {{{item}}}+{{#help}}+{{{help}}}+{{#optionality.default}}+(default: {{{.}}})+{{/optionality.default}}+{{/help}}+{{/page.options.items}}+.El
+ data/tag-list.mustache view
@@ -0,0 +1,8 @@+.Bl -tag -width {{{width}}}+{{#items}}+.It {{{item}}}+{{#help}}+{{{help}}}+{{/help}}+{{/items}}+.El
+ data/title1.mustache view
@@ -0,0 +1,3 @@+.Dd $Mdocdate$+.Dt {{{title}}} 1+.Os
+ data/title5.mustache view
@@ -0,0 +1,3 @@+.Dd $Mdocdate$+.Dt {{{title}}} 5+.Os
examples/crontab.5 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt CRONTAB 5 .Os@@ -20,10 +19,12 @@ Example: .Bd -literal -offset indent # enable bat-bat: 1+bar:+  bat: 1 .Pp # disable bat-bat: 0+bar:+  bat: 0 .Ed .It Cm bar.baz : Ar boolean Bar's baz of bazzle
examples/docker.1 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt DOCKER 1 .Os
examples/example.1 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt EXAMPLE 1 .Os
examples/examplerc.5 view
@@ -1,14 +1,9 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt EXAMPLERC 5 .Os .Sh NAME .Nm examplerc .Nd opt\-env\-conf example config-.Sh SYNOPSIS-.Bl -tag -width indent -compact-.It Pa .examplerc.yaml-.El .Sh DESCRIPTION .Bl -tag -width indent .It Cm debug : Ar boolean
examples/grep.1 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt GREP 1 .Os
examples/mandoc.1 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt MANDOC 1 .Os
examples/mdoc-dump.1 view
@@ -1,5 +1,4 @@-.\" vim: ft=nroff.mustache-.Dd $Mdocdate: September 29 2026 $+.Dd $Mdocdate: October 12 2026 $ .Dt MDOC\-DUMP 1 .Os .Sh NAME
examples/mdoc-dump.1.html view
@@ -1,8 +1,5 @@ <!DOCTYPE html> <html>-<!-- This is an automatically generated file.  Do not edit.-   vim: ft=nroff.mustache- --> <head>   <meta charset="utf-8"/>   <meta name="viewport" content="width=device-width, initial-scale=1.0"/>@@ -79,8 +76,8 @@ </div> <table class="foot">   <tr>-    <td class="foot-date">September 22, 2026</td>-    <td class="foot-os">Linux 6.19.11-arch1-1</td>+    <td class="foot-date">October 12, 2026</td>+    <td class="foot-os">Linux 7.2.6-arch2-1</td>   </tr> </table> </body>
examples/pass.1 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt PASS 1 .Os
examples/person.5 view
@@ -1,4 +1,3 @@-.\" vim: ft=nroff.mustache .Dd $Mdocdate: September 20 2026 $ .Dt PERSON 5 .Os
mdoc.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.18 name:               mdoc-version:            0.4.1.4+version:            0.5.0.0 license:            AGPL-3 license-file:       COPYING maintainer:         Pat Brisbin@@ -31,8 +31,16 @@ category:           Text build-type:         Simple extra-source-files:-    data/man1.template-    data/man5.template+    data/commands.mustache+    data/configs.mustache+    data/environment.mustache+    data/man1.mustache+    data/man5.mustache+    data/name.mustache+    data/options.mustache+    data/tag-list.mustache+    data/title1.mustache+    data/title5.mustache     examples/crontab.5     examples/docker.1     examples/example.1@@ -44,6 +52,11 @@     examples/pass.1     examples/person.5     examples/style.css+    templates/crontab.5.mustache+    templates/grep.1.mustache+    templates/mdoc-dump.1.mustache+    templates/pass.1.mustache+    templates/person.5.mustache  extra-doc-files:     README.md@@ -79,6 +92,7 @@         Mdoc.Examples.Docker         Mdoc.Examples.Grep         Mdoc.Examples.Mandoc+        Mdoc.Examples.MdocDump         Mdoc.Examples.OptEnvConf         Mdoc.Examples.Pass         Mdoc.Examples.Person@@ -133,7 +147,6 @@         containers >=0.6.8,         envparse >=0.6.0,         extra >=1.7.16,-        file-embed >=0.0.16.0,         filepath >=1.4.301.0,         generic-optics >=2.2.1.0,         megaparsec >=9.6.1,
src/Autodocodec/Schema/Mdoc.hs view
@@ -35,7 +35,7 @@ import Mdoc.Data.Optionality import Mdoc.Data.Page import Mdoc.Optics-import Mdoc.Syntax (textToMdoc)+import Mdoc.Syntax (textToMdocPp)  getPage :: JSONSchema -> Page getPage js = foldr addConfig mempty $ getConfigs Nothing js@@ -70,7 +70,7 @@         { item = Config {name = renderPrefix <$> mPrefix, schema}         , optionality = Required         , multiple = False-        , help = textToMdoc =<< comment+        , help = textToMdocPp =<< comment         , example = Nothing         } @@ -145,7 +145,7 @@                 JSONSchema.Required -> Required                 _ -> Optional             , multiple = False-            , help = textToMdoc =<< mcomment+            , help = textToMdocPp =<< mcomment             , example = Nothing             }         ]
src/Env/Mdoc.hs view
@@ -20,7 +20,7 @@ import Mdoc.Data.EnvVar import Mdoc.Data.Optionality import Mdoc.Data.Page-import Mdoc.Syntax (textToMdoc)+import Mdoc.Syntax (textToMdocPp)  getPage :: Parser e a -> Page getPage = flip appEndo mempty . foldAlt (Endo . addEnvVar . describeVarF) . unParser@@ -31,6 +31,6 @@     { item = EnvVar {names = pure $ varfName v, argument = Nothing}     , optionality = maybe Required Defaulted (varfHelpDef v)     , multiple = False-    , help = textToMdoc . pack =<< varfHelp v+    , help = textToMdocPp . pack =<< varfHelp v     , example = Nothing     }
src/Mdoc/Data/Page.hs view
@@ -16,19 +16,15 @@   , addOption   , addArgument   , addAlternation-  , addCommand   , addCommands   , addConfig      -- * @ENVIRONMENT@   , addEnvVar -    -- * Other, rarely-used elements-  , getPositionals+    -- * Access necessary for building 'Command's   , getSynopsis-  , setSynopsis-  , setPrologue-  , setEpilogue+  , getPositionals   ) where  import Mdoc.Prelude@@ -45,16 +41,13 @@ import Mdoc.Data.Synopsis (Synopsis) import Mdoc.Data.Synopsis qualified as Synopsis import Mdoc.Optics-import Mdoc.Syntax  data Page = Page   { synopsis :: Maybe Synopsis-  , prologue :: Maybe Mdoc   , options :: Maybe (List Indent (Described Positional))   , commands :: Maybe (List Indent Command)   , configs :: Maybe (List Indent (Described Config))   , environment :: Maybe (List ByItem (Described EnvVar))-  , epilogue :: Maybe Mdoc   }   deriving stock (Eq, Generic, Show)   deriving anyclass (ToJSON)@@ -90,31 +83,25 @@   (PositionalSwitch {}, Defaulted {}) -> described {optionality = Optional}   _ -> described -addCommand :: Command -> Page -> Page-addCommand c m = m & field @"commands" <?>~ List.singleton c- addCommands :: [Command] -> Page -> Page-addCommands = appEndo . foldMap (Endo . addCommand)+addCommands cs =+  appEndo+    $ Endo (field @"synopsis" <?>~ Synopsis.command)+      <> foldMap addCommand cs+ where+  addCommand :: Command -> Endo Page+  addCommand c = Endo $ field @"commands" <?>~ List.singleton c  addConfig :: Described Config -> Page -> Page-addConfig described m =-  m & field @"configs" <?>~ List.singleton described+addConfig described =+  field @"configs" <?>~ List.singleton described  addEnvVar :: Described EnvVar -> Page -> Page-addEnvVar described m =-  m & field @"environment" <?>~ List.singleton described--getPositionals :: Page -> [Described Positional]-getPositionals p = maybe [] (toList . (.items)) p.options+addEnvVar described =+  field @"environment" <?>~ List.singleton described  getSynopsis :: Page -> Synopsis getSynopsis p = fromMaybe mempty p.synopsis -setSynopsis :: Mdoc -> Page -> Page-setSynopsis s = field @"synopsis" ?~ Synopsis.custom s--setPrologue :: Mdoc -> Page -> Page-setPrologue p = field @"prologue" ?~ p--setEpilogue :: Mdoc -> Page -> Page-setEpilogue p = field @"epilogue" ?~ p+getPositionals :: Page -> [Described Positional]+getPositionals p = maybe [] (toList . (.items)) p.options
src/Mdoc/Data/Synopsis.hs view
@@ -10,7 +10,7 @@   ( Synopsis   , singleton   , alternation-  , custom+  , command   ) where  import Mdoc.Prelude@@ -25,28 +25,20 @@ import Mdoc.Pretty import Mdoc.Syntax -data Synopsis-  = Synopsis [SynopsisItem]-  | SynopsisCustom Mdoc+newtype Synopsis = Synopsis+  { items :: [SynopsisItem]+  }   deriving stock (Eq, Show)+  deriving newtype (Monoid, Semigroup)   deriving (ToJSON) via (Rendered Synopsis) -instance Semigroup Synopsis where-  _ <> a@SynopsisCustom {} = a-  a@SynopsisCustom {} <> _ = a-  Synopsis a <> Synopsis b = Synopsis $ a <> b--instance Monoid Synopsis where-  mempty = Synopsis mempty- instance Pretty Synopsis where-  pretty = \case-    Synopsis items -> renderUsage items-    SynopsisCustom ls -> pretty ls+  pretty = renderUsage . (.items)  data SynopsisItem   = Single (Described Positional)   | Alternation Optionality [Described Positional]+  | Command   deriving stock (Eq, Show)  instance Ord SynopsisItem where@@ -64,20 +56,48 @@ alternation :: Optionality -> [Described Positional] -> Synopsis alternation o = Synopsis . pure . Alternation o -custom :: Mdoc -> Synopsis-custom = SynopsisCustom+command :: Synopsis+command = Synopsis [Command]  data Usage ann = Usage   { chars :: [Char]-  , items :: [Doc ann]+  -- ^ list those [short] options not taking arguments first, in alphabetical+  -- order+  , shorts :: [Doc ann]+  -- ^ After that, list all [short] options taking arguments+  , longs :: [Doc ann]+  -- ^ If there are long options, list them after the short options that take+  -- arguments, just before the command line arguments+  , args :: [Doc ann]+  -- ^ Arguments follow the last option+  , command :: [Doc ann]   }   deriving stock (Generic, Show)   deriving (Monoid, Semigroup) via Generically (Usage ann) +usageSetter :: Positional -> Lens' (Usage ann) [Doc ann]+usageSetter = \case+  PositionalOption (Option {flag = Flag {}}) -> field @"shorts"+  PositionalOption (Option {flag = GNUFlag {}}) -> field @"longs"+  PositionalSwitch (GNUFlag {}) -> field @"longs"+  PositionalSwitch (Flag {}) -> field @"shorts" -- edge-case+  PositionalArgument {} -> field @"args"+ renderUsage :: [SynopsisItem] -> Doc ann renderUsage = go . buildUsage  where-  go u = vsep $ maybeToList (pChars <$> nonEmpty u.chars) <> u.items+  go u =+    let ws =+          nonEmpty+            $ maybeToList (pChars <$> nonEmpty u.chars)+              <> u.shorts+              <> u.longs+              <> u.args+              <> u.command+    in  case ws of+          Nothing -> mempty+          Just ne -> vsep $ ".Bk -words" : toList ne <> [".Ek"]+   pChars cs = ".Op Fl" <+> pretty (fixMacro $ esc $ pack $ toList cs)  -- | Fix for when short-switches accidentally become a macro name@@ -101,30 +121,26 @@  addUsage :: Usage ann -> SynopsisItem -> Usage ann addUsage acc = \case-  Single d-    | Just c <- getPositionalSwitchChar d.item ->-        acc & field @"chars" %~ sortOn toLower . (<> [c])-    | otherwise ->-        acc-          & field @"items"-            <>~ [ opLine d-                    $ ellipsis d-                    $ pretty-                    $ Positional1 d.item-                ]-  Alternation o ps ->+  Single (Described {item = PositionalSwitch (Flag c _)}) ->+    acc & field @"chars" %~ sortOn toLower . (<> [c])+  Single d ->     acc-      & field @"items"+      & usageSetter d.item+        <>~ [ opLine d+                $ ellipsis d+                $ pretty+                $ Positional1 d.item+            ]+  Alternation _ [] -> acc+  Alternation o ds@(d : _) ->+    acc+      & usageSetter d.item         <>~ [ opLine' o                 $ mconcat                 $ punctuate " | "-                $ map (pretty . Positional1 . (.item)) ps+                $ map (pretty . Positional1 . (.item)) ds             ]--getPositionalSwitchChar :: Positional -> Maybe Char-getPositionalSwitchChar = \case-  PositionalSwitch (Flag c _) -> Just c-  _ -> Nothing+  Command -> acc & field @"command" <>~ [".Ar command"]  opLine :: Described a -> Doc ann -> Doc ann opLine = opLine' . (.optionality)
src/Mdoc/Examples/Grep.hs view
@@ -15,31 +15,12 @@ import Env qualified import Env.Mdoc qualified as Env import Mdoc.Data.Named-import Mdoc.Data.Page-import Mdoc.Syntax import Options.Applicative import Options.Applicative.Mdoc  -- | Recreates <https://github.com/arp242/bsdgrep/blob/master/grep.1> grep1 :: Named-grep1 =-  mempty-    & (<> getPage grepOpt)-    & (<> Env.getPage grepEnv)-    & setEpilogue-      ( Mdoc-          [ MacroLine Sh ["SEE ALSO"]-          , MacroLine Xr ["ed", "1", ","]-          , MacroLine Xr ["ex", "1", ","]-          , MacroLine Xr ["sed", "1", ","]-          , MacroLine Xr ["zgrep", "1", ","]-          , MacroLine Xr ["re_format", "7"]-          ]-      )-    & name "grep" "file pattern searcher"-    & addSecondary "egrep"-    & addSecondary "fgrep"-    & addSecondary "rgrep"+grep1 = name "grep" "" $ getPage grepOpt <> Env.getPage grepEnv  {- FOURMOLU_DISABLE -} grepOpt :: Parser ()
+ src/Mdoc/Examples/MdocDump.hs view
@@ -0,0 +1,18 @@+module Mdoc.Examples.MdocDump+  ( mdocDump1+  ) where++import Mdoc.Prelude++import Env.Mdoc qualified as Env+import Mdoc+import Mdoc.Dump.Env (envParser)+import Mdoc.Dump.Options (optionsInfo, optionsParser)+import Options.Applicative.Mdoc qualified as Opt++mdocDump1 :: Named+mdocDump1 =+  mempty+    & (<> Opt.getPage optionsParser)+    & (<> Env.getPage envParser)+    & name "mdoc-dump" optionsInfo
src/Mdoc/Examples/OptEnvConf.hs view
@@ -15,25 +15,11 @@ import Mdoc.Prelude  import Mdoc.Data.Named-import Mdoc.Data.Page-import Mdoc.Syntax import OptEnvConf hiding (name) import OptEnvConf.Mdoc  crontab5 :: Named-crontab5 =-  mempty-    & (<> getPage confParser)-    & setSynopsis-      ( Mdoc-          [ MacroLine Bl ["-tag", "-width", "indent", "-compact"]-          , MacroLine It [Callable Pa, "/etc/cron.daily", ","]-          , MacroLine It [Callable Pa, "/etc/cron.hourly", ","]-          , MacroLine It [Callable Pa, "/etc/cron.weekly"]-          , MacroLine El []-          ]-      )-    & name "crontab" "tables for driving cron"+crontab5 = name "crontab" "tables for driving cron" $ getPage confParser  {- FOURMOLU_DISABLE -} confParser :: Parser ()@@ -42,29 +28,16 @@   <*> subConfig "bar" ((,)     <$> setting [ conf @Bool "baz", help "Bar's baz of bazzle"]     <*> setting [ conf @[Int] "bat", help "Bar's bat is better than that"-                , example "# enable bat\nbat: 1"-                , example "# disable bat\nbat: 0"+                , example "# enable bat\nbar:\n  bat: 1"+                , example "# disable bat\nbar:\n  bat: 0"                 ]) {- FOURMOLU_ENABLE -}  example1 :: Named-example1 =-  mempty-    & (<> getPage exampleParser)-    & name "example" "opt-env-conf example"+example1 = name "example" "opt-env-conf example" $ getPage exampleParser  examplerc5 :: Named-examplerc5 =-  mempty-    & (<> getPage exampleParser)-    & setSynopsis-      ( Mdoc-          [ MacroLine Bl ["-tag", "-width", "indent", "-compact"]-          , MacroLine It [Callable Pa, ".examplerc.yaml"]-          , MacroLine El []-          ]-      )-    & name "examplerc" "opt-env-conf example config"+examplerc5 = name "examplerc" "opt-env-conf example config" $ getPage exampleParser  {- FOURMOLU_DISABLE -} exampleParser :: Parser ()
src/Mdoc/Examples/Pass.hs view
@@ -13,56 +13,11 @@ import Mdoc.Prelude  import Mdoc.Data.Named-import Mdoc.Data.Page (setPrologue)-import Mdoc.Syntax import Options.Applicative import Options.Applicative.Mdoc  pass1 :: Named-pass1 =-  mempty-    & (<> getPage passOpt)-    & setPrologue-      ( Mdoc-          [ MacroLine Nm []-          , TextLine "is a very simple password store that keeps passwords inside"-          , MacroLine Xr ["gpg2", "1"]-          , TextLine "encrypted files inside a simple directory tree residing at"-          , MacroLine Pa ["~/.password-store", "."]-          , TextLine-              "The pass utility provides a series of commands for manipulating the password store, allowing the user to add, remove, edit, synchronize, generate, and manipulate passwords."-          , MacroLine Pp []-          , TextLine "If no COMMAND is specified, COMMAND defaults to either"-          , MacroLine Cm ["show"]-          , TextLine "or"-          , MacroLine Cm ["ls", ","]-          , TextLine "depending on the type of specifier in ARGS. Alternatively, if"-          , MacroLine Ar ["PASSWORD_STORE_ENABLE_EXTENSIONS"]-          , TextLine "is set to \"true\", and the file"-          , MacroLine Pa [".extensions/COMMAND.bash"]-          , TextLine-              "exists inside the password store and is executable, then it is sourced into the environment, passing any arguments and environment variables. Extensions existing in a system- wide directory, only installable by the administrator, are always enabled."-          , MacroLine Pp []-          , TextLine "Otherwise COMMAND must be one of the valid commands listed below."-          , MacroLine Pp []-          , TextLine-              "Several of the commands below rely on or provide additional functionality if the password store directory is also a git repository. If the password store directory is a git repository, all password store modification commands will cause a corresponding git commit. Sub- directories may be separate nested git repositories, and pass will use the inner-most directory relative to the current password. See the"-          , MacroLine Ar ["EXTENDED", "GIT", "EXAMPLE"]-          , TextLine "section for a detailed description using init and"-          , MacroLine Xr ["git", "1"]-          , MacroLine Pp []-          , TextLine "The"-          , MacroLine Cm ["init"]-          , TextLine-              "command must be run before other commands in order to initialize the password store with the correct gpg key id. Passwords are encrypted using the gpg key set with"-          , MacroLine Cm ["init", "."]-          , MacroLine Pp []-          , TextLine-              "There is a corresponding bash completion script for use with tab completing password names in"-          , MacroLine Xr ["bash", "1", "."]-          ]-      )-    & name "pass" "stores, retrieves, generates, and synchronizes passwords securely"+pass1 = name "pass" "" $ getPage passOpt  {- FOURMOLU_DISABLE -} passOpt :: Parser ()
src/Mdoc/Examples/Person.hs view
@@ -15,8 +15,6 @@ import Autodocodec (HasCodec (..), object, optionalField, requiredField, (.=)) import Autodocodec.Schema.Mdoc (getPageViaCodec) import Mdoc.Data.Named-import Mdoc.Data.Page-import Mdoc.Syntax  data Person = Person   { name :: Text@@ -51,14 +49,4 @@ {- FOURMOLU_ENABLE -}  person5 :: Named-person5 =-  mempty-    & (<> getPageViaCodec @Person)-    & setSynopsis-      ( Mdoc-          [ MacroLine Bl ["-tag", "-width", "indent", "-compact"]-          , MacroLine It [Callable Pa, "person.schema.json"]-          , MacroLine El []-          ]-      )-    & name "person" "person example via Codec"+person5 = name "person" "person example via Codec" $ getPageViaCodec @Person
src/Mdoc/Syntax/MacroArg.hs view
@@ -9,7 +9,7 @@ module Mdoc.Syntax.MacroArg   ( MacroArg (..) -    -- * Lenses+    -- * Optics   , _Mdocdate      -- * Pretty
src/Mdoc/Syntax/Mdoc.hs view
@@ -14,11 +14,13 @@      -- * Util   , textToMdoc+  , textToMdocPp   ) where  import Mdoc.Prelude  import Data.Text qualified as T+import Mdoc.Optics import Mdoc.Pretty import Mdoc.Syntax.MacroName import Mdoc.Syntax.MdocLine@@ -36,13 +38,36 @@ instance Pretty Mdoc where   pretty = unAnnotate . prettyMdoc +-- | Map 'Text' to an 'Mdoc' of 'TextLine's+--+-- @+-- Some text with+-- newlines+-- @+--+-- @+-- Some text with+-- newlines+-- @ textToMdoc :: Text -> Maybe Mdoc textToMdoc =-  fmap-    ( Mdoc-        . intersperse (MacroLine Pp [])-        . map (TextLine . esc)-        . toList-    )+  fmap (Mdoc . map (TextLine . esc) . toList)     . nonEmpty     . T.lines++-- | Map 'Text' to an 'Mdoc' of 'TextLine's, injecting a 'Pp' between each+--+-- @+-- Some text with+-- newlines+-- @+--+-- @+-- Some text with+-- .Pp+-- newlines+-- @+textToMdocPp :: Text -> Maybe Mdoc+textToMdocPp = fmap go . textToMdoc+ where+  go = field @"lines" %~ intersperse (MacroLine Pp [])
src/Mdoc/Syntax/MdocLine.hs view
@@ -9,7 +9,7 @@ module Mdoc.Syntax.MdocLine   ( MdocLine (..) -    -- * Lenses+    -- * Optics   , _Dd      -- * Pretty@@ -18,6 +18,7 @@  import Mdoc.Prelude +import Data.Text qualified as T import Mdoc.Optics import Mdoc.Pretty import Mdoc.Syntax.MacroArg@@ -46,7 +47,9 @@       $ annotate AnnComment "."         <> annotate AnnCommand (prettyMacroName name)         : map prettyMacroArg args-  TextLine x -> reflow x+  TextLine x ->+    let (leading, rest) = T.break (/= ' ') x+    in  pretty leading <> reflow rest   TableLines ls -> prettyTableLines ls   TroffMacro m -> prettyTroffMacro m 
src/Mdoc/Template.hs view
@@ -28,8 +28,6 @@  import Mdoc.Prelude -import Data.FileEmbed-import Data.Text.Encoding (decodeUtf8) import Data.Text.Lazy.Encoding (encodeUtf8) import Mdoc.Data.Named import Mdoc.Input@@ -37,6 +35,7 @@ import Mdoc.Syntax import System.IO (hPutStrLn, stderr) import Text.Mustache+import Text.Mustache.Compile.TH qualified as TH  data RenderResult   = Rendered Mdoc@@ -62,19 +61,13 @@   RenderedError err -> throwIO err  custom :: MonadIO m => FilePath -> m Template-custom = compileMustacheFile+custom p = (<> man1) <$> compileMustacheFile p  man1 :: Template-man1 =-  either (error . errorBundlePretty) id-    $ compileMustacheText "man1"-    $ decodeUtf8 $(embedFile "data/man1.template")+man1 = $(TH.compileMustacheDir "man1" "data")  man5 :: Template-man5 =-  either (error . errorBundlePretty) id-    $ compileMustacheText "man5"-    $ decodeUtf8 $(embedFile "data/man5.template")+man5 = $(TH.compileMustacheDir "man5" "data")  putMustacheWarnings :: MonadIO m => NonEmpty MustacheWarning -> m () putMustacheWarnings = liftIO . hPutStrLn stderr . displayMustacheWarnings
src/OptEnvConf/Mdoc.hs view
@@ -49,7 +49,6 @@ import Autodocodec.Schema.Mdoc qualified as JSONSchema import Control.Monad (foldM) import Control.Monad.State (MonadState (..), evalState, modify)-import Data.Text qualified as T import Mdoc.Data.Argument import Mdoc.Data.Command import Mdoc.Data.Config@@ -72,7 +71,7 @@   Command     { index     , name = commandDocArgument doc-    , description = textToMdoc $ pack $ commandDocHelp doc+    , description = textToMdocPp $ pack $ commandDocHelp doc     , synopsis = getSynopsis $ foldSetDocs addToPage $ commandDocs doc     } @@ -155,7 +154,7 @@         { item = d         , optionality = maybe Required Defaulted (setDocDefault d)         , multiple = False-        , help = textToMdoc . pack =<< setDocHelp d+        , help = textToMdocPp . pack =<< setDocHelp d         , example = exampleMdoc <$> nonEmpty (setDocExamples d)         }  where@@ -169,12 +168,13 @@         }  exampleMdoc :: NonEmpty String -> Mdoc-exampleMdoc ne =-  ne-    & toList -- [x]-    & map (map TextLine . T.lines . pack) -- [[x, y], [z]]-    & intercalate [MacroLine Pp []] -- [x, y, Pp, z]-    & Mdoc+exampleMdoc =+  mconcat+    -- Inject a Pp between each example+    . intersperse (Mdoc [MacroLine Pp []])+    -- Map each example to Mdoc without injecting Pps between lines+    . mapMaybe (textToMdoc . pack)+    . toList  dashedFlags :: [Dashed] -> Maybe Flag dashedFlags = fmap go . nonEmpty
src/Options/Applicative/Mdoc.hs view
@@ -26,7 +26,7 @@ import Mdoc.Data.Option import Mdoc.Data.Optionality import Mdoc.Data.Page-import Mdoc.Syntax (textToMdoc)+import Mdoc.Syntax (textToMdocPp) import Options.Applicative (Parser) import Options.Applicative.Common (treeMapParser) import Options.Applicative.Help.Chunk (Chunk (..), unChunk)@@ -43,7 +43,7 @@   Command     { index     , name-    , description = textToMdoc =<< docToText doc+    , description = textToMdocPp =<< docToText doc     , synopsis = getSynopsis $ getPage $ O.infoParser pinfo     }  where@@ -121,7 +121,7 @@             { item = o             , optionality = maybe Required Defaulted (O.optShowDefault o)             , multiple = False-            , help = textToMdoc =<< docToText (O.optHelp o)+            , help = textToMdocPp =<< docToText (O.optHelp o)             , example = Nothing             }       O.Internal -> pure acc
+ templates/crontab.5.mustache view
@@ -0,0 +1,12 @@+{{>title5}}+{{>name}}+.Sh SYNOPSIS+.Bl -tag -width indent -compact+.It Pa /etc/cron.daily ,+.It Pa /etc/cron.hourly ,+.It Pa /etc/cron.weekly+.El+.Sh DESCRIPTION+{{#page.configs}}+{{>configs}}+{{/page.configs}}
+ templates/grep.1.mustache view
@@ -0,0 +1,26 @@+{{>title1}}+.Sh NAME+.Nm grep ,+.Nm egrep ,+.Nm fgrep ,+.Nm rgrep+.Nd file pattern searcher+.Sh SYNOPSIS+.Nm+{{{page.synopsis}}}+.Sh DESCRIPTION+{{#page.options}}+{{>options}}+{{/page.options}}+.Sh ENVIRONMENT+{{#page.environment}}+{{>environment}}+{{/page.environment}}+.Sh EXIT STATUS+.Ex -std+.Sh SEE ALSO+.Xr ed 1 ,+.Xr ex 1 ,+.Xr sed 1 ,+.Xr zgrep 1 ,+.Xr re_format 7
+ templates/mdoc-dump.1.mustache view
@@ -0,0 +1,3 @@+{{>man1}}+.Sh SEE ALSO+.Xr mdoc 7
+ templates/pass.1.mustache view
@@ -0,0 +1,69 @@+{{>title1}}+.Sh NAME+.Nm pass+.Nd stores, retrieves, generates, and synchronizes passwords securely+.Sh SYNOPSIS+.Nm+{{{page.synopsis}}}+{{#page.commands.items}}+.Pp+.Nm+.Cm {{{name}}}+{{#synopsis}}+{{{.}}}+{{/synopsis}}+{{/page.commands.items}}+.Sh DESCRIPTION+.Nm+is a very simple password store that keeps passwords inside+.Xr gpg2 1+encrypted files inside a simple directory tree residing at+.Pa ~/.password-store .+The pass utility provides a series of commands for manipulating the password+store, allowing the user to add, remove, edit, synchronize, generate, and+manipulate passwords.+.Pp+If no COMMAND is specified, COMMAND defaults to either+.Cm show+or+.Cm ls ,+depending on the type of specifier in ARGS. Alternatively, if+.Ar PASSWORD_STORE_ENABLE_EXTENSIONS+is set to "true", and the file+.Pa .extensions/COMMAND.bash+exists inside the password store and is executable, then it is sourced into the+environment, passing any arguments and environment variables. Extensions+existing in a system- wide directory, only installable by the administrator, are+always enabled.+.Pp+Otherwise COMMAND must be one of the valid commands listed below.+.Pp+Several of the commands below rely on or provide additional functionality if the+password store directory is also a git repository. If the password store+directory is a git repository, all password store modification commands will+cause a corresponding git commit. Sub- directories may be separate nested git+repositories, and pass will use the inner-most directory relative to the current+password. See the+.Ar EXTENDED GIT EXAMPLE+section for a detailed description using init and+.Xr git 1+.Pp+The+.Cm init+command must be run before other commands in order to initialize the password+store with the correct gpg key id. Passwords are encrypted using the gpg key set+with+.Cm init .+.Pp+There is a corresponding bash completion script for use with tab completing+password names in+.Xr bash 1 .+{{#page.options}}+{{>options}}+{{/page.options}}+{{#page.commands}}+.Ss COMMANDS+{{>commands}}+{{/page.commands}}+.Sh EXIT STATUS+.Ex -std
+ templates/person.5.mustache view
@@ -0,0 +1,10 @@+{{>title5}}+{{>name}}+.Sh SYNOPSIS+.Bl -tag -width indent -compact+.It Pa person.schema.json+.El+.Sh DESCRIPTION+{{#page.configs}}+{{>configs}}+{{/page.configs}}
test/Mdoc/Data/ConfigSpec.hs view
@@ -32,14 +32,7 @@             , optionality = Required             , multiple = False             , help = Just $ Mdoc [TextLine "Push to git remote"]-            , example =-                textToMdoc-                  $ mconcat-                    [ "# disable pushing\n"-                    , "git:\n"-                    , "  push: false\n"-                    , "\n"-                    ]+            , example = Nothing             }      renderPlain (prettyDescribed config)
test/Mdoc/ExamplesSpec.hs view
@@ -22,6 +22,7 @@ import Mdoc.Examples.Docker import Mdoc.Examples.Grep import Mdoc.Examples.Mandoc+import Mdoc.Examples.MdocDump import Mdoc.Examples.OptEnvConf import Mdoc.Examples.Pass import Mdoc.Examples.Person@@ -37,15 +38,38 @@  spec :: Spec spec = do-  it "grep.1" $ exampleGolden man1 grep1 1-  it "example.1" $ exampleGolden man1 example1 1-  it "pass.1" $ exampleGolden man1 pass1 1-  it "docker.1" $ exampleGolden man1 docker1 1-  it "mandoc.1" $ exampleGolden man1 mandoc1 1-  it "crontab.5" $ exampleGolden man5 crontab5 5-  it "examplerc.5" $ exampleGolden man5 examplerc5 5-  it "person.5" $ exampleGolden man5 person5 5+  it "grep.1" $ do+    t <- custom "templates/grep.1.mustache"+    exampleGolden t grep1 1 +  it "example.1" $ do+    exampleGolden man1 example1 1++  it "pass.1" $ do+    t <- custom "templates/pass.1.mustache"+    exampleGolden t pass1 1++  it "docker.1" $ do+    exampleGolden man1 docker1 1++  it "mandoc.1" $ do+    exampleGolden man1 mandoc1 1++  it "mdoc-dump.1" $ do+    t <- custom "templates/mdoc-dump.1.mustache"+    exampleGolden t mdocDump1 1++  it "crontab.5" $ do+    t <- custom "templates/crontab.5.mustache"+    exampleGolden t crontab5 5++  it "examplerc.5" $ do+    exampleGolden man5 examplerc5 5++  it "person.5" $ do+    t <- custom "templates/person.5.mustache"+    exampleGolden t person5 5+ exampleGolden :: Template -> Named -> Int -> IO (Golden Mdoc) exampleGolden template named section = do   case renderTemplate template named of@@ -53,9 +77,12 @@       pure @IO         Golden           { output = fixMdocDate mdoc-          , encodePretty = unpack . renderPlain . prettyMdoc+          , encodePretty = show -- unpack . renderPlain . prettyMdoc           , writeToFile = \fp -> T.writeFile fp . (<> "\n") . renderPlain . prettyMdoc-          , readFromFile = \fp -> either exitParseError pure . parseMdocBytes fp =<< BSL.readFile fp+          , readFromFile = \fp ->+              either exitParseError (pure . fixMdocDate)+                . parseMdocBytes fp+                =<< BSL.readFile fp           , goldenFile = "examples" </> path           , actualFile = Nothing           , failFirstTime = False