help: add --info/--man/--pager/--cat flags, & choose best one by default (#579)
You can select a docs format/viewer with one of the `--info`, `--man`, `--pager`, `--cat` flags. Otherwise, it will use info if available, otherwise man if available, otherwise $PAGER if defined, otherwise less if available, otherwise it prints on stdout (and always prints on stdout when piped). Preferring info over man might not suit everyone.
This commit is contained in:
		
							parent
							
								
									daa9550929
								
							
						
					
					
						commit
						9eb1520b6f
					
				| @ -25,6 +25,8 @@ module Hledger.Cli.CliOptions ( | |||||||
|   argsFlag, |   argsFlag, | ||||||
|   showModeUsage, |   showModeUsage, | ||||||
|   withAliases, |   withAliases, | ||||||
|  |   likelyExecutablesInPath, | ||||||
|  |   hledgerExecutablesInPath, | ||||||
| 
 | 
 | ||||||
|   -- * CLI options |   -- * CLI options | ||||||
|   CliOpts(..), |   CliOpts(..), | ||||||
| @ -633,23 +635,27 @@ dropRedundantSourceVersion fs = fs | |||||||
| compiledExts = ["",".com",".exe"]  | compiledExts = ["",".com",".exe"]  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| -- | Get the sorted unique filenames of all hledger-* executables in | -- | Get all sorted unique filenames in the current user's PATH.  | ||||||
| -- the current user's PATH. Currently these are: files in any of the | -- We do not currently filter out non-file objects or files without execute permission. | ||||||
| -- PATH directories, named hledger-*, with either no extension (and no | likelyExecutablesInPath :: IO [String] | ||||||
| -- periods in the name) or one of the addonExtensions.  Limitations: | likelyExecutablesInPath = do | ||||||
| -- we do not currently check that the file is really a file (not eg a |  | ||||||
| -- directory) or whether it has execute permission. |  | ||||||
| hledgerExecutablesInPath :: IO [String] |  | ||||||
| hledgerExecutablesInPath = do |  | ||||||
|   pathdirs <- splitOneOf "[:;]" `fmap` getEnvSafe "PATH" |   pathdirs <- splitOneOf "[:;]" `fmap` getEnvSafe "PATH" | ||||||
|   pathfiles <- concat `fmap` mapM getDirectoryContentsSafe pathdirs |   pathfiles <- concat `fmap` mapM getDirectoryContentsSafe pathdirs | ||||||
|   return $ nub $ sort $ filter isHledgerExeName pathfiles |   return $ nub $ sort pathfiles | ||||||
|   -- XXX should exclude directories and files without execute permission. |   -- exclude directories and files without execute permission. | ||||||
|   -- These will do a stat for each hledger-*, probably ok. |   -- These will do a stat for each hledger-*, probably ok. | ||||||
|   -- But they need paths, not just filenames |   -- But they need paths, not just filenames | ||||||
|   -- hledgerexes  <- filterM doesFileExist hledgernamed |   -- exes'  <- filterM doesFileExist exe' | ||||||
|   -- hledgerexes' <- filterM isExecutable hledgerexes |   -- exes'' <- filterM isExecutable exes' | ||||||
|   -- return hledgerexes |   -- return exes'' | ||||||
|  | 
 | ||||||
|  | -- | Get the sorted unique filenames of all hledger-* executables in | ||||||
|  | -- the current user's PATH. These are files in any of the PATH directories, | ||||||
|  | -- named hledger-*, with either no extension (and no periods in the name)  | ||||||
|  | -- or one of the addonExtensions.  | ||||||
|  | -- We do not currently filter out non-file objects or files without execute permission. | ||||||
|  | hledgerExecutablesInPath :: IO [String] | ||||||
|  | hledgerExecutablesInPath = filter isHledgerExeName <$> likelyExecutablesInPath | ||||||
| 
 | 
 | ||||||
| -- isExecutable f = getPermissions f >>= (return . executable) | -- isExecutable f = getPermissions f >>= (return . executable) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ module Hledger.Cli.DocFiles ( | |||||||
|   ,printHelpForTopic |   ,printHelpForTopic | ||||||
|   ,runManForTopic |   ,runManForTopic | ||||||
|   ,runInfoForTopic |   ,runInfoForTopic | ||||||
|  |   ,runPagerForTopic | ||||||
| 
 | 
 | ||||||
|   ) where |   ) where | ||||||
| 
 | 
 | ||||||
| @ -94,6 +95,15 @@ printHelpForTopic :: Topic -> IO () | |||||||
| printHelpForTopic t = | printHelpForTopic t = | ||||||
|   putStrLn $ lookupDocTxt t |   putStrLn $ lookupDocTxt t | ||||||
| 
 | 
 | ||||||
|  | runPagerForTopic :: FilePath -> Topic -> IO () | ||||||
|  | runPagerForTopic exe t = do | ||||||
|  |   (Just inp, _, _, ph) <- createProcess (proc exe []){ | ||||||
|  |     std_in=CreatePipe | ||||||
|  |     } | ||||||
|  |   hPutStrLn inp (lookupDocTxt t) | ||||||
|  |   _ <- waitForProcess ph | ||||||
|  |   return () | ||||||
|  | 
 | ||||||
| runManForTopic :: Topic -> IO () | runManForTopic :: Topic -> IO () | ||||||
| runManForTopic t = | runManForTopic t = | ||||||
|   withSystemTempFile ("hledger-"++t++".nroff") $ \f h -> do |   withSystemTempFile ("hledger-"++t++".nroff") $ \f h -> do | ||||||
|  | |||||||
| @ -3,6 +3,8 @@ | |||||||
| The help command. | The help command. | ||||||
| 
 | 
 | ||||||
| |-} | |-} | ||||||
|  | --TODO rename manuals | ||||||
|  | --TODO substring matching | ||||||
| 
 | 
 | ||||||
| module Hledger.Cli.Help ( | module Hledger.Cli.Help ( | ||||||
| 
 | 
 | ||||||
| @ -14,29 +16,57 @@ module Hledger.Cli.Help ( | |||||||
| import Prelude () | import Prelude () | ||||||
| import Prelude.Compat | import Prelude.Compat | ||||||
| import Data.List | import Data.List | ||||||
|  | import Data.Maybe | ||||||
| import System.Console.CmdArgs.Explicit | import System.Console.CmdArgs.Explicit | ||||||
|  | import System.Environment | ||||||
|  | import System.IO | ||||||
| 
 | 
 | ||||||
| import Hledger.Data.RawOptions | import Hledger.Data.RawOptions | ||||||
| import Hledger.Cli.CliOptions | import Hledger.Cli.CliOptions | ||||||
| import Hledger.Cli.DocFiles | import Hledger.Cli.DocFiles | ||||||
|  | --import Hledger.Utils.Debug | ||||||
| 
 | 
 | ||||||
| helpmode = (defCommandMode $ ["help"] ++ aliases) { | helpmode = (defCommandMode $ ["help"] ++ aliases) { | ||||||
|   modeHelp = "show any of the hledger manuals" `withAliases` aliases |   modeHelp = "show any of the hledger manuals, as plain text. With no argument, list the manuals." `withAliases` aliases | ||||||
|  ,modeGroupFlags = Group { |  ,modeGroupFlags = Group { | ||||||
|      groupUnnamed = [] |      groupUnnamed = [ | ||||||
|  |       flagNone ["info"]  (setboolopt "info")  "show the manual with info" | ||||||
|  |      ,flagNone ["man"]   (setboolopt "man")   "show the manual with man" | ||||||
|  |      ,flagNone ["pager"] (setboolopt "pager") "show the manual with $PAGER or less" | ||||||
|  |      ,flagNone ["cat"]   (setboolopt "cat")   "show the manual on stdout" | ||||||
|  |      ,flagNone ["help","h"]  (setboolopt "help")  "show this help" | ||||||
|  |      ] | ||||||
|     ,groupHidden = [] |     ,groupHidden = [] | ||||||
|     ,groupNamed = [] |     ,groupNamed = [] | ||||||
|     } |     } | ||||||
|  } |  ,modeArgs = ([], Just $ argsFlag "[MANUAL]") | ||||||
|  | } | ||||||
|   where aliases = [] |   where aliases = [] | ||||||
| 
 | 
 | ||||||
| -- | Print detailed help on various topics. | -- | List or display one of the hledger manuals in various formats.  | ||||||
|  | -- You can select a docs viewer with one of the `--info`, `--man`, `--pager`, `--cat` flags. | ||||||
|  | -- Otherwise it will use the first available of: info, man, $PAGER, less, stdout | ||||||
|  | -- (and always stdout if output is non-interactive).  | ||||||
| help' :: CliOpts -> IO () | help' :: CliOpts -> IO () | ||||||
| help' opts = do | help' opts = do | ||||||
|   let args = listofstringopt "args" $ rawopts_ opts |   exes <- likelyExecutablesInPath | ||||||
|  |   pagerprog <- fromMaybe "less" <$> lookupEnv "PAGER" | ||||||
|  |   interactive <- hIsTerminalDevice stdout | ||||||
|  |   let | ||||||
|  |     args = take 1 $ listofstringopt "args" $ rawopts_ opts | ||||||
|  |     [info, man, pager, cat] =  | ||||||
|  |       [runInfoForTopic, runManForTopic, runPagerForTopic pagerprog, printHelpForTopic] | ||||||
|  |     viewer | ||||||
|  |       | boolopt "info"  $ rawopts_ opts = info | ||||||
|  |       | boolopt "man"   $ rawopts_ opts = man | ||||||
|  |       | boolopt "pager" $ rawopts_ opts = pager | ||||||
|  |       | boolopt "cat"   $ rawopts_ opts = cat | ||||||
|  |       | not interactive                 = cat  | ||||||
|  |       | "info"    `elem` exes           = info | ||||||
|  |       | "man"     `elem` exes           = man | ||||||
|  |       | pagerprog `elem` exes           = pager | ||||||
|  |       | otherwise                       = cat  | ||||||
|   case args of |   case args of | ||||||
|     []    -> putStrLn $ |     [t] -> viewer t | ||||||
|              "Choose a topic, eg: hledger help cli\n" ++ |     _   -> putStrLn $ "Please choose a manual:\nhledger help " ++ intercalate "|" docTopics | ||||||
|              intercalate ", " docTopics |  | ||||||
|     topic:_ -> printHelpForTopic topic |  | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -128,10 +128,7 @@ PROGNAME CMD [--] [OPTS] [ARGS]  run a command (use -- with addon commands) | |||||||
| PROGNAME-CMD [OPTS] [ARGS]       or run addon commands directly | PROGNAME-CMD [OPTS] [ARGS]       or run addon commands directly | ||||||
| PROGNAME -h                      show general usage | PROGNAME -h                      show general usage | ||||||
| PROGNAME CMD -h                  show command usage | PROGNAME CMD -h                  show command usage | ||||||
| PROGNAME help                    list available manuals | PROGNAME help [MANUAL]           show any of the hledger manuals in various formats | ||||||
| PROGNAME help MANUAL             show a manual as plain text |  | ||||||
| PROGNAME man  MANUAL             show a manual as man page |  | ||||||
| PROGNAME info MANUAL             show a manual as info manual |  | ||||||
| |] | |] | ||||||
|  } |  } | ||||||
| 
 | 
 | ||||||
| @ -263,7 +260,7 @@ OTHERCMDS | |||||||
| Help: | Help: | ||||||
|  hledger -h           show general usage |  hledger -h           show general usage | ||||||
|  hledger CMD -h       show command usage |  hledger CMD -h       show command usage | ||||||
|  help|man|info        show any of the hledger manuals in plain text/man/info format |  help                 show any of the hledger manuals in various formats | ||||||
| |] | |] | ||||||
| 
 | 
 | ||||||
| knownCommands :: [String] | knownCommands :: [String] | ||||||
|  | |||||||
| @ -304,18 +304,18 @@ you can alter the report mode with `--change`/`--cumulative`/`--historical`. | |||||||
| ## help | ## help | ||||||
| Show any of the hledger manuals. | Show any of the hledger manuals. | ||||||
| 
 | 
 | ||||||
| The `help` command displays any of the main [hledger man pages](/docs.html). | The `help` command displays any of the main [hledger manuals](/docs.html), in one of several ways. | ||||||
| (Unlike `hledger --help`, which displays only the hledger man page.) | Run it with no argument to list the manuals (their names are shortened for easier typing), | ||||||
| Run it with no arguments to list available topics (their names are shortened for easier typing), | and run `hledger help MANUAL` to select one. | ||||||
| and run `hledger help TOPIC` to select one. | 
 | ||||||
| The output is similar to a man page, but fixed width. | hledger help will choose one of these docs viewers, in order of preference:  | ||||||
| It may be long, so you may wish to pipe it into a pager. | info, man, $PAGER, less, stdout (and it always prints on stdout when piped).  | ||||||
| See also [info](#info) and [man](#man). | Or you can force a particular viewer with the `--info`, `--man`, `--pager`, `--cat` flags. | ||||||
| 
 | 
 | ||||||
| _shell_({{ | _shell_({{ | ||||||
| $ hledger help | $ hledger help | ||||||
| Choose a topic, eg: hledger help cli | Please choose a manual: | ||||||
| cli, ui, web, api, journal, csv, timeclock, timedot | hledger help cli|ui|web|api|journal|csv|timeclock|timedot | ||||||
| }}) | }}) | ||||||
| 
 | 
 | ||||||
| _shell_({{ | _shell_({{ | ||||||
| @ -329,9 +329,7 @@ NAME | |||||||
|        hledger - a command-line accounting tool |        hledger - a command-line accounting tool | ||||||
| 
 | 
 | ||||||
| SYNOPSIS | SYNOPSIS | ||||||
|        hledger [-f FILE] COMMAND [OPTIONS] [CMDARGS] |        hledger [-f FILE] COMMAND [OPTIONS] [ARGS] | ||||||
|        hledger [-f FILE] ADDONCMD -- [OPTIONS] [CMDARGS] |  | ||||||
| : |  | ||||||
| }}) | }}) | ||||||
| 
 | 
 | ||||||
| ## incomestatement | ## incomestatement | ||||||
| @ -404,6 +402,7 @@ Normally incomestatement shows revenues/expenses per period, though | |||||||
| as with [multicolumn balance reports](#multicolumn-balance-reports) | as with [multicolumn balance reports](#multicolumn-balance-reports) | ||||||
| you can alter the report mode with `--change`/`--cumulative`/`--historical`. | you can alter the report mode with `--change`/`--cumulative`/`--historical`. | ||||||
| 
 | 
 | ||||||
|  | ... | ||||||
| ## info | ## info | ||||||
| Show any of the hledger manuals using info. | Show any of the hledger manuals using info. | ||||||
| 
 | 
 | ||||||
| @ -423,6 +422,7 @@ This will fit the text to your terminal width, and probably invoke a pager autom | |||||||
| It requires the "man" program to be available in your PATH. | It requires the "man" program to be available in your PATH. | ||||||
| 
 | 
 | ||||||
| As with [help](#help), run it with no arguments to list available topics (manuals). | As with [help](#help), run it with no arguments to list available topics (manuals). | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ## print | ## print | ||||||
| Show transactions from the journal. | Show transactions from the journal. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user