#+title: Emacs Graphical Display Configuration #+author: Howard X. Abrams #+date: 2020-09-10 #+tags: emacs macos A literate programming file to configure the Emacs UI. #+begin_src emacs-lisp :exports none ;;; ha-display --- Emacs UI configuration. -*- lexical-binding: t; -*- ;; ;; © 2020-2023 Howard X. Abrams ;; Licensed under a Creative Commons Attribution 4.0 International License. ;; See http://creativecommons.org/licenses/by/4.0/ ;; ;; Author: Howard X. Abrams ;; Maintainer: Howard X. Abrams ;; Created: September 10, 2020 ;; ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: ;; ~/other/hamacs/ha-display.org ;; Using `find-file-at-point', and tangle the file to recreate this one . ;; ;;; Code: #+end_src And let’s make this Emacs look more like a fancy IDE with [[https://github.com/domtronn/all-the-icons.el][all-the-icons]]: #+begin_src emacs-lisp (use-package all-the-icons :if (display-graphic-p)) #+end_src * Mode Line Let's install and load some of packages from the [[https://github.com/hlissner/doom-emacs][Doom Emacs]] project, like [[https://github.com/seagle0128/doom-modeline][doom-modeline]] and maybe the themes: #+begin_src emacs-lisp (use-package doom-modeline :init (setq doom-modeline-minor-modes nil doom-modeline-buffer-encoding nil doom-modeline-major-mode-color-icon t doom-modeline-buffer-state-icon t doom-modeline-buffer-modification-icon t doom-modeline-modal 'evil doom-modeline-lsp-icon t doom-modeline-percent-position nil) (doom-modeline-mode 1)) (use-package doom-themes) #+end_src * Find the Bloody Cursor Large screen, lots of windows, so where is the cursor? While I used to use =hl-line+=, I found that the prolific [[https://protesilaos.com/][Protesilaos Stavrou]] [[https://protesilaos.com/codelog/2022-03-14-emacs-pulsar-demo/][introduced his Pulsar project]] is just what I need. Specifically, I might /loose the cursor/ and need to have it highlighted (using ~F8~), but also, this automatically highlights the cursor line with specific /actions/ , like changing windows. #+begin_src emacs-lisp (use-package pulsar :straight (:host github :repo "protesilaos/pulsar") :custom (pulsar-pulse-functions '(recenter-top-bottom move-to-window-line-top-bottom reposition-window bookmark-jump other-window delete-window delete-other-windows aw-delete-window forward-page backward-page scroll-up-command scroll-down-command evil-window-right evil-window-left evil-window-up evil-window-down aw-move-window aw-swap-window aw-copy-window aw-split-window-vert aw-split-window-horz aw-split-window-fair ha-new-window winum-select-window-1 winum-select-window-2 winum-select-window-3 winum-select-window-4 winum-select-window-5 winum-select-window-6 winum-select-window-7 winum-select-window-8 winum-select-window-9 winner-undo winner-redo tab-new tab-close tab-next org-next-visible-heading org-previous-visible-heading org-forward-heading-same-level org-backward-heading-same-level outline-backward-same-level outline-forward-same-level outline-next-visible-heading outline-previous-visible-heading outline-up-heading)) (pulsar-face 'pulsar-generic) (pulsar-delay 0.05) :bind ("" . pulsar-pulse-line) :config (pulsar-global-mode 1)) #+end_src * Themes One does get used to a particular collection of colors. Mine is Tomorrow: #+begin_src emacs-lisp (use-package color-theme-sanityinc-tomorrow) #+end_src Most of the time, Emacs is on my desk is a darkened room, so I choose the dark theme: #+begin_src emacs-lisp (defun laptop-inside () (interactive) (load-theme 'sanityinc-tomorrow-night t) (set-face-attribute 'region nil :background "#000096") (set-face-attribute 'mode-line nil :background "black") (set-face-attribute 'mode-line-inactive nil :background "#444444")) #+end_src But, when feeling adventurous, I /sometimes/ take my laptop outside: #+begin_src emacs-lisp (defun laptop-in-the-sun () (interactive) (load-theme 'sanityinc-tomorrow-day t) (set-face-attribute 'region nil :background "orange1") (set-face-attribute 'mode-line nil :background "#cccccc") (set-face-attribute 'mode-line-inactive nil :background "#888888")) #+end_src Oh, and turn off the line highlighting: #+begin_src emacs-lisp (global-hl-line-mode -1) #+end_src And of course, the default is /inside/ where it is dark and safe: #+begin_src emacs-lisp (laptop-inside) #+end_src * Full Size Frame Taken from [[https://emacsredux.com/blog/2020/12/04/maximize-the-emacs-frame-on-startup/][this essay]], I figured I would start the initial frame automatically in fullscreen, but not any subsequent frames (as this could be part of the capturing system). #+begin_src emacs-lisp (add-to-list 'initial-frame-alist '(fullscreen . maximized)) #+end_src But when capturing, I subsequently open smaller frames that shouldn’t be /odd looking/: #+begin_src emacs-lisp (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) (add-to-list 'default-frame-alist '(ns-appearance . dark)) #+end_src Now that I’m using v29 of Emacs, I can /un-decorate/ the non-full-sized frames: #+begin_src emacs-lisp (add-to-list 'default-frame-alist '(undecorated-round . t)) #+end_src * Font Configuration Am I ever really ever satisfied with any font? I regularly change my font based on the monospace du jour... [[http://blogs.adobe.com/typblography/2012/09/source-code-pro.html][Source Code Pro]] is attractive, and has been a staple on every programmers' screen. However, we all want ligatures, [[https://github.com/i-tu/Hasklig][Hasklig]] is a nice font that is thinner and easier to read than [[https://github.com/tonsky/FiraCode][Fira]], but [[https://typeof.net/Iosevka/][Iosevka]] seems to have it all. Oh, Microsoft just gave us [[https://docs.microsoft.com/en-us/windows/terminal/cascadia-code][Cascadia]] and that seems shiny. However, the [[https://github.com/ryanoasis/nerd-fonts][Nerd Font project]] adds the ligatures as well as all the other niceties to a font. ** Choosing a Font I stole the following idea from [[https://protesilaos.com/dotemacs/#h:9035a1ed-e988-4731-89a5-0d9e302c3dea][Protesilaos Stavrou's dotfile configuration]], and the following should minimally be /readable/: #+begin_example | Similarities | Regular | |--------------+----------------------------| | ()[]{}<>«»‹› | ABCDEFGHIJKLMNOPQRSTUVWXYZ | | 6bB8& | abcdefghijklmnopqrstuvwxyz | | 0ODdoaoOQGC | 0123456789 | | I1tilIJL | ~!@#$%^&*+ | | !¡ij | `'"‘’“”.,;:… | | 5$§SsS5 | ()[]{}—-_=<>/\ | | 17ZzZ2 | ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ | | 9gqpG6 | αβγδεζηθικλμνξοπρστυφχψω | | hnmMN | | | uvvwWuuwvy | | | x×X | | | .,·°% | | | ¡!¿? | | | :; | | | `''"‘’“” | | | —-~≈=≠+*_ | | | …⋯ | | | ... | | #+end_example The following is from [[https://source-foundry.github.io/Hack/font-specimen.html][Hack's website]]: #+begin_src c // The four boxing wizards jump #include // <= quickly. int main(int argc, char **argv) { long il1[]={1-2/3.4,5+6==7/8}; int OxFaced=0xBAD||"[{(CQUINE"; unsigned O0,l1,Z2,S5,G6,B8__XY; printf("@$Hamburgefo%c`",'\n'); return ~7&8^9?0:l1|!"j->k+=*w"; } #+end_src To install a font, I use the following command on my Mac: #+begin_src sh brew tap homebrew/cask-fonts brew install --cask font-hack-nerd-font #+end_src ** Specifying a Font My /current/ favorite font is actually the top list of fonts that may be installed on my system: #+begin_src emacs-lisp (defvar ha-fixed-font (when window-system (or (seq-first (seq-filter (lambda (font) (when (x-list-fonts font) font)) '("CaskaydiaCove Nerd Font" ; finally found it ;; funky font with litagures and a dotted 0 "Cascadia Code PL" ;; clean font, but no litagures!? "Hack Nerd Font" "FiraCode Nerd Font" ; has litagures "Cousine Nerd Font" "Iosevka Nerd Font" "FantasqueSansMono Nerd Font" "Monoid Nerd Font" "Hasklig" "Source Code Pro"))) "monospaced")) "My fixed width font based on what I have installed.") #+end_src I probably don't need to have such a ranking system, as chances are good I have them all installed. #+begin_src emacs-lisp (defvar ha-variable-font (when window-system (or (seq-first (seq-filter (lambda (font) (when (x-list-fonts font) font)) '("Literata" ; Clean, readable with litagures ;; Next best can be downloaded here: ;; https://fontesk.com/xcharter-typeface/ "XCharter" "Charter" ;; Interesting idea: "Iosevka Comfy Motion Duo" "Serif"))) (warn "Cannot find a Serif Font. Install Source Sans Pro.")))) (defvar ha-variable-header-font (when window-system (or (seq-first (seq-filter (lambda (font) (when (x-list-fonts font) font)) '("Overpass" "DejaVu Sans" "Verdana" "Overpass" "Source Sans Pro" "Lucida Grande" "Sans Serif"))) (warn "Cannot find a Sans Serif Font. Install Source Sans Pro.")))) #+end_src Simple function that gives me the font information based on the size I need. Recently updated after reading [[https://protesilaos.com/codelog/2020-09-05-emacs-note-mixed-font-heights/][this essay]], as I wanted my =fixed-pitch= to scale along with my =variable-pitch= font. #+begin_src emacs-lisp (defun ha-set-favorite-font-size (size) "Set the default font size as well as equalize the fixed and variable fonts." (let ((fav-font (format "%s-%d" ha-fixed-font size))) (set-face-attribute 'default nil :font fav-font) (set-face-attribute 'fixed-pitch nil :family ha-fixed-font :inherit 'default :height 1.0) (set-face-attribute 'variable-pitch nil :family ha-variable-font :inherit 'default :height 1.2))) #+end_src Define /interactive/ functions to quickly adjusting the font size based on my computing scenario: #+begin_src emacs-lisp (defun ha-mac-monitor-fontsize () "Quickly set reset my font size when I connect my laptop to a monitor on a Mac." (interactive) (ha-set-favorite-font-size 13)) (defun ha-linux-monitor-fontsize () "Quickly set reset my font size when I connect my laptop to a monitor on Linux." (interactive) (ha-set-favorite-font-size 12)) (defun ha-mac-laptop-fontsize () "Quickly set reset my font size when I disconnect my laptop to a monitor from a Mac." (interactive) (ha-set-favorite-font-size 32)) (defun ha-linux-laptop-fontsize () "Quickly set reset my font size when I disconnect my laptop to a monitor from Linux." (interactive) (ha-set-favorite-font-size 10)) (defun ha-imac-fontsize () "Quickly set reset my font size when I am on my iMac." (interactive) (ha-set-favorite-font-size 16)) #+end_src Which font to choose? #+begin_src emacs-lisp (defun font-monitor-size-default () "Set the default size according to my preference." (interactive) (cond ((eq system-type 'gnu/linux) (ha-linux-monitor-fontsize)) ((s-starts-with? "imac" system-name) (ha-imac-fontsize)) (t (ha-mac-monitor-fontsize)))) (defun font-laptop-size-default () "Set the default size according to my preference." (interactive) (if (eq system-type 'gnu/linux) (ha-linux-laptop-fontsize) (ha-mac-laptop-fontsize))) (font-monitor-size-default) #+end_src ** Zooming or Increasing Font Size Do we want to increase the size of font in a single window (using =text-scale-increase=), or globally (using my new =font-size-increase=)? Increase or decrease the set size of the face: #+begin_src emacs-lisp (defun font-size-adjust (delta) "Adjust the current frame's font size. DELTA would be something like 1 or -1." (interactive "nFont size difference: ") (when (null delta) (setq delta 1)) (let* ((font-family (face-attribute 'default :font)) (font-size (font-get font-family :size)) (new-size (+ delta font-size))) (ha-set-favorite-font-size new-size))) (defun font-size-increase () "Increase the `default' font size of all frames." (interactive) (font-size-adjust 1)) (defun font-size-decrease () "Decrease the `default' font size of all frames." (interactive) (font-size-adjust -1)) #+end_src And some keybindings to call them: #+begin_src emacs-lisp (global-set-key (kbd "s-+") 'font-size-increase) (global-set-key (kbd "s-=") 'font-size-increase) (global-set-key (kbd "s--") 'font-size-decrease) #+end_src * Emojis, Icons and Whatnot Display these two symbols as one: #+begin_src emacs-lisp (add-hook 'text-mode-hook (lambda () (dolist (pair '(("!?" . "‽") ("ae" . "æ") ("AE" . "Æ") ;; If we have ligatures, why these? ;; ("->" . ?→) ;; ("<-" . ?←) ;; ("=>" . ?⇒) )) (push pair prettify-symbols-alist)))) #+end_src And turn the prettifier on: #+begin_src emacs-lisp (global-prettify-symbols-mode 1) #+end_src In Emacs 28.1, we have better Unicode 14 support. Which means, we need to install [[https://github.com/googlefonts/noto-emoji][Noto Color Emoji]]. My systems, seems to work fine, but I’m leaving this code here in case I have issues, as I might use what Apple supplies when on a Mac (thanks [[http://xahlee.info/emacs/emacs/emacs_list_and_set_font.html][Xah Lee]]): #+begin_src emacs-lisp ;; set font for symbols (set-fontset-font t 'symbol (cond ((ha-running-on-macos?) (cond ((member "Apple Symbols" (font-family-list)) "Apple Symbols"))) ((ha-running-on-linux?) (cond ((member "Symbola" (font-family-list)) "Symbola"))))) ;; set font for emoji (should come after setting symbols) (set-fontset-font t 'emoji (cond ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji") ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji") ((member "Symbola" (font-family-list)) "Symbola"))) #+end_src Test this out: 😄 😱 😸 👸 👽 🙋 Not use what I'm doing with the [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] package, but the Doom Modeline uses much of this. #+begin_src emacs-lisp (use-package all-the-icons) #+end_src *Note:* Install everything with the function, =all-the-icons-install-fonts=. * Ligatures Seems like getting ligatures to work in Emacs has been a Holy Grail. On Mac, I've used special builds that have hacks, but now with Emacs 27 and Harfbuzz, I should be able to get --> to look like it should. #+begin_src emacs-lisp :tangle no (setq prettify-symbols-unprettify-at-point 'right-edge) (global-prettify-symbols-mode +1) (prettify-symbols-mode +1) #+end_src We'll start using that instead, but setting this [[file:ha-programming.org::*Ligatures][over here]] in the programming section. Also note that adding a /little/ extra space between lines makes text files easier to read. #+begin_src emacs-lisp (add-hook 'text-mode-hook (lambda () (setq-local line-spacing 0.1))) #+end_src * Technical Artifacts :noexport: Let's =provide= a name so we can =require= this file: #+begin_src emacs-lisp :exports none (provide 'ha-display) ;;; ha-display.el ends here #+end_src Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~ #+DESCRIPTION: A literate programming file to configure the Emacs UI. #+PROPERTY: header-args:sh :tangle no #+PROPERTY: header-args:emacs-lisp :tangle yes #+PROPERTY: header-args :results none :eval no-export :comments no :mkdirp yes #+OPTIONS: num:nil toc:t todo:nil tasks:nil tags:nil date:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+INFOJS_OPT: view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js