Categories: geek » emacs

View topic page - RSS - Atom - Subscribe via email

2024-11-04 Emacs news

| emacs, emacs-news

Reminder: Emacs News is moving to info-gnu-emacs instead of emacs-tangents. If you're subscribed through emacs-tangents, you may want to subscribe to info-gnu-emacs as well.

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, communick.news, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View org source for this post

Org Mode: Format Libby book highlights exported as JSON

| emacs, org

The Toronto Public Library (and many other libraries) offers e-book access through Overdrive, which I can read through the Libby app on my phone. It turns out that I can select passages to highlight. It also turns out that I can use the Reading Journey view to export the highlights as JSON, even for books I've returned. This is what the JSON looks like.

{
  "version": 1,
  "readingJourney": {
    "cover": {
      "contentType": "image/jpeg",
      "url": "https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg",
      "title": "How to Take Smart Notes",
      "color": "#D9D9D9",
      "format": "ebook"
    },
    "title": {
      "text": "How to Take Smart Notes",
      "url": "https://share.libbyapp.com/title/5796521",
      "titleId": "5796521"
    },
    "author": "Sönke Ahrens",
    "publisher": "Sönke Ahrens",
    "isbn": "9781393776819",
    "percent": 0.313229455252918
  },
  "highlights": [
    {
      "timestamp": 1729898852000,
      "chapter": "13       Share Your Insight",
      "percent": 0.824912451361868,
      "color": "#FFB",
      "quote": "For every document I write, I have another called “xy-rest.doc,” and every single time I cut something, I copy it into the other document, convincing myself that I will later look through it and add it back where it might fit. Of"
    },
    {
      "timestamp": 1729898760000,
      "chapter": "13       Share Your Insight",
      "percent": 0.801566108949416,
      "color": "#FFB",
      "quote": "I always work on different manuscripts at the same time. With this method, to work on different things simultaneously, I never encounter any mental blockages"
    },
    ...
 ]
}

I want to save those highlights in my books.org file for easy searching, grouping the highlights by chapter. The following code helps with that:

(defun my-org-insert-book-highlights-from-libby (url)
  (interactive "MURL: ")
  (let-alist (plz 'get url :as #'json-read)
    (insert
     "* "
     .readingJourney.title.text
     " - "
     .readingJourney.author
     "\n")
    (org-set-property "ISBN" .readingJourney.isbn)
    (org-set-property "COVER" .readingJourney.cover.url)
    (org-set-property "TITLE" .readingJourney.title.text)
    (org-set-property "AUTHOR" .readingJourney.author)
    (insert (org-link-make-string .readingJourney.title.url .readingJourney.cover.url)
            "\n")
    ;; sort the highlights by chapter
    (insert
     (mapconcat
      (lambda (row)
        (concat "** " (replace-regexp-in-string " +" " " (car row)) "\n"
                (mapconcat (lambda (quote)
                             (concat "#+begin_quote\n"
                                     (alist-get 'quote quote)
                                     "\n#+end_quote\n\n"))
                           (cdr row)
                           "")
                "\n\n"))
      (seq-group-by
       (lambda (o) (alist-get 'chapter o))
       (sort .highlights
             :key (lambda (o) (alist-get 'percent o))))))))

This is what the resulting document looks like:

* How to Take Smart Notes - Sönke Ahrens
:PROPERTIES:
:ISBN:     9781393776819
:COVER:    https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg
:TITLE:    How to Take Smart Notes
:AUTHOR:   Sönke Ahrens
:END:
https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg
** 1  Everything You Need to Know
#+begin_quote
 never force myself to do anything I don’t feel like. Whenever I am stuck, I do something else.”
#+end_quote

#+begin_quote
Luhmann’s only real help was a housekeeper who cooked for him and his children during the week, not that extraordinary considering he had to raise three children on his own after his wife died early.
#+end_quote

...
This is part of my Emacs configuration.
View org source for this post

Org Mode: Prompt for a heading and then refile it to point

| org

I sometimes want the inverse of org-refile when I create a subtree and think of things that should probably go into it. This function prompts for a heading that matches org-refile-targets and then moves it to the current location.

(defun my-org-refile-to-point (refloc)
  "Prompt for a heading and refile it to point."
  (interactive (list (org-refile-get-location "Heading: ")))
  (let* ((file (nth 1 refloc))
         (pos (nth 3 refloc)))
    (save-excursion
      (with-current-buffer (find-file-noselect file 'noward)
        (save-excursion
          (save-restriction
            (widen)
            (goto-char pos)
            (org-copy-subtree 1 t))))
      (org-paste-subtree nil nil nil t))))
View org source for this post

Yay Emacs 7: Rewriting and copying custom Org Mode links

| yay-emacs, emacs, org

I use org-link-set-parameters to define a lot of custom links in Org Mode for things like my blog or my Emacs config. Then I can code how I want to complete, open, and export those links. These links don't make sense to other people, of course. I want to be able to quickly copy or replace my custom links with regular web links, like the ones I use when I export to HTML.

My shortcut for this is C-. u to copy the exported URL and C-. r to rewrite a link. These stand for my-embark-org-copy-exported-url and my-embark-replace-link-with-exported-url respectively.

You can watch this short on YouTube, download the video, or download the audio.

View org source for this post

2024-10-28 Emacs news

| emacs, emacs-news

UPDATE: I'm moving Emacs News to the info-gnu-emacs mailing list instead of emacs-tangents. If you're subscribed to Emacs News through emacs-tangents, you may want to switch your subscriptions. Emacs News will also continue to be available on the web and through RSS. I'll post to both info-gnu-emacs and emacs-tangents for a little while.

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Mastodon #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, communick.news, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View org source for this post

Insert a link to an Org Mode heading from an org-refile prompt

| emacs, embark, org

I often want to link to an Org heading from somewhere in my org-refile-targets, which includes my agenda files and other things. I don't want to think about where the heading is, I just want to link to it. I could use C-u C-c C-w (org-refile) to go to the heading, use C-c l (my shortcut for org-store-link), head back with org-mark-ring-goto, and then insert it with C-c C-l (org-insert-link).

Or I can use this code to make an Embark command that hooks into minibuffer prompts that include "goto" or "refile", so I can link to something with C-. i right from a refile or goto query.

(defun my-embark-org-insert-link-from-path (path)
  (interactive (list (car (org-refile-get-location))))
  (let* ((extra (if org-refile-use-outline-path "/" ""))
         (tbl (mapcar
               (lambda (x)
                 (if (and (not (member org-refile-use-outline-path
                                       '(file full-file-path title)))
                          (not (equal filename (file-truename (nth 1 x)))))
                     (cons (concat (car x) extra " ("
                                   (file-name-nondirectory (nth 1 x)) ")")
                           (cdr x))
                   (cons (concat (car x) extra) (cdr x))))
               org-refile-target-table))
         link)
    (insert (save-window-excursion
              (save-excursion
                (org-goto-marker-or-bmk
                 (elt
                  (org-refile--get-location path tbl)
                  3))
                (org-store-link nil))))))
(defvar-keymap my-org-path-map
  :doc "Shortcuts for working with Org paths from `org-refile'."
  "i" #'my-embark-org-insert-link-from-path)
(with-eval-after-load 'marginalia
  (add-to-list 'marginalia-prompt-categories '("Goto\\|Refile" . my-org-path)))
(with-eval-after-load 'embark
  (add-to-list 'embark-keymap-alist '(my-org-path . my-org-path-map)))
2024-10-24_10-34-21.png
Figure 1: Screenshot of Embark menu invoked with "C-.", showing the new "i" shortcut for inserting a link

There are more Embark shortcuts in my Embark configuration.

This is part of my Emacs configuration.
View org source for this post

A git post-commit hook for tagging my subed.el release version

Posted: - Modified: | git, emacs, subed

[2024-12-09 Mon]: It looks like I also need to use P t to push the tags from Magit, or call git push --tags from the command-line. Since I'm using a postcommit hook, I'm not sure followTags will kick in for that. Hmm…

Debian uses Git repository tags to notice when to update packages. I kept forgetting to tag subed's versions, so now I made a git post-commit hook which I think will do the trick. I based it on https://gist.github.com/ajmirsky/1245103, just updated for Python 3 and tweaked to work with how I do versions in subed.el. I've also added it to my README.org.

#!/usr/bin/python

# place in .git/hooks/post-commit
# Based on https://gist.github.com/ajmirsky/1245103

import subprocess
import re

print("checking for version change...",)

output = subprocess.check_output(['git', 'diff', 'HEAD^', 'HEAD', '-U0']).decode("utf-8")

version_info = None
for d in output.split("\n"):
    rg = re.compile(r'\+(?:;;\s+)?Version:\s+(?P<major>[0-9]+)\.(?P<minor>[0-9]+)\.(?P<rev>[0-9]+)')
    m = rg.search(d)
    if m:
        version_info = m.groupdict()
        break

if version_info:
    tag = "v%s.%s.%s" % (version_info['major'], version_info['minor'], version_info['rev'])
    existing = subprocess.check_output(['git', 'tag']).decode("utf-8").split("\n")
    if tag in existing:
        print("%s is already tagged, not updating" % tag)
    else:
        result = subprocess.run(['git', 'tag', '-f', tag])
        if result.returncode:
            raise Exception('tagging not successful: %s %s' % (result.stdout, result.returncode))
        print("tagged revision: %s" % tag)
else:
    print("none found.")
View org source for this post