Giter Club home page Giter Club logo

Comments (10)

HuwCampbell avatar HuwCampbell commented on July 19, 2024

The argument ws is the "words" which have been passed in on the command line, as split by the shell. If I recall, we don't actually need i, the index of the word which the user pressed tab on, because the completion scripts cut the completion up to the caret position anyway.

In filter_names, ns is the names of the sub-commands which the subparser has. The function filter_names makes sure that the user could want the completion for a particular command by seeing if the current text at the position of the token is a prefix of the sub command name.

from optparse-applicative.

teto avatar teto commented on July 19, 2024

thanks ! I thought about "words" after postiung this but still was not sure.
I am now adapting the bashCompletionQuery for haskeline and there is the drop on this line that confuses me:

compl = runParserInfo pinfo (drop 1 ws')
, do we drop the first argument because we assume it's the name of the program ?

Also with the following parser (i.e., a subparser):

mainParser :: Parser CommandArgs
mainParser = subparser (
    commandGroup "Generic"
    <> command "help" helpParser
    <> command "quit" quit
    <> commandGroup "Loader commands"
    <> command "load-csv" CL.piLoadCsv
    )
    where
      helpParser = info (pure ArgsHelp) (progDesc "Display help")

do you know if bashCompletionQuery would generate completion for all commands ? in my tests, it seems to autocomplete only the first argument but not the subsequent ones because runParserInfo returns Nothing (while I would expect it to retreive at least one more Parser).

from optparse-applicative.

HuwCampbell avatar HuwCampbell commented on July 19, 2024

I'm not sure I follow sorry, but yes, the completion system sensibly completes within subparsers as well.

from optparse-applicative.

teto avatar teto commented on July 19, 2024

It doesn't seem to do it for me, let's say I have this Parser

mainParser :: Parser CommandArgs
mainParser = subparser (
    commandGroup "Generic"
    <> command "quit" quit
    <> command "load-csv" CL.piLoadCsv
    <> command "load-pcap" CL.piLoadPcapOpts

and then I try to aucomplete in haskeline (my code is a slightly modified version of bashCompletionQuery adapted to haskeline), only "load-csv" or "load-pcap" will be completed, not the arguments of the children parser piLoadCsv and piLoadPcapOpts (e.g., let's say I type load-pcap to with "toto" as a possible completion, it should autocomplete to load-pcap toto but right now mapParser just evals the top-level parser).

The completion code relies on runParserInfo that relies on mapParser.
If I call mapParser on my top-level parser:

debugParser :: ArgumentReachability -> Option x -> String
debugParser reachability opt = case optMain opt of
      OptReader ns _ _ -> "optreader"
      FlagReader ns _ -> "flagReader"
      ArgReader rdr -> "argreader"
         -- >>= \x -> return $ Completion x "argreader help" True
      CmdReader _ ns p -> "cmdreader"

  let out = mapParser debugParser mainParser
  putStrLn $ "out=" ++ show  out

It displays only "cmdReader" even though piLoadCsv has argument parsers too. I would expect mapParser to enter each child parser ?

That's why I've tried to modify treeMapParser to get into all the children subparsers:

@@ -268,16 +275,22 @@ treeMapParser g = simplify . go False g
     has_default :: Parser a -> Bool
     has_default p = isJust (evalParser p)
 
+    -- genLeaf :: (String -> Maybe (Parser a)) -> String -> OptTree b
+    genLeaf fn arg = case fn arg of
+      Nothing -> Nothing
+      Just p -> Just $ infoParser p
+
     go :: Bool
        -> (forall x. ArgumentReachability -> Option x -> b)
        -> Parser a
        -> OptTree b
     go _ _ (NilP _) = MultNode []
     go r f (OptP opt)
-      | optVisibility opt > Internal
-      = Leaf (f (ArgumentReachability r) opt)
-      | otherwise
-      = MultNode []
+      | optVisibility opt > Internal = case opt of
+          -- AltP
+          (Option (CmdReader _ ns fn) _) -> MultNode $ [Leaf (f (ArgumentReachability r) opt)] ++ ( map (\x -> go r f x ) (catMaybes $ map (genLeaf fn) ns ))
+          _else -> Leaf (f (ArgumentReachability r) opt)
+      | otherwise = MultNode []
     go r f (MultP p1 p2) =
       MultNode [go r f p1, go r' f p2]
       where r' = r || hasArg p1

it seems better as now mapParser does now collect the options of each parser.
The CmdReader (Maybe String) [String] (String -> Maybe (ParserInfo a)) is a bit annoying though. Why not CmdReader (Maybe String) Map String ParserInfo ?

from optparse-applicative.

HuwCampbell avatar HuwCampbell commented on July 19, 2024

I don't really know what to say regarding your Haskeline version. The bash and zsh shells work here, here's an example I have lying around. This is with zsh.

Screen Shot 2021-10-26 at 1 02 47 pm

Screen Shot 2021-10-26 at 1 02 58 pm

The sub command compile completes, then once in the subcommand its options complete as well.

My guess is that your lexing and splitting of the input words is not quite right.

from optparse-applicative.

teto avatar teto commented on July 19, 2024

I've changed optparse-applicative's examples/Cabal.hs to an executable to test the zsh completion.
It seemed to work. Back to my code, I noticed that when typing the full command name, completion would work, but it would fail when the command was half-typed. I tracked it down to

Nothing -> hoistMaybe result <|> parseError arg p

and the following seems to do the trick:

diff --git a/src/Options/Applicative/Common.hs b/src/Options/Applicative/Common.hs
index c40f3c4..4edbd05 100644
--- a/src/Options/Applicative/Common.hs
+++ b/src/Options/Applicative/Common.hs
@@ -208,7 +208,9 @@ runParser policy isCmdStart p args = case args of
   (arg : argt) -> do
     (mp', args') <- do_step arg argt
     case mp' of
-      Nothing -> hoistMaybe result <|> parseError arg p
+      Nothing -> 
+        trace "ERROR" hoistMaybe result <|> exitP isCmdStart policy p Nothing
       Just p' -> runParser (newPolicy arg) CmdCont p' args'
   where
     result =

In terms of API, an idea I like from haskeline would be to return a completion datatype(https://hackage.haskell.org/package/haskeline-0.8.2/docs/System-Console-Haskeline-Completion.html#t:Completion) in
newtype Completer = Completer { runCompleter :: String -> IO [String] } => newtype Completer = Completer { runCompleter :: String -> IO [Completion] } .

optparse-applicative could return the completion and its description and toggle what to display depending on "Richness" ?

from optparse-applicative.

teto avatar teto commented on July 19, 2024

another thing that is annoying is that let's say I have my positional argument with a <> completeWith ["toto", "tata"] modifier, there is no validation of the resulting value during runCompletion. Let's say my previous command load-pcap expects as argument "toto" or "tata" I wouldl ike to trigger the completion if the value isn't one of those but right now optparse accepts any value.

from optparse-applicative.

HuwCampbell avatar HuwCampbell commented on July 19, 2024

Yeah... using a type which included an optional richness would be a lot better that just a string which gets a sentinal tab in it. We would allow users to also supply rich completions where they're supported... don't know I didn't do that the first time round.

Obviously until a better API for shells is developed we would have to smash in the tab in eventually, but we would push it to the boundary.

from optparse-applicative.

teto avatar teto commented on July 19, 2024

so I found the issue with eitherReader, it throws an ErrorMsg (which doesn't contian the parser) so runCompletion returns a Nothing instead of the parser with the error. I've hacked the searchArg function so that upon any error it gets rewritten with a ParseError that actually contains the parser:

      ArgReader rdr -> let
          tmp = runExcept $ runReaderT (unReadM $ crReader rdr) arg 
        in
        -- rewrite the error so that completion can access the parser
        fmap pure . lift . lift $ either (const $ exitP CmdStart AllPositionals parser Nothing) return tmp

This way I can access the parser that failed during autocompletion, and display the available completions. This hack may break other stuff but it solves the last (big) issue I had with live completion. I am running after a deadline but once I get more time, I can submit PRs if there is interest. Out of the box completion with haskeline would be a neat feature IMO (or at least making it easier).

from optparse-applicative.

teto avatar teto commented on July 19, 2024

closing as I got it working as I wanted in the end. thanks for the help throughout !

from optparse-applicative.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.