Skip to content

Repository files navigation

Consult extension for searching on Hacker News

https://github.com/agzam/consult-hn/actions/workflows/run-tests.yml/badge.svg

Why …

Alright, real talk time. Why are you here? Why do you need Hacker News in Emacs? What’s next, Tinder in Vim? Instagram in sed?

Listen, I get it - you’ve already got your email, calendar, therapist, and pizza delivery service running in Emacs. But at some point we need to draw the line.

Go outside! Touch grass! Read a book! Hug your loved ones - your partner, your kids, your dog, that suspicious potted plant that’s been eyeing you funny. Hell, go have a meaningful conversation with your toaster for all I care.

Please, for the love of Stallman’s beard, stop trying to consume the orange website from inside your text editor. Your productivity theatre has gone too far. The call is coming from inside the buffer!

(Who am I kidding, see you in the comments section in 5 minutes.)

Alright, alright, fine. So why does this package exist?

a) Because, why not?

b) I just needed to solve this weird itch for myself - very often I get a link to a blog post, a book or a video. And sometimes, I’m curious what HN comments say about that thing. Also, sometimes I’d like to find comments I posted myself long ago, just to get reassurance of how stupid I was back then and hopefully not getting any stupider now.

What …

This is an Emacs extension that extends an extension. Because Emacs is extensible beyond imaginable limits, it allows you to extend what’s already been extended. So, in order to minimize confusion (or vice versa), we Emacsians do not call them “extensions”. We call them “packages”.

So, this is a package that packages some functionality for another (very popular and awesome) package called Consult. If you love Emacs, but not using Consult - stop hugging your toaster, close this page and go install it, asap!

This package searches through HN using public Algolia API.

How …

You can install the package through your favorite Emacs package manager, it’s on MELPA, or you can recipe-it from GitHub directly, e.g., for Doom:

(package! consult-hn :recipe (:host github :repo "agzam/consult-hn"))

Then run consult-hn. Type a query and it searches both comments and stories, newest first by default.

The prompt opens with a # already in it - that is Consult’s doing, and it is what separates the part of the input that reaches Hacker News from the part that filters what came back. Type the query after it.

Everything else about a search - stories or comments, an author, a points floor, how far back to reach - is a key away from inside the session, described below. consult-hn-transient opens a menu over the same set for anyone who would rather compose a search before running it.

Here’s a YouTube video demoing it (7 minutes). It predates the parameter keys and shows the older -- input syntax, which still works but is no longer the way in.

Shaping a search without leaving it

These keys work while the session is open. Each one re-runs the search at once, keeping your input, and what is set shows up in the prompt:

KeyDoes
C-c tcycle the type: everything, stories, comments
C-c aan author, empty answer for anyone
C-c pa points floor, empty answer for none
C-c ca comment-count floor, empty answer for none
C-c rcycle how far back: all time, 24h, week, month, year
C-c ftoggle the front page
C-c utoggle matching URLs rather than text
C-c scycle the order: default, newest first, most relevant

So C-c t twice and C-c a answered with pg leaves the prompt reading HN Search: [comment · pg] and the results are Paul Graham’s comments. There is no reset key and no need of one: cycling comes back around to the default, an empty answer clears an author or a floor, and the prompt says what is still in force.

Whatever you shape a session into is what the next one starts as, which is what makes a one-key front page (C-c f) worth having.

Examples

Emacs - everything that contains “Emacs”

Emacs then C-c t - articles with Emacs in the title

"I hate Emacs" then C-c t twice - comments matching the query

C-c a answered with pg, on an empty query - everything Paul Graham posted

A URL, pasted, then C-c u - the discussions of that link. The transient turns URL matching on by itself when what you typed is a URL.

Narrowing what came back

A second # filters the results already fetched, instantly and without asking Hacker News anything:

#Emacs#Vim - fetch everything containing “Emacs”, then keep only the items that also mention “Vim”

That is worth knowing because a broad query can pull a thousand items in, and sifting them locally costs nothing, while editing the query itself sends you back to the network.

Queries containing # are the one awkward case, since # is the separator. Consult takes the separator from whatever punctuation the input starts with, so replace the leading # with something the query does not contain: /C#/ searches for C# and narrows on whatever follows the second /.

Customization

Once you find HN items you have multiple choices:

  • preview (without closing the Consult buffer)
  • browse (close the search buffer, open the item)
  • push all the found items into Embark-Collect buffer. See Embark’s documentation for that.

Embark

Results are of the consult-hn-result category, and embark-act on one offers:

b bopen it with consult-hn-browse-fn, the same thing RET does
b oopen it in a web browser
b eopen it in eww
wcopy its Hacker News url

The item is the same in every case - the Hacker News object the search returned, not the story it links to; only the reader differs. Bind your own on consult-hn-embark-map.

You can customize consult-hn-browse-fn var, setting it to a function, here’s for example how to make it always open selected item in the browser.

(setopt consult-hn-browse-fn
       (lambda (&rest args)
         (browse-url (plist-get args :hn-object-url))))

Similarly, you can customize consult-hn-preview-fn

If you’re using hnreader, you may want to read the comments in its buffer - they show up in an Org-mode outline, it’s very nice:

(cl-defun consult-hn-reader (&key hn-object-url &allow-other-keys)
  (hnreader-comment hn-object-url))

(setopt consult-hn-browse-fn #'consult-hn-reader

consult-hn takes the same parameters as arguments, so a keybinding can be a whole search:

(defun my/hn-front-page ()
  "The front page, one key away."
  (interactive)
  (consult-hn nil :front-page t))

(defun my/hn-emacs-stories ()
  "Well-received Emacs stories."
  (interactive)
  (consult-hn "emacs" :type 'story :points 100))

The keywords are :type (all, story, comment), :author, :points, :comments, :range (all, 24h, week, month, year), :front-page, :url-match and :sort (nil, date, relevance). They hold for that call alone and leave the state the interactive command carries between sessions alone.

A caveat about the front page: HN orders it with a proprietary algorithm the API does not expose, so what you get will not be in exactly the order the site shows.

consult-hn-initial-input-string is obsolete, replaced by the arguments above. It still seeds a session if you have it set.

Comments are shown under the matching item, wrapped to consult-hn-comment-width and cut off after consult-hn-max-comment-lines lines with an ellipsis - open the item to read the whole thing, and note the full text stays searchable regardless of what is shown. The cap is not cosmetic: completion UIs size their display by the number of candidates and are blind to the extra screen lines an annotation occupies, so uncapped comments grow the minibuffer (or the posframe) to dozens of lines. For the same reason vertico-count is scaled down for the duration of the session, in proportion to the lines each candidate takes; a value you have already made buffer-local, through vertico-multiform for instance, is left alone.

Additionally, you can customize consult-hn-default-search-params, like so:

(setopt consult-hn-default-search-params '((numericFilters "num_comments>11")))

Be careful though - these reach the endpoint on every search and show up nowhere in the prompt, so for the example above stories with fewer than 12 comments are silently missing and nothing on screen says why. Anything the session sets outranks them, and it does so wholesale rather than piecemeal: one C-c c replaces that numericFilters default entirely, floors and date ranges together. A keybinding passing :comments 11 does the same job visibly, so I suggest leaving this var unchanged. The keys it accepts are the ones in the official API documentation.

Miscellaneous considerations

A search fetches results page by page until it runs out or reaches consult-hn-max-pages (10 by default), requesting consult-hn-hits-per-page items per page (100 by default). That’s up to a thousand items - more than anyone scrolls through. Since the API returns a large page as cheaply as a small one, big pages mean fewer requests: 10 instead of 50 at twenty per page. On a slow connection, lower consult-hn-hits-per-page; if you truly want everything, raise consult-hn-max-pages. Algolia’s API has daily usage limits, so use specific search terms and jump into an Embark Collect buffer early to avoid hitting them.

About

Hackernews search with Consult

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Contributors

Languages