#+TITLE: Start Screen #+AUTHOR: Howard Abrams #+DATE: 2022-11-02 #+FILETAGS: :emacs: A literate programming file for configuring Emacs to show a startup screen. #+begin_src emacs-lisp :exports none ;;; ha-dashboard --- show a startup screen. -*- lexical-binding: t; -*- ;; ;; © 2022-2023 Howard Abrams ;; Licensed under a Creative Commons Attribution 4.0 International License. ;; See http://creativecommons.org/licenses/by/4.0/ ;; ;; Author: Howard Abrams ;; Maintainer: Howard Abrams ;; Created: November 2, 2022 ;; ;; While obvious, GNU Emacs does not include this file or project. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: ;; /Users/howard/other/hamacs/ha-dashboard.org ;; And tangle the file to recreate this one. ;; ;;; Code: #+end_src * Left Side ** Dad Jokes! The /critical part/ of my dashboard, is the [[https://icanhazdadjoke.com/][Dad Joke]] function, a =curl= call to a web service: #+begin_src sh curl -sH "Accept: text/plain" https://icanhazdadjoke.com/ #+end_src For this, I use the [[https://github.com/tkf/emacs-request][request]] package (and I’ll use this elsewhere too) and the =dashboard= project (defined below) will incorporate it: #+begin_src emacs-lisp (use-package request :init (defvar ha-dad-joke nil "Holds the latest dad joke.") :config (defun ha-dad-joke () "Display a random dad joke." (interactive) (message (ha--dad-joke))) (defun ha--dad-joke () "Return string containing a dad joke from www.icanhazdadjoke.com." (setq ha-dad-joke nil) ; Clear out old joke (ha--dad-joke-request) (ha--dad-joke-wait)) (defun ha--dad-joke-wait () (while (not ha-dad-joke) (sit-for 1)) (unless ha-dad-joke (ha--dad-joke-wait)) ha-dad-joke) (defun ha--dad-joke-request () (request "https://icanhazdadjoke.com" :sync t :complete (cl-function (lambda (&key data &allow-other-keys) (setq ha-dad-joke data)))))) #+end_src ** Dashboard The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] project makes a nicer startup screen. #+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))) (setq dashboard-footer-messages (list (ha--dad-joke))) :config (dashboard-setup-startup-hook) ;; Real shame that :config is incompatible with :hook, otherwise: ;; :hook (dashboard-after-initialize . ha-dashboard) (add-hook 'dashboard-after-initialize-hook 'ha-dashboard)) #+end_src This dashboard project 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 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 * Right Side On the right side should show a list of keybindings or other hints that I want to work on memorizing. ** Cheatsheet Lots of things to learn and keep straight. Let’s try the [[https://github.com/mykyta-shyrin/cheatsheet][cheatsheet.el]] project. #+begin_src emacs-lisp (use-package cheatsheet :config (cheatsheet-add-group 'Text-Objects '(:key "w" :description "word") '(:key "s" :description "sentence") '(:key "p" :description "paragraph") '(:key "l" :description "line") '(:key "o" :description "symbol") '(:key "a" :description "argument") '(:key "g" :description "s-exp") '(:key "'" :description "string") '(:key "d" :description "function") '(:key "j" :description "smaller indent block") '(:key "k" :description "larger indent block") '(:key "i" :description "indented block") '(:key "c" :description "comment")) (cheatsheet-add-group 'Symbols '(:key "(" :description "h d ... jump start s-expression") '(:key ")" :description "h f ... jump to end s-expression") '(:key "{" :description "h e ... forward expression") '(:key "}" :description "h r ... backward expression") '(:key "[" :description "h c ... backward expression") '(:key "]" :description "h v ... forward expression") '(:key "@" :description "h w ... play macro") '(:key "!" :description "h q ... shell command") '(:key "#" :description "h a ... reverse search (not `n')") '(:key "^" :description "h x ... start of line") '(:key "$" :description "h s ... end of line") '(:key "%" :description "h z ... jump paren start/end") '(:key "~" :description "h b ... change case") '(:key "`" :description "h g ... jump to mark. See `m'") '(:key "|" :description "h t ... goto column. Number prefix") ) (cheatsheet-add-group 'G '(:key "g ;" :description "goto last change") '(:key "g ," :description "return from last change") '(:key "g ." :description "goto definition") '(:key "g >" :description "goto definition other window") '(:key "g ," :description "return definition stack") '(:key "g <" :description "go forward (like definition)") '(:key "g /" :description "find references") '(:key "g ?" :description "find references and replace") '(:key "g h" :description "find apropos with LSP") '(:key "g d" :description "goto definition ... g b to go back") '(:key "g w" :description "fill to object, g q to fill and move") '(:key "g c" :description "comment line") '(:key "g e" :description "go backward word end") '(:key "g s" :description "visual search for line") '(:key "g r" :description "search for symbol (SPC s j/k)"))) #+end_src ** Learn This Simple function to display a file in the top-right corner (if the file exists): #+begin_src emacs-lisp (defun ha-show-learn-this () "" (interactive) (let ((filename "~/other/hamacs/learn-this.org") (curr-win (get-buffer-window (buffer-name)))) (when (file-exists-p filename) (split-window-below 15) (select-window curr-win) (find-file filename)))) #+end_src * Altogether The =dashboard= project hooks to [[help:emacs-startup-hook][emacs-startup-hook]] and this =ha-dashboard= function hooks to dashboard’s [[help:dashboard-after-initialize-hook][dashboard-after-initialize-hook]]: #+begin_src emacs-lisp (defun ha-dashboard () "Shows the extra stuff with the dashboard." (interactive) (let ((width (thread-first (window-total-width) (/ 3) (* 2)))) (split-window-right width) (cheatsheet-show) (ha-show-learn-this))) #+end_src * Technical Artifacts :noexport: Let's =provide= a name so we can =require= this file: #+begin_src emacs-lisp :exports none (provide 'ha-dashboard) ;;; ha-dashboard.el ends here #+end_src #+DESCRIPTION: configuring Emacs to show a startup screen. #+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