{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.DocFiles (
Topic
,printHelpForTopic
,runManForTopic
,runInfoForTopic
,runPagerForTopic
,runTldrForPage
) where
import Control.Exception
import Data.ByteString (ByteString)
import Data.ByteString.Char8 qualified as BC
import Data.Maybe (fromMaybe)
import Data.String
import System.Environment (setEnv)
import System.IO
import System.IO.Temp
import System.Process
import Hledger.Utils (first3, second3, third3, embedFileRelative, error')
import Text.Printf (printf)
import System.Environment (lookupEnv)
import Hledger.Utils.Debug
type Tool = String
type Topic = String
type TldrPage = String
tldrs :: [(TldrPage, ByteString)]
tldrs :: [(Tool, ByteString)]
tldrs = [
(Tool
"hledger-accounts", $(embedFileRelative "embeddedfiles/hledger-accounts.md"))
,(Tool
"hledger-add", $(embedFileRelative "embeddedfiles/hledger-add.md"))
,(Tool
"hledger-aregister", $(embedFileRelative "embeddedfiles/hledger-aregister.md"))
,(Tool
"hledger-balance", $(embedFileRelative "embeddedfiles/hledger-balance.md"))
,(Tool
"hledger-balancesheet", $(embedFileRelative "embeddedfiles/hledger-balancesheet.md"))
,(Tool
"hledger-import", $(embedFileRelative "embeddedfiles/hledger-import.md"))
,(Tool
"hledger-incomestatement", $(embedFileRelative "embeddedfiles/hledger-incomestatement.md"))
,(Tool
"hledger-print", $(embedFileRelative "embeddedfiles/hledger-print.md"))
,(Tool
"hledger-ui", $(embedFileRelative "embeddedfiles/hledger-ui.md"))
,(Tool
"hledger-web", $(embedFileRelative "embeddedfiles/hledger-web.md"))
,(Tool
"hledger", $(embedFileRelative "embeddedfiles/hledger.md"))
]
manuals :: [(Tool, (ByteString, ByteString, ByteString))]
manuals :: [(Tool, (ByteString, ByteString, ByteString))]
manuals = [
(Tool
"hledger",
($(embedFileRelative "embeddedfiles/hledger.1")
,$(embedFileRelative "embeddedfiles/hledger.txt")
,$(embedFileRelative "embeddedfiles/hledger.info")
))
,(Tool
"hledger-ui",
($(embedFileRelative "embeddedfiles/hledger-ui.1")
,$(embedFileRelative "embeddedfiles/hledger-ui.txt")
,$(embedFileRelative "embeddedfiles/hledger-ui.info")
))
,(Tool
"hledger-web",
($(embedFileRelative "embeddedfiles/hledger-web.1")
,$(embedFileRelative "embeddedfiles/hledger-web.txt")
,$(embedFileRelative "embeddedfiles/hledger-web.info")
))
]
manualTxt :: Tool -> ByteString
manualTxt :: Tool -> ByteString
manualTxt Tool
name = ByteString
-> ((ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString)
-> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Tool -> ByteString
forall a. IsString a => Tool -> a
fromString (Tool -> ByteString) -> Tool -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
"No text manual found for tool: "Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
name) (ByteString, ByteString, ByteString) -> ByteString
forall {a} {b} {c}. (a, b, c) -> b
second3 (Maybe (ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString) -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
-> [(Tool, (ByteString, ByteString, ByteString))]
-> Maybe (ByteString, ByteString, ByteString)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Tool
name [(Tool, (ByteString, ByteString, ByteString))]
manuals
manualMan :: Tool -> ByteString
manualMan :: Tool -> ByteString
manualMan Tool
name = ByteString
-> ((ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString)
-> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Tool -> ByteString
forall a. IsString a => Tool -> a
fromString (Tool -> ByteString) -> Tool -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
"No man page found for tool: "Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
name) (ByteString, ByteString, ByteString) -> ByteString
forall {a} {b} {c}. (a, b, c) -> a
first3 (Maybe (ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString) -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
-> [(Tool, (ByteString, ByteString, ByteString))]
-> Maybe (ByteString, ByteString, ByteString)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Tool
name [(Tool, (ByteString, ByteString, ByteString))]
manuals
manualInfo :: Tool -> ByteString
manualInfo :: Tool -> ByteString
manualInfo Tool
name = ByteString
-> ((ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString)
-> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Tool -> ByteString
forall a. IsString a => Tool -> a
fromString (Tool -> ByteString) -> Tool -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
"No info manual found for tool: "Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
name) (ByteString, ByteString, ByteString) -> ByteString
forall {a} {b} {c}. (a, b, c) -> c
third3 (Maybe (ByteString, ByteString, ByteString) -> ByteString)
-> Maybe (ByteString, ByteString, ByteString) -> ByteString
forall a b. (a -> b) -> a -> b
$ Tool
-> [(Tool, (ByteString, ByteString, ByteString))]
-> Maybe (ByteString, ByteString, ByteString)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Tool
name [(Tool, (ByteString, ByteString, ByteString))]
manuals
printHelpForTopic :: Tool -> Maybe Topic -> IO ()
printHelpForTopic :: Tool -> Maybe Tool -> IO ()
printHelpForTopic Tool
tool Maybe Tool
_mtopic = ByteString -> IO ()
BC.putStr (Tool -> ByteString
manualTxt Tool
tool)
runInfoForTopic :: Tool -> Maybe Topic -> IO ()
runInfoForTopic :: Tool -> Maybe Tool -> IO ()
runInfoForTopic Tool
tool Maybe Tool
mtopic =
Tool -> (Tool -> Handle -> IO ()) -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
Tool -> (Tool -> Handle -> m a) -> m a
withSystemTempFile (Tool
"hledger-"Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
toolTool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
".info") ((Tool -> Handle -> IO ()) -> IO ())
-> (Tool -> Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Tool
f Handle
h -> do
Handle -> ByteString -> IO ()
BC.hPutStrLn Handle
h (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> ByteString
manualInfo Tool
tool
Handle -> IO ()
hClose Handle
h
Tool -> IO ()
callCommand (Tool -> IO ()) -> Tool -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> Tool -> Tool
forall a. Show a => Tool -> a -> a
dbg1 Tool
"info command" (Tool -> Tool) -> Tool -> Tool
forall a b. (a -> b) -> a -> b
$
Tool
"info -f " Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
f Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool -> (Tool -> Tool) -> Maybe Tool -> Tool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Tool
"" (Tool -> Tool -> Tool
forall r. PrintfType r => Tool -> r
printf Tool
" -n '%s'") Maybe Tool
mtopic
less :: Tool
less = Tool
"less -s -i --use-backslash"
runPagerForTopic :: Tool -> Maybe Topic -> IO ()
Tool
tool Maybe Tool
mtopic = do
Tool -> (Tool -> Handle -> IO ()) -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
Tool -> (Tool -> Handle -> m a) -> m a
withSystemTempFile (Tool
"hledger-"Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
toolTool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
".txt") ((Tool -> Handle -> IO ()) -> IO ())
-> (Tool -> Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Tool
f Handle
h -> do
Handle -> ByteString -> IO ()
BC.hPutStrLn Handle
h (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> ByteString
manualTxt Tool
tool
Handle -> IO ()
hClose Handle
h
envpager <- Tool -> Maybe Tool -> Tool
forall a. a -> Maybe a -> a
fromMaybe Tool
less (Maybe Tool -> Tool) -> IO (Maybe Tool) -> IO Tool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Tool -> IO (Maybe Tool)
lookupEnv Tool
"PAGER"
let
exactmatch = Bool
True
(pager, searcharg) =
case mtopic of
Maybe Tool
Nothing -> (Tool
envpager, Tool
"")
Just Tool
t -> (Tool
less, Tool
"-p'^( )?" Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
t Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ if Bool
exactmatch then Tool
"\\$'" else Tool
"")
callCommand $ dbg1 "pager command" $ unwords [pager, searcharg, f]
runManForTopic :: Tool -> Maybe Topic -> IO ()
runManForTopic :: Tool -> Maybe Tool -> IO ()
runManForTopic Tool
tool Maybe Tool
mtopic =
Tool -> (Tool -> Handle -> IO ()) -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
Tool -> (Tool -> Handle -> m a) -> m a
withSystemTempFile (Tool
"hledger-"Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
toolTool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
".1") ((Tool -> Handle -> IO ()) -> IO ())
-> (Tool -> Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Tool
f Handle
h -> do
Handle -> ByteString -> IO ()
BC.hPutStrLn Handle
h (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> ByteString
manualMan Tool
tool
Handle -> IO ()
hClose Handle
h
let
exactmatch :: Bool
exactmatch = Bool
True
pagerarg :: Tool
pagerarg =
case Maybe Tool
mtopic of
Maybe Tool
Nothing -> Tool
""
Just Tool
t -> Tool
"-P \"" Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
less Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
" -p'^( )?" Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
t Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ (if Bool
exactmatch then Tool
"\\\\$" else Tool
"") Tool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++ Tool
"'\""
Tool -> IO ()
callCommand (Tool -> IO ()) -> Tool -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> Tool -> Tool
forall a. Show a => Tool -> a -> a
dbg1 Tool
"man command" (Tool -> Tool) -> Tool -> Tool
forall a b. (a -> b) -> a -> b
$ [Tool] -> Tool
unwords [Tool
"man", Tool
pagerarg, Tool
f]
tldr :: TldrPage -> Maybe ByteString
tldr :: Tool -> Maybe ByteString
tldr Tool
name = Tool -> [(Tool, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Tool
name [(Tool, ByteString)]
tldrs
runTldrForPage :: TldrPage -> IO ()
runTldrForPage :: Tool -> IO ()
runTldrForPage Tool
name =
case Tool -> Maybe ByteString
tldr Tool
name of
Maybe ByteString
Nothing -> Tool -> IO ()
forall a. Tool -> a
error' (Tool -> IO ()) -> Tool -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool
"sorry, there's no " Tool -> Tool -> Tool
forall a. Semigroup a => a -> a -> a
<> Tool
name Tool -> Tool -> Tool
forall a. Semigroup a => a -> a -> a
<> Tool
" tldr page yet"
Just ByteString
b -> (do
Tool -> (Tool -> Handle -> IO ()) -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
Tool -> (Tool -> Handle -> m a) -> m a
withSystemTempFile (Tool
nameTool -> Tool -> Tool
forall a. [a] -> [a] -> [a]
++Tool
".md") ((Tool -> Handle -> IO ()) -> IO ())
-> (Tool -> Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Tool
f Handle
h -> do
Handle -> ByteString -> IO ()
BC.hPutStrLn Handle
h ByteString
b
Handle -> IO ()
hClose Handle
h
Tool -> Tool -> IO ()
setEnv Tool
"TLDR_AUTO_UPDATE_DISABLED" Tool
"1"
Tool -> IO ()
callCommand (Tool -> IO ()) -> Tool -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool -> Tool -> Tool
forall a. Show a => Tool -> a -> a
dbg1 Tool
"tldr command" (Tool -> Tool) -> Tool -> Tool
forall a b. (a -> b) -> a -> b
$ Tool
"tldr --render " Tool -> Tool -> Tool
forall a. Semigroup a => a -> a -> a
<> Tool
f
) IO () -> (IOException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (\(IOException
_e::IOException) -> do
Handle -> Tool -> IO ()
hPutStrLn Handle
stderr (Tool -> IO ()) -> Tool -> IO ()
forall a b. (a -> b) -> a -> b
$ Tool
"Warning: could not run tldr --render, using fallback viewer instead.\n"
ByteString -> IO ()
BC.putStrLn ByteString
b
)