lazamar / haskell-docs-cli

Browse Hackage from the terminal
BSD 3-Clause "New" or "Revised" License
93 stars 11 forks source link

Maintain context across calls #2

Open ChrisPenner opened 3 years ago

ChrisPenner commented 3 years ago

Figured I'd drop a note here to ask your opinion before I go implement anything; for context:

My goal is to rig up some fzf vim commands to very quickly search docs without leaving the editor.

I'm imagining running something like this:

hdc $currentWord | rg '^\d+' | fzf --tac | rg '^(\d+)' -or '$1' | hdc 

Breaking it down:

  1. hdc $currentWord: Search hoogle for the word under the cursor (or type one myself)
  2. rg '^\d+' use ripgrep to find the list of possible results (all result rows start with a number)
  3. fzf --tac use the fzf fuzzyfinder to interactively select which result I want docs for
  4. rg '^(\d+)' -or '$1' | hdc pull out only the number from the selected line and pass it to hdc to give me the docs.

Currently this doesn't work because hdc loses all of its context in between invocations.

I'm wondering, do you have ideas on how best to solve this? Ideally hdc would have fuzzy-find built-in, but that might be a bit too much to ask, and would only help support this very specific workflow.

Although it's a bit of a hack since it might cause confusion if multiple scripts are running at once, I'm wondering if stashing the context on exit and re-loading it on startup would be a reasonable solution here?

Perhaps a more reasonable solution would be to simply rely on the search being cached and provide a full query as the second search?

Let me know your thoughts, thanks!

ChrisPenner commented 3 years ago

Looking into this further, I think it would work well to allow a query like:

> async 2

Which would search for "async" then immediately select result 2.

This way I could write my command like this:

hdc $search | rg '^\d+' | fzf --tac | rg '^(\d+)' -or "$search \$1" | hdc

And we avoid any conflict between multiple scripts, the cache makes this plenty fast :)

lazamar commented 3 years ago

I see what you mean.

You may find it difficult to do it using rg to select the lines. Lines are cropped at 80 characters, so if a type signature is too long your script wouldn't show all of it.

It might be more worth it to have an editor command that would drop you into an interactive session in hdc with the results for the word you are interested in. There wouldn't be fuzzy-finding but you would be able to select an option by number or by infix using the / notation.

Currently this is not possible as the only two modes are interactive, which has no starting search, or non-interactive, which accepts a term to search but exits immediately.

A new flag could be added, --interactive, which forces the execution to be interactive even if an initial search term is provided. Do you think that would work with your setup?

andreystepanov commented 1 year ago

A new flag could be added, --interactive, which forces the execution to be interactive even if an initial search term is provided. Do you think that would work with your setup?

@lazamar, it would've been great if you could implement it. I'm planning to use the same workflow as @ChrisPenner described.

lazamar commented 1 year ago

@andreystepanov I'm away from my computer now, but does it work if you pass the input through stdin instead of as an argument?

andreystepanov commented 1 year ago

@lazamar Thanks for quick reply.

It seems i can pass selection number using this command:

echo -e "map\n2" | hdc

And the output would be:

...
3  map :: (Word8 -> Word8) -> ByteString -> ByteString
   bytestring Data.ByteString, bytestring Data.ByteString.Lazy,
   rio RIO.ByteString, rio RIO.ByteString.Lazy
2  map :: (a -> b) -> NonEmpty a -> NonEmpty b
   base Data.List.NonEmpty, base-compat Data.List.NonEmpty.Compat,
   rio RIO.NonEmpty
1  map :: (a -> b) -> [a] -> [b]
   base Prelude, base Data.List, base GHC.Base, base GHC.List, base GHC.OldList,
   ghc GHC.Prelude.Basic, base-compat Prelude.Compat,
   haskell-gi-base Data.GI.Base.ShortPrelude, relude Relude.List.Reexport
search: map
==================================================
map :: (a -> b) -> NonEmpty a -> NonEmpty b
base Data.List.NonEmpty, base-compat Data.List.NonEmpty.Compat, rio RIO.NonEmpty
Map a function over a NonEmpty stream. 
https://hackage.haskell.org/package/rio/docs/RIO-NonEmpty.html#v:map
https://hackage.haskell.org/package/base-compat/docs/Data-List-NonEmpty-Compat.html#v:map
https://hackage.haskell.org/package/base/docs/Data-List-NonEmpty.html#v:map
==================================================
search: map
> ⏎ 

So it first sends function name to search for, and then selection number.

But i still exits immediately, and the plan was to stay in interactive mode and play around with different searched (in case i selected a wrong option).