Emacs

The pages where I write about Emacs. It doesn’t happen very often. I think you’re probably best off following Planet Emacsen.

2016-12-08 Cider Woes

I’m trying to get Cider to work on my laptop running OSX and failing. This makes me unhappy because I managed to do it on a Windows machine with lots of Cygwin so I felt that getting it to work on a Mac should be a breeze.

Basically, what I have set up my little project using lein and can run it from the command line and from eshell, and I use Clojure Mode, but when I run M-x cider-jack-in I see is this in my *Messages* buffer:

Starting nREPL server via /Users/alex/bin/lein update-in :dependencies conj \[org.clojure/tools.nrepl\ \"0.2.12\"\ \:exclusions\ \[org.clojure/clojure\]\] -- update-in :plugins conj \[cider/cider-nrepl\ \"0.15.0-SNAPSHOT\"\] -- repl :headless...
Mark set
nREPL server started on 53929
[nREPL] Establishing direct connection to localhost:53929 ...
error in process filter: nrepl--direct-connect: [nREPL] Direct connection failed
error in process filter: [nREPL] Direct connection failed

But now I have three buffers named *nrepl-server ... with contents such as nREPL server started on port 53872 on host 127.0.0.1 - nrepl://127.0.0.1:53872.

This reminds me… My Mac keeps deleting my /etc/hosts file which means that localhost is borked:

$ ping localhost
ping: cannot resolve localhost: Unknown host

So I added it back to /etc/hosts.

127.0.0.1 localhost

Then I killed the three nrepl-server buffers and tried C-c M-j again.

And it works. Phew!

Sometimes writing these posts just helps me focus as I’m troubleshooting.

Tags:

Comments on 2016-12-08 Cider Woes

Your mac deleting /etc/hosts file sounds really bad

– nickf 2016-12-08 22:53 UTC


Yeah. I think it rewrites the file whenever the system updates? So any code that depends on localhost mapping to 127.0.0.1 usually breaks after an update. Gah!

– Alex Schroeder 2016-12-08 22:59 UTC


Hi Alex, that deletion of /etc/hosts sounds vary odd. I use emacs, cider, lein etc almost daily on OSX and have not run itno that issue ever. I do use hombrew for emacs and lein. I am now running macOSSierra, but have been doing clojure et. al. on a Macbook for the past few years and used the last2 or 3 OSX versions.

– Tim X 2016-12-09 08:30 UTC


Strange. I also have OpenVPN installed on the Mac and it puts stuff into the file. Googling for the problem shows that some versions of a Cisco VPN used to do the same. I should just deinstall it and see whether that resolves it.

– AlexSchroeder 2016-12-09 11:47 UTC

Add Comment

2016-12-02 Emacs Avent of Code Day 2

First question of day 2: You start on key 5 on a keypad as shown below. With instructions to go up, down, left or right. Ignore instructions that would take you off the keypad.

1 2 3
4 5 6
7 8 9

The example input provided for the four numbers is shown below. At the end of each line you’ll end up on the key which is part of the answer. In this example the correct answer is 1985.

ULL
RRDDD
LURDL
UUUUD

Code:

(let ((pos 5)
      (code nil)
      (instructions '((U L L)
		      (R R D D D)
		      (L U R D L)
		      (U U U U D))))
  (dolist (instruction instructions)
    (dolist (move instruction)
      (case move
	((U) (when (> pos 3) (setq pos (- pos 3))))
	((D) (when (< pos 7) (setq pos (+ pos 3))))
	((L) (when (not (= (mod pos 3) 1)) (setq pos (- pos 1))))
	((R) (when (> (mod pos 3) 0) (setq pos (+ pos 1))))))
    (push pos code))
  (reverse code))

For the second star, I was too lazy to figure out how to compute the next position and decided to implement tables instead:

    1
  2 3 4
5 6 7 8 9
  A B C
    D

Given a direction, I just list all the possible positions and the results. It’s crude, but it works.

(let ((pos 5)
      (code nil)
      (instructions '((U L L)
		      (R R D D D)
		      (L U R D L)
		      (U U U U D))))
(dolist (instruction instructions)
    (dolist (move instruction)
      (setq pos (funcall move pos)))
    (push pos code))
  (reverse code))

(defun U (pos)
  (case pos
    ((3) 1)
    ((6) 2)
    ((7) 3)
    ((8) 4)
    ((A) 6)
    ((B) 7)
    ((C) 8)
    ((D) 'B)
    (t pos)))

(defun D (pos)
  (case pos
    ((1) 3)
    ((2) 6)
    ((3) 7)
    ((4) 8)
    ((6) 'A)
    ((7) 'B)
    ((8) 'C)
    ((B) 'D)
    (t pos)))

(defun L (pos)
  (case pos
    ((6) 5)
    ((3) 2)
    ((7) 6)
    ((B) 'A)
    ((4) 3)
    ((8) 7)
    ((C) 'B)
    ((9) 8)
    (t pos)))

(defun R (pos)
  (case pos
    ((5) 6)
    ((2) 3)
    ((6) 7)
    ((A) 'B)
    ((3) 4)
    ((7) 8)
    ((B) 'C)
    ((8) 9)
    (t pos)))

Tags:

Add Comment

2016-12-01 Emacs Advent of Code

I looked at Advent of Code and foolishly decided to solve the first riddle. Perhaps we’ll learn something about Elisp coding style? Feel free to leave comments regarding the code.

You must follow instructions: R or L means turn left or right, followed by a number of steps to take. What’s the final distance in steps? Example: “R5, L5, R5, R3 leaves you 12 blocks away.”

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R5, L5, R5, R3")))
      (direction 0)
      (x 0)
      (y 0))
  (dolist (instruction instructions)
    (destructuring-bind (turn . steps) instruction
      (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
      (case direction
	(0 (setq y (+ y steps)))
	(1 (setq x (+ x steps)))
	(2 (setq y (- y steps)))
	(3 (setq x (- x steps))))))
  (+ (abs x) (abs y)))

Sadly, for the second star, my solution fails… The question is now: which location was visited twice? The example provided says “if your instructions are R8, R4, R4, R8, the first location you visit twice is 4 blocks away, due East.” The code works for the example given but fails for the data I was provided with in the test.

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R8, R4, R4, R8")))
      (direction 0)
      (x 0)
      (y 0)
      (last-x 0)
      (last-y 0)
      (seen nil)
      (final-x nil)
      (final-y nil))
  (or (catch 'twice
	(dolist (instruction instructions)
	  (destructuring-bind (turn . steps) instruction
	    (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
	    (case direction
	      (0 (setq y (+ y steps)))
	      (1 (setq x (+ x steps)))
	      (2 (setq y (- y steps)))
	      (3 (setq x (- x steps)))))
	  (dolist (line (cdr seen))	; skip the last element
	    (destructuring-bind ((x1 . y1) (x2 . y2)) line
	      (when (or (and (= x last-x) ; last move was vertical 
			     (= y1 y2)	  ; looking at a horizontal
			     (>= x x1)  (<= x x2)
			     (or (and (<= y y1)  (>= last-y y1))
				 (and (>= y y1)  (<= last-y y1)))
			     (setq final-x x
				   final-y y1))
			(and (= y last-y) ; last move was horizontal
			     (= x1 x2)	  ; looking at a vertical
			     (>= y y1)  (<= y y2)
			     (or (and (<= x x1)  (>= last-x x1))
				 (and (>= x x1)  (<= last-x x1)))
			     (setq final-x x1
				   final-y y)))
		;; (error "Moving from %S to %S crosses the line from %S to %S in %S"
		;; 	   (cons last-x last-y) (cons x y)
		;; 	   (cons x1 y1) (cons x2 y2)
		;; 	   seen)
		(throw 'twice (+ (abs final-x) (abs final-y))))))
	  (push (list (cons last-x last-y) (cons x y)) seen)
	  (setq last-x x
		last-y y)))
      (+ (abs x) (abs y))))

Well, I decided to brute force it and remember every point I moved through because my “crossing lines” solution was obviously off by 3. Perhaps I just reported the wrong result, who knows.

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R8, R4, R4, R8")))
      (direction 0)
      (x 0)
      (y 0)
      (last-x 0)
      (last-y 0)
      (seen '((0 . 0))))
  (or (catch 'twice
	(dolist (instruction instructions)
	  (destructuring-bind (turn . steps) instruction
	    (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
	    (case direction
	      (0 (setq y (+ y steps)))
	      (1 (setq x (+ x steps)))
	      (2 (setq y (- y steps)))
	      (3 (setq x (- x steps)))))
	  (while (not (and (= last-x x) (= last-y y)))
	    (if (not (= last-x x))
		(setq last-x (funcall (if (< last-x x) '1+ '1-) last-x))
	      (setq last-y (funcall (if (< last-y y) '1+ '1-) last-y)))
	    (let ((last (cons last-x last-y)))
	      (if (member last seen)
		  (error "Repetition seen: %S in %S" last seen)
		(push last seen))))))
      (error "No repetitions in %S" seen)))

Tags:

Add Comment

2016-09-21 OSX Emacs

Same procedure as always, one would think. But somehow, it manages to be different every single time.

This is what I want:

alex@Megabombus:~$ brew install railwaycat/emacsmacport/emacs-mac --with-gnutls --with-imagemagick --with-official-icon --with-xml2
==> Installing emacs-mac from railwaycat/emacsmacport
...

Homebrew also wanted me to do some other stuff, oh well.

alex@Megabombus:~$ sudo chown root:wheel /usr/local
alex@Megabombus:~$ sudo mv /opt/homebrew-cask/Caskroom /usr/local

Tags:

Comments on 2016-09-21 OSX Emacs

Today…

alex@Megabombus:~$ brew update
Checking out v1.0.6 in /usr/local/Homebrew...
To checkout master in /usr/local/Homebrew run:
  'cd /usr/local/Homebrew && git checkout master
Checking out v1.0.6 in /usr/local/Homebrew/Library/Taps/caskroom/homebrew-cask...
To checkout master in /usr/local/Homebrew/Library/Taps/caskroom/homebrew-cask run:
  'cd /usr/local/Homebrew/Library/Taps/caskroom/homebrew-cask && git checkout master
fatal: Cannot update paths and switch to branch 'v1.0.6' at the same time.
...

And many repeats. WTF!

Google found an answer on Stack Exchange that seemed similar enough for me to try it:

alex@Megabombus:~$ cd $(brew --repo); git fetch; git reset --hard origin/master; brew update
HEAD is now at faebc64 Merge pull request #1216 from reitermarkus/fix-language-audit
Updated 11 taps (caskroom/cask, homebrew/boneyard, homebrew/core, homebrew/dupes, homebrew/fuse, homebrew/games, homebrew/science, homebrew/services, homebrew/tex, homebrew/versions, homebrew/x11).
...

Looks good!

Also, I learned that now --enable-mac-app is required…

And so:

alex@Megabombus:~$ brew install railwaycat/emacsmacport/emacs-mac --with-gnutls --with-imagemagick --with-official-icon --with-xml2 --enable-mac-app
Warning: railwaycat/emacsmacport/emacs-mac-emacs-25.1-z-mac-6.0 already installed
alex@Megabombus:~$ brew remove railwaycat/emacsmacport/emacs-mac
Uninstalling /usr/local/Cellar/emacs-mac/emacs-25.1-z-mac-6.0... (4,066 files, 109.9M)
emacs-mac emacs-24.5-z-mac-5.17, emacs-24.5-z-mac-5.18 are still installed.
Remove all versions with `brew uninstall --force emacs-mac`.
alex@Megabombus:~$ brew uninstall --force emacs-mac
Uninstalling emacs-mac... (7,874 files, 225.7M)
alex@Megabombus:~$ brew install railwaycat/emacsmacport/emacs-mac --with-gnutls --with-imagemagick --with-official-icon --with-xml2 --enable-mac-app
==> Installing emacs-mac from railwaycat/emacsmacport
==> Installing dependencies for railwaycat/emacsmacport/emacs-mac: nettle, imagemagick
==> Installing railwaycat/emacsmacport/emacs-mac dependency: nettle
...
==> Caveats
This is YAMAMOTO Mitsuharu's "Mac port" addition to
GNU Emacs 25. This provides a native GUI support for Mac OS X
10.6 - 10.12. After installing, see README-mac and NEWS-mac
in /usr/local/Cellar/emacs-mac/emacs-25.1-z-mac-6.0 for the port details.

Emacs.app was installed to:
  /usr/local/Cellar/emacs-mac/emacs-25.1-z-mac-6.0

To link the application to default Homebrew App location:
  brew linkapps
or:
  ln -s /usr/local/Cellar/emacs-mac/emacs-25.1-z-mac-6.0/Emacs.app /Applications
Other ways please refer:
  https://github.com/railwaycat/homebrew-emacsmacport/wiki/Alternative-way-of-place-Emacs.app-to-Applications-directory

For an Emacs.app CLI starter, see:
  https://gist.github.com/4043945

.app bundles were installed.
Run `brew linkapps emacs-mac` to symlink these to /Applications.
==> Summary
🍺  /usr/local/Cellar/emacs-mac/emacs-25.1-z-mac-6.0: 4,067 files, 109.8M, built in 15 minutes 56 seconds
alex@Megabombus:~$ brew linkapps emacs-mac
Linking: /usr/local/opt/emacs-mac/Emacs.app
Linked 1 app to /Applications

– Alex Schroeder 2016-10-06 19:47 UTC

Add Comment

2016-05-28 nginx as a caching proxy

Remember the fiasco at the end of 2014 and the beginning of 2015, when Emacs Wiki was down as I tried to switch to Fast CGI, and it kept staying down as I tried to use mod_perl, when finally Nic Ferrier stepped in and started paying for new hosting. He used nginx as a caching proxy for Apache, which continued to call the wiki as a simply CGI script.

The comments reveal quite a bit of caching issues, though. The problem was that nginx seemed to ignore that two pages with an identical URL but for different language preferences could be different. This in turn meant that a German visitor to a page not in the cache would put the page in the cache but with German menus at the bottom, for example (“Diese Seite bearbeiten” instead of “Edit this page”). And if the next visitor to the same page didn’t understand German, this was annoying.

I thought the answer was that Apache should send the “Vary” header telling the cache that accept-language should be part of the cache key. See this discussion of the Vary header, for example: Understanding the HTTP Vary Header and Caching Proxies. But it just didn’t work.

Recently, I suddenly realized that perhaps nginx doesn’t care about the Vary header Apache is sending. I learned about the proxy_header_key setting in the nginx caching guide. As you can see, the default is inadequate! $scheme$proxy_host$request_uri is not what I’m expecting. I needed to add http_accept_language to that key:

# proxy cache key is $scheme$proxy_host$request_uri by default
proxy_cache_key $scheme$proxy_host$request_uri$http_accept_language;

I get the feeling that things are working, right now! If so, it only took 17Β½ month to find the solution. I’m writing it down in case anybody else stumbles over this problem (and in case I need to remember in the future).

Perhaps the problem is also related to how I compute Etags for my pages: the wiki doesn’t take accept-language into account when computing Etags. Now that I think about it, perhaps that would also have helped solve the problem?

Tags:

Add Comment

2016-05-18 Renaming Files

I had a bunch of files named like this, from various albums.

Cure - [1984] The top - 01 - Shake dog shake.mp3
Cure - [1984] The top - 02 - Bird mad girl.mp3
Cure - [1984] The top - 03 - Wailing wall.mp3

I wanted to move them into subdirectories, one for each album.

(dolist (file (directory-files "c:/Users/asc/Music/The Cure" t "\\.mp3$"))
  (let* ((name (file-name-nondirectory file))
	 (data (split-string name " - "))
	 (album (nth 1 data)))
    (unless (file-directory-p (concat "c:/Users/asc/Music/The Cure/" album))
      (make-directory (concat "c:/Users/asc/Music/The Cure/" album)))
    (rename-file file (concat "c:/Users/asc/Music/The Cure/" album "/" name))))

Tags: RSS

Comments on 2016-05-18 Renaming Files

If your files have ID3 tags, you can do some thing like this, too:

exiftool '-filename<${Artist;} - ${Year} - ${Album}/${Track;} ${Artist;} - ${Title;}.%e' **.mp3

– Sam 2016-05-18 11:54 UTC


Nice! And using exiftool! :)

– Alex Schroeder 2016-05-18 13:17 UTC


A graphic alternative is exfalso (from quodlibet music player).

– Anonymous 2016-05-19 09:58 UTC


Here is a way to do it combining dired, wdired and multiple-cursors. This approach requires the existence of the album directory which might not make it particularly useful for your exact use case. Still, I find it cool and so should you :-).

Damien Cassou 2016-05-19 18:10 UTC


Very cool. And a nice video on top. Thumbs up!

– Alex Schroeder 2016-05-21 06:33 UTC

Add Comment

2016-05-15 Gmail, Gnus, GPG Guide Update

I updated my Gmail, Gnus, GPG Guide. It now includes all the stuff about setting up the GPG Agent.

The GPG Agent is a service that will remember your passphrase for a short while. If you don’t use it, Gnus will ask you for your passphrase for every backend it uses (because it needs to log in) and for every encrypted mail you read and for every encrypted mail you send. You’ll be typing your passphrase a lot. You want to use it.

Please let me know if you tried to follow the instructions and it didn’t work. I’d like to make the instructions very easy to follow and troubleshoot. So if you missed something and ran into errors, I’d still like to know so that I can start adding typical problems people might have and how to resolve them.

And finally, feel free to test this system by sending me encrypted email! See Contact for more.

Tags: RSS RSS RSS

Add Comment

2016-04-11 Atreus, Windows, and Emacs

So, I want to define an interesting layout for my Atreus keyboard. On OSX, I used Ukulele to do it. On Windows, I’m using Microsoft Keyboard Layout Creator 1.4.

+---+---+---+---+---+          +---+---+---+---+---+
|Q  |W <|E >|R (|T )|          |Z {|U }|I [|O ]|P €|
|q 6|w 7|e 8|r 9|t 0|          |z 1|u 2|i 3|o 4|p 5|
+---+---+---+---+---+          +---+---+---+---+---+
|A  |S  |D  |F  |G $|          |H ^|J &|K  |L Γ—|: ||
|a  |s  |d  |f  |g @|          |h =|j +|k -|l *|. …|
+---+---+---+---+---+          +---+---+---+---+---+
|Y  |X  |C  |V  |B %|          |N ~|M ο½£|_ β€”|Β΄ ’|` ”|
|y  |x  |c  |v  |b #|          |n Β¨|m ο½’|- –|' β€˜|" β€œ|
+---+---+---+---+---+---+  +---+---+---+---+---+---+
|   |   |   |   |DEL|   |  |   |   |   |; Β»|? \|   |
|ESC|TAB|SUP|SH |BCK|CTR|  |ALT|SPC|FN |, Β«|! /|RET|
+---+---+---+---+---+---+  +---+---+---+---+---+---+

When I switch to my new layout, I still have some problems with it:

  • I was able to define my extra stuff using AltGr, which is the equivalent of Alt+Ctrl at the same time, which means that under Windows, I need to press both of them to access @ on g, for example. Is there a way to make this work for both Mac and Windows? Change the Alt key to Right Alt and it’ll work?
  • When using Emacs, I get A-C-g is undefined. Other programs, like Firefox, will correctly interpret A-C-g as AltGr + g and give me the @. What can I do to fix this?
  • When using Emacs, I want to use the windows key as meta. On my keyboard, that’s SUP (Super). But in this case, I get some Windows action. So I start experimenting.
  (setq w32-lwindow-modifier 'meta ; windows is meta
	w32-pass-lwindow-to-system nil
	w32-rwindow-modifier 'meta ; windows is meta
	w32-pass-rwindow-to-system nil
	w32-recognize-altgr t
	w32-pass-alt-to-system t   ; alt is alt
	w32-alt-is-meta nil)
   ;; w32-phantom-key-code??

Perhaps it would be easier if I changed that key to Meta using the keyboard’s firmware and it would work correctly on both OSX and Windows?

And I’m still not sure how to change bindings for simple keys using the Alt key. Perhaps I need a different utility? A good Microsoft Keyboard Layout Creator alternative…

I guess the alternative would be to use Fn together with these extra keys. But then I can’t bind them to something interesting like β€œ…” because in order to that, I would need access to these keys on Microsoft Keyboard Layout Creator, which I do not.

Tags: RSS RSS RSS

Comments on 2016-04-11 Atreus, Windows, and Emacs

Well, right now I am back at the US standard layout. Perhaps I can do everything else using dead keys? Might be simpler than all this extra fiddling. I’m hating everything about it already. I’m spending too much time worrying about programming the keyboard but as it stands, I won’t ever get a system, where I can just carry my keyboard to another desk and start typing. It just requires too many features by the operating system and the various solutions are incompatible anyway.

Current mood: frustrated.

– Alex Schroeder 2016-04-11 19:40 UTC


I want a keyboard with Super and Hyper that works on both Windows and OS X. I still don’t have a precise answer but this seems good ot know: https://ergodox-ez.com/pages/our-firmware They define a “Hyper” and a “Meh” key. I pre(re)invented that approach using AutoHotKey and duplicated bindings, and decided it was a poor use of my time. If it is built into your keyboard, however, might be nice. I still want to answer “Why can’t we have a GUI key that is separate from the SUPER key?”. Seems possible, and I would like it a lot because we do need a GUI key, too.

Grant Rettke 2016-04-11 21:00 UTC


Oh! Right. Whenever I have to use another computer I usually connect to it with my laptop using, er, Synergy. Synergy is great, but… it is an interesting case of a GPL-ed free software getting crippled so that they can sell it…

So I guess that it is just waiting for a fork to appear. Meanwhile you can get a bit older version from here: http://synergy-project.org/download/free/ (or compile it yourself, though in case of crippled software it is usually not as simple. But who knows). Same version is debian repos (so I haven’t really noticed).

It’s kinda interesting that instead of starting some crowd funding they decided to turn the software into something that I don’t really want to recommend to anybody just because of their β€œmonetizationβ€œ shit. Awful.

But! It allows me to use my laptop (and therefore my own configuration) for any computer I connect with. So, perhaps that’s an option?

– AlexDaniel 2016-04-11 21:09 UTC


Grant, I saw you blog post just now and I’m reminded of what I discovered when I looked at the keycodes available in the firmware:

/* Modifiers */
KC_LCTRL            KC_LCTRL        E0 Keyboard LeftControl
KC_LSHIFT           KC_LSFT         E1 Keyboard LeftShift
KC_LALT                             E2 Keyboard LeftAlt
KC_LGUI                             E3 Keyboard Left GUI(Windows/Apple/Meta key)
KC_RCTRL            KC_RCTL         E4 Keyboard RightControl
KC_RSHIFT           KC_RSFT         E5 Keyboard RightShift
KC_RALT                             E6 Keyboard RightAlt
KC_RGUI                             E7 Keyboard Right GUI(Windows/Apple/Meta key)

No KC_RHYPER or KC_LHYPER! No KC_RSUPER or KC_LSUPER! The comment points to another document: “Keycodes are defined in ‘common/keycode.h’. Range of 00-A4 and E0-E7 are identical with HID Usage.” In the header file mentioned, it says: “Virtual keycodes are defined out of above range to support special actions. Keycodes based on HID Usage Keyboard/Keypad Page(0x07) plus special codes.” As the URLs are no longer pointing anywhere, here’s what I think this refers to the USB HID Usage Tables on page 53ff.

I think this means that there cannot be a USB keyboard with a Hyper key. I think what you therefore need to do is make a key that sends multiple modifiers at the same time, ie. mapping Caps Lock to Shift+Ctrl+Option+Command or something like that. The solution for a Mac involves Karabiner and Seil for OSX. Like the ideas I had myself, this setup is hardly portable to other computers, unfortunately. Apparently, you can do something similar using AutoHotKey.

Xah Lee has collected some info the topic: Emacs: How to Define Super Hyper Keys, AutoHotkey Tutorial.

– Alex Schroeder 2016-04-12 07:31 UTC


How is it going?

– AlexDaniel 2016-04-24 06:23 UTC


I’ve been using the Atreus with my la-top at home, using the US standard layout. I use the Latin Prefix input method to write German. This also meant that I no longer require Alt/Option as AltGr and so I use Alt as Hyper again, but have no keys bound using Hyper. Boooo.

– Alex Schroeder 2016-04-24 16:37 UTC


Alex can you show your keyboard layout (like you did up above) showing your current mappings?

I’m confused by your post: did you get what you wanted when you re-configured left and right GUI?

I guessed that you would place LEFT_ALT and where you wanted it to be META, and RIGHT_ALT wherever you wanted it to be ALT. It would look confusing because the keycaps would have ALT all over, but for Emacs, it would be exactly what you want. Right? I think that I might have understood something wrong here.

Grant Rettke 2016-05-14 19:00 UTC


The end result of all the above is that I am using the default firmware for the keyboard. This means that I’m short one modifier on the Mac: I need the command key to run OSX commands; I need Alt to enter German characters; there’s no key for Meta. Under OSX, the usual solution is to use the Command key as Meta, of possible. So, in order to get that, I would have to swap Alt and Super on the Atreus firmware, assuming I wanted to use my right thumb for Meta. I guess I do?

But the main thing that I wanted to talk about when I replied to your message above was this: All USB keyboards will be limited by the USB standard for keyboards. You can find the necessary information in USB HID Usage Tables on page 53ff. There, on page 59, you’ll note that there is no way a USB keyboard will be able to send the Hyper modifier: There is only Control, Shift, Alt, and “GUI” (Super) for left and right. In order to get Hyper in addition to those present, you’ll have to map your key to something like F13 in the firmware and then you’ll have tell your operating system that F13 should act as Hyper. I think I could figure this out for a GNU/Linux environment, but I’m unwilling to spend the time necessary to figure it out for OSX and Windows.

And so I determined that the two easiest options right now are the following:

  1. don’t use the Atreus keyboard
  2. if I use the Atreus keyboard, use the default firmware, switch to a US layout in OSX, and use something like the following for Emacs:
(defun atreus-layout ()
  "If using the Atreus on a Mac, we want the Alt key to be Meta."
  (interactive)
  (setq mac-option-modifier 'meta)
  (setq default-input-method 'german-prefix)
  (set-input-method 'german-prefix))

But, I don’t like any of it and I’m unhappy with the current state of affairs. The sad part is that I don’t see an easy way forward. Maybe during my summer break.

– Alex Schroeder 2016-05-15 00:19 UTC


Gotcha. I am sorry that it isn’t going as planned. Here is what I tried https://www.wisdomandwonder.com/article/10146/every-emacser-can-use-hyper-on-every-usb-hid-keyboard . This is how I came up with “using hyper in Emacs” given that there are only 8 modifiers (left or right, shift control alt gui) in the USB HID spec and there is no xmodmap option for Windows. It seemed happy on my Mac and Windows box; I tried the following on both boxes. The important thing for me was that Windows and OS X had their important modifiers: ALT and GUI so I could switch window focus and use OS actions like inserting special characters and opening the Run dialog in Windows. I read your post like it would work the same way for the Altreus. The way I read your post I figured that you MIGHT modify your default keyboard https://atreus.technomancy.us/ by changing the default layout (by names there): super as RIGHT_GUI (aka option), ctrl as RIGHT_CONTROL, alt as RIGHT_ALT (aka command), and then moving - ‘ , to the Fn layer, so you can redefine - as LEFT_CONTROL (Meta), ‘ as LEFT_ALT (Super), and , as LEFT_GUI (Hyper) only for Emacs using the mac-right-*modifier and mac-left*-modifier settings. I didn’t want the CONTROL-ALT-GUI-SHIFT style hyper key since I only want these modifiers in Emacs. I tried that approach and didn’t like it only because I only wanted the modifiers inside of Emacs. If things work like I am seeing them work on the Mac, then this will work on your Altreus. Otherwise I am wrong and need to revise my post ASAP.

Grant Rettke 2016-05-15 09:31 UTC


Hah, excellent! I’ll give this a try. :)

– Alex Schroeder 2016-05-15 10:44 UTC


Alex, how did it go?

Grant Rettke 2016-07-15 10:58 UTC


My summer break just started at the beginning of the month and I still haven’t used my Atreus keyboard for anything. :(

– Alex Schroeder 2016-07-15 20:19 UTC


First, have a great break. Do what you enjoy!

If you happen to enjoy configuring your Emacs keyboard then know that we are all dying to hear the results!

Grant Rettke 2016-07-18 18:31 UTC


Good afternoon Alex. Have you tried the keyboard with Emacs yet?

Grant Rettke 2016-12-03 21:13 UTC


Right now I’m trying to get used to the US keyboard layout again. This requires some changes in my motor patterns. The Atreus keyboard with standard config is here, next to the laptop, but I rarely use it.

– Alex Schroeder 2016-12-03 23:35 UTC

Add Comment

2016-03-17 GPG Agent and Emacs

I updated Gmail, Gnus and GPG on a Mac, on Emacs Wiki, with the information I discovered below.

In my Gmail Gnus GPG Guide I don’t mention gpg-agent because I never managed to set it up correctly for OSX.

Well, perhaps things will change. I followed the instructions on this blog post, I think, and it works on the command line. I can encrypt a text to myself, when I decrypt it, I’m asked for my passphrase, and when I decrypt it again, I’m not asked for my passphrase because the agent handles it.

This requires my gpg-agent.conf file to contain the line pinentry-program /usr/local/bin/pinentry which is the equivalent to pinentry-curses.

It used to say pinentry-program /usr/local/bin/pinentry-mac, however!

If I use pinentry-mac:

alex@Megabombus:~$ gpg -d test.txt.gpg 

You need a passphrase to unlock the secret key for
user: "Alex Schroeder <kensanata@keybase.io>"
8192-bit RSA key, ID 4529A45C, created 2015-03-01 (main key ID ACECFEAE)

gpg: problem with the agent: No pinentry
gpg: encrypted with 8192-bit RSA key, ID 4529A45C, created 2015-03-01
      "Alex Schroeder <kensanata@keybase.io>"
gpg: public key decryption failed: Operation cancelled
gpg: decryption failed: No secret key

If I use pinentry-curses:

alex@Megabombus:~$ echo RELOADAGENT | gpg-connect-agent 
OK
alex@Megabombus:~$ gpg -d test.txt.gpg 
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ Please enter the passphrase to unlock the secret key for the OpenPGP  β”‚
   β”‚ certificate:                                                          β”‚
   β”‚ "Alex Schroeder <kensanata@keybase.io>"                               β”‚
   β”‚ 8192-bit RSA key, ID 4529A45C,                                        β”‚
   β”‚ created 2015-03-01 (main key ID ACECFEAE).                            β”‚
   β”‚                                                                       β”‚
   β”‚                                                                       β”‚
   β”‚ Passphrase __________________________________________________________ β”‚
   β”‚                                                                       β”‚
   β”‚          <OK>                                         <Cancel>        β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Within Emacs

Without the agent running, and with pinentry-mac, it would work from within Emacs (which is what I want to get working). When the agent is running, no matter what the pinentry-program line says, it won’t work.

This is what the *Messages* buffer says:

Decrypting /Users/alex/test.txt.gpg...done
epa-file--find-file-not-found-function: Opening input file: Decryption failed, 

I’m guessing this is a pinentry problem. Not exactly the same string, though. So… Any ideas? What’s wrong? Should I be setting GPG_TTY? The problem appears to be that if I don’t use gpg-agent, Emacs using gpg knows how to call pinentry-mac. If I do use the gpg-agent, then the gpg-agent tries to call pinentry-mac and fails.

Currently the environment for my Emacs session has the following, as determined by running printenv in *eshell*:

GPG_TTY=not a tty
GPG_AGENT_INFO=/tmp/gpg-oqrtL2/S.gpg-agent:40161:1

That looks wrong… I’m surprised that GPG_TTY is set in the first place. I’m setting it in my .bashrc file! So starting Emacs uses a shell? I don’t know how Emacs does that.

alex@Megabombus:~$ ps -fx|grep emacs
  502 42011     1   0  7:34am ??         0:02.88 /usr/local/Cellar/emacs-mac/emacs-24.5-z-mac-5.15/Emacs.app/Contents/MacOS/Emacs

My Config

In ~/Library/LaunchAgents/org.gnupg.gpg-agent.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
   "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>org.gnupg.gpg-agent</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Users/alex/bin/start-gpg-agent.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>

In ~/bin/startup-gpg-agent.sh:

# ${HOME}/.gpg-agent-info is the default filename
if test -f $HOME/.gpg-agent-info && \
	kill -0 `cut -d: -f 2 $HOME/.gpg-agent-info` 2>/dev/null; then
    GPG_AGENT_INFO=`cat $HOME/.gpg-agent-info`
    export GPG_AGENT_INFO
else
    eval `/usr/local/bin/gpg-agent --daemon --write-env-file`
fi

In ~/.bashrc, which is also sourced from ~/.bash_profile:

# GPG
if [ -f "${HOME}/.gpg-agent-info" ]; then
    . "${HOME}/.gpg-agent-info"
    export GPG_AGENT_INFO
    export SSH_AUTH_SOCK
fi
GPG_TTY=$(tty)
export GPG_TTY

In ~/.gnupg/gnu-agent.conf:

pinentry-program /usr/local/bin/pinentry-mac
enable-ssh-support

Result

OK, this is weird.

In a terminal, it works, if I provide --pinentry-program=/usr/local/bin/pinentry-mac as a startup parameter to gpg-agent.

In Emacs, it works, if I use pinentry-program /usr/local/bin/pinentry-mac in my gpg-agent.conf file.

One would think that the two affect the same thing, but not so. I have no idea why that is so. I’ll have to test this.

Log out and log back in. Nope, nothing works. So, at least I know that there is a way to fix this, even if I don’t know what it is!

gpg: problem with the agent: No pinentry

So here’s how I managed to “fix” it again, in a terminal:

  1. use ps aux | grep gpg to determine the process id of gpg-agent
  2. use kill to kill it
  3. run bin/start-gpg-agent.sh again
  4. run source ~/.gpg-agent-info to set the environment variables again
  5. try gpg -d test.txt.gpg to decrypt my test file – and the GUI pinentry opens!

So. What changed? I have no idea.

Within Emacs, I used setenv to set the GPG_AGENT_INFO to the new value, and it worked: I could open my test file, got asked for my passphrase, killed the buffer, reopened it, and was no longer asked for a passphrase.

So now I’m going to revert the addition of --pinentry-program to the start-gpg-agent.sh script, and see whether simply killing and restarting it from a terminal also “fixes” it. And then we’ll start worrying about the difference between all this stuff.

OK, so restarting this Mac apparently “fixed” all the issues I was having.

Tags:

Comments on 2016-03-17 GPG Agent and Emacs

I recently stumbled over this somewhere: https://github.com/ecraven/pinentry-emacs

Works great for me (especilly when ssh’ing with X-forwarding) - might be worth trying as well.

Adam 2016-03-18 20:08 UTC


Haha, “This is probably totally insecure, and your passphrase may be leaked! Use at your own risk!” Also, what happens when you’re in a terminal and use gpg – does it start Emacs, or the Emacs Client, and thus you need to be running Emacs somewhere?

– Alex Schroeder 2016-03-18 21:32 UTC


There is also an ELPA package called “pinentry”; as the note in the package description says, it works “with GnuPG (2.1.5+) and Pinentry (not yet released, possibly 0.9.5+)”. It works here.

– Sam 2016-03-19 10:21 UTC


Is that the same pinentry-emacs as https://bugs.gnupg.org/gnupg/issue2034 ? I see a pinentry-emacs is installed by pinentry 0.9.7 on my Arch box.

I have the same question about what happens when if using that when outside emacs (would prefer having both possibilities).

– Kevin Unhammer 2016-04-25 07:28 UTC


pinentry.el works for me :) http://unix.stackexchange.com/questions/55638/can-emacs-use-gpg-agent-in-a-terminal-at-all/278875#278875

– Kevin Unhammer 2016-04-25 08:04 UTC


I could not get passphrase entry to work, so I installed MacGPG2 from https://gpgtools.org/ and now I have a graphical prompt on Mac OS X.

– Anonymous 2016-10-25 02:05 UTC

Add Comment

2016-03-06 Javascript Comments

I like to write the doc strings for functions using the following style, when writing Javascript (using js-mode).

/**
 * Erase floor tile, if any.
 */
function removeFloor (x, y) {
  var old   = Map.data.get(x, y).floor;
  if (old)
    replaceFloor(x, y, old, null);
}

By default, hitting RET inside a comment or writing long comment lines does nothing special. Here’s what I prefer:

(add-hook 'js-mode-hook
	  (lambda ()
	    (setq indent-tabs-mode nil
		  js-indent-level 2)
	    (idle-highlight-mode 1)
            ;; writing longer comments
            (setq-local comment-auto-fill-only-comments t)
            (auto-fill-mode 1)
            (setq-local comment-multi-line t)
            (local-set-key (kbd "RET") 'c-indent-new-comment-line)))

Writing long comment lines will fill them automatically, and when I hit RET, comments are continued using the prefix “ * “ instead of just “ *”.

Tags: RSS

Comments on 2016-03-06 Javascript Comments

Thanks for this, Alex. I don’t write Javascript often, and had never been sufficiently motivated to figure out why (local-set-key (kbd "RET") (key-binding (kbd "M-j"))) was so broken for Javascript block comments. Presumably js-mode should actually be binding M-j to c-indent-new-comment-line

– Anonymous 2016-03-07 03:41 UTC


…in fact I see that it’s the combination of (setq-local comment-multi-line t) and (local-set-key (kbd "RET") 'c-indent-new-comment-line) which fixes this, rather than the command alone. (So that comment-multi-line setting is important for both the indent-new-comment-line behaviour and the auto-fill behaviour).

My (local-set-key (kbd "RET") (key-binding (kbd "M-j"))) happens in prog-mode-hook so I’ve added the following at js-mode-hook:

(setq-local comment-multi-line t)
(local-set-key [remap indent-new-comment-line] 'c-indent-new-comment-line))

– Phil 2016-03-07 04:30 UTC


I did not consider using remap. Interesting.

My setup has the strange effect that // are also continued on the next line. That’s unexpected:

/**
 * test
 */
function () {
  foo; // bar
       // β–ˆ

Actually, now that I’ve gone back, it seems to me that comment-multi-line can still be nil. I use M-q on long comments with comment-multi-line set to nil and got the following:

/**
 * test test test test test test test test test test test test test
 * test test test test test test test
 */
function () {
  foo; // bar test test test test test test test test test test test
       // test test test test test test test test
  quux;

Good enough for M-q? Yes.

But now I remember: comment-multi-line has an effect on auto-fill-mode. Here’s what you get as you type a long comment line with comment-multi-line set to t:

/**
 * test test test test test test test test test test test test test
 test β–ˆ
 */
function () {
  foo; // bar
       // 

Here’s what you get as you type a long comment line with comment-multi-line set to nil:

/**
 * test test test test test test test test test test test test test */
 /**test β–ˆ
 */
function () {
  foo; // bar
       // 

OK, so that explains comment-multi-line. I still thought I had a good solution for auto-fill-mode and now it seems that I don’t. Looking at do-auto-fill it seems that fill-context-prefix finds no prefix. It determines first-line-prefix to be the empty string and second-line-prefix to be “ * “. So why isn’t it used?

There’s this test: (string-match re first-line-prefix) with re being \`.*\*". So where’s the problem? Should first-line-prefix be /** such that this test succeeds and second-line-prefix is picked? Because now we’re getting to “the longest common substring of both prefixes” resulting in the empty string.

It seems to me that fill-match-adaptive-prefix ought to return /** and it does not. There, we find (looking-at adaptive-fill-regexp) which matches and (match-string 0) which returns the empty string.

Sooo… (setq adaptive-fill-regexp "[ ]*\\(//+\\|/?\\**\\)[ ]*\\([ ]*\\([-–!|#%;>*·‒‣⁃◦]+[ ]*\\)*\\)") fixes this by inserting /?. The segment in question is from c-comment-prefix-regexp which is set to //+\\|\\**. Now what? It’s doc string says: “it does not need to match a block comment starter” Does it?

So, I propose:

(setq c-comment-prefix-regexp "//+\\|/?\\**")
(let ((c-buffer-is-cc-mode t))
  (c-setup-paragraph-variables))

Either way, it’s not too bad in // comments:

/**
 * test
 */
function () {
  foo; // bar test test test test test test test test test test test
  // test β–ˆ

– Alex Schroeder 2016-03-07 11:28 UTC

Add Comment

More...

Comments


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.

Referrers: Planet Emacsen