Hi Metasearch.el

One of the less obvious super powers of Emacs is its ability to start any shell command. In the past few days I put together a small package that uses this to start web searches from within Emacs:

Metasearch.el allows to simultaneously use the same search string in multiple search engines. Search engines can be organised and called in sets. Active regions are respected (as the search query).

For more info see https://github.com/rtrppl/metasearch.

A fun alternative to LLMs 🙂

orgrr goes global

I use orgrr, my note-taking package for Emacs, for many different but sometimes overlapping aspects of my life: A main slipbox for professional knowledge, several writing projects, an org-journal folder, a folder with tasks for work, downloaded websites/mastodon posts (via mastodon.el) and more.

Recent additions to orgrr, such as global variants of find, insert, show-backlinks, show-related-notes, or orgrr-search (new in 0.9.6!), ignore the boundaries between these different containers (which are just different org-directories). Imagine invoking C-u orgrr-show-backlinks on a note in your slipbox and finding that relevant section of a newspaper article you read months before or that insight you linked in your journal in 2021.

More on the new orgrr-search:

As most of orgrr itself, orgrr-search and orgrr-global-search (or C-u orgrr-search), draw on ripgrep. The search string entered here is directly passed to ripgrep, so all regex that ripgrep understands should also work here. Search in orgrr is not case sensitive (i.e. rg -i is set). Search results are presented in context and clicking on the linked headline above a result will directly take you to the line in the source file.

Adding orgrr-related-notes

I wrote a new function to better surface related notes for my minimalist org-roam v1 clone orgrr. The function collects all notes related to a given note to the second degree – the backlinks for the backlinks and the outgoing links mentioned by outgoing links. To use the image of a family, it considers parents and grandparents as well as all children and grandchildren of a note. All links to a specific note are counted and the resulting list is ranked by frequency and presented in side-window (invoking the function again closes the side-window). Pretty stoked by the results!

Adding orgrr-projects

One of the main ideas of the Zettelkasten-approach (“This is the way”) is to be able to pull out a number of cards and to look at them at the same time. For a while I tried different ways to replicate this with orgroam (and orgrr).

One of my ideas was to open all relevant notes in a new frame. This worked only ok-ish. Managing multiple frames in Emacs is somewhat hard (for example, all windows have to be re-arranged manually) and there is a limit to the number of notes that you would be able to see at the same time.

Another idea was to use the great org-transclusion package. In my personal use, however, I frequently encountered two issues. First, I only needed a line or two from a note and entering the line-numbers for org-transclusion – despite being easy – added a bit of friction. Secondly, I frequently use my notes as a starting point to write more comprehensive articles/notes. This requires changes to the contents of an existing note that should not affect the source note.

So in sum, I wanted to see a number of snippets from different notes at the same time (with links to their respective sources) but fully moldable to my liking. And I wanted to be able to rapidly add snippets to different thematic “desktops”. Enter orgrr-projects.

Orgrr-projects is the first major deviation from the original org-roam v1 ideas in orgrr. All notes within the org-directory and the roam_tag orgrr-project are an orgrr-project. This makes it very easy to add a note to or to remove it from the list of orgrr-projects. orgrr-open-project presents you a list of all active projects and lets you quickly open the selected one. One use case, for example, would be to have quick access to your favorite problems.

orgrr-add-to-project now lets you add the current line – of either any visited org-document in the active buffer (within the org-directory) or in the *Orgrr Backlinks* buffer – to any of these projects. A link to the source document is also added.

orgrr: org-roam-ripgrep

Org-roam v2 is an amazing project and brought org-roam to a new level of sophistication. Still, I never made the switch. As a reminder, the crucial difference between the two was the move from files as the main unit of interaction to “nodes”, which are org headlines with an org-id attached to them. This allowed for impressive graphs and more thorough linking to headlines (and even to show backlinks for nodes) but it never clicked with me and so I continued to use v1.

This worked fine for me until recently, where some weird emacsql problem broke the interaction between Emacs 29 and orgroam v1 on a new (old) intel Mac from work, which I wanted to use for field research (instead of my newer and expensive MBP). Enter orgrr:

Orgrr is an almost feature-complete replica of the core functionality of org-roam v1, built using ripgrep(rg), a lot of regex and hashtables. It does recognize alternative note titles (#+roam_alias) and tags (#+roam_tags) as introduced by org-roam v1. Orgrr currently only works with org-files (i.e. files ending in .org). If you also miss the first version of org-roam or prefer to not use databases (or to reduce dependencies), then this might be something for you.

PS For full text search I strongly recommend deadgrep, which also uses rg.

Automatically add org-files to “org-agenda-files” or remove them, based on whether or not they contain org-keywords

As mentioned before, I use Emacs, org-roam and org-journal. In total I have about 3000 org-files and a tiny fraction of them contains org-keywords. Those files I would like to have in my org-agenda-files (so that they show up in my org-agenda). If there is no TODO or any other org-keyword left, these files should be automatically removed.

This is what I came up with: My solution uses rg (ripgrep) and directly modifies “org-agenda-files”. Put the snippet below in your .emacs, adjust your org-keyword and whenever you save a buffer, “agenda_files.el” is updated. rg is really fast and this causes no tangible delay in my setup.

(defun lt/auto-add-org-agenda ()
  "Automatically add org-files to org-agenda-files or remove them, based on whether or not they contain org-keywords."
  (interactive)
  (with-temp-file org-agenda-files (insert (shell-command-to-string (concat "rg --sort modified -e '\\*.(TODO|NEXT|WAITING|RECREATION|PROJECT).[^%]' -g \"*.org\" -l " org-directory)))))
  (add-hook 'org-agenda-mode-hook 'lt/auto-add-org-agenda)

Copy org-ified toot to clipboard/org-journal (mastodon.el)

(On the left is the orginal toot, on the right is the “org-ified” version pasted into org-journal.)

There is a lot of useful information flying around in Mastodon. Some of it I would like to archive in my text-based database (i.e. org-roam). To access Mastodon inside Emacs I use mastodon.el. This little hack copies an org-ified version of the “toot” at point in the mastodon.el timeline to the clipboard. It uses the URL of said toot to pull it’s title from the web (via org-web-tools) and creates an org-link as the heading/context for the toot. The content of the toot is then pasted between #+begin_quote and #+end_quote. I also added a keybinding (“j”) for this to work inside mastodon.el.

Caveats: For boosted toots you need to focus on the original toot first (via “T”). Line breaks are still a bit of a mess.

((defun lt/mastodon-toot--copy-orgified-toot-to-clipboard ()
          "Copy org-ified toot at point to clipboard."
            (interactive)
            (let* ((toot (mastodon-tl--property 'toot-json)))
            (when toot
              (let* 
              ((url (alist-get 'url toot))
               (content (mastodon-tl--content toot))
               (html (org-web-tools--get-url url))
               (title (org-web-tools--html-title html)))       
  (with-temp-buffer
     (emacs-lisp-mode)
     (insert content)
     (fill-region (point-min) (point-max))
     (let* ((content (buffer-substring (point-min) (point-max)))              
            (complete-toot (concat "\[\[" url "\]\[" title "\]\]\n\n" 
               "#+begin_quote\n\n" content "\n#+end_quote\n\n")))
            (kill-new complete-toot)
(message "Copied: '%s' to the clipboard." title)))))))
(define-key mastodon-mode-map (kbd "j") 'lt/mastodon-toot--copy-orgified-toot-to-clipboard)

Update 2023_02_04: I played around with this setup and decided to directly paste the toot into an org-journal entry. The following code will add that functionality to the keybinding “J” (when in Mastodon.el).

(defun lt/mastodon-toot--copy-orgified-toot-to-org-journal ()
          "Copy org-ified toot at point to org-journal."
            (interactive)
            (lt/mastodon-toot--copy-orgified-toot-to-clipboard)
            (org-journal-new-entry nil)
            (org-yank))
 (define-key mastodon-mode-map (kbd "J") 'lt/mastodon-toot--copy-orgified-toot-to-org-journal)

Btw: If you replace (org-journal-new-entry nil) in the second snipped with (org-capture nil "xyz") (whereby xyz stands for a template key) this should also work with org-capture.

Update 2023_02_11: Added a correction for the arbitary line breaks (via fill-region in a temporary buffer).

Add a website from Emacs to Things’ inbox

This code snippet will quickly add a website from any Emacs buffer to Things‘ inbox. The name of the new task is the name of the website, the URL is added as a note. It requires org-web-tools, uses the URL-scheme of Things and in Emacs the cursor must be on the URL you want to add. Everything happens in the background, the focus continues to be on Emacs.

 (cl-defun lt/add-url-to-things (&optional (url (org-web-tools--read-url)))
    "Add a website to Things' inbox."
    (interactive)
      (let* ((html (org-web-tools--get-url url))
         (title (org-web-tools--html-title html)))
         (setq things-url (concat "things:///add?title=" title "&notes=" url))
         (shell-command (concat "open " "-g " "\"" things-url "\""))
         (message "%s" (concat "\"" title "\"" " has been added to Things."))))

Backstory: I’m checking Mastodon with via mastodon.el in Emacs and often encounter interesting websites that I want to come back to later. In the past I’ve used pocket-reader.el to add these sites to Pocket. But this feels like wasting them – I don’t check Pocket just for fun and often just forget that I’ve added something there. Things is (currently) my task manager (despite using org-mode for a lot) and I like to process my findings here.

Reading Chinese

One reason I enjoy working with Emacs is the relative ease to process text in specific ways. One example: reading Chinese official documents can be quite exhausting, so I let them read to me. For a long time I used read-aloud.el for that. Unfortunately, macOS Ventura broke this package from 2016 – but I was able to replace it with this tiny function:

(defun lt/read-chinese (start end)
"Read region in Chinese."
(interactive "r")
(shell-command-on-region start end "say -v Ting-Ting"))