Tuesday, December 29, 2020

Making emacs happier on a Chromebook: An ssh and console friendly browse-url-browser-function

I recently learned of, and started playing with, emacs' oauth2 support. This library simplifies access to a slew of APIs and has single handedly added a number of mini-projects to my TODO list. I first experimented with oauth2 on my Mac. Evaluating this code opened up a browser window and started me down the OAuth permission process:

(defvar bs-blogger-token
  (oauth2-auth-and-store
   "https://accounts.google.com/o/oauth2/v2/auth"
   "https://oauth2.googleapis.com/token"
   "https://www.googleapis.com/auth/blogger"
   "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
   "YYYYYYYYYYYYYYYYYYYYYYYYYYYY")
  "The token to access blogger with.")

I copied the access code from my browser back into the emacs prompt. With the token defined, I was able to make authenticated API requests to Blogger. It was magic.

A few days later, eager to make improvements to my code, I again evaluated the above snippet. This time I was ssh'd into an AWS EC2 instance running a terminal version of emacs and was greeted with with the error: No usable browser found. Gah!

I searched Google and haphazardly poked around the browse-url library. It didn't take long before I learned that I could make the message go away by telling browse-url to use a native emacs web browser such as eww. For example:

(setq browse-url-browser-function 'eww-browse-url)
(browse-url "https://blogbyben.com")

While this is nifty, it's not very useful. When I invoke oauth2-auth-and-store the system attempts to open a convoluted URL that doesn't render right in eww. So while I fixed the "No usable browser found" error, I was no closer to using oauth2 on a console version of emacs.

What if I sidestepped the browser issue? What if I convinced browse-url to store the URL in a file or somewhere else out of the way. I could then grab the URL from the file, copy into my browser and be off and running. Turns out, this is surprisingly easy to do. And I don't need to store the URL in a file, I can store the URL in a temporary and easily accessible location: the kill ring. Here's the code to do this:

(defun kill-url-browse-url-function (url &rest ignore)
  (kill-new url)
  (message "Killed: %s" url))

(unless window-system
  (setq  browse-url-browser-function 'kill-url-browse-url-function))

On Windows or Mac, browse-url seamlessly opens URLs like it always has. In a console version of emacs, browse-url captures the URL in the kill ring where I can manually work with it.

In this particular case, I'm on a Chromebook using the Secure Shell App. I have the invaluable osc52.el library configured in my init like so:

(require 'osc52)
(osc52-set-cut-function)

With this code in place, emacs' kill ring is automtically sync'd with my Chromebook's copy and paste buffer. The result: evaluating browse-url places the URL not only in the emacs kill ring, but also in my Chromebook's paste buffer. This means that I can evaluate (oauth2-auth-and-store ...), Alt-Tab over to a browser window and hit Control-V to paste the URL that emacs tried to visit. In the case of oauth2 it started the authentication process as smoothly as if I had been on a windowing system.

Magic restored!

No comments:

Post a Comment