SamuelSchlesinger / commander-cli

A simple library I wrote to allow me to quickly and easily construct command line interfaces.
MIT License
29 stars 2 forks source link

Generics for Records #49

Open BebeSparkelSparkel opened 1 year ago

BebeSparkelSparkel commented 1 year ago

I find to be filling in a lot of record fields from the cli parameters and it would be much faster to have some generic way of generating parser code.

data AB f = AB {a :: f Int, b :: f String}

type ProgramType :: Type -> Type
type family ProgramType a

genericOptions :: forall (mkOption :: Symbol -> Symbol) (mkName :: Symbol -> Symbol) p b m a. Generic a => (a -> ParserT p m b) -> ParserT (ProgramType (Rep a) & p) m b)

Which genericOptions @("--" ++) @ID @(AB Maybe) would generate something like

\f ->
  opt @"--a" @"a" $ \a ->
  opt @"--b" @"b" $ \b ->
  f AB {..}

There seems like there could be several versions for Opt Arg Flag. Does this make sense or is there a better way?

SamuelSchlesinger commented 1 year ago

I think this makes sense, seems like a reasonable approach.

BebeSparkelSparkel commented 1 year ago

I have created a simplistic working example https://github.com/BebeSparkelSparkel/commander-cli/blob/generics/src/Options/Commander/Generics.hs

What do you think?

BebeSparkelSparkel commented 1 year ago

One problem I am having is how to allow for descriptions.

Perhaps there could be a type like newtype Description (d :: Symbol) a = Description a, but that seems invasive.

Or a type family Description (datatype :: Symbol) (module :: Symbol) (package :: Symbol) (fieldName :: Symbol) :: Symbol that would resolve to the description.

SamuelSchlesinger commented 1 year ago

I honestly wouldn't mind the newtype at all, I think that's quite helpful. Looks like it's on the right track, but I'm concerned about all of them being arguments rather than options and so on. Another thing to keep in mind is that this functionality is already very easily implemented by optparse-generic and I'm not so sure I want to encourage people to use this package for this functionality when its (arguably) better implemented in that package.

I'd be happy to help plug away at a patch which implemented this functionality well, but I'd be more likely to push it up to hackage if we:

Looks pretty doable from your code though, appreciate the example.

BebeSparkelSparkel commented 1 year ago

Thanks for the optparse-generic link. I'll look at that carefully. It might be the better option.