diff --git a/hledger-lib/Hledger/Utils.hs b/hledger-lib/Hledger/Utils.hs index cd54380a58e..f343b8c95c0 100644 --- a/hledger-lib/Hledger/Utils.hs +++ b/hledger-lib/Hledger/Utils.hs @@ -56,6 +56,7 @@ module Hledger.Utils ( -- * Other module Hledger.Utils.Debug, + module Hledger.Utils.DocFiles, module Hledger.Utils.Parse, module Hledger.Utils.IO, module Hledger.Utils.Regex, @@ -83,6 +84,7 @@ import Lens.Micro ((&), (.~)) import Lens.Micro.TH (DefName(TopName), lensClass, lensField, makeLensesWith, classyRules) import Hledger.Utils.Debug +import Hledger.Utils.DocFiles import Hledger.Utils.Parse import Hledger.Utils.IO import Hledger.Utils.Regex diff --git a/hledger-lib/Hledger/Utils/DocFiles.hs b/hledger-lib/Hledger/Utils/DocFiles.hs new file mode 100644 index 00000000000..b17c400a4d9 --- /dev/null +++ b/hledger-lib/Hledger/Utils/DocFiles.hs @@ -0,0 +1,115 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-| + +Helpers for viewing documentation files in various formats. + +|-} + +module Hledger.Utils.DocFiles ( + Topic + ,TldrPage + + ,printHelpForTopic' + ,runManForTopic' + ,runInfoForTopic' + ,runPagerForTopic' + ,runTldrForPage' + + ) where + +import Control.Exception +import Data.ByteString (ByteString) +import qualified Data.ByteString.Char8 as BC +import Data.Maybe (fromMaybe) +import System.Environment (setEnv) +import System.IO +import System.IO.Temp +import System.Process + +import Hledger.Utils.IO (error') +import Text.Printf (printf) +import System.Environment (lookupEnv) +import Hledger.Utils.Debug + +-- The name of any hledger executable. +type Tool = String + +-- Any heading in the hledger user manual (and perhaps later the hledger-ui/hledger-web manuals). +type Topic = String + +-- Any name of a hledger tldr page (hledger, hledger-ui, hledger-print etc.) +type TldrPage = String + +-- | Print plain text help for this tool. +-- Takes an optional topic argument for convenience but it is currently ignored. +printHelpForTopic' :: ByteString -> Maybe Topic -> IO () +printHelpForTopic' b _mtopic = BC.putStr b + +-- | Display an info manual for this topic, opened at the given topic if provided, +-- using the "info" executable in $PATH. +-- Topic can be an exact heading or a heading prefix; info will favour an exact match. +runInfoForTopic' :: Tool -> ByteString -> Maybe Topic -> IO () +runInfoForTopic' tool b mtopic = + withSystemTempFile ("hledger-"++tool++".info") $ \f h -> do + BC.hPutStrLn h b + hClose h + callCommand $ dbg1 "info command" $ + "info -f " ++ f ++ maybe "" (printf " -n '%s'") mtopic + +-- less with any vertical whitespace squashed, case-insensitive searching, the $ regex metacharacter accessible as \$. +less = "less -s -i --use-backslash" + +-- | Display plain text help for this tool, scrolled to the given topic if any, using the users $PAGER or "less". +-- When a topic is provided we always use less, ignoring $PAGER. +-- +-- This is less robust than the newer Hledger.Utils.IO.runPager, +-- but that one doesn't yet support scrolling to a topic. +runPagerForTopic' :: Tool -> ByteString -> Maybe Topic -> IO () +runPagerForTopic' tool b mtopic = do + withSystemTempFile ("hledger-"++tool++".txt") $ \f h -> do + BC.hPutStrLn h b + hClose h + envpager <- fromMaybe less <$> lookupEnv "PAGER" + let + exactmatch = True + (pager, searcharg) = + case mtopic of + Nothing -> (envpager, "") + Just t -> (less, "-p'^( )?" ++ t ++ if exactmatch then "\\$'" else "") + callCommand $ dbg1 "pager command" $ unwords [pager, searcharg, f] + +-- | Display a man page for this tool, scrolled to the given topic if provided, using "man". +-- When a topic is provided we force man to use "less", ignoring $MANPAGER and $PAGER. +runManForTopic' :: Tool -> ByteString -> Maybe Topic -> IO () +runManForTopic' tool b mtopic = + -- This temp file path should have a slash in it, man requires at least one. + withSystemTempFile ("hledger-"++tool++".1") $ \f h -> do + BC.hPutStrLn h b + hClose h + let + exactmatch = True + pagerarg = + case mtopic of + Nothing -> "" + Just t -> "-P \"" ++ less ++ " -p'^( )?" ++ t ++ (if exactmatch then "\\\\$" else "") ++ "'\"" + callCommand $ dbg1 "man command" $ unwords ["man", pagerarg, f] + +-- | Display one of the tldr pages, using "tldr". +runTldrForPage' :: [(TldrPage, ByteString)] -> TldrPage -> IO () +runTldrForPage' tldrs name = + case lookup name tldrs of + Nothing -> error' $ "sorry, there's no " <> name <> " tldr page yet" + Just b -> (do + withSystemTempFile (name++".md") $ \f h -> do + BC.hPutStrLn h b + hClose h + -- tldr clients tend to auto-update their data, try to discourage that here + -- tealdeer - doesn't auto-update by default + -- tlrc - ? + -- tldr-node-client - undocumented env var suggested in output + setEnv "TLDR_AUTO_UPDATE_DISABLED" "1" + callCommand $ dbg1 "tldr command" $ "tldr --render " <> f + ) `catch` (\(_e::IOException) -> do + hPutStrLn stderr $ "Warning: could not run tldr --render, using fallback viewer instead.\n" + BC.putStrLn b + ) diff --git a/hledger-lib/hledger-lib.cabal b/hledger-lib/hledger-lib.cabal index b20dd9424b1..546d2171070 100644 --- a/hledger-lib/hledger-lib.cabal +++ b/hledger-lib/hledger-lib.cabal @@ -106,6 +106,7 @@ library Hledger.Reports.PostingsReport Hledger.Utils Hledger.Utils.Debug + Hledger.Utils.DocFiles Hledger.Utils.IO Hledger.Utils.Parse Hledger.Utils.Regex @@ -160,6 +161,7 @@ library , tasty >=1.2.3 , tasty-hunit >=0.10.0.2 , template-haskell + , temporary , terminal-size >=0.3.3 , text >=1.2.4.1 , time >=1.5 @@ -220,6 +222,7 @@ test-suite doctest , tasty >=1.2.3 , tasty-hunit >=0.10.0.2 , template-haskell + , temporary , terminal-size >=0.3.3 , text >=1.2.4.1 , time >=1.5 @@ -282,6 +285,7 @@ test-suite unittest , tasty >=1.2.3 , tasty-hunit >=0.10.0.2 , template-haskell + , temporary , terminal-size >=0.3.3 , text >=1.2.4.1 , time >=1.5 diff --git a/hledger-lib/package.yaml b/hledger-lib/package.yaml index ded3c37d9eb..e5a78a09a4d 100644 --- a/hledger-lib/package.yaml +++ b/hledger-lib/package.yaml @@ -76,6 +76,7 @@ dependencies: - tabular >=0.2 - tasty >=1.2.3 - tasty-hunit >=0.10.0.2 +- temporary - template-haskell - terminal-size >=0.3.3 - text >=1.2.4.1 @@ -172,6 +173,7 @@ library: - Hledger.Reports.PostingsReport - Hledger.Utils - Hledger.Utils.Debug + - Hledger.Utils.DocFiles - Hledger.Utils.IO - Hledger.Utils.Parse - Hledger.Utils.Regex diff --git a/hledger-ui/Hledger/UI/DocFiles.hs b/hledger-ui/Hledger/UI/DocFiles.hs new file mode 100644 index 00000000000..02446adfbc3 --- /dev/null +++ b/hledger-ui/Hledger/UI/DocFiles.hs @@ -0,0 +1,48 @@ +{-# LANGUAGE TemplateHaskell #-} +{-| + +Embedded documentation files in various formats, and helpers for viewing them. + +|-} + +module Hledger.UI.DocFiles ( + printHelpForTopic + ,runManForTopic + ,runInfoForTopic + ,runPagerForTopic + ,runTldrForPage + ) where + +import Data.ByteString (ByteString) + +import Hledger.Utils (embedFileRelative) +import Hledger.Utils.DocFiles + +-- | All hledger-ui pages from the tldr-pages project. +tldrs :: [(TldrPage, ByteString)] +tldrs = [ + ("hledger-ui", $(embedFileRelative "embeddedfiles/hledger-ui.md")) + ] + +-- | The main hledger-ui manuals as source for man, info and as plain text. +man :: ByteString +man = $(embedFileRelative "embeddedfiles/hledger-ui.1") +txt :: ByteString +txt = $(embedFileRelative "embeddedfiles/hledger-ui.txt") +info :: ByteString +info = $(embedFileRelative "embeddedfiles/hledger-ui.info") + +printHelpForTopic :: Maybe Topic -> IO () +printHelpForTopic = printHelpForTopic' txt + +runManForTopic :: Maybe Topic -> IO () +runManForTopic = runManForTopic' "hledger-ui" man + +runInfoForTopic :: Maybe Topic -> IO () +runInfoForTopic = runInfoForTopic' "hledger-ui" info + +runPagerForTopic :: Maybe Topic -> IO () +runPagerForTopic = runPagerForTopic' "hledger-ui" txt + +runTldrForPage :: TldrPage -> IO () +runTldrForPage = runTldrForPage' tldrs diff --git a/hledger-ui/Hledger/UI/Main.hs b/hledger-ui/Hledger/UI/Main.hs index fda3c341305..cface27c761 100644 --- a/hledger-ui/Hledger/UI/Main.hs +++ b/hledger-ui/Hledger/UI/Main.hs @@ -35,7 +35,9 @@ import Brick hiding (bsDraw) import qualified Brick.BChan as BC import Hledger -import Hledger.Cli hiding (progname,prognameandversion) +import Hledger.Cli (withJournalDo) +import Hledger.Cli.CliOptions hiding (progname,prognameandversion) +import Hledger.UI.DocFiles import Hledger.UI.Theme import Hledger.UI.UIOptions import Hledger.UI.UITypes @@ -100,8 +102,8 @@ hledgerUiMain = withGhcDebug' $ withProgName "hledger-ui.log" $ do -- force Hle case True of _ | boolopt "help" rawopts -> runPager $ showModeUsage uimode ++ "\n" _ | boolopt "tldr" rawopts -> runTldrForPage "hledger-ui" - _ | boolopt "info" rawopts -> runInfoForTopic "hledger-ui" Nothing - _ | boolopt "man" rawopts -> runManForTopic "hledger-ui" Nothing + _ | boolopt "info" rawopts -> runInfoForTopic Nothing + _ | boolopt "man" rawopts -> runManForTopic Nothing _ | boolopt "version" rawopts -> putStrLn prognameandversion -- _ | boolopt "binary-filename" rawopts -> putStrLn (binaryfilename progname) _ -> withJournalDo copts' (runBrickUi opts) diff --git a/hledger-ui/Hledger/UI/UIUtils.hs b/hledger-ui/Hledger/UI/UIUtils.hs index 285239fbb20..fca6dc0abdf 100644 --- a/hledger-ui/Hledger/UI/UIUtils.hs +++ b/hledger-ui/Hledger/UI/UIUtils.hs @@ -64,7 +64,7 @@ import Lens.Micro.Platform import Hledger -- import Hledger.Cli.CliOptions (CliOpts(reportspec_)) -import Hledger.Cli.DocFiles +import Hledger.UI.DocFiles -- import Hledger.UI.UIOptions (UIOpts(uoCliOpts)) import Hledger.UI.UITypes @@ -228,9 +228,9 @@ helpHandle ev = do let ui' = ui{aMode=Normal} case ev of VtyEvent e | e `elem` closeHelpEvents -> put' ui' - VtyEvent (EvKey (KChar 'p') []) -> suspendAndResume (runPagerForTopic "hledger-ui" Nothing >> return ui') - VtyEvent (EvKey (KChar 'm') []) -> suspendAndResume (runManForTopic "hledger-ui" Nothing >> return ui') - VtyEvent (EvKey (KChar 'i') []) -> suspendAndResume (runInfoForTopic "hledger-ui" Nothing >> return ui') + VtyEvent (EvKey (KChar 'p') []) -> suspendAndResume (runPagerForTopic Nothing >> return ui') + VtyEvent (EvKey (KChar 'm') []) -> suspendAndResume (runManForTopic Nothing >> return ui') + VtyEvent (EvKey (KChar 'i') []) -> suspendAndResume (runInfoForTopic Nothing >> return ui') _ -> return () where closeHelpEvents = moveLeftEvents ++ [EvKey KEsc [], EvKey (KChar '?') [], EvKey (KChar 'q') []] diff --git a/hledger-ui/embeddedfiles/hledger-ui.1 b/hledger-ui/embeddedfiles/hledger-ui.1 new file mode 120000 index 00000000000..bfade9d095c --- /dev/null +++ b/hledger-ui/embeddedfiles/hledger-ui.1 @@ -0,0 +1 @@ +../hledger-ui.1 \ No newline at end of file diff --git a/hledger-ui/embeddedfiles/hledger-ui.info b/hledger-ui/embeddedfiles/hledger-ui.info new file mode 120000 index 00000000000..717a740b9b1 --- /dev/null +++ b/hledger-ui/embeddedfiles/hledger-ui.info @@ -0,0 +1 @@ +../hledger-ui.info \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-ui.md b/hledger-ui/embeddedfiles/hledger-ui.md similarity index 100% rename from hledger/embeddedfiles/hledger-ui.md rename to hledger-ui/embeddedfiles/hledger-ui.md diff --git a/hledger-ui/embeddedfiles/hledger-ui.txt b/hledger-ui/embeddedfiles/hledger-ui.txt new file mode 120000 index 00000000000..40860a74a23 --- /dev/null +++ b/hledger-ui/embeddedfiles/hledger-ui.txt @@ -0,0 +1 @@ +../hledger-ui.txt \ No newline at end of file diff --git a/hledger-ui/hledger-ui.cabal b/hledger-ui/hledger-ui.cabal index e77439522b0..7b446eca68e 100644 --- a/hledger-ui/hledger-ui.cabal +++ b/hledger-ui/hledger-ui.cabal @@ -31,9 +31,10 @@ tested-with: extra-source-files: CHANGES.md README.md - hledger-ui.1 - hledger-ui.txt - hledger-ui.info + embeddedfiles/hledger-ui.md + embeddedfiles/hledger-ui.1 + embeddedfiles/hledger-ui.txt + embeddedfiles/hledger-ui.info source-repository head type: git @@ -59,6 +60,7 @@ library Hledger.UI.AccountsScreen Hledger.UI.BalancesheetScreen Hledger.UI.CashScreen + Hledger.UI.DocFiles Hledger.UI.Editor Hledger.UI.ErrorScreen Hledger.UI.IncomestatementScreen @@ -79,6 +81,7 @@ library , async , base >=4.14 && <4.21 , brick >=2.1.1 && <2.3.2 || >2.3.2 && <2.9 + , bytestring , cmdargs >=0.8 , containers >=0.5.9 , data-default diff --git a/hledger-ui/package.yaml b/hledger-ui/package.yaml index ead28cd45a7..1e631caac88 100644 --- a/hledger-ui/package.yaml +++ b/hledger-ui/package.yaml @@ -24,11 +24,12 @@ stability : stable tested-with: GHC==8.10.7, GHC==9.0.2, GHC==9.2.8, GHC==9.4.5, GHC==9.6.2 extra-source-files: - - CHANGES.md - - README.md - - hledger-ui.1 - - hledger-ui.txt - - hledger-ui.info +- CHANGES.md +- README.md +- embeddedfiles/hledger-ui.md +- embeddedfiles/hledger-ui.1 +- embeddedfiles/hledger-ui.txt +- embeddedfiles/hledger-ui.info #data-files: @@ -95,6 +96,7 @@ library: - hledger >=1.42.99 && <1.43 - ansi-terminal >=0.9 - async + - bytestring - cmdargs >=0.8 - containers >=0.5.9 - data-default diff --git a/hledger-web/Hledger/Web/DocFiles.hs b/hledger-web/Hledger/Web/DocFiles.hs new file mode 100644 index 00000000000..f3023a60097 --- /dev/null +++ b/hledger-web/Hledger/Web/DocFiles.hs @@ -0,0 +1,48 @@ +{-# LANGUAGE TemplateHaskell #-} +{-| + +Embedded documentation files in various formats, and helpers for viewing them. + +|-} + +module Hledger.Web.DocFiles ( + printHelpForTopic + ,runManForTopic + ,runInfoForTopic + ,runPagerForTopic + ,runTldrForPage + ) where + +import Data.ByteString (ByteString) + +import Hledger.Utils (embedFileRelative) +import Hledger.Utils.DocFiles + +-- | All hledger-web pages from the tldr-pages project. +tldrs :: [(TldrPage, ByteString)] +tldrs = [ + ("hledger-web", $(embedFileRelative "embeddedfiles/hledger-web.md")) + ] + +-- | The main hledger-web manuals as source for man, info and as plain text. +man :: ByteString +man = $(embedFileRelative "embeddedfiles/hledger-web.1") +txt :: ByteString +txt = $(embedFileRelative "embeddedfiles/hledger-web.txt") +info :: ByteString +info = $(embedFileRelative "embeddedfiles/hledger-web.info") + +printHelpForTopic :: Maybe Topic -> IO () +printHelpForTopic = printHelpForTopic' txt + +runManForTopic :: Maybe Topic -> IO () +runManForTopic = runManForTopic' "hledger-web" man + +runInfoForTopic :: Maybe Topic -> IO () +runInfoForTopic = runInfoForTopic' "hledger-web" info + +runPagerForTopic :: Maybe Topic -> IO () +runPagerForTopic = runPagerForTopic' "hledger-web" txt + +runTldrForPage :: TldrPage -> IO () +runTldrForPage = runTldrForPage' tldrs diff --git a/hledger-web/Hledger/Web/Main.hs b/hledger-web/Hledger/Web/Main.hs index ee1274433da..fe139590c2e 100644 --- a/hledger-web/Hledger/Web/Main.hs +++ b/hledger-web/Hledger/Web/Main.hs @@ -33,8 +33,10 @@ import Yesod.Default.Config import Yesod.Default.Main (defaultDevelApp) import Hledger -import Hledger.Cli hiding (progname,prognameandversion) +import Hledger.Cli (withJournalDo) +import Hledger.Cli.CliOptions hiding (progname,prognameandversion) import Hledger.Web.Application (makeApplication) +import Hledger.Web.DocFiles import Hledger.Web.Settings (Extra(..), parseExtra) import Hledger.Web.Test (hledgerWebTest) import Hledger.Web.WebOptions @@ -75,8 +77,8 @@ hledgerWebMain = withGhcDebug' $ do if | boolopt "help" rawopts_ -> runPager $ showModeUsage webmode ++ "\n" | boolopt "tldr" rawopts_ -> runTldrForPage "hledger-web" - | boolopt "info" rawopts_ -> runInfoForTopic "hledger-web" Nothing - | boolopt "man" rawopts_ -> runManForTopic "hledger-web" Nothing + | boolopt "info" rawopts_ -> runInfoForTopic Nothing + | boolopt "man" rawopts_ -> runManForTopic Nothing | boolopt "version" rawopts_ -> putStrLn prognameandversion -- boolopt "binary-filename" rawopts_ -> putStrLn (binaryfilename progname) | boolopt "test" rawopts_ -> do diff --git a/hledger-web/embeddedfiles/hledger-web.1 b/hledger-web/embeddedfiles/hledger-web.1 new file mode 120000 index 00000000000..42793a18b1b --- /dev/null +++ b/hledger-web/embeddedfiles/hledger-web.1 @@ -0,0 +1 @@ +../hledger-web.1 \ No newline at end of file diff --git a/hledger-web/embeddedfiles/hledger-web.info b/hledger-web/embeddedfiles/hledger-web.info new file mode 120000 index 00000000000..64b870e7896 --- /dev/null +++ b/hledger-web/embeddedfiles/hledger-web.info @@ -0,0 +1 @@ +../hledger-web.info \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-web.md b/hledger-web/embeddedfiles/hledger-web.md similarity index 100% rename from hledger/embeddedfiles/hledger-web.md rename to hledger-web/embeddedfiles/hledger-web.md diff --git a/hledger-web/embeddedfiles/hledger-web.txt b/hledger-web/embeddedfiles/hledger-web.txt new file mode 120000 index 00000000000..825aabee2e4 --- /dev/null +++ b/hledger-web/embeddedfiles/hledger-web.txt @@ -0,0 +1 @@ +../hledger-web.txt \ No newline at end of file diff --git a/hledger-web/hledger-web.cabal b/hledger-web/hledger-web.cabal index 62b42d86d3e..3435b50b40f 100644 --- a/hledger-web/hledger-web.cabal +++ b/hledger-web/hledger-web.cabal @@ -104,9 +104,10 @@ extra-source-files: templates/manage.hamlet templates/register.hamlet templates/upload-form.hamlet - hledger-web.1 - hledger-web.txt - hledger-web.info + embeddedfiles/hledger-web.md + embeddedfiles/hledger-web.1 + embeddedfiles/hledger-web.txt + embeddedfiles/hledger-web.info source-repository head type: git @@ -142,6 +143,7 @@ library Hledger.Web.Test other-modules: Hledger.Web.App + Hledger.Web.DocFiles Hledger.Web.Handler.AddR Hledger.Web.Handler.EditR Hledger.Web.Handler.JournalR diff --git a/hledger-web/package.yaml b/hledger-web/package.yaml index fd0788004f1..33db8433d09 100644 --- a/hledger-web/package.yaml +++ b/hledger-web/package.yaml @@ -42,9 +42,10 @@ extra-source-files: - static/hledger.js - static/js/*.js - templates/*.hamlet -- hledger-web.1 -- hledger-web.txt -- hledger-web.info +- embeddedfiles/hledger-web.md +- embeddedfiles/hledger-web.1 +- embeddedfiles/hledger-web.txt +- embeddedfiles/hledger-web.info flags: library-only: diff --git a/hledger/Hledger/Cli.hs b/hledger/Hledger/Cli.hs index 4adf6048bfc..5292c915d62 100644 --- a/hledger/Hledger/Cli.hs +++ b/hledger/Hledger/Cli.hs @@ -385,8 +385,8 @@ main = withGhcDebug' $ do -- 6.1. no command and a help/doc flag found - show general help/docs | nocmdprovided && helpFlag -> runPager $ showModeUsage (mainmode []) ++ "\n" | nocmdprovided && tldrFlag -> runTldrForPage "hledger" - | nocmdprovided && infoFlag -> runInfoForTopic "hledger" Nothing - | nocmdprovided && manFlag -> runManForTopic "hledger" Nothing + | nocmdprovided && infoFlag -> runInfoForTopic Nothing + | nocmdprovided && manFlag -> runManForTopic Nothing -- 6.2. --version flag found and none of these other conditions - show version | versionFlag && not (isaddoncmd || helpFlag || tldrFlag || infoFlag || manFlag) -> putStrLn prognameandversion @@ -409,8 +409,8 @@ main = withGhcDebug' $ do -- 6.5.1. help/doc flag - show command help/docs | helpFlag -> runPager $ showModeUsage cmdmode ++ "\n" | tldrFlag -> runTldrForPage $ maybe "hledger" (("hledger-"<>)) mmodecmdname - | infoFlag -> runInfoForTopic "hledger" mmodecmdname - | manFlag -> runManForTopic "hledger" mmodecmdname + | infoFlag -> runInfoForTopic mmodecmdname + | manFlag -> runManForTopic mmodecmdname -- 6.5.2. builtin command which should not require or read the journal - run it | cmdname `elem` ["commands","demo","help","test"] -> diff --git a/hledger/Hledger/Cli/CliOptions.hs b/hledger/Hledger/Cli/CliOptions.hs index 1c850127f05..e699714c8ac 100644 --- a/hledger/Hledger/Cli/CliOptions.hs +++ b/hledger/Hledger/Cli/CliOptions.hs @@ -78,9 +78,6 @@ module Hledger.Cli.CliOptions ( -- | For register: registerWidthsFromOpts, - -- * Other utils - topicForMode, - -- -- * Convenience re-exports -- module Data.String.Here, -- module System.Console.CmdArgs.Explicit, @@ -114,7 +111,6 @@ import Text.Megaparsec import Text.Megaparsec.Char import Hledger -import Hledger.Cli.DocFiles import Hledger.Cli.Version import Data.Time.Clock.POSIX (POSIXTime) import Data.List (isPrefixOf, isSuffixOf) @@ -511,15 +507,6 @@ highlightHelp -- ,"General flags" -- ,"Examples" -- ] --- | Get the most appropriate documentation topic for a mode. --- Currently, that is either the hledger, hledger-ui or hledger-web --- manual. -topicForMode :: Mode a -> Topic -topicForMode m - | n == "hledger-ui" = "ui" - | n == "hledger-web" = "web" - | otherwise = "cli" - where n = headDef "" $ modeNames m -- | Add command aliases to the command's help string. withAliases :: String -> [String] -> String diff --git a/hledger/Hledger/Cli/Commands/Help.hs b/hledger/Hledger/Cli/Commands/Help.hs index d26ad1ff140..8b4b7fa6c88 100644 --- a/hledger/Hledger/Cli/Commands/Help.hs +++ b/hledger/Hledger/Cli/Commands/Help.hs @@ -67,4 +67,4 @@ help' opts _ = do | "less" `elem` exes = pager | otherwise = cat - viewer "hledger" mtopic + viewer mtopic diff --git a/hledger/Hledger/Cli/Commands/Run.hs b/hledger/Hledger/Cli/Commands/Run.hs index f36d342b79a..337840d1a72 100644 --- a/hledger/Hledger/Cli/Commands/Run.hs +++ b/hledger/Hledger/Cli/Commands/Run.hs @@ -153,8 +153,8 @@ runCommand defaultJournalOverride findBuiltinCommand addons cmdline = do if | helpFlag -> runPager $ showModeUsage cmdmode ++ "\n" | tldrFlag -> runTldrForPage $ maybe "hledger" (("hledger-"<>)) mmodecmdname - | infoFlag -> runInfoForTopic "hledger" mmodecmdname - | manFlag -> runManForTopic "hledger" mmodecmdname + | infoFlag -> runInfoForTopic mmodecmdname + | manFlag -> runManForTopic mmodecmdname | otherwise -> do withJournalCached (Just defaultJournalOverride) opts $ \(j,jpaths) -> do if cmdname == "run" -- allow "run" to call "run" diff --git a/hledger/Hledger/Cli/DocFiles.hs b/hledger/Hledger/Cli/DocFiles.hs index 3b98ef609f4..d86eda292bf 100644 --- a/hledger/Hledger/Cli/DocFiles.hs +++ b/hledger/Hledger/Cli/DocFiles.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE TemplateHaskell, OverloadedStrings, PackageImports, ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} {-| Embedded documentation files in various formats, and helpers for viewing them. @@ -6,41 +6,19 @@ Embedded documentation files in various formats, and helpers for viewing them. |-} module Hledger.Cli.DocFiles ( - - Topic - ,printHelpForTopic + printHelpForTopic ,runManForTopic ,runInfoForTopic ,runPagerForTopic ,runTldrForPage - ) where -import Control.Exception import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 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 --- The name of any hledger executable. -type Tool = String +import Hledger.Utils (embedFileRelative) +import Hledger.Utils.DocFiles --- Any heading in the hledger user manual (and perhaps later the hledger-ui/hledger-web manuals). -type Topic = String - --- Any name of a hledger tldr page (hledger, hledger-ui, hledger-print etc.) -type TldrPage = String - --- | All hledger-related pages from the tldr-pages project. +-- | All hledger (but not hledger-ui/web) pages from the tldr-pages project. -- All are symlinked into the hledger package directory to allow embeddeding. tldrs :: [(TldrPage, ByteString)] tldrs = [ @@ -52,118 +30,28 @@ tldrs = [ ,("hledger-import", $(embedFileRelative "embeddedfiles/hledger-import.md")) ,("hledger-incomestatement", $(embedFileRelative "embeddedfiles/hledger-incomestatement.md")) ,("hledger-print", $(embedFileRelative "embeddedfiles/hledger-print.md")) - ,("hledger-ui", $(embedFileRelative "embeddedfiles/hledger-ui.md")) - ,("hledger-web", $(embedFileRelative "embeddedfiles/hledger-web.md")) ,("hledger", $(embedFileRelative "embeddedfiles/hledger.md")) ] -- | The main hledger manuals as source for man, info and as plain text. --- All are symlinked into the hledger package directory to allow embeddeding. -manuals :: [(Tool, (ByteString, ByteString, ByteString))] -manuals = [ - ("hledger", - ($(embedFileRelative "embeddedfiles/hledger.1") - ,$(embedFileRelative "embeddedfiles/hledger.txt") - ,$(embedFileRelative "embeddedfiles/hledger.info") - )) - ,("hledger-ui", - ($(embedFileRelative "embeddedfiles/hledger-ui.1") - ,$(embedFileRelative "embeddedfiles/hledger-ui.txt") - ,$(embedFileRelative "embeddedfiles/hledger-ui.info") - )) - ,("hledger-web", - ($(embedFileRelative "embeddedfiles/hledger-web.1") - ,$(embedFileRelative "embeddedfiles/hledger-web.txt") - ,$(embedFileRelative "embeddedfiles/hledger-web.info") - )) - ] - --- | Get the manual as plain text for this tool, or a not found message. -manualTxt :: Tool -> ByteString -manualTxt name = maybe (fromString $ "No text manual found for tool: "++name) second3 $ lookup name manuals - --- | Get the manual as man source (nroff) for this tool, or a not found message. -manualMan :: Tool -> ByteString -manualMan name = maybe (fromString $ "No man page found for tool: "++name) first3 $ lookup name manuals - --- | Get the manual as info source (texinfo) for this tool, or a not found message. -manualInfo :: Tool -> ByteString -manualInfo name = maybe (fromString $ "No info manual found for tool: "++name) third3 $ lookup name manuals - --- | Print plain text help for this tool. --- Takes an optional topic argument for convenience but it is currently ignored. -printHelpForTopic :: Tool -> Maybe Topic -> IO () -printHelpForTopic tool _mtopic = BC.putStr (manualTxt tool) - --- | Display an info manual for this topic, opened at the given topic if provided, --- using the "info" executable in $PATH. --- Topic can be an exact heading or a heading prefix; info will favour an exact match. -runInfoForTopic :: Tool -> Maybe Topic -> IO () -runInfoForTopic tool mtopic = - withSystemTempFile ("hledger-"++tool++".info") $ \f h -> do - BC.hPutStrLn h $ manualInfo tool - hClose h - callCommand $ dbg1 "info command" $ - "info -f " ++ f ++ maybe "" (printf " -n '%s'") mtopic +man :: ByteString +man = $(embedFileRelative "embeddedfiles/hledger.1") +txt :: ByteString +txt = $(embedFileRelative "embeddedfiles/hledger.txt") +info :: ByteString +info = $(embedFileRelative "embeddedfiles/hledger.info") --- less with any vertical whitespace squashed, case-insensitive searching, the $ regex metacharacter accessible as \$. -less = "less -s -i --use-backslash" +printHelpForTopic :: Maybe Topic -> IO () +printHelpForTopic = printHelpForTopic' txt --- | Display plain text help for this tool, scrolled to the given topic if any, using the users $PAGER or "less". --- When a topic is provided we always use less, ignoring $PAGER. --- --- This is less robust than the newer Hledger.Utils.IO.runPager, --- but that one doesn't yet support scrolling to a topic. -runPagerForTopic :: Tool -> Maybe Topic -> IO () -runPagerForTopic tool mtopic = do - withSystemTempFile ("hledger-"++tool++".txt") $ \f h -> do - BC.hPutStrLn h $ manualTxt tool - hClose h - envpager <- fromMaybe less <$> lookupEnv "PAGER" - let - exactmatch = True - (pager, searcharg) = - case mtopic of - Nothing -> (envpager, "") - Just t -> (less, "-p'^( )?" ++ t ++ if exactmatch then "\\$'" else "") - callCommand $ dbg1 "pager command" $ unwords [pager, searcharg, f] +runManForTopic :: Maybe Topic -> IO () +runManForTopic = runManForTopic' "hledger" man --- | Display a man page for this tool, scrolled to the given topic if provided, using "man". --- When a topic is provided we force man to use "less", ignoring $MANPAGER and $PAGER. -runManForTopic :: Tool -> Maybe Topic -> IO () -runManForTopic tool mtopic = - -- This temp file path should have a slash in it, man requires at least one. - withSystemTempFile ("hledger-"++tool++".1") $ \f h -> do - BC.hPutStrLn h $ manualMan tool - hClose h - let - exactmatch = True - pagerarg = - case mtopic of - Nothing -> "" - Just t -> "-P \"" ++ less ++ " -p'^( )?" ++ t ++ (if exactmatch then "\\\\$" else "") ++ "'\"" - callCommand $ dbg1 "man command" $ unwords ["man", pagerarg, f] +runInfoForTopic :: Maybe Topic -> IO () +runInfoForTopic = runInfoForTopic' "hledger" info --- | Get the named tldr page's source, if we know it. -tldr :: TldrPage -> Maybe ByteString -tldr name = lookup name tldrs +runPagerForTopic :: Maybe Topic -> IO () +runPagerForTopic = runPagerForTopic' "hledger" txt --- | Display one of the hledger tldr pages, using "tldr". runTldrForPage :: TldrPage -> IO () -runTldrForPage name = - case tldr name of - Nothing -> error' $ "sorry, there's no " <> name <> " tldr page yet" - Just b -> (do - withSystemTempFile (name++".md") $ \f h -> do - BC.hPutStrLn h b - hClose h - -- tldr clients tend to auto-update their data, try to discourage that here - -- tealdeer - doesn't auto-update by default - -- tlrc - ? - -- tldr-node-client - undocumented env var suggested in output - setEnv "TLDR_AUTO_UPDATE_DISABLED" "1" - callCommand $ dbg1 "tldr command" $ "tldr --render " <> f - ) `catch` (\(_e::IOException) -> do - hPutStrLn stderr $ "Warning: could not run tldr --render, using fallback viewer instead.\n" - BC.putStrLn b - ) +runTldrForPage = runTldrForPage' tldrs diff --git a/hledger/embeddedfiles/README b/hledger/embeddedfiles/README index a86876a3d30..4262b5bd8ae 100644 --- a/hledger/embeddedfiles/README +++ b/hledger/embeddedfiles/README @@ -2,7 +2,6 @@ These files are embedded into the hledger executable at compile time. They include: - symbolic links to all the main hledger manuals in several formats, for embedding in Hledger/Cli/DocFiles.hs. - (Having the hledger-ui/hledger-web files also symlinked here within the hledger package allows embedding them without using absolute paths.) - symbolic links to all the hledger tldr pages. diff --git a/hledger/embeddedfiles/hledger-ui.1 b/hledger/embeddedfiles/hledger-ui.1 deleted file mode 120000 index 172714a7277..00000000000 --- a/hledger/embeddedfiles/hledger-ui.1 +++ /dev/null @@ -1 +0,0 @@ -../../hledger-ui/hledger-ui.1 \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-ui.info b/hledger/embeddedfiles/hledger-ui.info deleted file mode 120000 index 7ce58155b1d..00000000000 --- a/hledger/embeddedfiles/hledger-ui.info +++ /dev/null @@ -1 +0,0 @@ -../../hledger-ui/hledger-ui.info \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-ui.txt b/hledger/embeddedfiles/hledger-ui.txt deleted file mode 120000 index 97e5b31d927..00000000000 --- a/hledger/embeddedfiles/hledger-ui.txt +++ /dev/null @@ -1 +0,0 @@ -../../hledger-ui/hledger-ui.txt \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-web.1 b/hledger/embeddedfiles/hledger-web.1 deleted file mode 120000 index 56fa56b5b9e..00000000000 --- a/hledger/embeddedfiles/hledger-web.1 +++ /dev/null @@ -1 +0,0 @@ -../../hledger-web/hledger-web.1 \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-web.info b/hledger/embeddedfiles/hledger-web.info deleted file mode 120000 index adc31deb002..00000000000 --- a/hledger/embeddedfiles/hledger-web.info +++ /dev/null @@ -1 +0,0 @@ -../../hledger-web/hledger-web.info \ No newline at end of file diff --git a/hledger/embeddedfiles/hledger-web.txt b/hledger/embeddedfiles/hledger-web.txt deleted file mode 120000 index 3e423b3ba48..00000000000 --- a/hledger/embeddedfiles/hledger-web.txt +++ /dev/null @@ -1 +0,0 @@ -../../hledger-web/hledger-web.txt \ No newline at end of file diff --git a/hledger/hledger.cabal b/hledger/hledger.cabal index 93e0341847c..b25ed804bb9 100644 --- a/hledger/hledger.cabal +++ b/hledger/hledger.cabal @@ -46,18 +46,10 @@ extra-source-files: embeddedfiles/hledger-import.md embeddedfiles/hledger-incomestatement.md embeddedfiles/hledger-print.md - embeddedfiles/hledger-ui.md - embeddedfiles/hledger-web.md embeddedfiles/hledger.md embeddedfiles/hledger.1 embeddedfiles/hledger.txt embeddedfiles/hledger.info - embeddedfiles/hledger-ui.1 - embeddedfiles/hledger-ui.txt - embeddedfiles/hledger-ui.info - embeddedfiles/hledger-web.1 - embeddedfiles/hledger-web.txt - embeddedfiles/hledger-web.info Hledger/Cli/Commands/Accounts.txt Hledger/Cli/Commands/Activity.txt Hledger/Cli/Commands/Add.txt diff --git a/hledger/package.yaml b/hledger/package.yaml index 2e83d0274b3..d48e401034d 100644 --- a/hledger/package.yaml +++ b/hledger/package.yaml @@ -43,19 +43,11 @@ extra-source-files: - embeddedfiles/hledger-import.md - embeddedfiles/hledger-incomestatement.md - embeddedfiles/hledger-print.md -- embeddedfiles/hledger-ui.md -- embeddedfiles/hledger-web.md - embeddedfiles/hledger.md - embeddedfiles/hledger.1 - embeddedfiles/hledger.txt - embeddedfiles/hledger.info -- embeddedfiles/hledger-ui.1 -- embeddedfiles/hledger-ui.txt -- embeddedfiles/hledger-ui.info -- embeddedfiles/hledger-web.1 -- embeddedfiles/hledger-web.txt -- embeddedfiles/hledger-web.info - Hledger/Cli/Commands/Accounts.txt - Hledger/Cli/Commands/Activity.txt