#+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-2022 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 * Dashboard The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] project makes a nicer startup screen. It requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project): #+begin_src emacs-lisp (use-package page-break-lines) #+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 #+begin_src emacs-lisp (use-package dashboard :init (defun ha-dashboard-version () (let ((smaller-version (replace-regexp-in-string (rx " (" (zero-or-more any) eol) "" (emacs-version)))) (string-replace "\n" "" smaller-version))) (setq dashboard-banner-logo-title (format "Emacs %s ⸺ %s" (if (and (fboundp 'native-comp-available-p) (native-comp-available-p)) "with Native Compilation" "") (ha-dashboard-version)) dashboard-startup-banner "~/other/hamacs/support/levitating-gnu.png" dashboard-center-content t dashboard-set-init-info t dashboard-projects-switch-function 'projectile-persp-switch-project dashboard-items '((projects . 5) ;; (agenda . 5) (bookmarks . 5))) :config (dashboard-setup-startup-hook) (setq dashboard-footer-messages (list (ha--dad-joke)))) #+end_src I would appreciate seeing if my Emacs installation has the features that I expect: #+begin_src emacs-lisp (defun ha-hamacs-features (&optional iconic) "Simple display of features I'm most keen about. If ICONIC is non-nil, return a string of icons." (interactive) (let* ((png-icon (all-the-icons-material "image")) (svg-icon (all-the-icons-alltheicon "svg")) (tls-icon (all-the-icons-faicon "expeditedssl")) (json-icon (all-the-icons-fileicon "jsx")) (mag-icon (all-the-icons-faicon "magic")) (jit-icon (all-the-icons-faicon "cog")) (results (s-join " " (list (when (and (fboundp 'native-comp-available-p) (native-comp-available-p)) (if iconic jit-icon "Native-Compilation")) (when (image-type-available-p 'svg) (if iconic svg-icon "SVG")) (when (image-type-available-p 'png) (if iconic png-icon "PNG")) (when (gnutls-available-p) (if iconic tls-icon "TLS")) (when (json-available-p) (if iconic json-icon "JSON")) (when (fboundp 'imagemagick-types) (if iconic mag-icon "ImageMagick")))))) (if (called-interactively-p) (message "Enabled features: %s" results) results))) #+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 (:type git :protocol ssh :host gitlab :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 forward-page backward-page scroll-up-command scroll-down-command windmove-right windmove-left windmove-up windmove-down windmove-swap-states-right windmove-swap-states-left windmove-swap-states-up windmove-swap-states-down 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 :tangle no (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/: | Similarities | Regular | |--------------+----------------------------| | ()[]{}<>«»‹› | ABCDEFGHIJKLMNOPQRSTUVWXYZ | | 6bB8& | abcdefghijklmnopqrstuvwxyz | | 0ODdoaoOQGC | 0123456789 | | I1tilIJL | ~!@#$%^&*+ | | !¡ij | `'"‘’“”.,;:… | | 5$§SsS5 | ()[]{}—-_=<>/\ | | 17ZzZ2 | ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ | | 9gqpG6 | αβγδεζηθικλμνξοπρστυφχψω | | hnmMN | | | uvvwWuuwvy | | | x×X | #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"; | | ... | | 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 (they usually are): #+begin_src emacs-lisp (defvar ha-fixed-font (when window-system (cond ((x-list-fonts "Hack Nerd Font") "Hack Nerd Font") ((x-list-fonts "Cousine Nerd Font") "Cousine Nerd Font") ((x-list-fonts "Iosevka Nerd Font") "Iosevka Nerd Font") ((x-list-fonts "Iosevka") "Iosevka") ((x-list-fonts "FantasqueSansMono Nerd Font") "FantasqueSansMono Nerd Font") ((x-list-fonts "Monoid Nerd Font") "Monoid Nerd Font") ((x-list-fonts "Hasklig") "Hasklig") ((x-list-fonts "Cascadia Code PL") "Cascadia Code PL") ((x-list-fonts "Source Code Pro") "Source Code Pro") ((x-list-fonts "Anonymous Pro") "Anonymous Pro") (t "monospaced"))) "My fixed width font based on what is installed, `nil' if not defined.") #+end_src Force something as well: #+begin_src emacs-lisp :tangle no (setq ha-fixed-font "Hack Nerd Font") #+end_src I probably don't need to have such a ranking system, as chances are really good that I'll have all of them installed. Still. #+begin_src emacs-lisp (defvar ha-variable-font (when window-system (cond ((x-list-fonts "Overpass") "Overpass") ((x-list-fonts "Source Sans Pro") "Source Sans Pro") ((x-list-fonts "Lucida Grande") "Lucida Grande") ((x-list-fonts "Verdana") "Verdana") ((x-family-fonts "Sans Serif") "Sans Serif") (nil (warn "Cannot find a Sans Serif Font. Install Source Sans Pro.")))) "My variable width font available to org-mode files and whatnot.") #+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 16)) (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) (global-set-key (kbd "s-0") 'font-size-monitor-default) (global-set-key (kbd "s-9") 'font-size-laptop-default) #+end_src * Emojis, Icons and Whatnot Display these two symbols as one: #+begin_src emacs-lisp (add-hook 'text-mode-hook (lambda () (push '("!?" . "‽") prettify-symbols-alist))) #+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