isaias-dias-machado

isaias-dias-machado

ExHelp - documentation fuzzy search and paging CLI tool for Elixir/Erlang

IEx’s h macro is great but it lacks a pager, so I built a small tool that caches documentation and lets you fuzzy search through it in your OS shell.

It follows the Unix philosophy - Internally pipes to fzf and your default $PAGER. The cache lives at ~/.cache/exh and builds up over time as you workon different projects (no duplicates).

It compiles your project, loads all the available modules, and encodes the documentation using ETF.

Performance-wise, it caches a vanilla Phoenix project in about 10 seconds on first run, 3 seconds on subsequent runs. Tested on my old T420.

The formatting of the docs matches IEx’s `h` macro since I borrowed some of that code.

Example usage:

$ exh fetch
$ exh

Originally tried making it IEx-native using Ports (check the less-in-iex branch), but, despite redirecting the group leader and waiting for the Port’s exit message, couldn’t find a way to make the BEAM fully yield terminal control - resulted in race conditions between the BEAM and the TUI. If anyone has insights on this, I’m all ears!

Feedback welcome!

Most Liked

rhcarvalho

rhcarvalho

Interesting! How do you deal with versioning?

E.g., the help for a certain module/ function may change depending on the current branch/commit, in particular for “in development” state, not between tagged releases.

The cache invalidation problem :slight_smile:

nikfp

nikfp

This solves a pain point I’ve been experiencing a lot, and never got a chance to dig in. (Too busy scrolling up after calling help!)

Looking forward to trying it out.

isaias-dias-machado

isaias-dias-machado

I feel you! Let me know if everything works smoothly or not.

nikfp

nikfp

Does the cache speed improve on subsequent runs because it’s only compiling user land code? Whereas first run also caches and prepares dependencies?

rhcarvalho

rhcarvalho

I find myself consuming docs most of the time from hexdocs.pm or source code. When I do use h inside IEx, I’m typically inside tmux and can “scroll” back up with the keyboard.

So, speaking hypothetically, if exh clean nukes the whole cache, it would be too aggressive if I just want to refresh docs for a particular project. A refetch or fetch --force would be more targeted.

I still wonder how are you structuring the cache. Do you shard by package version? How do you treat Elixir and Erlang documentation?

This idea of centrally storing a deduplicated cache of packages reminds me of the Go Module Cache. In the Go ecosystem published modules have an immutable cryptographic checksum, and the multiple versions of a package are cached read-only in a single place. Separately, there’s also a build cache. How I’d translate that idea to Elixir is that published Hex packages could be cached by version, while “current project” needs special treatment as it can change anytime without a version change.

Where Next?

Popular in Announcing Top

martosaur
Hello, I’m excited to introduce InstructorLite – a fork of the Instructor package. Instructor brought the very idea of structured LLM p...
New
isaias-dias-machado
IEx’s h macro is great but it lacks a pager, so I built a small tool that caches documentation and lets you fuzzy search through it in yo...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
zteln
Hello Elixir community, I’ve written a small embedded key-value database in Elixir called Goblin. It’s based on the Log-Structured Merge...
New
lucaong
CubDB is an embedded database written in pure Elixir, designed for robustness and minimal use of resources. It strives to be as developer...
New
munksgaard
flakify is an igniter installer that allows you to quickly get a Nix flake-based development shell up and running for your Elixir/Phoenix...
New
rms.mrcs
Hi there :waving_hand: Just dropping by to share PhonixLiveState, a lib I’ve just published. It’s still VERY RAW, but already in a reas...
New
tmbb
Playfair (named after: William Playfair) is a data visualization/plotting library with the goal of being able to produce publication-qual...
New
brainlid
LangChain is short for Language Chain. An LLM, or Large Language Model, is the “Language” part. This library makes it easier for Elixir a...
New
jallum
Hey folks :waving_hand: I’ve been building a distributed key-value store in Elixir/OTP called Bedrock. It implements FoundationDB’s arch...
New

Other popular topics Top

freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement