Posts tagged "productivity":

01 Nov 2019

Track down basic Emacs bugs & hangs

I ran into a hang today with only ivy enabled and nothing else configured or installed. The behavior was such that after I typed a hostname with a TLD (such as not.existant.com1), then typed C-x d to visit a directory or C-x C-f to find a file, Emacs would hang. My mouse would turn into a pin-wheel. My only recourse was to send the 'quit' command via C-g to cancel the operation. Unfortunately this meant I could not do one of the simplest operations in Emacs - visiting files and directories.

Enter debug-on-quit

After some searching I found the debug-on-quit and debug-on-error variables2, with their corresponding commands toggle-debug-on-quit and toggle-debug-on-error. Enabling debug-on-quit means I can get a backtrace when I type C-g of what was happening before I signaled Emacs to quit the current command. Here is an example backtrace:

Debugger entered--Lisp error: (quit)
  make-network-process(:name "ffap-machine-p" :buffer nil :host "not.existant.com" :service "discard" :nowait nil :tls-parameters nil)
  open-network-stream("ffap-machine-p" nil "not.existant.com" "discard")
  ffap-machine-p("not.existant.com")
  ffap-machine-at-point()
  ffap-guesser()
  ffap-guess-file-name-at-point()
  run-hook-with-args-until-success(ffap-guess-file-name-at-point)
  ivy-thing-at-point()
  ivy--reset-state(#s(ivy-state :prompt "Find file: " :collection read-file-name-internal :predicate nil :require-match confirm-after-completion :initial-input nil :history file-name-history :preselect nil :keymap (keymap (96 lambda (&optional arg) "nil (`nil')" (interactive "p") (if (string= "" ivy-text) (execute-kbd-macro (kbd "M-o b")) (self-insert-command arg))) (C-backspace . counsel-up-directory) (67108991 . counsel-up-directory)) :update-fn nil :sort nil :frame #<frame (Emacs) dummy.txt [Text] /tmp/dummy.txt 0x70a1e20> :window #<window 7 on dummy.txt> :buffer #<buffer dummy.txt> :text nil :action (1 ("o" counsel-find-file-action "default") ("i" #f(compiled-function (x) #<bytecode 0x1b79a11>) "insert") ("w" #f(compiled-function (x) #<bytecode 0x1b79a21>) "copy") ("j" find-file-other-window "other window") ("f" find-file-other-frame "other frame") ("b" counsel-find-file-cd-bookmark-action "cd bookmark") ("x" counsel-find-file-extern "open externally") ("r" counsel-find-file-as-root "open as root") ("R" find-file-read-only "read only") ("k" counsel-find-file-delete "delete") ("c" counsel-find-file-copy "copy file") ("m" counsel-find-file-move "move or rename") ("d" counsel-find-file-mkdir-action "mkdir")) :unwind nil :re-builder nil :matcher counsel--find-file-matcher :dynamic-collection nil :display-transformer-fn ivy-read-file-transformer :directory "/tmp/" :caller counsel-find-file :current nil :def nil :ignore t :multi-action nil :extra-props nil))
  ivy-read("Find file: " read-file-name-internal :matcher counsel--find-file-matcher :initial-input nil :action counsel-find-file-action :preselect nil :require-match confirm-after-completion :history file-name-history :keymap (keymap (96 lambda (&optional arg) "nil (`nil')" (interactive "p") (if (string= "" ivy-text) (execute-kbd-macro (kbd "M-o b")) (self-insert-command arg))) (C-backspace . counsel-up-directory) (67108991 . counsel-up-directory)) :caller counsel-find-file)
  counsel--find-file-1("Find file: " nil counsel-find-file-action counsel-find-file)
  counsel-find-file()
  funcall-interactively(counsel-find-file)
  call-interactively(counsel-find-file nil nil)
  command-execute(counsel-find-file)

If one tries this, they'll also notice every function is a link to the corresponding Emacs lisp or C source function. Pressing RET with point on an item will find its definition. Use C-. and C-, as usual to follow and return from function definitions.

Thanks to this feature, I was able to quickly focus on a "bug" related to the find file at point subsystem as used by ivy, which causes Emacs to ping random hostname-looking addresses under the point. I reported it, maybe a default will get changed; most importantly, it's documented somewhere now.

Don't forget about debug-on-error

debug-on-error is also extremely useful, especially when extending Emacs with your own Elisp code. When I write Elisp, I almost always enabled this when testing. The Elisp language and its libraries are somewhat anachronistic and each component is seemingly tightly coupled with the next, making it hard to understand any particular subsystem. You will write bad Elisp, even if you're a wizard. Everybody writes buggy Elisp. That's why I find an Emacs bug every few months. It's just a very awkward language. Regardless, Emacs is probably the most flexible and powerful editor out there, and in this case, Worse is Better. And don't forget, a good challenge is a fun challenge.

Footnotes:

1

I know I misspelled existent. What's important is it's recognized as a valid fully qualified domain name by Emacs.

2

By the way, you can just read the info pages in Emacs (C-h i). Don't be like me, and read the infopages in the web browser, that's silly. Emacs is the best documetation browser. :)

Tags: emacs productivity
28 Jul 2019

Open URL in existing Qutebrowser from Emacs Daemon on Gentoo

On my Gentoo desktops, I use Emacs Daemon via sys-emacs/emacs-daemon1 to ensure an Emacs instance is ready to go and always available from boot. This is done via creating a symbolic link like /etc/init.d/emacs.winston to /etc/init.d/emacs which will start Emacs for the given user. See the package README for more details.

A shortcoming of this setup is XDG_RUNTIME_DIR2 is not set, as this is set by my Desktop Session - maybe LightDM or consolekit set this? As a result, when I open a URL from Emacs Daemon, it opens a fresh qutebrowser session, loading the saved default session, and making a mess of my workflow.

One approach to fix this might be to instead run Emacs daemon from my .xsession script, but I rather not supervise daemons at the user level; if I were to consider this, I'd be better off to switch to systemd for user-level services anyway.

The solution I came up with is to add some lines to my init.el to ensure XDG_RUNTIME_DIR is set to the expected value:

(defun winny/ensure-XDG_RUNTIME_DIR ()
  "Ensure XDG_RUNTIME_DIR is set. Used by qutebrowser and other utilities."
  (let ((rd (getenv "XDG_RUNTIME_DIR")))
    (when (or (not rd) (string-empty-p rd))
      (setenv "XDG_RUNTIME_DIR" (format "/run/user/%d" (user-uid))))))

(add-hook 'after-init-hook #'winny/ensure-XDG_RUNTIME_DIR)

A strange emacs-ism: (user-uid) returns float or integer, despite the backing uid_t (on *nix) is guarenteed to be an integer type. I'll just assume this'll never return a float. Please contact me otherwise, I'd love to hear about this.

Footnotes:

Tags: emacs productivity computing gentoo qutebrowser
09 Jan 2019

Toggle Redshift with Keyboard Shortcut

Redshift is a screen-tinting program that achieves similar goals to the popular f.lux1 program.

I perused through the redshift man-pages and noticed there is no documented way to toggle redshift. Of course one can click the notification area icon when using redshift-gtk or SIGTERM the redshift process, but neither is very user friendly. (The mouse is not user friendly.) After some awkward DuckDuckGo-ing and Googling I found an obvious solution on the redshift homepage2: simply send SIGUSR1 to the redshift or redshift-gtk process. When using redshift-gtk, one can choose to send SIGUSR1 to either redshift or redshift-gtk.

This is the script I came up with:

#!/bin/sh
set -eu
if ! pkill -x -SIGUSR1 redshift; then
    echo 'Could not find redshift process to toggle.' >&2
    exit 1
fi

After installing the script into my system's PATH, now all I have to do is add a line to my Xbindkeys3 configuration file (~/.xbindkeysrc.scm) such as:

(xbindkey '(Mod4 F2) "toggle-redshift")

Now I can type Mod4-F2 and toggle Redshift.

Footnotes:

Tags: productivity computing
Other posts