#+TITLE: Emacs Graphical Display Configuration #+AUTHOR: Howard X. Abrams #+DATE: 2020-09-10 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-percent-position nil) :config (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 ~F6~), but also, this automatically highlights the cursor line with specific /actions/ , like changing windows. #+begin_src emacs-lisp (use-package pulsar :straight (:repo "https://git.sr.ht/~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-magenta) (pulsar-delay 0.055) :bind ("" . pulsar-pulse-line)) #+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 "#333333")) #+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 * 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)) '("Hack Nerd Font" "Cousine Nerd Font" "Iosevka Nerd Font" "Iosevka" "FantasqueSansMono Nerd Font" "Monoid Nerd Font" "Hasklig" "Cascadia Code PL" "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)) '(; Interesting idea: "Iosevka Comfy Motion Duo" "XCharter" ; https://fontesk.com/xcharter-typeface/ "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" "Source Sans Pro" "Lucida Grande" "Verdana" "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 18)) (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 14)) (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 '(("!?" . "‽") ("->" . ?→) ("<-" . ?←) ("=>" . ?⇒))) (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 :tangle no ;; set font for symbols (set-fontset-font t 'symbol (cond ((string-equal system-type "darwin") (cond ((member "Apple Symbols" (font-family-list)) "Apple Symbols"))) ((string-equal system-type "gnu/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 Note, in Doom, is appears we have a =ligatures= module. We'll start using that instead, but changing it in [[file:general-programming.org][general-programming]] file. * 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:nil todo:nil tasks:nil tags:nil date:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js