Content tagged elisp

display-graphic-p, cl-letf and themes

Published on:

I had a problem with my theme a while where the colors would be different depending on whether I was starting Emacs as a daemon or not. The colors module has some code that changes the way it works depending on whether a graphical or non-graphical display is run. This was messing with some of the colors in my theme.

My first thought was that it should just wait until the first frame is created before setting the theme. For a while this worked.

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame) (load-theme 'yoshi t)))
  (add-hook 'emacs-startup-hook (lambda () (load-theme 'yoshi t))))

Some time later, that stopped working, because apparently display-graphic-p stopped returning true during the execution of the after-make-frame-functions hook. So I set out to change it so it would work again. This would have been easy in earlier versions of Emacs, where flet wasn't yet deprecated.

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (flet ((display-graphic-p () t))
                  (load-theme 'yoshi t))))
  (add-hook 'emacs-startup-hook (lambda () (load-theme 'yoshi t))))

Unfortunately, as stated, flet is deprecated. Whenever you compile it you're warned and told that you should use cl-flet or cl-letf instead. I couldn't quite figure out how, though. cl-flet does almost the same thing as flet, but lexically, so you can't dynamically rebind display-graphic-p that way. cl-letf did't seem to be anything like flet at all, so I didn't know how to ever use that to accomplish this.

Thankfully, there was noflet. This, for my purposes at least, works the same way as flet did. It is not part of Emacs, however. But in this case I didn't know what else to do.

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (noflet ((display-graphic-p (&optional display) t))
                  (load-theme 'yoshi t))))
  (add-hook 'emacs-startup-hook (lambda () (load-theme 'yoshi t))))

This worked perfectly, but I really don't like depending on external packages for starting up emacs.

Then Artur Malabarba wrote a post about using cl-letf and things became very clear.

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (cl-letf (((symbol-function 'display-graphic-p))
                          (lambda (&optional display) t))
                  (load-theme 'yoshi-theme t))))
  (add-hook 'emacs-startup-hook (lambda () (load-theme 'yoshi-theme t))))

It's a bit more involved than the noflet solution, but it does remove a requirement from my init.el. What I failed to realize before reading Artur's post is that cl-letf works a lot like Emacs' new setf, which works a lot like Common Lisp's setf, which makes it very powerful.

By now, my theme doesn't use the colors module anymore.


Stop shr from using background color

Published on:

Here's just one more example why Emacs is so awesome

Reading mail in Gnus is very nice, but shr has become a little too good at its job. Add to this the many occasions when a background is specified without specifying a foreground, plus a color theme that is the inverse of what is usually expected, and you can get hard-to-read HTML messages, gray foreground and gray background.

I've looked at the other possible renderers, but they don't look very nice compared to shr. So just remove its ability to add background colors.

(defun oni:shr-colorize-remove-last-arg (args)
  "If ARGS has more than 3 items, remove the last one."
  (if (> (length args) 3)
      (butlast args)
    args))

(with-eval-after-load 'shr
  (advice-add #'shr-colorize-region :filter-args
              #'oni:shr-colorize-remove-last-arg))

C-d to close eshell

Published on:

One of the "tricks" that I have learned to use when working with terminals is using C-d to close them, or when working on a TTY logout. It somehow grew to the extent that if I can't use it, I get annoyed, like with eshell.

I have customized ansi-term to immediately close its buffer after the shell quits. This makes it very easy to start an ansi-term, which I've bound to C-c t, run a quick command (perhaps make, or similar), C-d, and I'm out. I want that for my eshell too.

There are a few conditions that I want met before the buffer is killed, though.

  1. Since eshell is an Emacs mode like any other, C-d is usually used to forward-kill characters, I don't want to lose this.
  2. I only want it to quit when the line of input is empty.

The following piece of code make sure these conditions are met.

  1. It interactively calls delete-char, which keeps keybindings like C-4 C-d to delete 4 characters working.
  2. It catches the error condition which is signaled whenever delete-char can't do it's job (like when there's nothing left to delete in the buffer).
  3. It checks to make sure that the signaled error is the end-of-buffer error. I don't want to kill the buffer if I try to delete more characters than are in the buffer because I feel that could cause irritating surprises.
  4. It checks of the cursor is at the eshell prompt. This, combined with only responding to the end-of-buffer error, makes sure we're on an empty line and not just at the end of the input. Sometimes keys are pressed at the wrong time and I don't want to have to re-type a command just because I was being an idiot.
  5. If the right conditions aren't met, signal the error again so I can see what's going on.
(defun eshell-C-d ()
  "Either call `delete-char' interactively or quit."
  (interactive)
  (condition-case err
      (call-interactively #'delete-char)
    (error (if (and (eq (car err) 'end-of-buffer)
                    (looking-back eshell-prompt-regexp))
               (kill-buffer)
             (signal (car err) (cdr err))))))

I then bind this to C-d in eshell.

(add-hook 'eshell-mode-hook
          (lambda () (local-set-key (kbd "C-d") #'eshell-C-d)))

This blog covers archlinux, avandu, avandu-lua, cask, ci, clark, common-lisp, config, conkeror, diff, dispass, dispass.el, editors, elisp, emacs, eshell, evil, exherbo, experiments, file-synchronization, games, git, github, gnus, hla, html, javascript, lisp, lua, markam, meta, mpd, notion, org-mode, ox-coleslaw, projects, rc, sbcl, small-recent-posts, software, stumpwm, systemd, tasks, tekuti, testing, tips, todo, ttrss, utility, vagrant, vc, vim, visual, wdocker docker docker-compose, wm, wordpress, yoshi-theme

View content from 2016-02, 2015-09, 2015-08, 2014-12, 2014-10, 2014-08, 2014-07, 2014-06, 2014-04, 2014-01, 2013-11, 2013-10, 2013-08, 2013-05, 2013-04, 2013-02, 2013-01