git.iko.soy/typeable/pandoc
on master help sign in
New method for producing man pages.

This change adds `--man1` and `--man5` options to pandoc, so pandoc can generate its own man pages. It removes the old overly complex method of building a separate executable (but not installing it) just to create the man pages. The man pages are no longer automatically created in the build process. The man/ directory has been removed. The man page templates have been moved to data/. New unexported module: Text.Pandoc.ManPages. Text.Pandoc.Data now exports readmeFile, and `readDataFile` knows how to find README. Closes #2190.

commitfe625e053d078e03d824a1df746196b8a2c697b1 authorJohn MacFarlane <jgm@berkeley.edu> dateSun 28 Jun 2015, 14:39 (11 years ago) parent3e5b4fa
11 files changed+151−147
INSTALL+5−1 README+8 Setup.hs−18 man/man1/pandoc.1.template → data/pandoc.1.template man/man5/pandoc_markdown.5.template → data/pandoc_markdown.5.template man/make-pandoc-man-pages.hs−104 pandoc.cabal+5−18 pandoc.hs+15 src/Text/Pandoc/Data.hsb+3 src/Text/Pandoc/ManPages.hs+101 src/Text/Pandoc/Shared.hs+14−6
INSTALL+5−1
@@ -75,7 +75,11 @@ Quick install
7575 --extra-include-dirs=/usr/local/Cellar/icu4c/51.1/include \
7676 -funicode_collation text-icu pandoc-citeproc
7777
78−The build process will create man pages in `man/man1` and `man/man5`.
78+To build the `pandoc.1` and `pandoc_markdown.5` man pages, you
79+can ues pandoc itself:
80+
81+ pandoc --man1 > pandoc.1
82+ pandoc --man5 > pandoc_markdown.5
7983
8084To build the `pandoc-citeproc` man pages, go to the pandoc-citeproc
8185build directory, and
README+8
@@ -240,6 +240,14 @@ General options
240240 `epub.css`, `templates`, `slidy`, `slideous`, or `s5` directory
241241 placed in this directory will override pandoc's normal defaults.
242242
243+`--man1`
244+
245+: Write `pandoc.1` man page to *stdout*.
246+
247+`--man5`
248+
249+: Write `pandoc_markdown.5` man page to *stdout*.
250+
243251`--verbose`
244252
245253: Give verbose debugging output. Currently this only has an effect
Setup.hs−18
@@ -31,18 +31,7 @@ main :: IO ()
3131main = defaultMainWithHooks $ simpleUserHooks {
3232 -- enable hsb2hs preprocessor for .hsb files
3333 hookedPreProcessors = [ppBlobSuffixHandler]
34− -- ensure that make-pandoc-man-pages doesn't get installed to bindir
35− , copyHook = \pkgdescr ->
36− copyHook simpleUserHooks pkgdescr{ executables =
37− [x | x <- executables pkgdescr, exeName x `notElem` noInstall] }
38− , instHook = \pkgdescr ->
39− instHook simpleUserHooks pkgdescr{ executables =
40− [x | x <- executables pkgdescr, exeName x `notElem` noInstall] }
41− , postBuild = \args bf pkgdescr lbi ->
42− makeManPages args bf pkgdescr lbi
4334 }
44− where
45− noInstall = ["make-pandoc-man-pages"]
4635
4736ppBlobSuffixHandler :: PPSuffixHandler
4837ppBlobSuffixHandler = ("hsb", \_ _ ->
@@ -56,10 +45,3 @@ ppBlobSuffixHandler = ("hsb", \_ _ ->
5645 Nothing -> error "hsb2hs is needed to build this program: cabal install hsb2hs"
5746 return ()
5847 })
59−
60−makeManPages :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
61−makeManPages _ bf _ LocalBuildInfo{buildDir=buildDir}
62− = rawSystemExit verbosity progPath []
63− where
64− verbosity = fromFlagOrDefault normal $ buildVerbosity bf
65− progPath = buildDir </> "make-pandoc-man-pages" </> "make-pandoc-man-pages"
man/man1/pandoc.1.template → data/pandoc.1.templaterenamed

The content is the same.

man/man5/pandoc_markdown.5.template → data/pandoc_markdown.5.templaterenamed

The content is the same.

man/make-pandoc-man-pages.hsdeleted−104
@@ -1,104 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−-- Create pandoc.1 man and pandoc_markdown.5 man pages from README
3−import Text.Pandoc
4−import Text.Pandoc.Error (handleError)
5−import qualified Text.Pandoc.UTF8 as UTF8
6−import Data.Char (toUpper)
7−import Control.Monad
8−import System.FilePath
9−import System.Environment (getArgs)
10−import Text.Pandoc.Shared (normalize)
11−import Data.Maybe ( catMaybes )
12−import Prelude hiding (catch)
13−import Control.Exception ( catch )
14−import System.IO.Error ( isDoesNotExistError )
15−#if MIN_VERSION_directory(1,2,0)
16−import Data.Time.Clock (UTCTime(..))
17−#else
18−import System.Time (ClockTime(..))
19−#endif
20−import System.Directory
21−
22−main :: IO ()
23−main = do
24− ds1 <- modifiedDependencies ("man" </> "man1" </> "pandoc.1")
25− ["README", "man" </> "man1" </> "pandoc.1.template"]
26− ds2 <- modifiedDependencies ("man" </> "man5" </> "pandoc_markdown.5")
27− ["README", "man" </> "man5" </> "pandoc_markdown.5.template"]
28−
29− unless (null ds1 && null ds2) $ do
30− rmContents <- UTF8.readFile "README"
31− let (Pandoc meta blocks) = normalize $ handleError $ readMarkdown def rmContents
32− let manBlocks = removeSect [Str "Wrappers"]
33− $ removeSect [Str "Pandoc's",Space,Str "markdown"] blocks
34− let syntaxBlocks = extractSect [Str "Pandoc's",Space,Str "markdown"] blocks
35− args <- getArgs
36− let verbose = "--verbose" `elem` args
37− unless (null ds1) $
38− makeManPage verbose ("man" </> "man1" </> "pandoc.1") meta manBlocks
39− unless (null ds2) $
40− makeManPage verbose ("man" </> "man5" </> "pandoc_markdown.5") meta syntaxBlocks
41−
42−makeManPage :: Bool -> FilePath -> Meta -> [Block] -> IO ()
43−makeManPage verbose page meta blocks = do
44− let templ = page <.> "template"
45− manTemplate <- UTF8.readFile templ
46− writeManPage page manTemplate (Pandoc meta blocks)
47− when verbose $ putStrLn $ "Created " ++ page
48−
49−writeManPage :: FilePath -> String -> Pandoc -> IO ()
50−writeManPage page templ doc = do
51− let version = pandocVersion
52− let opts = def{ writerStandalone = True
53− , writerTemplate = templ
54− , writerVariables = [("version",version)] }
55− let manPage = writeMan opts $
56− bottomUp (concatMap removeLinks) $
57− bottomUp capitalizeHeaders doc
58− UTF8.writeFile page manPage
59−
60−removeLinks :: Inline -> [Inline]
61−removeLinks (Link l _) = l
62−removeLinks x = [x]
63−
64−capitalizeHeaders :: Block -> Block
65−capitalizeHeaders (Header 1 attr xs) = Header 1 attr $ bottomUp capitalize xs
66−capitalizeHeaders x = x
67−
68−capitalize :: Inline -> Inline
69−capitalize (Str xs) = Str $ map toUpper xs
70−capitalize x = x
71−
72−removeSect :: [Inline] -> [Block] -> [Block]
73−removeSect ils (Header 1 _ x:xs) | x == ils =
74− dropWhile (not . isHeader1) xs
75−removeSect ils (x:xs) = x : removeSect ils xs
76−removeSect _ [] = []
77−
78−extractSect :: [Inline] -> [Block] -> [Block]
79−extractSect ils (Header 1 _ z:xs) | z == ils =
80− bottomUp promoteHeader $ takeWhile (not . isHeader1) xs
81− where promoteHeader (Header n attr x) = Header (n-1) attr x
82− promoteHeader x = x
83−extractSect ils (x:xs) = extractSect ils xs
84−extractSect _ [] = []
85−
86−isHeader1 :: Block -> Bool
87−isHeader1 (Header 1 _ _ ) = True
88−isHeader1 _ = False
89−
90−
91−-- | Returns a list of 'dependencies' that have been modified after 'file'.
92−modifiedDependencies :: FilePath -> [FilePath] -> IO [FilePath]
93−modifiedDependencies file dependencies = do
94− fileModTime <- catch (getModificationTime file) $
95− \e -> if isDoesNotExistError e
96−#if MIN_VERSION_directory(1,2,0)
97− then return (UTCTime (toEnum 0) 0) -- the minimum ClockTime
98−#else
99− then return (TOD 0 0) -- the minimum ClockTime
100−#endif
101− else ioError e
102− depModTimes <- mapM getModificationTime dependencies
103− let modified = zipWith (\dep time -> if time > fileModTime then Just dep else Nothing) dependencies depModTimes
104− return $ catMaybes modified
pandoc.cabal+5−18
@@ -106,13 +106,12 @@ Data-Files:
106106 data/sample.lua
107107 -- documentation
108108 README, COPYRIGHT
109+ -- man page templates
110+ data/pandoc.1.template
111+ data/pandoc_markdown.5.template
109112Extra-Source-Files:
110113 -- documentation
111114 INSTALL, BUGS, CONTRIBUTING.md, changelog
112− -- code to create pandoc.1 man page
113− Makefile
114− man/man1/pandoc.1.template
115− man/man5/pandoc_markdown.5.template
116115 -- trypandoc
117116 trypandoc/Makefile
118117 trypandoc/index.html
@@ -323,6 +322,7 @@ Library
323322 Text.Pandoc.Readers.Native,
324323 Text.Pandoc.Readers.Haddock,
325324 Text.Pandoc.Readers.TWiki,
325+ Text.Pandoc.Readers.Txt2Tags,
326326 Text.Pandoc.Readers.Docx,
327327 Text.Pandoc.Readers.EPUB,
328328 Text.Pandoc.Writers.Native,
@@ -356,7 +356,7 @@ Library
356356 Text.Pandoc.XML,
357357 Text.Pandoc.SelfContained,
358358 Text.Pandoc.Process,
359− Text.Pandoc.Readers.Txt2Tags
359+ Text.Pandoc.ManPages
360360 Other-Modules: Text.Pandoc.Readers.Docx.Lists,
361361 Text.Pandoc.Readers.Docx.Reducible,
362362 Text.Pandoc.Readers.Docx.Parse,
@@ -422,19 +422,6 @@ Executable trypandoc
422422 else
423423 Buildable: False
424424
425−-- NOTE: A trick in Setup.hs makes sure this won't be installed:
426−Executable make-pandoc-man-pages
427− Main-Is: make-pandoc-man-pages.hs
428− Hs-Source-Dirs: man
429− Build-Depends: pandoc,
430− base >= 4.2 && < 5,
431− directory >= 1 && < 1.3,
432− filepath >= 1.1 && < 1.5,
433− old-time >= 1.0 && < 1.2,
434− time >= 1.2 && < 1.6
435− Default-Language: Haskell98
436− Buildable: True
437−
438425Test-Suite test-pandoc
439426 Type: exitcode-stdio-1.0
440427 Main-Is: test-pandoc.hs
pandoc.hs+15
@@ -39,6 +39,7 @@ import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
3939 safeRead, headerShift, normalize, err, warn,
4040 openURL )
4141import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag )
42+import Text.Pandoc.ManPages ( manPandoc1, manPandocMarkdown5 )
4243import Text.Pandoc.XML ( toEntities )
4344import Text.Pandoc.SelfContained ( makeSelfContained )
4445import Text.Pandoc.Process (pipeProcess)
@@ -869,6 +870,20 @@ options =
869870 (\opt -> return opt { optIgnoreArgs = True }))
870871 "" -- "Ignore command-line arguments."
871872
873+ , Option "" ["man1"]
874+ (NoArg
875+ (\_ -> do
876+ manPandoc1 >>= UTF8.hPutStr stdout
877+ exitWith ExitSuccess ))
878+ "" -- "Print pandoc.1 man page"
879+
880+ , Option "" ["man5"]
881+ (NoArg
882+ (\_ -> do
883+ manPandocMarkdown5 >>= UTF8.hPutStr stdout
884+ exitWith ExitSuccess ))
885+ "" -- "Print pandoc_markdown.5 man page"
886+
872887 , Option "" ["verbose"]
873888 (NoArg
874889 (\opt -> return opt { optVerbose = True }))
src/Text/Pandoc/Data.hsb+3
@@ -5,3 +5,6 @@ import qualified Data.ByteString as B
55
66dataFiles :: [(FilePath, B.ByteString)]
77dataFiles = %blobs "data"
8+
9+readmeFile :: B.ByteString
10+readmeFile = %blob "README"
src/Text/Pandoc/ManPages.hsnew file+101
@@ -0,0 +1,101 @@
1+{-# LANGUAGE CPP #-}
2+{-
3+Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.ManPages
22+ Copyright : Copyright (C) 2013-2015 John MacFarlane
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : John MacFarlane <jgm@berkeley.edu>
26+ Stability : alpha
27+ Portability : portable
28+
29+Functions to build pandoc's man pages (pandoc.1 and pandoc_markdown.5)
30+from pandoc's README.
31+-}
32+module Text.Pandoc.ManPages (
33+ manPandoc1,
34+ manPandocMarkdown5
35+ ) where
36+import Text.Pandoc
37+import Text.Pandoc.Error (handleError)
38+import Data.Char (toUpper)
39+import System.FilePath
40+import Text.Pandoc.Shared (normalize, readDataFileUTF8)
41+
42+manPandoc1 :: IO String
43+manPandoc1 = do
44+ readme <- readDataFileUTF8 Nothing "README"
45+ let (Pandoc meta blocks) = normalize $ handleError
46+ $ readMarkdown def readme
47+ let manBlocks = removeSect [Str "Wrappers"]
48+ $ removeSect [Str "Pandoc's",Space,Str "markdown"] blocks
49+ makeManPage "pandoc.1" meta manBlocks
50+
51+manPandocMarkdown5 :: IO String
52+manPandocMarkdown5 = do
53+ readme <- readDataFileUTF8 Nothing "README"
54+ let (Pandoc meta blocks) = normalize $ handleError
55+ $ readMarkdown def readme
56+ let syntaxBlocks = extractSect [Str "Pandoc's",Space,Str "markdown"] blocks
57+ makeManPage "pandoc_markdown.5" meta syntaxBlocks
58+
59+makeManPage :: String -> Meta -> [Block] -> IO String
60+makeManPage page meta blocks = do
61+ let templ = page <.> "template"
62+ manTemplate <- readDataFileUTF8 Nothing templ
63+ return $ writeManPage manTemplate (Pandoc meta blocks)
64+
65+writeManPage :: String -> Pandoc -> String
66+writeManPage templ doc =
67+ writeMan def{ writerStandalone = True
68+ , writerTemplate = templ
69+ , writerVariables = [("version", pandocVersion)] } $
70+ bottomUp (concatMap removeLinks) $
71+ bottomUp capitalizeHeaders doc
72+
73+removeLinks :: Inline -> [Inline]
74+removeLinks (Link l _) = l
75+removeLinks x = [x]
76+
77+capitalizeHeaders :: Block -> Block
78+capitalizeHeaders (Header 1 attr xs) = Header 1 attr $ bottomUp capitalize xs
79+capitalizeHeaders x = x
80+
81+capitalize :: Inline -> Inline
82+capitalize (Str xs) = Str $ map toUpper xs
83+capitalize x = x
84+
85+removeSect :: [Inline] -> [Block] -> [Block]
86+removeSect ils (Header 1 _ x:xs) | x == ils =
87+ dropWhile (not . isHeader1) xs
88+removeSect ils (x:xs) = x : removeSect ils xs
89+removeSect _ [] = []
90+
91+extractSect :: [Inline] -> [Block] -> [Block]
92+extractSect ils (Header 1 _ z:xs) | z == ils =
93+ bottomUp promoteHeader $ takeWhile (not . isHeader1) xs
94+ where promoteHeader (Header n attr x) = Header (n-1) attr x
95+ promoteHeader x = x
96+extractSect ils (_:xs) = extractSect ils xs
97+extractSect _ [] = []
98+
99+isHeader1 :: Block -> Bool
100+isHeader1 (Header 1 _ _ ) = True
101+isHeader1 _ = False
src/Text/Pandoc/Shared.hs+14−6
@@ -132,7 +132,7 @@ import qualified Data.Text as T (toUpper, pack, unpack)
132132import Data.ByteString.Lazy (toChunks)
133133
134134#ifdef EMBED_DATA_FILES
135−import Text.Pandoc.Data (dataFiles)
135+import Text.Pandoc.Data (dataFiles, readmeFile)
136136#else
137137import Paths_pandoc (getDataFileName)
138138#endif
@@ -743,6 +743,12 @@ inDirectory path action = E.bracket
743743 (const $ setCurrentDirectory path >> action)
744744
745745readDefaultDataFile :: FilePath -> IO BS.ByteString
746+readDefaultDataFile "README" =
747+#ifdef EMBED_DATA_FILES
748+ return readmeFile
749+#else
750+ getDataFileName "README" >>= checkExistence >>= BS.readFile
751+#endif
746752readDefaultDataFile fname =
747753#ifdef EMBED_DATA_FILES
748754 case lookup (makeCanonical fname) dataFiles of
@@ -755,13 +761,15 @@ readDefaultDataFile fname =
755761 go as x = x : as
756762#else
757763 getDataFileName ("data" </> fname) >>= checkExistence >>= BS.readFile
758− where checkExistence fn = do
759− exists <- doesFileExist fn
760− if exists
761− then return fn
762− else err 97 ("Could not find data file " ++ fname)
763764#endif
764765
766+checkExistence :: FilePath -> IO FilePath
767+checkExistence fn = do
768+ exists <- doesFileExist fn
769+ if exists
770+ then return fn
771+ else err 97 ("Could not find data file " ++ fn)
772+
765773-- | Read file from specified user data directory or, if not found there, from
766774-- Cabal data directory.
767775readDataFile :: Maybe FilePath -> FilePath -> IO BS.ByteString