Announcing hgrep

My long weekend project is (arguably) useful enough to share, so I've published it. It's called hgrep , and it uses ghc-exactprint and regular expressions to search Haskell source code from the command line. You can grab it on Hackage or Github.

String search

For navigational search, I tend to lean pretty heavily on ag . This has all sorts of ramifications - for example, I always format my code such that a declaration foo can be found by searching for "^foo ::" . When a colleague uses a different style, I'm totally hosed. I'll save you from additional anecdotes; rest assured that string search is not great for huge piles of source code.

We don't need a GHC session to do navigational search across Haskell files. The syntax is really rich and complicated. All we need is an AST!

Syntactic search

My project this long weekend, hgrep , aims to replace ag in my workflow. Instead of bluntly searching the strings, hgrep uses ghc-exactprint to parse Haskell source code. Your query is run against that source tree, and the results are printed with surrounding context from the originating file, with optional syntax highlighting.

This means we can explicitly search for definitions, imports, or usage sites.

Thus far, hgrep is kinda embarrassingly simple: you give it a string and some files, it finds Haskell definitions that precisely match the string. If the terminal supports ANSI escape codes, it runs it through HsColour on the way out. It looks a bit like this:

It's not all that pretty, but it works:

This means it replaces ag FooBar and ag "foo ::" for me, which is a pleasant first step. The second step requires a little bit of thought.

I've already been reaching for it all day at work, so I suspect it's useful enough to release as-is. Nevertheless, I plan to make it a lot more useful with filters and regular expressions over the weekend, so stay tuned!

Syntactic search is not necessarily an improvement over fast string-search tools like ag and rg ! There are a number of pros and cons.

Pros:

Potential for very interesting search queries

Knows the difference between a type and a type declaration

Knows the difference between a pattern and a constructor

Knows the difference between exports and imports

Accompanying documentation and expression context is captured

Cons:

Parsing Haskell source is much slower than applying a regex

Most use cases are simple enough to approximate with regex

CLI must be designed carefully to make complex queries easy

Future direction: more interesting queries

Arguably, the current feature set of hgrep could be implemented with a handful of regular expressions. It wouldn't be as precise, nor would it print as much useful context, but it'd be faster and "good enough."

Here are a few things I'd like to achieve over the next little while:

Simple filters ( --declarations , --values , ...)

, , ...) Pleasant visual output

An expressive query DSL, usable as a library

Better throughput

Support for GHC 8.2

CPP to limit breakage in future GHC versions

Recursively search directories for Haskell files (support hgrep foo . shorthand)

Before I do serious work on a fancy set of queries, I'd like to hear from potential users. What would you like to see in a general-purpose tool for Haskell syntactic search?

I'd like to hear about the kind of navigational search you do when working in large Haskell codebases. Please get in touch if you regularly get stuck in the maelstrom of Hoogle and text search. Your feedback will help me figure out how this tool should ultimately function.

Contributing

This codebase is still pretty small, so it's perfect for newcomers to Haskell or to open source in general. If you're looking for a project to hack on, I've done my best to identify a bunch of low-hanging fruit. All of these should be achievable in an hour or an evening.

If you're interested in diving into one of those issues, I'm willing to provide plenty of help and support! Get in touch.