Generating an Org Link to a Web Page

Recently, I was rereading Vivek Haldar's post on the seven levels of Emacs proficiency and suddenly realized that I'd regressed in one aspect of my Emacs skills. Haldar says

Up until now, you probably had one large Emacs window plus many other
shell windows spread out on your screen. Also, if you are a typical
developer, you often had to cut and paste text between those windows.
And that was a major road bump, because you had to use the mouse to
select text in an xterm.

I thought I'd long since stopped committing that sin but my epiphany upon rereading Haldar's post was that I was still guilty of it in one important case: grabbing links to Web pages. Almost all my blog posts link to at least one Web page and often several. I generated those links in exactly the way that Haldar deprecates: change focus to the Web page, cut the URL from the title bar, switch back to Emacs, paste the URL into the Org link. Clearly, I needed a better method; something that would allow me to grab the URL of the currently displayed browser page and turn it into a link in my Org buffer without leaving Emacs.

The org-mac-link package almost does what I needed but it fills in the link description with the Web page title, which was not what I wanted. So I looked at the org-mac-link code and Kris Jenkins' excellent video on using AppleScript to play Spotify tracks from Emacs and put together a bit of Elisp that does just what I want:

(defun jcs-get-link (link)
  "Retrieve URL from current Safari page and prompt for description.
Insert an Org link at point."
  (interactive "sLink Description: ")
  (let ((result (shell-command-to-string
                 "osascript -e 'tell application \"Safari\" to return URL of document 1'")))
    (insert (format "[[%s][%s]]" (org-trim result) link))))

Of course, this works only on OS X but that's OK for me because I write all my blog posts on one of my Macs. Doubtless other operating systems have a way to do the same thing1. You could, for example, find a way of doing this in Python and then call Python instead of AppleScript to retrieve the URL. If your main OS is Linux or Windows and this interests you, leave a comment for others if you find a way of doing it in your environment.



A quick check suggests that org-protocol may be a good place to look but I haven't researched this in any detail.

This entry was posted in Programming and tagged , . Bookmark the permalink.
  • Do you use WordPress's editor or Emacs to write these blogposts? What is your workflow?

    • jcs

      I write everything in Emacs/Org mode. I wrote about my workflow here. That post is about 3 three years old but is still mostly accurate.

  • Matthew Darling

    It's not built in like AppleScript, but the Windows equivalent would probably use AutoHotKey. It's not a nice general purpose programming language, but it's a lovely way to simulate user input and run a useful subset of the Windows COM interface.

    A quick search brought me to an older blog post with a global org-capture hotkey - the code in that post would provide the user with a hotkey that either runs org-capture or switches to Emacs and then runs org-capture.

    Something similar would likely work for org-protocol, though I don't actually know much about interfacing with org-protocol or running emacsclient on Windows.

    • Jonathan

      Getting Org-Protocol to work on Windows is a bit of a pain at times. Took me multiple attempts to get it working right with Conkeror, and I'm still not sure if it'll pick up properly in Chrome and Firefox (Sometimes they work, sometimes too much of the command is stripped when passed to the prompt so it just outputs nonsense).

      The code here: works for Conkeror (combining the registry entry and the relevant js code for Conkeror).

      The only change I had to make was in the registry to have it point to 'emacsclientw.exe', and then add that to my path to ensure it was always available.

    • arbc

      I use expect and mozrepl to get the current url from firefox on windows.

      #!/usr/bin/expect -f

      log_user 0
      spawn telnet localhost 4242
      expect -re "repl\\d?>" { send ";\r" }
      expect -re "\"!^\"+\"" { send_user "$expect_out(1,string)" }
      expect -re "repl\\d?>" { send \x1d }
      expect "telnet>"
      send -- "quit\r"
      expect eof

      (defun my-org-moz-repl-current-url ()
      (shell-command-to-string "c:/dev/cygwin64/bin/expect -f /cygdrive/c/dev/currenturl.exp"))

  • Rest assured, your regression has been reversed. Fetching the url from a browser is at least a full level above just using shell in emacs.