Emacs

Emacs is a Lisp (LISt Processing language) interpreter written in Emacs Lisp. An introduction to programming in Emacs Lisp is provied by the Free Software Foundation (FSF).

There are many good resources to get started with Emacs. Sash Chuha compiles a list of news on her blog and sends them as a y to the emacs-tangents email list. David Wilson has created an Elisp video introduction series.

Use ielm to interactively write Elisp. With ielm can you use C-j to evaluate the sexp following the prompt. Use RET to insert a newline and indent. M-RET works like RET but doesn't print the evaluated input. Use C-M-i to complete lisp symbols or filenames within strings.

Installation

To get Emacs+ on MacOS do download with Homebrew. Can for example use this:

brew uninstall emacs-plus@29 && brew install emacs-plus@29 --with-dbus --with-mailutils --with-no-frame-refocus --with-imagemagic --with-native-comp

This will also uninstall the current version of emacs before installing the new version.

Startup

Eveything done in Emacs is eventually loaded into the Emacs environment. The startup time is dependent on how much is loaded into Emacs on startup.

Elisp syntax

In Elisp are all spaces ignored and the parenthases are use as the delimiters. The syntax is composed of lists, symbols and values.

defun is a macro used to define functions, which, in this case, takes one parameter ("answer") as input.

(defun the-meaning-of-life (answer)
  (message "the answer is %s" answer))

Call the newly created function.

(setq answer 42)
(the-meaning-of-life answer) ;; the answer is 42
(the-meaning-of-life '"the question") ;; the answer is the question

setq is a special form of set.

nil vs t

The symbol nil has three separate meanings:

  1. it is a symbol with the name ‘nil’
  2. it is the logical truth value false
  3. and it is the empty list—the list of zero elements.

When nil is used as a variable it always has the value nil. As far as the Lisp reader is concerned, ‘()’ and ‘nil’ are identical: they stand for the same object, the symbol nil. The different ways of writing the symbol are intended entirely for human readers. After the Lisp reader has read either ‘()’ or ‘nil’, there is no way to determine which representation was actually written by the programmer.

In contexts where a truth value is expected, any non-nil value is considered to be true. However, t is the preferred way to represent the truth value true. When you need to choose a value that represents true, and there is no other basis for choosing, use t. The symbol t always has the value t.

In Emacs Lisp, nil and t are special symbols that always evaluate to themselves. This is so that you do not need to quote them to use them as constants in a program. An attempt to change their values results in a setting-constant error.

Profiling

gc-cons-threshold is the number of bytes of consing between garbage collections. The emacs-startup-hook is run after loading init files.

(setq gc-cons-threshold (* 50 1000 1000))

(add-hook 'emacs-startup-hook
          (lambda ()
            (message "*** Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

Quote Symbol: Use the quote symbol (') infront of "something", when emacs should treat it literally (when it should not be evaluated).

Package System Setup

defvar is used to define a global variable.

The is the "normal" version.

(require 'package)

(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))

(package-initialize)
(unless package-archive-contents
  (package-refresh-contents))

Straight

This version is with straight.

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

; (setq straight-use-package-by-default t)  ; Only use if I want to use straight all the time.

Use-package

Use use-package to configure setup and installation of packages.

(unless (package-installed-p 'use-package)
  (package-install 'use-package))

(require 'use-package)
(setq use-package-always-ensure t)

(use-package diminish :ensure t :after use-package)
(use-package bind-key :ensure t :after use-package)
(use-package delight :ensure t :after use-package)

Repeat

Do use repeat-mode. See It bears repeating for ideas.

(repeat-mode 1)

UI Configuration

Clean up the UI and make the visual bell (ring-bell-function) less annoying by only flashing the modeline in a subtle way.

(menu-bar-mode -1)
(tool-bar-mode -1)
(toggle-scroll-bar -1)
(global-hl-line-mode 1)
(global-visual-line-mode 1)
(setq-default initial-scratch-message nil)
(setq inhibit-startup-screen t
      visible-bell t
      disabled-command-function nil)

(setq ring-bell-function
      (lambda ()
        (let ((orig-fg (face-foreground 'mode-line)))
          (set-face-foreground 'mode-line "#F2804F")
          (run-with-idle-timer 0.1 nil
                               (lambda (fg) (set-face-foreground 'mode-line fg))
                               orig-fg))))

(set-face-attribute 'default nil :font "JetBrains Mono" :weight 'light :height 155)
(set-face-attribute 'fixed-pitch nil :font "JetBrains Mono" :weight 'light :height 150)
(set-face-attribute 'variable-pitch nil :font "Source Sans Pro" :weight 'light :height 110)

(global-display-line-numbers-mode t)
(dolist (mode '(org-mode-hook  ; Don't show line numbers for these modes.
                term-mode-hook
                eshell-mode-hook
                shell-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0))))

(setq-default fill-column 120)

Configure the UI to be smoother and snappier.

(setq confirm-kill-processes nil)
(setq use-short-answers t)
(show-paren-mode t)

Modeline

Reduce clutter in the modeline with diminish.

(use-package diminish
  :config
  (diminish 'abbrev-mode)
  (diminish 'flycheck-mode)
  (diminish 'eldoc-mode))

Theme

Set the modus vivendi theme.

(setq modus-themes-mode-line '(accented borderless)
      modus-themes-region '(bg-only)
      modus-themes-completions '((matches . (extrabold underline))
                                 (selection . (semibold italic)))
      modus-themes-bold-constructs t
      modus-themes-italic-constructs t
      modus-themes-paren-match '(bold intense)
      modus-themes-syntax '(green-strings yellow-comments)
      modus-themes-headings '((1 . (rainbow 1.5))
                              (2 . (rainbow 1.4))
                              (3 . (rainbow 1.3))
                              (4 . (rainbow 1.2))
                              (t . (monochrome 1.1)))
      modus-themes-scale-headings t
      modus-themes-org-blocks 'tinted-background)

(load-theme 'modus-vivendi t)

Scale Text

Scale text and add repeat map.

(global-set-key (kbd "C-c t s i") 'text-scale-increase)
(global-set-key (kbd "C-c t s d") 'text-scale-decrease)
(global-set-key (kbd "C-c t s s") 'text-scale-map)


(defvar text-scale-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "i") #'text-scale-increase)
    (define-key map (kbd "d") #'text-scale-decrease)
   map))

(dolist (cmd '(text-scale-increase text-scale-decrease))
  (put cmd 'repeat-map 'text-scale-map))

Rainbow delimiters

rainbow-delimiters makes it more obvious which delimiters belong together by assigning different colors to them.

(use-package rainbow-delimiters
  :diminish rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

prog-mode is the programming mode which represents all the modes used for programming.

All the icons

Use All the icons to get icons. To install the icons do M-x all-the-icons-install-fonts.

(use-package all-the-icons)
(propertize (all-the-icons-octicon "package")
            'face `(:family ,(all-the-icons-octicon-family) :height 1.2)
            'display '(raise -0.1))

Which-key

which-key is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.

(use-package which-key
  :init (which-key-mode)
  :diminish which-key-mode
  :config
  (setq which-key-idle-delay 0.3))

Vertico

Vertico provides streamlined interface for minibuffer completions. Vertico is using Emacs' own completion engine but provides it's own UI.

(use-package vertico
  :init
  (vertico-mode)
  :bind (:map vertico-map
              ("C-a" . vertico-first)
              ("C-e" . vertico-exit)
              ("C-f" . vertico-flat-mode)
              ("C-i" . vertico-insert)
              ("C-j" . vertico-next)
              ("C-k" . vertico-previous)
              ("C-l" . vertico-last)
              ("C-r" . vertico-repeat)
              ("C-s" . vertico-save)
              :map minibuffer-local-map
              ("M-h" . backward-kill-word))
  :custom
  (vertico-cycle t))

Savehist

Persists history over Emacs restarts.

(use-package savehist
  :init
  (savehist-mode))

Marginalia

Marginalia.el provides more information in the completion buffer.

(use-package marginalia
  :init
  (marginalia-mode)
  :after vertico
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))

Helpful

Helpful makes help more helpful by providing contextual information.

(use-package helpful
  :bind
  ("C-h f" . helpful-callable)
  ("C-h v" . helpful-variable)
  ("C-h k" . helpful-key)
  ("C-c d" . helpful-at-point)
  ("C-h F" . helpful-function)
  ("C-h C" . helpful-command))

Window management

Use C-x r w a to save the selected fram's windows in register "a". Use C-x r f a to save the state of all frames into register "a". Use C-x r j a to restore the state of all frames into register "a".

Move windows with winmove commands and use repeat.el for easier navigation.

(defvar window-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "b") #'switch-to-buffer)
    (define-key map (kbd "d") #'kill-current-buffer)
    (define-key map (kbd "f") #'find-file)
    (define-key map (kbd "F") #'project-switch-project)
    (define-key map (kbd "h") #'windmove-left)
    (define-key map (kbd "H") #'windmove-swap-states-left)
    (define-key map (kbd "l") #'windmove-right)
    (define-key map (kbd "L") #'windmove-swap-states-right)
    (define-key map (kbd "k") #'windmove-up)
    (define-key map (kbd "K") #'windmove-swap-states-up)
    (define-key map (kbd "j") #'windmove-down)
    (define-key map (kbd "J") #'windmove-swap-states-down)
    (define-key map (kbd "o") #'other-frame)
    (define-key map (kbd "s") #'isearch-forward)
    (define-key map (kbd "S") #'ripgrep-regexp)
    (define-key map (kbd "w") #'split-window-right)
    (define-key map (kbd "W") #'split-window-below)
    (define-key map (kbd "å") #'winner-undo)
    (define-key map (kbd "Å") #'winner-redo)
    (define-key map (kbd "0") #'delete-window)
    map))

(dolist (cmd '(delete-window kill-current-buffer other-frame split-window-below split-window-right windmove-left windmove-swap-states-left windmove-right windmove-swap-states-right windmove-up windmove-swap-states-up windmove-down windmove-swap-states-down winner-redo winner-undo))
  (put cmd 'repeat-map 'window-repeat-map))

Winner-mode

(use-package winner
  :bind
  ("M-å" . winner-undo)
  ("M-Å" . winner-redo)
  :config
  (winner-mode 1))

Current Window Only

Current window only by FrostyX.

(use-package current-window-only
  :straight (current-window-only
             :type git
             :host github
             :repo "FrostyX/current-window-only")
  :config
  (current-window-only-mode))

Editing

When editing files do auto-revert the buffer it has changed on disk. However if there are unsaved changes in the buffer, then prompt to save them first.

Also clear up extra whitespace and tell Emacs not to use two spaces to end a sentence.

(global-auto-revert-mode 1)
(add-hook 'before-save-hook #'whitespace-cleanup)
(setq-default sentence-end-double-space nil)

Character encoding

Setting utf-8 as default encoding.

(set-language-environment "UTF-8")

(prefer-coding-system 'utf-8)

(setq coding-system-for-read 'utf-8
      coding-system-for-write 'utf-8)

(set-default-coding-systems 'utf-8-unix)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)

(setq default-buffer-file-coding-system 'utf-8
      x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))

Mac customisations

Some adjustments for working on the mac.

(setq mac-option-modifier nil
      mac-right-option-modifier 'meta
      mac-command-modifier 'meta
      mac-right-command-modifier 'control
      mac-control-modifier 'command)

Global key bindings

The following key bindings will be available in all modes.

(defun wyper/insert-zero-width-space()
  (interactive)
  (insert-char ?\u200B))

(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
(global-set-key (kbd "M-H") 'hippie-expand)
(global-set-key (kbd "M-q") 'kill-current-buffer)
(global-set-key (kbd "M-ä") 'wyper/insert-zero-width-space)
(global-set-key [f1] 'eshell)
(global-set-key [f9] 'toggle-truncate-lines)
(global-set-key [f12] 'global-visual-line-mode)

Search

Adding repeat for search.

(defvar isearch-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "s") #'isearch-repeat-forward)
    (define-key map (kbd "r") #'isearch-repeat-backward)
    map))

(dolist (cmd '(isearch-repeat-forward isearch-repeat-backward))
  (put cmd 'repeat-map 'isearch-repeat-map))

Save cursor position

Move to last position in a buffer when accessing it after the first time.

(require 'saveplace
  :init (save-place-mode))

Tabs as spaces

For tangling of Python source code from org-babel do we need to remove the mix of tabs and spaces in the tangled output. The setq-default indent-tabs-mode nil takes care of not inserting tabs intermixed with the spaces.

(setq-default indent-tabs-mode nil)

EvilMode

(use-package evil
  :init
  (setq evil-want-integration t)
  (setq evil-want-keybinding nil)
  :config
  (evil-mode 1)
  (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state)
  (define-key evil-insert-state-map (kbd "C-h") 'evil-delete-backward-char-and-join)
  (evil-global-set-key 'motion "j" 'evil-next-visual-line)  ; Enable use of visual line motions even outside of visual-line mode buffers.
  (evil-global-set-key 'motion "k" 'evil-previous-visual-line)
  (evil-set-initial-state 'messages-buffer-mode 'normal)
  (evil-set-initial-state 'dashboard-mode 'normal)
  (evil-set-leader 'normal (kbd "SPC"))
  (evil-define-key 'normal 'global
    (kbd "<leader>ae") 'org-ai-explain-code
    (kbd "<leader>ap") 'org-ai-prompt
    (kbd "<leader>ar") 'org-ai-on-region
    (kbd "<leader>aR") 'org-ai-refactor-code
    (kbd "<leader>as") 'org-ai-summarize
    (kbd "<leader>er") 'eglot-rename
    (kbd "<leader>f") 'project-find-file
    (kbd "<leader>F") 'project-switch-project
    (kbd "<leader>op") 'org-present
    (kbd "<leader>ti") 'text-scale-increase
    (kbd "<leader>td") 'text-scale-decrease
    (kbd "<leader>tm") 'modus-themes-toggle
    (kbd "<leader>ts") 'ispell
    (kbd "<leader>w0") 'delete-window
    (kbd "<leader>wh") 'windmove-left
    (kbd "<leader>wH") 'windmove-swap-states-left
    (kbd "<leader>wj") 'windmove-down
    (kbd "<leader>wJ") 'windmove-swap-states-down
    (kbd "<leader>wk") 'windmove-up
    (kbd "<leader>wK") 'windmove-swap-states-up
    (kbd "<leader>wl") 'windmove-right
    (kbd "<leader>wL") 'windmove-swap-states-right
    (kbd "<leader>wo") 'other-frame
    (kbd "<leader>ww") 'split-window-right
    (kbd "<leader>wW") 'split-window-below
    (kbd "<leader>xb") 'xwidget-webkit-back
    (kbd "<leader>xg") 'xwidget-webkit-browse-url))

(use-package evil-collection
  :after evil
  :diminish evil-collection-unimpaired-mode
  :config
  (evil-collection-init))

Spelling

(use-package ispell
  :init
  (setq ispell-program-name "/opt/homebrew/Cellar/aspell/0.60.8.1_1/bin/aspell"))

Completions

Hippie expand

(use-package hippie-exp
  :bind ([remap dabbrev-expand] . hippie-expand)
  :commands (hippie-expand)
  :config
  (setq hippie-expand-try-functions-list
        '(try-expand-line
          try-expand-dabbrev
          try-expand-dabbrev-all-buffers
          try-expand-dabbrev-from-kill
          try-complete-lisp-symbol-partially
          try-complete-lisp-symbol
          try-complete-file-name
          try-expand-all-abbrevs
          try-expand-list)))

Corfu

Corfu enhances completion at point with a small completion popup.

(use-package corfu
  :custom
  (corfu-cycle t)
  (corfu-auto t)
  (corfu-auto-prefix 2)
  (corfu-auto-delay 0.0)
  (corfu-quit-at-boundary 'separator)
  (corfu-echo-documentation 1.25)
  (corfu-preview-current 'insert)
  (corfu-preselect-first nil)
  :bind (:map corfu-map
              ("S-SPC" . corfu-insert-separator)
              ("RET" . nil)
              ("TAB" . corfu-next)
              ([tab] . corfu-next)
              ("S-TAB" . corfu-previous)
              ([backtab] . corfu-previous)
              ("S-<return>" . corfu-insert))
  :init
  (global-corfu-mode)
  (corfu-history-mode)
  (corfu-popupinfo-mode) ; Popup completion info
  :config
  (add-hook 'eshell-mode-hook
            (lambda () (setq-local corfu-quit-at-boundary t
                              corfu-quit-no-match t
                              corfu-auto nil)
              (corfu-mode))))

Cape

Cape provides Completion At Point Extensions which can be used in combination with the Corfu completion UI or the default completion UI.

(use-package cape
  :defer 10
  :bind ("C-c f" . cape-file)
  :init
  ;; Add `completion-at-point-functions', used by `completion-at-point'.
  (defalias 'dabbrev-after-2 (cape-capf-prefix-length #'cape-dabbrev 2))
  (add-to-list 'completion-at-point-functions 'dabbrev-after-2 t)
  (cl-pushnew #'cape-file completion-at-point-functions)
  :config
  ;; Silence then pcomplete capf, no errors or messages!
  (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)

  ;; Ensure that pcomplete does not write to the buffer
  ;; and behaves as a pure `completion-at-point-function'.
  (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify))

Embark

Embark allows the user to jump to definitions, navigate lists, retrieve recently visited locations, and manipulate buffer content with ease. It also offers powerful completion mechanisms that eliminate the need to remember complicated keystrokes or arguments. With Embark can you quickly find and interact with the data and functions, without having to navigate through menus or use multiple Emacs commands.

(use-package embark
  :init
  (setq prefix-help-command #'embark-prefix-help-command)
  :bind
  ("C-." . embark-act)
  ("M-." . embark-dwim)
  ("C-h B" . embark-bindings))

Macros

(fset 'Ledger
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([24 6 1 11 126 47 68 111 99 117 109 101 110 116 115 47 46 108 101 100 103 101 114 47 103 114 111 110 46 108 101 100 103 101 114 return] 0 "%d")) arg)))

PIM

org-mode is an Emacs mode for working with text files to provide personal information management functionalities.

(use-package org
  :config
  (setq org-startup-folded t
        org-ellipsis " ▾"
        org-adapt-indentation nil
        org-agenda-start-with-log-mode t
        org-agenda-todo-ignore-scheduled 'future
        org-agenda-tags-todo-honor-ignore-options t))

Faces

(require 'org-faces)
(dolist (face '((org-level-1 . 1.4)
                  (org-level-2 . 1.3)
                  (org-level-3 . 1.2)
                  (org-level-4 . 1.1)
                  (org-level-5 . 1.1)
                  (org-level-6 . 1.1)
                  (org-level-7 . 1.1)
                  (org-level-8 . 1.1))))

(set-face-attribute 'org-block nil :foreground 'unspecified :inherit 'fixed-pitch)
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
(set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
(set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
(set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
(set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
(set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch)

Navigating org-mode

(defvar org-nav-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "b") #'org-backward-heading-same-level)
    (define-key map (kbd "f") #'org-forward-heading-same-level)
    (define-key map (kbd "n") #'org-next-visible-heading)
    (define-key map (kbd "p") #'org-previous-visible-heading)
   map))

(dolist (cmd '(org-backward-heading-same-level org-forward-heading-same-level org-next-visible-heading org-previous-visible-heading))
  (put cmd 'repeat-map 'org-nav-map))

Todos and Tags

Use list-colors-display to get a list of available colors.

(setq org-todo-keywords
      '((sequence "TODO(t)" "|" "DONE(d@/!)")
        (sequence "DELEGATED(D@/!)" "WAITING(w@/!)" "|" "CANCELED(c@/!)")))
(setq org-todo-keyword-faces
      '(("TODO" . "brown3")
        ("DELEGATED" . "DodgerBlue2")
        ("WAITING" . "firebrick1")
        ("DONE" . "green3")
        ("CANCELED" . "PaleGreen3")))
(setq org-highest-priority ?A)  ;Priorities
(setq org-default-priority ?C)
(setq org-lowest-priority ?E)
(setq org-priority-faces '((?A . (:foreground "firebrick1"))
                           (?B . (:foreground "yellow"))
                           (?C . (:foreground "gold"))
                           (?D . (:foreground "orange"))
                           (?E . (:foreground "pink"))))
(require 'org-habit)
(add-to-list 'org-modules 'org-habit)
(setq org-habit-graph-column 60)

(setq org-tag-alist
      '(("@anywhere" .?a)
        ("@errand" .?e)
        ("@home" .?h)
        ("@work" .?w)
        ("LG" .?l)
        ("Pekka" .?p)))
(setq org-use-tag-inheritance nil)

Tables

Do org-table-export to export a table. Use C-c ^ to sort a table (org-sort).

(setq org-startup-shrink-all-tables t)

(defun dfeich/org-export-delete-commented-cols (back-end)
  "Delete columns $2 to $> marked as `<#>' on a row with `/' in $1. If you want a non-empty column $1 to be deleted make it $2 by inserting an empty column before and adding `/' in $1."
  (while (re-search-forward "^[ \t]*| +/ +|\\(.*|\\)? +\\(<#>\\) *|" nil t)
    (goto-char (match-beginning 2))
    (org-table-delete-column)
    (beginning-of-line)))
    (add-hook 'org-export-before-processing-hook #'dfeich/org-export-delete-commented-cols)

Using special characters like the pipe | character does not work well in org-mode tables. To come around this do use the "Org entity" version of writing the same symbol. You can find a reference to the symbols you can use under org-entites-help.

Column View

Use the before-save-hook to update all dblocks.

(add-hook 'before-save-hook 'org-update-all-dblocks)

(defun org-dblock-write:block-update-time (params)
  (let ((fmt (or (plist-get params :format) "%d. %m. %Y")))
    (insert "Last block update at: "
            (format-time-string fmt))))

Diary

Update the diary with sexp entries.

(defun diary-sunrise ()
  (let ((dss (diary-sunrise-sunset)))
    (with-temp-buffer
      (insert dss)
      (goto-char (point-min))
      (while (re-search-forward " ([^)]*)" nil t)
        (replace-match "" nil nil))
      (goto-char (point-min))
      (search-forward ",")
      (buffer-substring (point-min) (match-beginning 0)))))

(defun diary-sunset ()
  (let ((dss (diary-sunrise-sunset))
        start end)
    (with-temp-buffer
      (insert dss)
      (goto-char (point-min))
      (while (re-search-forward " ([^)]*)" nil t)
        (replace-match "" nil nil))
      (goto-char (point-min))
      (search-forward ", ")
      (setq start (match-end 0))
      (search-forward " at")
      (setq end (match-beginning 0))
      (goto-char start)
      (capitalize-word 1)
      (buffer-substring start end))))

(setq calendar-latitude 60.1785)
(setq calendar-longitude 19.9156)
(setq calendar-location-name "Mariehamn")
(display-time)
(setq diary-file "~/Documents/org/kalender")
(setq org-agenda-include-diary t)  ; Include the diary in the agenda.

Org capture

Org-mode capture template and template expansion.

(setq org-capture-templates
      '(("c" "CBS")
        ("i" "Inbox" entry (file "~/Documents/emacs.org") "* TODO %?\n  %i\n  %a")
        ("l" "Latest" entry (file+headline "~/Documents/ref/index.org" "Latest News") "* %T\n %?")))

Agenda views

Which column shows TODO progress in org-mode?

[AI]: In org-mode, the TODO progress is typically shown in the "TODO" column. This column indicates the status or progress of each item in the outline hierarchy. By default, the TODO column is displayed on the right side of the buffer, but you can customize its position using the `org-columns-default-format` variable.

[ME]:

(setq org-agenda-custom-commands
      '(("h" "Project Hax"
         ((tags "hax" ((org-agenda-sorting-strategy '(alpha-up)))))
         ((org-agenda-files (append org-agenda-files org-agenda-files-hax))
          (org-agenda-view-columns-initially t)
          (org-agenda-compact-blocks t)
          (org-agenda-overriding-header "Hax")
          (org-overriding-columns-format "%ITEM(Source) %FILE(in File) %TODO(Todo) %LANGUAGE(Lang)")))
        ("k" "Komp"
         ((org-agenda-list 1)
          (tags "+TODO=\"WAITING\"+SCHEDULED=\"\"")
          (tags "+TODO=\"TODO\"+SCHEDULED=\"\"" ((org-agenda-sorting-strategy '(priority-down deadline-up))))
          (todo "DELEGATED")
          (todo "BACKLOG")
          (tags "+TODO=\"WAITING\"-SCHEDULED=\"\"" ((org-agenda-sorting-strategy '(priority-down scheduled-up)))))
         ((org-agenda-files (append org-agenda-files org-agenda-files-cbs org-agenda-files-hax))
          (org-agenda-view-columns-initially t)
          (org-agenda-compact-blocks t)
          (org-agenda-overriding-header "")
          (org-agenda-overriding-columns-format "%60ITEM(Item) %TODO(Status) %PRIORITY(P)")))
        ("r" "Time Report"
         ((org-agenda-list 1))
         ((org-agenda-files (append org-agenda-files org-agenda-files-cbs))
          (org-agenda-view-columns-initially t)
          (org-agenda-compact-blocks t)
          (org-agenda-overriding-columns-format "%40ITEM(Task) %5EASIT(Easit) %CLOCKSUM(Spent Time) %EFFORT(Estimated Time){:} %14DEADLINE(Due) %4CUSTOM_ID(ID)")
          (org-agenda-clockreport-mode t)))
        ("w" . "With")
        ("wg" "LG"
         ((tags "LG" ((org-agenda-sorting-strategy '(deadline-up priority-down)))))
         ((org-agenda-files (append org-agenda-files org-agenda-files-cbs))
          (org-agenda-view-columns-initially t)
          (org-agenda-compact-blocks t)
          (org-agenda-overriding-header "")
          (org-agenda-overriding-columns-format "%35ITEM(Todo) %TODO(Status) %PRIORITY(P) %EFFORT(ETC) %CLOCKSUM(Time Spent) %14SCHEDULED(Scheduled) %14DEADLINE(Deadline) %4CUSTOM_ID(ID)")))
        ("wp" "Pekka"
         ((tags "Pekka" ((org-agenda-sorting-strategy '(deadline-up priority-down)))))
         ((org-agenda-files (append org-agenda-files org-agenda-files-cbs))
          (org-agenda-view-columns-initially t)
          (org-agenda-compact-blocks t)
          (org-agenda-overriding-header "")
          (org-agenda-overriding-columns-format "%35ITEM(Todo) %TODO(Status) %PRIORITY(P) %EFFORT(ETC) %CLOCKSUM(Time Spent) %14SCHEDULED(Scheduled) %14DEADLINE(Deadline) %4CUSTOM_ID(ID)")))))

Export

Export options.

(setq org-export-backends '(ascii html icalendar latex md))

Ledger

(use-package ledger-mode)

(autoload 'ledger-mode "ledger-mode" "A major mode for Ledger" t)
(add-to-list 'load-path
             (expand-file-name "/opt/homebrew/Cellar/ledger/3.3.2_1/share/ledger/"))
(add-to-list 'auto-mode-alist '("\\.ledger$" . ledger-mode))

AI Integration

Org-AI

With org-ai can you add a #+begin_ai block followed by a #+end_ai block in the question or request for image (:image) in between. To specify a system prompt, write ([SYS]:) on the first input line. This will "prime" the models answer. If you want to get variations of an image do use the command org-ai-image-variation. To see your openai usage there is a shortcut to open the openai/usage page with command org-ai-open-account-usage-page.

Text prompt options:

  • :max-tokens [number] : specify maximum number of tokens, like :max-tokens 250
  • :temperature [number] : temperature of the model (default: 1)
  • :top-p [number] : topp of the model (default: 1)
  • :frequency-penalty [number] : frequency penalty of the model (default: 0)
  • :presence-penalty [number] : presence penalty of the model (default: 0)
  • :sys-everywhere : repeat the system prompt for every user message (default: nil)

Image prompt options (when :image has been added to the ai block.

  • :size [number]x[number] : number in pixels. Possible options are 256x256, 512x512 or 1024x1024.
  • :n : the number of images to generate (default: 1)
(use-package org-ai
  :diminish org-ai-mode
  :commands (org-ai-mode)
  :custom
  (org-ai-openai-api-token API_TOKEN)
  :init
  (add-hook 'org-mode-hook #'org-ai-mode)
  :config
  (setq org-ai-image-directory "~/Pictures/OpenAI/"))

The following custom variables can be used to configure the chat:

  • org-ai-default-chat-model : (default: "gpt-3.5-turbo")
  • org-ai-default-max-tokens : How long the response should be. Currently cannot exceed 4096. If this value is too small an answer might be cut off (default: nil)
  • org-ai-default-chat-system-prompt : How to "prime" the model. This is a prompt that is injected before the user's input. (default: "You are a helpful assistant inside Emacs.")
  • org-ai-default-inject-sys-prompt-for-all-messages : Wether to repeat the system prompt for every user message. Sometimes the model "forgets" how it was primed. This can help remind it. (default: nil)

The following custom variables can be used to configure the DALL-E (image generation):

  • org-ai-image-directory : where to store the generated images (default: ~/org/org-ai-images/)

File Managment

Backups

(setq make-backup-files nil)
(setq auto-save-default nil)

Dired

(use-package dired
  :ensure nil
  :commands (dired dired-jump)
  :bind (("C-x C-j" . dired-jump))
  :config
  (evil-collection-define-key 'normal 'dired-mode-map
    "h" 'dired-single-up-directory
    "l" 'dired-single-buffer))

(use-package dired-single
  :commands (dired dired-jump))

(use-package all-the-icons-dired
  :hook (dired-mode . all-the-icons-dired-mode))

(use-package dired-open
  :config
  (setq dired-open-extensions '(("doc" . "start winword")
                                ("docx" . "start winword")
                                ("mkv" . "mpv")
                                ("pptx" . "start powerpnt")
                                ("xlsx" . "start excel"))))

; Fix keymap
(define-key dired-jump-map (kbd "j") nil)
(define-key dired-jump-map (kbd "C-j") nil)

Openwith

Use openwith to open files with external applications.

(use-package openwith
  :config
  (setq openwith-associations
        (list
         (list (openwith-make-extension-regexp '("bmp" "pbm" "pgm" "pnm" "ppm" "tif" "xbm")) "open -a \"/Applications/Gimp-2.10.app\"" '(file))
         (list (openwith-make-extension-regexp '("xls" "xlsm" "xlsx" "xltm" "xltx")) "open -a \"/Applications/Microsoft Excel.app\"" '(file))
         (list (openwith-make-extension-regexp '("one")) "open -a \"/Applications/Microsoft OneNote.app\"" '(file))
         (list (openwith-make-extension-regexp '("pps" "ppsx" "ppt" "pptx")) "open -a \"/Applications/Microsoft PowerPoint.app\"" '(file))
         (list (openwith-make-extension-regexp '("doc" "docm" "docx" "dotx")) "open -a \"/Applications/Microsoft Word.app\"" '(file))
         (list (openwith-make-extension-regexp '("dvi" "pdf" "ps" "ps.gz")) "open -a \"/Applications/PDF Expert.app\"" '(file))
         (list (openwith-make-extension-regexp '("m4a" "mpg" "mpeg" "mp3" "mp4" "avi" "wmv" "wav" "mov" "flv" "ogm" "ogg" "mkv")) "open -a \"quicktime player\"" '(file))))
  (openwith-mode t))

Terminals

All external interactive shells in emacs are derived from comint-mode.

term

Specify a function for term-mode to open in zsh shell.

(defun wyper-send-via-tmux (command)
  (message (concat "running: " command))
  (call-process "/usr/local/bin/tmux" nil nil nil "send-keys" "-t 0" command "C-m"))

(defun tz ()
  (interactive)
  (split-window-right)
  (other-window 1)
  (switch-to-buffer "*Messages*")
  (split-window-below)
  (term "/bin/zsh")
  (rename-buffer "jupyter"))
;  (call-process "/usr/local/bin/tmux" nil nil nil "send-keys" "-t jupyter" "cd && jupyter-lab" "C-m"))

(defun tzt ()
  (interactive)
  (term "/bin/zsh")
  (rename-buffer "terminal"))

eshell

  • Send output of command on to a buffer with : echo "hello" #<buffer test-buffer>.
  • Save command history when commands are entered.
  • Truncate buffer for performance.
  • Bind some useful keys for evil-mode.
(defun wyper/configure-eshell ()
  (add-hook 'eshell-pre-command-hook 'eshell-save-some-history)
  (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer)
  (evil-define-key '(normal insert visual) eshell-mode-map (kbd "<home>") 'eshell-bol)
  (evil-normalize-keymaps)
  (setq eshell-history-size 10000
        eshell-buffer-maximum-lines 10000
        eshell-hist-ignoredups t
        eshell-scroll-to-bottom-on-input t))

(use-package eshell
  :hook (eshell-first-time-mode . wyper/configure-eshell)
  :config
  (with-eval-after-load 'esh-opt
    (setq eshell-destroy-buffer-when-process-dies t)
    (setq eshell-visual-commands '("htop" "zsh" "vim"))))

Prompt with eshell-prompt-extras. Requires that virtualenvwrapper is installed with python (pip install virtualenvwrapper).

(use-package virtualenvwrapper)
(use-package eshell-prompt-extras)

(with-eval-after-load "esh-opt"
  (require 'virtualenvwrapper)
  (venv-initialize-eshell)
  (autoload 'epe-theme-lambda "eshell-prompt-extras")
  (setq eshell-highlight-prompt nil
        eshell-prompt-function 'epe-theme-lambda))

Development

Start with fixing path on MacOS.

(use-package exec-path-from-shell)
(when (memq window-system '(mac ns x))
  (exec-path-from-shell-initialize))

Languages

Applescript

(use-package applescript-mode)

CSV

(use-package csv-mode
  :config
  (setq csv-separators '("," ";" "^")))

HTML

(use-package rainbow-mode)

(use-package htmlize)

CSS

(use-package css-mode
  :mode "\\.css\\'")

Json

Json-mode

(use-package flymake-json
  :hook 'json-mode-hook 'flymake-json-load)

(use-package json-mode)

JavaScript

(use-package js)

Markdown

(use-package markdown-mode
    :ensure t)

Python

Set up environment for Python with pyenv.

(setq python-indent-offset 4)

(use-package pyvenv
  :demand t
  :init
  (setenv "WORKON_HOME" "~/.pyenv/versions"))

(defun wyper/set-python-env ()
  (interactive)
  (pyvenv-workon "3.12.0/"))

(wyper/set-python-env)

Use IPython as interpreter.

(setq python-shell-interpreter "ipython"
        python-shell-interpreter-args "-i --simple-prompt --InteractiveShell.display_page=True")

Rust

On MacOS, get hold of rust-analyzer with homebrew through brew install rust-analyzer.

(use-package rustic
  :ensure
  :bind (:map rustic-mode-map
              ("M-j" . lsp-ui-imenu)
              ("M-?" . lsp-find-references)
              ("C-c C-c l" . flycheck-list-errors)
              ("C-c C-c a" . lsp-execute-code-action)
              ("C-c C-c r" . lsp-rename)
              ("C-c C-c q" . lsp-workspace-restart)
              ("C-c C-c Q" . lsp-workspace-shutdown)
              ("C-c C-c s" . lsp-rust-analyzer-status))
  :config
  ;; uncomment for less flashiness
  ;; (setq lsp-eldoc-hook nil)
  ;; (setq lsp-enable-symbol-highlighting nil)
  ;; (setq lsp-signature-auto-activate nil)

  ;; comment to disable rustfmt on save
  (setq rustic-format-on-save t)
  (add-hook 'rustic-mode-hook 'rk/rustic-mode-hook))

(defun rk/rustic-mode-hook ()
  ;; so that run C-c C-c C-r works without having to confirm, but don't try to
  ;; save rust buffers that are not file visiting. Once
  ;; https://github.com/brotzeit/rustic/issues/253 has been resolved this should
  ;; no longer be necessary.
  (when buffer-file-name
    (setq-local buffer-save-without-query t))
  (add-hook 'before-save-hook 'lsp-format-buffer nil t))

SQL

(use-package ob-sql-mode)

Swift

Use swift-mode.

  • Run Swift REPL in a buffer M-x run-swift.
  • Build Swift module M-x swift-mode:build-swift-module.
  • Build iOS app M-x swift-mode:build-ios-app.
  • Running debugger on Swift module M-x swift-mode:debug-swift-module.
  • Running debugger on iOS app in simulator or device M-x swift-mode:debug-ios-app ios-deploy is required to debug on device.
(use-package swift-mode
  :hook (swift-mode . (lambda () (lsp))))

(use-package lsp-sourcekit
  :after lsp-mode
  ;:after eglot
  :config
  (setq lsp-sourcekit-executable "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp"))

(use-package ob-swift)

(use-package flycheck-swift)
(eval-after-load 'flycheck '(flycheck-swift-setup))

(use-package lsp-mode
  :hook (swift-mode . lsp-deferred)
  :commands (lsp lsp-deferred))

Yaml

(use-package yaml-mode)
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))

Treesitter

Install treesitter languages with M-x treesit-install-language-grammar.

(setq treesit-language-source-alist
   '((bash "https://github.com/tree-sitter/tree-sitter-bash")
     (cmake "https://github.com/uyha/tree-sitter-cmake")
     (css "https://github.com/tree-sitter/tree-sitter-css")
     (elisp "https://github.com/Wilfred/tree-sitter-elisp")
     (go "https://github.com/tree-sitter/tree-sitter-go")
     (html "https://github.com/tree-sitter/tree-sitter-html")
     ; (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
     (json "https://github.com/tree-sitter/tree-sitter-json")
     (make "https://github.com/alemuller/tree-sitter-make")
     (markdown "https://github.com/ikatyang/tree-sitter-markdown")
     (python "https://github.com/tree-sitter/tree-sitter-python")
     (rust "https://github.com/tree-sitter/tree-sitter-rust")
     (swift "https://github.com/alex-pinkus/tree-sitter-swift")
     (toml "https://github.com/tree-sitter/tree-sitter-toml")
     (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
     (yaml "https://github.com/ikatyang/tree-sitter-yaml")))

Remap the major modes to point to the treesitter modes.

(setq major-mode-remap-alist
      '((yaml-mode . yaml-ts-mode)
        (bash-mode . bash-ts-mode)
        (css-mode . css-ts-mode)
        (js2-mode . js-ts-mode)
        (json-mode . json-ts-mode)
        (python-mode . python-ts-mode)
        (typescript-mode . typescript-ts-mode)))

Eglot

Use eglot as language server.

(use-package eglot
  :ensure t
  :defer t
  :bind (:map eglot-mode-map
              ("C-c C-d" . eldoc)
              ("C-c C-e" . eglot-rename)
              ("C-c C-o" . python-sort-imports)
              ("C-c C-f" . eglot-format-buffer))
  :hook ((python-ts-mode . eglot-ensure)
         (python-ts-mode . superword-mode)
         (python-ts-mode . hs-minor-mode)
         (python-ts-mode . (lambda () (set-fill-column 120))))
  :config
  (setq-default eglot-workspace-configuration
                '((:pylsp . (:configurationSources ["flake8"]
                             :plugins (
                                       :pycodestyle (:enabled :json-false)
                                       :mccabe (:enabled :json-false)
                                       :pyflakes (:enabled :json-false)
                                       :flake8 (:enabled :json-false
                                                :maxLineLength 120)
                                       :ruff (:enabled t
                                              :lineLength 120)
                                       :pydocstyle (:enabled t
                                                    :convention "numpy")
                                       :yapf (:enabled :json-false)
                                       :autopep8 (:enabled :json-false)
                                       :black (:enabled t
                                               :line_length 120
                                               :cache_config t)))))))

Copilot

(use-package copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :ensure t
  :config
  (add-hook 'prog-mode-hook 'copilot-mode)
  (add-hook 'org-mode 'copilot-mode)
  (define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion)
  (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion))

Source Control

(use-package magit
  :commands (magit-status magit-get-current-branch)  ;Don't load magit until one of these commands are called
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))

Project

(use-package project
  :bind (:map project-prefix-map
("R" . project-forget-project)))

Ripgrep

(use-package rg)
(global-set-key (kbd "M-s r") 'rg)

Docker

Docker file mode.

(use-package dockerfile-mode)
(put 'dockerfile-image-name 'safe-local-variable #'stringp)
(setq dockerfile-mode-command "docker")

Kubernetes

Kubel and youtube talk.

(use-package kubel-evil
  :after (vterm)
  :config (kubel-vterm-setup))

Org Babel

  • :mkdirp yes : Use to create folders if they don't already exist.
  • noweb : take a value from one block and uses in another block
    • use #+NAME: name : to refer to the block
  • If you want to use these , or , or #+ or ,#+ inside of a code block then you have to escape them with a ",".
  • A example source code block can also be started with a ":".
  • Make a tangled file executable with :tangle-mode (identity #o755)
  • There are also these source code blocks: center”, “comment”, “dynamic”, “example”, “export”, “quote”, “special”, and “verse”
  • Python Soure Code Blocks in Org Mode
(setq org-babel-python-command "python3")

(org-babel-do-load-languages  ;Babel - language support
 'org-babel-load-languages
 '((emacs-lisp . t)
   (plantuml . t)
   (python . t)
   (sql . t)
   (sqlite . t)
   (swift . t)))

(push '("conf-unix" . conf-unix) org-src-lang-modes)

(setq org-src-preserve-indentation t)  ; Fix indent.

(setq org-confirm-babel-evaluate nil)  ;Don't ask before running code

(require 'org-tempo)  ;Add these to org-mode source block list
(add-to-list 'org-structure-template-alist '("ai" . "ai"))
(add-to-list 'org-structure-template-alist '("ap" . "src applescript"))
(add-to-list 'org-structure-template-alist '("css" . "src css"))
(add-to-list 'org-structure-template-alist '("co" . "src conf-unix"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("html" . "src html"))
(add-to-list 'org-structure-template-alist '("js" . "src js"))
(add-to-list 'org-structure-template-alist '("json" . "src json"))
(add-to-list 'org-structure-template-alist '("p" . "src python"))
(add-to-list 'org-structure-template-alist '("pn" . "src python :eval no"))
(add-to-list 'org-structure-template-alist '("rs" . "src rust"))
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("sql" . "src sql-mode"))
(add-to-list 'org-structure-template-alist '("sw" . "src swift"))
(add-to-list 'org-structure-template-alist '("swn" . "src swift :eval no"))
(add-to-list 'org-structure-template-alist '("uml" . "src plantuml"))
(add-to-list 'org-structure-template-alist '("xml" . "src xml"))
(add-to-list 'org-structure-template-alist '("xslt" . "src xml"))
(add-to-list 'org-structure-template-alist '("yml" . "src yaml"))

Mail

mu4e

(global-set-key [M-f12] 'mu4e)

(setq mue4e-headers-skip-duplicates t mu4e-view-show-images t mu4e-view-show-addresses t mu4e-compose-format-flowed nil mu4e-date-format "%y-%m-%d" mu4e-headers-date-format "%Y-%m-%d" mu4e-change-filenames-when-moving t mu4e-attachments-dir "~/Desktop"

mu4e-maildir "~/Mail" ;; top-level Maildir ;; note that these folders below must start with / ;; the paths are relative to maildir root mu4e-refile-folder "/Archive" mu4e-sent-folder "/Sent Items" mu4e-drafts-folder "/Drafts" mu4e-trash-folder "/Trash")

;; this setting allows to re-sync and re-index mail ;; by pressing U (setq mu4e-get-mail-command "mbsync -a")

Send Mail

(setq smtpmail-default-smtp-server "mail.hover.com" smtpmail-local-domain "hover.com") (load-library "smtpmail") (setq send-mail-function 'smtpmail-send-it) (setq send-mail-function 'smtpmail-send-it smtpmail-smtp-server "mail.hover.com" smtpmail-stream-type 'ssl smtpmail-smtp-service 587)

Presenting

HTML

Make sure to use CSS defined by myself when using htmlize.

(setq org-html-htmlize-output-type 'inline-css)

HTML macro replacement

Defining some common macro replacements for HTML.

(setq org-export-global-macros
  '(("b" . "@@html:<strong>@@$1@@html:</strong>@@")
    ("br" . "@@html:<br />@@")
    ("code" . "@@html:<code>@@$1@@html:</code>@@")
    ("em" . "@@html:<font color=\"red\">@@")
    ("hr" . "@@html:<hr>@@")
    ("ol1" . "@@html:<ol><li>@@$1@@html:</li></ol>@@")
    ("ol2" . "@@html:<ol><li>@@$1@@html:</li><li>@@$2@@html:</li></ol>@@")
    ("ol3" . "@@html:<ol><li>@@$1@@html:</li><li>@@$2@@html:</li><li>@@$3@@html:</li></ol>@@")
    ("ol4" . "@@html:<ol><li>@@$1@@html:</li><li>@@$2@@html:</li><li>@@$3@@html:</li><li>@@$4@@html:</li></ol>@@")
    ("ul1" . "@@html:<ul><li>@@$1@@html:</li></ul>@@")
    ("ul2" . "@@html:<ul><li>@@$1@@html:</li><li>@@$2@@html:</li></ul>@@")
    ("ul3" . "@@html:<ul><li>@@$1@@html:</li><li>@@$2@@html:</li><li>@@$3@@html:</li></ul>@@")
    ("ul4" . "@@html:<ul><li>@@$1@@html:</li><li>@@$2@@html:</li><li>@@$3@@html:</li><li>@@$4@@html:</li></ul>@@")))

Latex

Inserting in-line quoted with @ symbols:

Code embedded in-line @@latex:any arbitrary LaTeX code@@ in a paragraph.

Inserting as one or more keyword lines in the Org file:

#+LATEX: any arbitrary LaTeX code

Inserting as an export block in the Org file, where the back-end exports any code between begin and end markers:

#+BEGIN_EXPORT latex
  any arbitrary LaTeX code
#+END_EXPORT
(with-eval-after-load 'ox-latex
  (add-to-list 'org-latex-classes
               '("CrosskeyFSD"
                 "\\documentclass{article}
\\usepackage{xcolor}")
               '("bjmarticle"
                 "\\documentclass{article}
\\usepackage[utf8]{inputenc}
\\usepackage[T1]{fontenc}
\\usepackage{graphicx}
\\usepackage{longtable}
\\usepackage{hyperref}
\\usepackage{natbib}
\\usepackage{amssymb}
\\usepackage{amsmath}
\\usepackage{geometry}
\\geometry{a4paper,left=2.5cm,top=2cm,right=2.5cm,bottom=2cm,marginparsep=7pt, marginparwidth=.6in}"
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}" . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))

Presentations

System Crafters have put together a way of working with org-present, which is used below. The only difference to the code David is using is the in the function wyper/ord-present-end in how the changes to the "faces" are reset.

Visual fill column mode enables centering of the column on the screen.

(use-package visual-fill-column)
(setq visual-fill-column-width 160)
(setq visual-fill-column-center-text t)

Org-present is a minimalist presentation tool for Emacs org-mode. Simply layout your presentation with each slide under a top-level header, start the minor mode with 'org-present', and page through each slide with left/right keys.

(defun wyper/org-present-prepare-slide (buffer-name heading)
  ;; Show only top-level headlines
  (org-overview)

  ;; Unfold the current entry
  (org-show-entry)

  ;; Show only direct subheadings of the slide but don't expand them
  (org-show-children))

(defun wyper/org-present-start ()
  (setq-local face-remapping-alist '((default (:height 2.4) variable-pitch)
                                     (header-line (:height 5.0) variable-pitch)
                                     (org-document-title (:height 2.00) org-document-title)
                                     (org-code (:height 1.55) org-code)
                                     (org-verbatim (:height 1.75) org-verbatim)
                                     (org-block (:height 1.35) org-block)
                                     (org-block-begin-line (:height 0.7) org-block)))
  (setq header-line-format " ")
  (setq-local visual-fill-column-width 160)
  (setq-local visual-fill-column-center-text t)
  (visual-fill-column-mode 1)
  (visual-line-mode 1)
  (org-display-inline-images)
  (setq-local org-hide-emphasis-markers t))

(defun wyper/org-present-end ()
  (setq-local face-remapping-alist (assq-delete-all 'default face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'header-line face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'org-document-title face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'org-code face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'org-verbatim face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'org-block face-remapping-alist))
  (setq-local face-remapping-alist (assq-delete-all 'org-block-begin-line face-remapping-alist))
  (setq header-line-format nil)
  (visual-fill-column-mode 0)
  (visual-line-mode 0)
  (setq-local org-hide-emphasis-markers nil))

(use-package org-present
  :bind
  ("<f16>" . org-present)
  (:map org-present-mode-keymap
              ("S-<f16>" . org-present-quit)
              ("<f16>" . org-present-beginning)
              ("<f17>" . org-present-prev)
              ("<f18>" . org-present-next)
              ("<f19>" . org-present-end)))

(add-hook 'org-present-mode-hook 'wyper/org-present-start)
(add-hook 'org-present-mode-quit-hook 'wyper/org-present-end)
(add-hook 'org-present-after-navigate-functions 'wyper/org-present-prepare-slide)

(defvar org-present-map
  (let ((map (make-sparse-keymap)))
        (define-key map (kbd "h") #'org-present-beginning)
        (define-key map (kbd "j") #'org-present-prev)
        (define-key map (kbd "k") #'org-present-next)
        (define-key map (kbd "l") #'org-present-end)
        (define-key map (kbd "ö") #'org-present-quit)
        map))

(dolist (cmd '(org-present org-present-beginning org-present-prev org-present-next org-present-end))
  (put cmd 'repeat-map 'org-present-map))

Desktop

Open desktop but avoid buffers with modes from dired, fundamental or org.

(setq desktop-path '("~/.emacs.d/desktop/"))
(desktop-save-mode 1)
(add-to-list 'desktop-modes-not-to-save 'dired-mode)
(add-to-list 'desktop-modes-not-to-save 'fundamental-mode)
(add-to-list 'desktop-modes-not-to-save 'org-mode)
(add-to-list 'desktop-modes-not-to-save 'markdown-mode)