fix: help, --man: fix jumping to TOPIC when viewing a man page

And clarify exact/prefix matching behaviour.
This commit is contained in:
Simon Michael 2024-05-29 09:21:20 -10:00
parent 085910708b
commit d4dcbbd4c8
2 changed files with 55 additions and 56 deletions

View File

@ -1,30 +1,30 @@
## help
Show the hledger user manual in the terminal, with `info`, `man`, or a pager.
With a TOPIC argument, open it at that topic if possible.
TOPIC can be any heading in the manual, or a heading prefix, case insensitive.
Eg: `commands`, `print`, `forecast`, `journal`, `amount`, `"auto postings"`.
Show the hledger user manual with `info`, `man`, or a pager.
With a (case insensitive) TOPIC argument, try to open it at that section heading.
_FLAGS
This command shows the hledger manual built in to your hledger version.
This command shows the hledger manual built in to your hledger executable.
It can be useful when offline, or when you prefer the terminal to a web browser,
or when the appropriate hledger manual or viewing tools are not installed on your system.
or when the appropriate hledger manual or viewers are not installed properly on your system.
By default it chooses the best viewer found in $PATH, trying (in this order):
`info`, `man`, `$PAGER`, `less`, `more`.
You can force the use of info, man, or a pager with the `-i`, `-m`, or `-p` flags,
If no viewer can be found, or the command is run non-interactively, it just prints
the manual to stdout.
By default it chooses the best viewer found in $PATH, trying in this order:
`info`, `man`, `$PAGER`, `less`, `more`, stdout.
(If a TOPIC is specified, `$PAGER` and `more` are not tried.)
You can force the use of info, man, or a pager with the `-i`, `-m`, or `-p` flags.
If no viewer can be found, or if running non-interactively, it just prints the manual to stdout.
If using `info`, note that version 6 or greater is needed for TOPIC lookup. If you are
on mac you will likely have info 4.8, and should consider installing a newer version,
eg with `brew install texinfo` (#1770).
When using `info`, TOPIC can match either the full heading or a prefix.
If your `info --version` is < 6, you'll need to upgrade it, eg with '`brew install texinfo`' on mac.
When using `man` or `less`, TOPIC must match the full heading.
For a prefix match, you can write '`TOPIC.*`'.
Examples
```cli
$ hledger help --help # show how the help command works
$ hledger help # show the hledger manual with info, man or $PAGER
$ hledger help journal # show the journal topic in the hledger manual
$ hledger help -m journal # show it with man, even if info is installed
$ hledger help -h # show the help command's usage
$ hledger help # show the manual with info, man or $PAGER
$ hledger help 'time periods' # show the manual's "Time periods" topic
$ hledger help 'time periods' -m # use man, even if info is installed
```

View File

@ -22,7 +22,7 @@ module Hledger.Cli.DocFiles (
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BC
import Data.Maybe (fromMaybe, isNothing)
import Data.Maybe (fromMaybe)
import Data.String
import System.IO
import System.IO.Temp
@ -85,45 +85,9 @@ printHelpForTopic :: Tool -> Maybe Topic -> IO ()
printHelpForTopic tool _mtopic =
BC.putStr (toolDocTxt tool)
-- | Display plain text help for this tool, scrolled to the given topic
-- if provided, using the given pager executable.
-- Note when a topic is provided we ignore the provided pager and
-- use the "less" executable in $PATH.
runPagerForTopic :: Tool -> Maybe Topic -> IO ()
runPagerForTopic tool mtopic = do
-- avoids a temp file but different from the others and not sure how to make it scroll
-- pager <- fromMaybe "less" <$> lookupEnv "PAGER"
-- (Just inp, _, _, ph) <- createProcess (proc pager []){
-- std_in=CreatePipe
-- }
-- BC.hPutStrLn inp (toolDocTxt tool)
-- _ <- waitForProcess ph
-- return ()
withSystemTempFile ("hledger-"++tool++".txt") $ \f h -> do
BC.hPutStrLn h $ toolDocTxt tool
hClose h
let defpager = "less -is"
envpager <- fromMaybe defpager <$> lookupEnv "PAGER"
-- force the use of less if a topic is provided, since we know how to scroll it
let pager = if isNothing mtopic then envpager else defpager
callCommand $ dbg1 "pager command" $
pager ++ maybe "" (printf " +'/^( )?%s'") mtopic ++ " " ++ f
-- | Display a man page for this tool, scrolled to the given topic if provided,
-- using the "man" executable in $PATH. Note when a topic is provided we force
-- man to use the "less" executable in $PATH, ignoring $MANPAGER and $PAGER.
runManForTopic :: Tool -> Maybe Topic -> IO ()
runManForTopic tool mtopic =
withSystemTempFile ("hledger-"++tool++".nroff") $ \f h -> do
BC.hPutStrLn h $ toolDocMan tool
hClose h
-- the temp file path will presumably have a slash in it, so man should read it
callCommand $ dbg1 "man command" $
"man " ++ f ++ maybe "" (printf " -P \"less -is +'/^( )?%s'\"") mtopic
-- | 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
@ -131,3 +95,38 @@ runInfoForTopic tool mtopic =
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.
runPagerForTopic :: Tool -> Maybe Topic -> IO ()
runPagerForTopic tool mtopic = do
withSystemTempFile ("hledger-"++tool++".txt") $ \f h -> do
BC.hPutStrLn h $ toolDocTxt 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]
-- | 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 $ toolDocMan 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]