hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-03 00:59:51 +0200
committerhachem <im@hachem.wtf>2026-09-03 00:59:51 +0200
commit97a80d04489dd74c6d756eac75f9355b315d3b40 (patch)
tree1acba755c647ef722ca32495118029be1e3ce50f
parent0893b9de6610f0b94e79203afa094340487a9d93 (diff)
docs: man page and README
-rw-r--r--Makefile5
-rw-r--r--README.md63
-rw-r--r--jafm.1132
3 files changed, 195 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index c39a8e0..609a125 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,9 @@ TARGET := jafm
SRC := jafm.c
PREFIX ?= /usr/local
+MANPREFIX ?= $(PREFIX)/share/man
BINDIR := $(DESTDIR)$(PREFIX)/bin
+MANDIR := $(DESTDIR)$(MANPREFIX)/man1
all: $(TARGET)
@@ -52,9 +54,12 @@ check:
install: $(TARGET)
install -d $(BINDIR)
install -m 755 $(TARGET) $(BINDIR)/$(TARGET)
+ install -d $(MANDIR)
+ install -m 644 $(TARGET).1 $(MANDIR)/$(TARGET).1
uninstall:
rm -f $(BINDIR)/$(TARGET)
+ rm -f $(MANDIR)/$(TARGET).1
clean:
rm -rf $(TARGET) $(TARGET).dSYM
diff --git a/README.md b/README.md
index c924903..18edd85 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,68 @@
# just a fucking manual
-jafm is just a convenient utility program that searches through your man pages instead of making you find the man page yourself. I find it genuinely insane how illiterate the default `man` command can be. I was making a simple HTTP server in C, and, as you know, I wanted to look up the man page for `sockaddr_in`. But every single time I tried `man sockaddr_in`, `man` would go: `No manual entry for sockaddr_in`. And this *should* work, because it works on Linux. But, as it so happens, I am not on Linux all the time.
+`jafm` searches through **all your man pages** for a symbol, figures out which
+page actually documents it, and opens it for you.
-The documentation for `sockaddr_in` was there. It was inside another man page. So naturally, I had to somehow figure out which random man page contained the thing I was looking for. jafm fixes that. It just looks through **all your man pages**, tells you where it found your query, gives you a selector, and opens the man page for you.
+I find it genuinely insane how fucking illiterate the default `man` command can be. I was making a simple HTTP server in C and wanted the man page for `sockaddr_in`. Every single time I tried `man sockaddr_in` it went: `No manual entry for sockaddr_in`. And this *should* work, because it works on Linux. But, as it so happens, I am not on Linux all the time. The docs for `sockaddr_in` were right there, inside another page (`inet`). So I had to somehow guess which random man page contained the thing I was looking for. `jafm` fixes that. It reads every page, ranks the hits so the real one is on top, shows you a picker with a live preview, and opens whatever you choose.
```sh
-$ jafm sockaddr_in
+$ jafm sockaddr
```
That's it. I find it genuinely unacceptable that this is not an already solved issue.
-## License
+## What you get
+
+`jafm` searches every page in your `manpath`, in parallel, in a fraction of a second. It **ranks by relevance** so the page that actually documents your symbol floats to the top, tells you *what* it found and its **kind** (`sockaddr_in (struct)`), and gives you an **interactive picker** with a live `man` **preview** on the side and the match highlighted in the page.
+
+## Usage
+
+```text
+$ jafm --help
+jafm 0.1.0 - just a fucking manual
+
+greps your whole manpath for a symbol and opens the page that actually
+documents it, because `man <symbol>` gives up way too easily.
+
+usage: jafm [-1] [-l] [-e] [-t type] [-j threads] <symbol>
+ jafm [-v | -h]
+
+options:
+ -1, --first open the best match without asking
+ -l, --list just print what it found, open nothing
+ -e, --exact match the symbol as a whole word only
+ -t, --type KIND only show matches where the symbol is a KIND
+ (struct, union, enum, typedef, function)
+ -j, --jobs N scan with N worker threads (default 8)
+ -v, --version print version and bail
+ -h, --help print this and bail
+
+by hachem <im@hachem.wtf>
+```
+
+In the picker: `↑`/`↓` or `k`/`j` to move, `Enter` to open, `q` to bail. Pipe
+its stdin instead of a tty and it drops to a numbered prompt.
+
+```sh
+$ jafm sockaddr # pick from the list
+$ jafm -1 getentropy # open the best match straight away
+$ jafm -t struct -l sockaddr # every struct named *sockaddr*, printed
+$ jafm -e -1 inet # whole word, open the winner
+```
+
+## Build
+Needs a C17 compiler, `zlib`, and pthreads. Nothing else.
+
+```sh
+$ sudo make install # -> /usr/local/bin + man page
+$ make install PREFIX=~/.local # or somewhere without sudo
+```
-jafm is licensed under the MIT License. See [LICENSE](LICENSE) for more information.
+It really is one file, so if you don't want the Makefile:
+
+```sh
+cc -O2 -std=c17 jafm.c -o jafm -lz -lpthread
+```
+
+## License
+`jafm` is licensed under the MIT License. See [LICENSE](LICENSE) for more.
diff --git a/jafm.1 b/jafm.1
new file mode 100644
index 0000000..a2e5f0f
--- /dev/null
+++ b/jafm.1
@@ -0,0 +1,132 @@
+.TH JAFM 1 2026-09-03 "jafm 0.1.0" "General Commands Manual"
+.SH NAME
+jafm \- just a fucking manual: find a symbol across every man page and open it
+.SH SYNOPSIS
+.B jafm
+.RB [ \-1 ]
+.RB [ \-l ]
+.RB [ \-e ]
+.RB [ \-t
+.IR type ]
+.RB [ \-j
+.IR threads ]
+.I symbol
+.br
+.B jafm
+.RB [ \-v | \-h ]
+.SH DESCRIPTION
+.B jafm
+greps every man page in your
+.B manpath
+for
+.IR symbol ,
+ranks the hits so the page that actually documents it floats to the top, and
+drops you into an interactive picker with a live preview. Pick one and it opens
+in
+.BR man (1).
+.PP
+It exists because
+.B "man <symbol>"
+gives up the moment the thing you want lives inside some other page.
+.BR sockaddr_in ,
+for example, is documented inside
+.BR inet (4).
+jafm just reads all of them and finds it.
+.PP
+When standard input is not a terminal (say, a pipe), jafm skips the interactive
+UI: it prints the numbered matches and reads a selection number from stdin.
+.SH OPTIONS
+.TP
+.BR \-1 ", " \-\-first
+Open the best (top\-ranked) match immediately, without the picker.
+.TP
+.BR \-l ", " \-\-list
+Print the matches and exit. Opens nothing.
+.TP
+.BR \-e ", " \-\-exact
+Match
+.I symbol
+as a whole word only, so
+.B sockaddr
+no longer drags in
+.BR sockaddr_in .
+.TP
+.BR \-t ", " \-\-type " " \fIkind\fR
+Only show pages where the symbol appears as
+.IR kind :
+one of
+.BR struct ", " union ", " enum ", " typedef ", or " function .
+.TP
+.BR \-j ", " \-\-jobs " " \fIn\fR
+Scan with
+.I n
+worker threads (default 8, capped at 64).
+.TP
+.BR \-v ", " \-\-version
+Print version and exit.
+.TP
+.BR \-h ", " \-\-help
+Print a usage summary and exit.
+.SH KEYS
+Inside the picker:
+.TP
+.BR \(ua ", " \(da ", " k ", " j
+Move the selection.
+.TP
+.B Enter
+Open the highlighted page in
+.BR man (1).
+.TP
+.BR q ", Ctrl-C"
+Quit without opening anything.
+.SH RANKING
+Matches are scored by where the symbol shows up, best first: its filename, then
+the NAME section, then a type definition
+.RB ( "struct ... {" ),
+then the SYNOPSIS, then anywhere in the body. Pages in the core sections
+(headers and sections 2, 4, 5, 7, 9) are weighted above library and command
+pages, and a page found under several man roots is collapsed to one entry.
+.SH COMPRESSION
+Plain and
+.B gzip
+pages are read directly;
+.BR zstd ", " xz ", and " bzip2
+pages are read through the matching decompressor if it is installed, which
+it will be on any system that stores its pages that way.
+.SH EXAMPLES
+.nf
+.RS
+# find the page that documents sockaddr, pick from a list
+jafm sockaddr
+
+# skip the picker, open the best match
+jafm -1 getentropy
+
+# only structs, printed rather than opened
+jafm -t struct -l sockaddr
+
+# whole word, open the winner
+jafm -e -1 inet
+.RE
+.fi
+.SH EXIT STATUS
+.TP
+.B 0
+A page was opened, or
+.B \-l
+listed matches.
+.TP
+.B 1
+Bad usage, no matches, or nothing was selected.
+.SH ENVIRONMENT
+.TP
+.B MANPATH
+Honored via
+.BR manpath (1),
+which jafm runs to find where your pages live.
+.SH SEE ALSO
+.BR man (1),
+.BR manpath (1),
+.BR apropos (1)
+.SH AUTHOR
+hachem <im@hachem.wtf>