#+TITLE: My literate GNU Emacs config #+AUTHOR: Marius Peter #+DATE: <2020-07-23 Thu> #+STARTUP: showall customtime #+SETUPFILE: ~/.emacs.d/templates/documents/personal.org #+INCLUDE: ~/.emacs.d/templates/documents/personal.org_title \begin{abstract} GNU Emacs is most often used as a text editor. The utmost level of customisation is afforded by enabling the user to rewrite \textit{any} part of the source code and observe the editor's modified behaviour in real time. Since its inception in 1984, GNU Emacs has grown to be much more than a full-featured, high-productivity text editor---new \textit{modes} have been written to interact with hundreds of file formats, including \texttt{.txt}, \texttt{.pdf}, \texttt{.jpg}, \texttt{.csv}, and \texttt{.zip} just to name a few. This configuration file itself was written in \textit{Org mode}, a collection of functions enabling the harmonious mixing of code and comments in view of publication: this is the endgame of \textit{literate programming}. \end{abstract} # * Test # #+BEGIN_SRC emacs-lisp # (org-babel-load-file "~/.emacs.d/blendoit/test.org") # #+END_SRC * README :PROPERTIES: :UNNUMBERED: t :END: The =README.org= was exported from the first section of my literate configuration file, [[file:blendoit-init.org]]. * Document structure :PROPERTIES: :UNNUMBERED: t :END: ** Blending Linux and Windows The GNU Emacs cabal is attempting to create a complete OS out of a text editor. Microsoft has a notorious /embrace, extend, extinguish/ approach when it comes to rival technologies. Both are simultaneously possible. * TODO First-time setup Spacemacs-like dialog for default settings. #+NAME: first-setup #+BEGIN_SRC emacs-lisp ;; Prompt enterprise or personal install. Create file in .emacs.d/ on Linux, ;; AppData/ on Windows. Ask user for details and preferred bindings. #+END_SRC * Early setup ** Garbage collection First, we increase the RAM threshold beyond which the garbage collector is activated. #+NAME: garbage-collection #+BEGIN_SRC emacs-lisp (setq gc-cons-threshold 100000000) #+END_SRC ** Emacs client Makes opening emacs faster for following instances. #+NAME: emacs-client #+BEGIN_SRC emacs-lisp ; (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*"))) #+END_SRC ** Refresh configuration Add an ~after-save-hook~ that tangles and loads this literary configuration. # #+NAME: emacs-client # #+BEGIN_SRC emacs-lisp # (defun my/tangle-and-load-blendoit-init() # (org-babel-load-file "~/.emacs.d/blendoit/blendoit-init.org") # ) # (add-hook 'after-save-hook 'my/tangle-and-load-blendoit-init) # (my/tangle-and-load-blendoit-init) # #+END_SRC ** Custom file Load settings created automatically by GNU Emacs Custom. (For example, any clickable option/toggle is saved here.) Useful for fooling around with M-x customize-group . #+NAME: custom-file-location #+BEGIN_SRC emacs-lisp (setq custom-file "~/.emacs.d/init-custom.el") (load custom-file) #+END_SRC ** Profiling --- start We start the profiler now , and will interrupt it in section [[Profiling --- stop]]. We will then present profiling report in section [[Profiling --- report]]. #+NAME: profiler-start #+BEGIN_SRC emacs-lisp ; (profiler-start) #+END_SRC ** Customization shortcuts We begin by defining a user shortcut to this very file: #+NAME: shortcut-config #+BEGIN_SRC emacs-lisp (defun find-init-blendoit () "Jump to this very file." (interactive) (find-file "~/.emacs.d/blendoit/blendoit-init.org")) (global-set-key (kbd "C-c c") 'find-init-blendoit) #+END_SRC Now, different shortcuts for other customization actions: #+NAME: shortcuts-customization #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-c v") 'customize-variable) (global-set-key (kbd "C-c f") 'customize-face) #+END_SRC ** Backups Backups are so important that they should be described right after the shortcut to this file. #+BEGIN_SRC emacs-lisp (setq backup-directory-alist `((".*" . ,temporary-file-directory)) auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) backup-by-copying t ; Don't delink hardlinks version-control t ; Use version numbers on backups delete-old-versions t ; Automatically delete excess backups kept-new-versions 20 ; how many of the newest versions to keep kept-old-versions 5 ; and how many of the old ) #+END_SRC ** Secrets #+INCLUDE: ./secrets.org #+BEGIN_SRC emacs-lisp (setq user-full-name "Marius Peter" user-mail-address "blendoit@gmail.com") #+END_SRC ** File system paths In this subsection, we tell Emacs about relevant paths to resources. On my Windows machine, I add the path to Portable Git.[fn::Download from https://git-scm.com/download/win] #+BEGIN_SRC emacs-lisp (if (string-equal system-type "windows-nt") (add-to-list 'exec-path "C:/Users/marius.peter/PortableGit/bin/")) #+END_SRC * Global key bindings The following bindings strive to further enhance CUA[fn::Common User Access.] mode. ** Navigation #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-`") 'delete-other-windows) (global-set-key (kbd "C-s") 'save-buffer) (global-set-key (kbd "C-b") 'ibuffer-sidebar-toggle-sidebar) (global-set-key (kbd "C-o") 'menu-find-file-existing) (global-set-key (kbd "C-r") 'counsel-recentf) ; (global-set-key (kbd "C-n") 'make-frame) ; 7aram! #+END_SRC The following bindings lead to more natural exit behaviors. #+BEGIN_SRC emacs-lisp (defun delete-window-or-previous-buffer () "Delete window; if sole window, previous buffer." (interactive) (if (> (length (window-list)) 2) (delete-window) (previous-buffer))) (global-set-key (kbd "C-w") 'delete-window-or-previous-buffer) (global-set-key (kbd "C-q") 'save-buffers-kill-terminal) #+END_SRC ** Mouse zoom The typical binding on both GNU/Linux and MS Windows is adequate here: ~C-=~ to zoom, ~C--~ to unzoom. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C--") 'text-scale-decrease) (global-set-key (kbd "C-=") 'text-scale-increase) (global-set-key (kbd "C-+") 'text-scale-increase) #+END_SRC * Packages Packages are collections of =.el= files providing added functionality to Emacs. ** Package archives List of package archives. #+NAME: packages #+BEGIN_SRC emacs-lisp (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t) (package-initialize) #+END_SRC ** ~use-package~ Ensure =use-package= is installed, as well as all packages described in this configuration file. #+BEGIN_SRC emacs-lisp (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package) (eval-when-compile (require 'use-package))) (setq use-package-always-ensure t) #+END_SRC ** TODO Convenient package update One-function rollup of upgradeable package tagging, download and lazy install. ** ~ivy~ Auto completion. #+BEGIN_SRC emacs-lisp (use-package ivy :config (setq ivy-use-virtual-buffers t ivy-count-format "%d/%d " enable-recursive-minibuffers t)) (ivy-mode t) #+END_SRC *** ~counsel~ Wonderful counsellor! #+BEGIN_SRC emacs-lisp (use-package counsel :bind ("M-x" . counsel-M-x) :config (counsel-mode t)) (global-set-key (kbd "C-f") 'counsel-grep-or-swiper) #+END_SRC *** ~swiper~ #+BEGIN_SRC emacs-lisp (use-package swiper :bind (("C-f" . counsel-grep-or-swiper))) #+END_SRC ** ~evil-mode~ Forgive me, for I have sinned. #+BEGIN_SRC emacs-lisp (use-package evil) ;; (evil-mode 1) #+END_SRC ** ~org-mode~ Phew, I can finally introduce Org mode! I am so *excited*. Org mode replaces aword processor, a presentation creator, and a spreadsheet editor. IMHO, the spreadsheet ability captures more than 80% use cases wherein one wishes to include a table in a text document destined for physical publication. (It is clear that Excel spreadsheets are /not/ destined for physical publication---simply attempt to print an Excel spreadsheet with the default settings.) In my opinion, Org mode matches all /useful/ features of the Microsoft Office suite 1-to-1. What follows are customizations designed to make Org mode behave more like Microsoft Word. The end goal is, once again, to draw as many new users to Emacs as possible! *** Basic customization Org base directory is in user home on GNU/Linux, or in =AppData= in MS Windows. #+NAME: org-basic #+BEGIN_SRC emacs-lisp (setq org-directory "~/org") #+END_SRC First, we hide markup symbols for *bold*, /italic/, _underlined_ and +strikethrough+ text, and ensure our document appears indented upon loading:[fn::It /appears/ indented, but the underlying plaintext file does not contain tab characters!] #+NAME: org-basic #+BEGIN_SRC emacs-lisp (setq org-hide-emphasis-markers t) (setq org-startup-indented t) #+END_SRC Then, we customize Org headings to emulate WYSIWYG[fn::What You See Is What You Get (input and output are identical), as opposed to What You See Is What You Mean (the input contains instructions that can modify the output).] behavior normally found in Word: #+NAME: org-list-bullets #+BEGIN_SRC emacs-lisp (font-lock-add-keywords 'org-mode '(("^ *\\([-]\\) " (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))) #+END_SRC - Look at - This beautifully indented - List... - Of lists! - (Rendered with pretty bullets in Emacs) *** Org-bullets The following prettifies Org mode heading bullets: # #+NAME: org-heading-bullets # #+BEGIN_SRC emacs-lisp # (use-package org-bullets # :hook # (org-mode . org-bullets-mode) # ) # #+END_SRC *** Invisible edits #+BEGIN_SRC emacs-lisp (setq org-catch-invisible-edits t) #+END_SRC *** Agenda The agenda displays a chronological list of headings across all agenda files for which the heading or body contain a matching =org-time-stamp=.[fn::An =org-time-stamp= can be inserted with =C-c .= (period)] #+BEGIN_SRC emacs-lisp (global-set-key (kbd "C-c a") 'org-agenda-list) #+END_SRC *** Timestamps More literary timestamps are exported to LaTeX using the following custom format: #+BEGIN_SRC emacs-lisp (setq org-time-stamp-custom-formats '("%d %b, %Y (%a)" . "%d %b, %Y (%a), at %H:%M")) #+END_SRC *** LaTeX export The following makes =CLOSED= items appear green in LaTeX. Very stylish, much flair! #+BEGIN_SRC emacs-lisp (setq org-latex-inactive-timestamp-format "\\textcolor{ForestGreen!60}{\\textit{%s}}") #+END_SRC *** Publish In the following /alist/ (association list), we describe the projects publishable via =org-publish=. We separate the publishing of =.org= files and attachments, because an online tutorial recommended we do so. #+BEGIN_SRC emacs-lisp (require 'ox-publish) (setq org-publish-project-alist '( ("Safran-VIP-html" :base-directory "~/org/WORK/Safran/programs/B787/VIP/doc/org/" :base-extension "org" :publishing-directory "~/org/WORK/Safran/programs/B787/VIP/doc/wiki/" :recursive t :publishing-function org-html-publish-to-html :auto-preamble t :auto-sitemap t :sitemap-title "" ) ("Safran-VIP-static" :base-directory "~/org/WORK/Safran/programs/B787/VIP/doc/org/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|mp4\\|ogg\\|swf" :publishing-directory "~/org/WORK/Safran/programs/B787/VIP/doc/wiki/" :recursive t :publishing-function org-publish-attachment ) ("Safran-VIP-all" :components ("Safran-VIP-html" "Safran-VIP-static")) ("Safran-MA700-html" :base-directory "~/org/WORK/Safran/programs/MA700/doc/org/" :base-extension "org" :publishing-directory "~/org/WORK/Safran/programs/MA700/doc/wiki/" :recursive t :publishing-function org-html-publish-to-html :auto-preamble t :auto-sitemap t :sitemap-title "" ) ("Safran-MA700-static" :base-directory "~/org/WORK/Safran/programs/MA700/doc/org/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|mp4\\|ogg\\|swf" :publishing-directory "~/org/WORK/Safran/programs/MA700/doc/wiki/" :recursive t :publishing-function org-publish-attachment ) ("Safran-MA700-all" :components ("Safran-MA700-html" "Safran-MA700-static")))) (add-to-list 'org-latex-packages-alist '("table" "xcolor" t ("pdflatex"))) (add-to-list 'org-latex-packages-alist '("AUTO" "babel" t ("pdflatex"))) (add-to-list 'org-latex-packages-alist '("AUTO" "polyglossia" t ("xelatex" "lualatex"))) #+END_SRC *** Export This creates a shorter binding for the most common Org export: Org \rightarrow LaTeX \rightarrow PDF. #+BEGIN_SRC emacs-lisp (defun blendoit-org-quick-export () "Org export to PDF and open. This basically reimplements `C-c C-e l o'." (interactive) (org-latex-export-to-pdf) (org-open-file (concat (substring buffer-file-truename 0 -3) "pdf"))) (global-set-key (kbd "C-c e") 'blendoit-org-quick-export) #+END_SRC ** ~undo-tree~ #+BEGIN_SRC emacs-lisp (global-undo-tree-mode) #+END_SRC ** ~dumb-jump~ #+BEGIN_SRC emacs-lisp (use-package dumb-jump) (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) #+END_SRC ** gnuplot #+BEGIN_SRC emacs-lisp (use-package gnuplot) #+END_SRC ** Ledger #+BEGIN_SRC emacs-lisp (use-package ledger-mode :bind ("C-c r" . ledger-report) ("C-c C" . ledger-mode-clean-buffer)) #+END_SRC ** ibuffer-sidebar #+BEGIN_SRC emacs-lisp (use-package ibuffer-sidebar) (ibuffer-sidebar-show-sidebar) ; :bind ("mouse-1" . ibuffer-mouse-visit-buffer) ; :bind ("mouse-3" . ibuffer-mouse-toggle-mark)) ; (add-hook 'ibuffer-sidebar-mode-hook ; (lambda () ; (local-unset-key (quote mouse-1)) ; (local-unset-key (quote mouse-2)) ; (local-set-key (quote mouse-1) (quote ibuffer-mouse-visit-buffer)) ; (local-set-key (quote mouse-2) (quote ibuffer-mouse-toggle-mark)))) #+END_SRC ** Which-key #+BEGIN_SRC emacs-lisp (use-package which-key :init (which-key-mode) ;; :config ;; (setq which-key-idle-delay 1000) ;; (setq which-key-idle-secondary-delay 0.05) ;; (setq which-key-show-early-on-C-h t) ) #+END_SRC ** Company #+NAME: company #+BEGIN_SRC emacs-lisp ; (add-hook 'after-init-hook 'global-company-mode) #+END_SRC ** Flycheck #+NAME: flycheck #+BEGIN_SRC emacs-lisp (use-package flycheck :init (global-flycheck-mode)) #+END_SRC ** CSV #+BEGIN_SRC emacs-lisp (use-package csv-mode) #+END_SRC ** JSON Oí, Jason! #+BEGIN_SRC emacs-lisp (use-package json-mode) #+END_SRC ** Magit #+BEGIN_SRC emacs-lisp (use-package magit :bind ("C-c g" . magit-status)) #+END_SRC ** PDF-tools #+BEGIN_SRC emacs-lisp (use-package pdf-tools) ;; (pdf-tools-install) #+END_SRC ** Dashboard We replace the standard welcome screen with our own. #+BEGIN_SRC emacs-lisp (setq inhibit-startup-message t) (use-package dashboard :config (dashboard-setup-startup-hook) (setq dashboard-startup-banner "~/.emacs.d/blendoit/img/Safran_logo.svg") (setq dashboard-items '((recents . 5) (projects . 5))) (setq dashboard-banner-logo-title "A modern professional text editor.")) #+END_SRC ** rainbow This highlights hexadecimal numbers which look like colors, in that same color. #+BEGIN_SRC emacs-lisp (use-package rainbow-mode :ensure t :init (add-hook 'prog-mode-hook 'rainbow-mode)) #+END_SRC ** Projectile This enables us to better manage our =.git= projects. #+BEGIN_SRC emacs-lisp (use-package projectile :bind ("C-c p" . 'projectile-command-map) :init (projectile-mode 1) (setq projectile-completion-system 'ivy)) #+END_SRC ** Better parentheses #+BEGIN_SRC emacs-lisp (show-paren-mode 1) (use-package smartparens :config (add-hook 'prog-mode-hook #'smartparens-mode)) (use-package rainbow-delimiters :config (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)) #+END_SRC * Cosmetics ** Faces & cursors In order to imitate other modern text editors, we'll resort to a blinking bar cursor. We choose red, the most captivating color, because the cursor is arguably the region on our screen: 1. most often looked at; 2. most often searched when lost. The default cursor already blinks. *** Default cursor In files containing only fixed-pitch fonts (i.e. files containing only code), the cursor becomes a high-visibility box. #+BEGIN_SRC emacs-lisp (setq-default cursor-type (quote box)) #+END_SRC *** Mixed pitch in Org mode Fixed-pitch and variable-pitch fonts will be used intelligently in all hooked modes. #+BEGIN_SRC emacs-lisp (use-package mixed-pitch :hook ((org-mode . mixed-pitch-mode) (Info-mode . mixed-pitch-mode))) #+END_SRC ** Initial frame These settings affect the first and subsequent frames spawned by Emacs in GNU/Linux. Frame transparency increases when focus is lost. #+BEGIN_SRC emacs-lisp ; (if (and (display-graphic-p) (string-equal system-type "gnu/linux")) ; ((set-frame-parameter (selected-frame) 'alpha '(85 . 50)) ; (add-to-list 'default-frame-alist '(alpha . (85 . 50))))) #+END_SRC ** Theme #+BEGIN_SRC emacs-lisp (setq custom-theme-directory "~/.emacs.d/blendoit/themes/") (load-theme 'blendoit-light) #+END_SRC ** All the icons #+BEGIN_SRC emacs-lisp (use-package all-the-icons) #+END_SRC * Editing preferences These customizations enhance editor usability. A line of text is considered `filled' when it reaches 79 characters in length. #+BEGIN_SRC emacs-lisp (setq-default fill-column 79) #+END_SRC We replace the longer ~yes-or-no-p~ questions with more convenient ~y-or-n-p~. #+BEGIN_SRC emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+END_SRC Disable minibuffer scroll bar. #+BEGIN_SRC emacs-lisp (set-window-scroll-bars (minibuffer-window) nil nil) ; (set-window-scroll-bars (ibuffer-sidebar-window) nil nil) #+END_SRC ** Clean up menus Originally, I wished to inhibit certain entries in the GUI menus. Not worth the effort at this time. ~menu-bar-mode~ is inhibited if on Linux. #+BEGIN_SRC emacs-lisp (setq menu-bar-mode t) #+END_SRC ** Coding standards This is just a better default. #+BEGIN_SRC emacs-lisp (setq c-default-style "linux" c-basic-offset 4) #+END_SRC ** Dividers This ensures users can resize windows using the GUI. #+BEGIN_SRC emacs-lisp (menu-bar-bottom-and-right-window-divider) #+END_SRC ** Tabs #+BEGIN_SRC emacs-lisp #+END_SRC ** ~auto-fill~ Automatically break lines longer than =fill-column=. #+BEGIN_SRC emacs-lisp (add-hook 'org-mode-hook 'turn-on-auto-fill) #+END_SRC ** Recent files #+BEGIN_SRC emacs-lisp (recentf-mode 1) (setq recentf-max-menu-items 25) (setq recentf-max-saved-items 25) (run-at-time nil (* 5 60) 'recentf-save-list) #+END_SRC * Late setup ** Profiling --- stop #+BEGIN_SRC emacs-lisp ;; (profiler-stop) #+END_SRC ** Profiling --- report #+BEGIN_SRC emacs-lisp ;; (profiler-report) #+END_SRC * Conclusion In this configuration file, we described a series of customization steps taken to make Emacs more palatable to modern IDE users.