ndmitchell / cmdargs

Haskell library for command line argument processing
Other
91 stars 12 forks source link

A problem with common flags and multiple typFile resulting in "ITEM" #52

Closed oshyshko closed 6 years ago

oshyshko commented 6 years ago

I am trying to get a help page that looks like:

$ ./cmdargs.hs --help
The tape program

tape [COMMAND] ... [OPTIONS]
  Records and replays stdout/stder produced by a command

Common flags:
  -? --help       Display help message
  -V --version    Print version information
  -f --file=FILE  Use file instead of stdin/stdout

tape record [OPTIONS] COMMAND [ARGS]

tape replay [OPTIONS]
  -d --delays     Reproduce delays in stdout/stderr (off by default)

tape inspect [OPTIONS]

I made it to this point:

#!/usr/bin/env stack
-- stack --resolver lts-9.20 script --package cmdargs

{-# LANGUAGE DeriveDataTypeable #-}

module Main where

import           System.Console.CmdArgs as Args
import           System.IO

data Tape = Record  {file :: Maybe String, command :: String, commandArgs :: [String]}
          | Replay  {file :: Maybe String, delays :: Bool}
          | Inspect {file :: Maybe String}
            deriving (Data, Typeable, Show, Eq)
main :: IO ()
main = do
  let fileSpec = def &= typFile &= help "Use file instead of stdin/stdout"
  _ <- cmdArgs $ modes
         [ Record  { file        = fileSpec
                   , command     = def &= typ "COMMAND" &= argPos 0
                   , commandArgs = def &= typ "ARGS"    &= args     }
         , Replay  { file        = fileSpec
                   , delays      = def &= help "Reproduce delays in stdout/stderr (off by default)"}
         , Inspect { file        = fileSpec }
         ]
         &= help    "Records and replays stdout/stder produced by a command"
  return ()

...that results in:

$ ./cmdargs.hs --help
The tape program

tape [COMMAND] ... [OPTIONS]
  Records and replays stdout/stder produced by a command

Common flags:
  -? --help       Display help message
  -V --version    Print version information

tape record [OPTIONS] COMMAND [ARGS]

  -f --file=FILE  Use file instead of stdin/stdout

tape replay [OPTIONS]

  -f --file=ITEM
  -d --delays     Reproduce delays in stdout/stderr (off by default)

tape inspect [OPTIONS]

  -f --file=ITEM

I am trying to find a workaround to these problems:

What would be your recommendations in fixing these two things?

P.S. Thank you for your beautifully designed library.

ndmitchell commented 6 years ago

Have you tried adding {-# OPTIONS_GHC -fno-cse #-} to the top of the module? Does that fix it?

oshyshko commented 6 years ago

I've just tried it. It doesn't seem to make any change to --help output.

I tried adding {-# OPTIONS_GHC -fno-cse #-} at 3 places:

Just in case, my environment is:

$ stack list-dependencies | grep cmdargs
cmdargs 0.10.18
$ stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2
ndmitchell commented 6 years ago

OK, I see the problem. You have basically done CSE by hand :). The second problem is a consequence of the first - if they were all the same they'd become a common flag. To make them common again you can define:

  let fileSpec x = x &= typFile &= help "Use file instead of stdin/stdout"
  _ <- cmdArgs $ modes
         [ Record  { file        = fileSpec def
                   , command     = def &= typ "COMMAND" &= argPos 0
                   , commandArgs = def &= typ "ARGS"    &= args     }
         , Replay  { file        = fileSpec def
                   , delays      = def &= help "Reproduce delays in stdout/stderr (off by default)"}
         , Inspect { file        = fileSpec def}
         ]
         &= help    "Records and replays stdout/stder produced by a command"
  return ()

By making the annotations under a lambda they apply correctly in all the places. Not ideal, but it should work robustly.

oshyshko commented 6 years ago

Nice. The lambda + {-# OPTIONS_GHC -fno-cse #-} did the trick.

Thank you.