* Systems and custom functions

#+BEGIN_SRC emacs-lisp
  (if (string-equal system-type "android")
      (setq fileroot "/storage/emulated/0/Sync/")
    (setq fileroot "~/Documents/drive/"))
#+END_SRC

  Firstly, tell Emacs where to look for custom functions (via [[https://www.emacswiki.org/emacs/LoadingLispFiles][EmacsWiki]]).

  #+BEGIN_SRC emacs-lisp
    (defun load-directory (dir)
      "Add all files in a directory to load-path"
      (let ((load-it (lambda (f)
                       (load-file (concat (file-name-as-directory dir) f)))))
        (mapc load-it (directory-files dir nil "\\.el$"))))
    (load-directory "~/.emacs.d/custom/")
    (load-directory (concat (file-name-as-directory fileroot) "admin/emacs/custom/"))
#+END_SRC

* Identity

Set name and location based on who I’m being right now.

#+BEGIN_SRC emacs-lisp
  (if (string-equal user-login-name "3055822")
      (load-file (concat (file-name-as-directory fileroot) "admin/emacs/identity-work.el"))
    (if workhours
        (load-file (concat (file-name-as-directory fileroot) "admin/emacs/identity-work.el"))
      (load-file (concat (file-name-as-directory fileroot) "admin/emacs/identity-home.el"))))
#+END_SRC

* Suppress certain warnings

#+BEGIN_SRC emacs-lisp
  (setq ad-redefinition-action 'accept)
  (setq python-indent-guess-indent-offset-verbose nil)
  (setq byte-compile-warnings '(cl-functions))
#+END_SRC

* Miscellaneous changes to make to the basic config

I don’t want finding files to be case-sensitive, same as in =zsh=:

#+BEGIN_SRC emacs-lisp
  (setq completion-ignore-case t)
  (setq read-file-name-completion-ignore-case t)
  (setq read-buffer-completion-ignore-case t)
#+END_SRC

Remove certain graphical elements.

#+BEGIN_SRC emacs-lisp
  (setq inhibit-startup-screen t)
  (tool-bar-mode -1)
  (unless (string-equal system-type "android")
    (scroll-bar-mode -1))
  (tooltip-mode -1)
#+END_SRC

Make everything just a little tiny bit transparent unless I’m using the boring Windows desktop.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (unless (string-equal user-login-name "3055822")
      (set-frame-parameter (selected-frame) 'alpha 95)
      (add-to-list 'default-frame-alist '(alpha . 95))))
#+END_SRC

Stop creating all those =~= files everywhere. Put them somewhere I can ignore them.

#+BEGIN_SRC emacs-lisp
  (setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
#+END_SRC

This gives buffers sensible names.

#+BEGIN_SRC emacs-lisp
  (require 'uniquify)
  (setq uniquify-buffer-name-style 'forward)
#+END_SRC

Give me an excuse to use regex more often (from [[https://git.sr.ht/~technomancy/better-defaults][Better Defaults]]).

#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-s") 'isearch-forward-regexp)
  (global-set-key (kbd "C-r") 'isearch-backward-regexp)
  (global-set-key (kbd "C-M-s") 'isearch-forward)
  (global-set-key (kbd "C-M-r") 'isearch-backward)
#+END_SRC

Go back to the same place in a file.

#+BEGIN_SRC emacs-lisp
  (save-place-mode 1)
#+END_SRC

Turn on automatic bracket/quotation mark matching.

#+BEGIN_SRC emacs-lisp
  (electric-pair-mode 1)
#+END_SRC

Stop =init.el= getting forcibly appended with package information.

#+BEGIN_SRC emacs-lisp
  (defun package--save-selected-packages (&rest opt) nil)
#+END_SRC

SOMETIMES I WANT TO UPCASE OR DOWNCASE AN ENTIRE REGION, WHAT OF IT.

#+BEGIN_SRC emacs-lisp
  (put 'upcase-region 'disabled nil)
  (put 'downcase-region 'disabled nil)
#+END_SRC

And to narrow to them.

#+BEGIN_SRC emacs-lisp
  (put 'narrow-to-region 'disabled nil)
#+END_SRC

It’s +2022+ +2023+ unquestionably the python3 era.

#+BEGIN_SRC emacs-lisp
  (setq python-shell-interpreter "python3")
#+END_SRC

Make new directories automatically (from [[https://emacsredux.com/blog/2022/06/12/auto-create-missing-directories/][Emacs Redux]]).

#+BEGIN_SRC emacs-lisp
  (defun er-auto-create-missing-dirs ()
    "Make new directories automatically"
    (let ((target-dir (file-name-directory buffer-file-name)))
      (unless (file-exists-p target-dir)
        (make-directory target-dir t))))

  (add-to-list 'find-file-not-found-functions #'er-auto-create-missing-dirs)
#+END_SRC

Indent using spaces.

#+BEGIN_SRC emacs-lisp
  (setq-default indent-tabs-mode nil)
#+END_SRC

** OS-specific stuff

On Linux, I have to tell Emacs to use +Chrome+ Vivaldi for web links.

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "gnu/linux")
    (setq browse-url-browser-function 'browse-url-generic
          browse-url-generic-program "vivaldi"))
#+END_SRC

Honestly I don’t know if I’ll ever use macOS again, but in case I do, I need the meta key to work.

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "darwin")
    (setq ns-alternate-modifier 'meta)
    (setq ns-right-alternate-modifier 'none))
#+END_SRC

Windows likes to set the default directory to the folder where the Emacs binary is stored, which it probably thinks is helpful, but is in fact Very Stupid.

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "windows-nt")
    (setq default-directory "~/"))
#+END_SRC

Android has enormous issues with keybindings, so requiring =yes-or-no-p= where possible helps a bit.

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "android")
    (defalias 'y-or-n-p 'yes-or-no-p))
#+END_SRC

* =use-package=

Set up package handling, including =use-package= in the standard way.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (package-initialize)
    (add-to-list 'package-archives
                 '("melpa" . "https://melpa.org/packages/") t)
    (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))
    (setq package-check-signature nil)
    (unless (package-installed-p 'use-package)
      (package-refresh-contents)
      (package-install 'use-package))
    (require 'use-package-ensure)
    (setq use-package-always-ensure t))
#+END_SRC

* Packages, modes, etc.
** =atomic-chrome=

Use Emacs to type into the browser.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package atomic-chrome
      :config
      (atomic-chrome-start-server)
      (setq atomic-chrome-default-major-mode 'markdown-mode)))
    #+END_SRC
** =bibtex=

I use BibLaTeX for better compatibility with accented characters and generally being more sensible.

#+BEGIN_SRC
(unless (string-equal system-type "android")
(use-package bibtex
    :mode ("\\.bib" . bibtex-mode)
    :config
    (setq bibtex-dialect 'biblatex)))
#+END_SRC

** =csv-mode=

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package csv-mode
      :mode
      (("\\.csv\\'" . csv-mode))
      :hook
      (csv-mode . csv-align-mode)
      :config
      (setq csv-align-max-width 1000)))
#+END_SRC

** =deft=

Lets me search my journal files when I’m not at work, and reading notes otherwise. Set regexp search by default.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package deft
      :config
      (setq deft-extensions '("org" "md"))
      (if (string-equal user-login-name "3055822")
          (progn
            (setq deft-directory deft-secret-filepath)
            (setq deft-use-filename-as-title t))
        (setq deft-directory "~/Documents/drive/org/journal"))
      (setq deft-current-sort-method 'title)
      (setq deft-incremental-search nil)
      (setq deft-recursive t)))
#+END_SRC

** =dimmer=

Dims inactive buffers. Adjustments for =modus-themes= as suggested.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package dimmer
      :config
      (setq dimmer-fraction 0.4)
      (setq dimmer-adjustment-mode :foreground)
      (setq dimmer-use-colorspace :rgb)
      (dimmer-mode 1)))
#+END_SRC

** =doom-modeline=

Much nicer-looking modeline.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package doom-modeline
      :init
      (doom-modeline-mode 1)
      :config
      (setq doom-modeline-buffer-file-name-style 'buffer-name)
      (setq doom-modeline-minor-modes t)
      (setq doom-modeline-enable-word-count t)
      (setq doom-modeline-continuous-word-count-modes '(markdown-mode gfm-mode))
      (setq doom-modeline-buffer-encoding nil)))
#+END_SRC

** =git-gutter=

Shows =git diff= in the left margin if the file is being tracked by =git=.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package git-gutter
      :config
      (global-git-gutter-mode 1)
      (set-face-foreground 'git-gutter:added "forest green")
      (set-face-foreground 'git-gutter:modified "goldenrod")
      (set-face-foreground 'git-gutter:deleted "brown")
      (setq git-gutter:added-sign "+"
            git-gutter:modified-sign "×"
            git-gutter:deleted-sign "-")))
#+END_SRC

** isearch

From [[https://zck.org/improved-emacs-search][here]]:

#+BEGIN_SRC emacs-lisp
  (setq isearch-lazy-count t)
  (setq lazy-count-prefix-format nil)
  (setq lazy-count-suffix-format " (%s/%s)")
#+END_SRC

** =lastfm=

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (unless (string-equal user-login-name "3055822")
      (use-package lastfm)))
#+END_SRC

** =markdown-mode=

I kind of hate markdown but I still have to use it sometimes.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package markdown-mode
      :mode (("README\\.md\\'" . gfm-mode)
             ("\\.md\\'" . markdown-mode)
             ("\\.markdown\\'" . markdown-mode))
      :hook
      (markdown-mode . auto-fill-mode)
      :config
      (setq markdown-asymmetric-header t)
      :custom
      (markdown-header-scaling t)
      :custom-face
      (markdown-header-face ((t (:inherit (default font-lock-function-name-face) :weight bold))))))
#+END_SRC

** =minions=

Lists minor modes in a menu.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package minions
      :config
      (minions-mode)))
#+END_SRC

** =mu4e=

Does this work in emacs28???

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "gnu/linux")
    (add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
    (setq mu4e-sent-folder "/Fastmail/sent"
      mu4e-drafts-folder "/Fastmail/drafts"
      smtpmail-default-smtp-server "smtp.fastmail.com"
      smtpmail-smtp-server "smtp.fastmail.com"
      smtpmail-smtp-service 587)
    (require 'mu4e)
    (setq send-mail-function 'smtpmail-send-it))
#+END_SRC

** =neotree=

Show a nice filetree with icons. I use this much less often than I should.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package neotree
      :init
      (global-set-key [f8] 'neotree-toggle)
      :config
      (setq neo-theme (if (display-graphic-p) 'icons 'arrow))))
#+END_SRC

** =nXML-mode=

Attempting to do TEI stuff at work but I can’t link directly to the =.rnc= file here; have to list it in a =schemas.xml= file first, which references the =.rnc= file locally (not sure how we would do an absolute filepath for this).

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (setq rng-schema-locating-files
          '("schemas.xml" "~/.emacs.d/tei/schemas.xml" "c:/Program Files/Emacs/x86_64/share/emacs/27.1/etc/schema/schemas.xml"))
    (defun indent-the-file ()
      (interactive)
      (indent-region (point-min) (point-max)))
    (add-hook 'nxml-mode-hook
              (lambda () (local-set-key (kbd "C-c C-i") 'indent-the-file)))
    (add-hook 'nxml-mode-hook
            (lambda () (local-set-key (kbd "<tab>") 'completion-at-point))))
  #+END_SRC

** =org=

*** Initial settings

I want to indent under headings, I don’t want pointless line breaks when text can just wrap sensibly in the window, and I want to be able to ignore asterisks etc. when I skip to the beginning of lines.

#+BEGIN_SRC emacs-lisp
  (add-hook 'org-mode-hook 'org-indent-mode)
  (add-hook 'org-mode-hook 'visual-line-mode)
  (setq org-special-ctrl-a/e t)
  #+END_SRC

Display images in =org= buffers. I’ve increased the width to 500px because 300 was quite small. I’m assuming this doesn’t work on mobile, but why?
  
  #+BEGIN_SRC emacs-lisp
    (unless (string-equal system-type "android")
      (setq org-display-inline-images t)
      (setq org-redisplay-inline-images t)
      (setq org-startup-with-inline-images "inlineimages")
      (setq org-image-actual-width '(500)))
#+END_SRC

Some agenda settings.
  
  #+BEGIN_SRC emacs-lisp
    (setq org-agenda-show-current-time-in-grid nil)
    (setq org-extend-today-until 3)
    (setq org-agenda-skip-scheduled-if-done t)
    (setq org-agenda-skip-deadline-if-done t)
    (setq org-agenda-skip-timestamp-if-done t)
    (setq org-agenda-breadcrumbs-separator " ▸ ") ; requires org 9.3
    (setq calendar-day-name-array ["de Sul" "de Lun" "de Meurth" "de Mergher"
                                   "de Yow" "de Gwener" "de Sadorn"])
    (setq calendar-day-abbrev-array ["Su" "L" "Mth" "Mr" "Y" "G" "Sa"])
    (setq calendar-month-name-array ["mis Genver" "mis Whevrel" "mis Meur’"
                                     "mis Ebrel" "mis Me" "mis Efen"
                                     "mis Gorefen" "mis Est" "mis Gwyngala"
                                     "mis Hedra" "mis Du" "mis Kevardhu"])
    (setq org-agenda-time-grid
          '((daily today require-timed remove-match)
             (800 1000 1200 1400 1600 1800 2000)
             "......" "----------------"))
    (setq org-agenda-time-leading-zero t)
#+END_SRC

Set general TODO keywords.

#+BEGIN_SRC emacs-lisp
  (setq org-todo-keywords
        '((sequence "TODO" "|" "DONE" "CANCELLED")))
#+END_SRC

Track when I complete todos.

  #+BEGIN_SRC emacs-lisp
    (setq org-log-done 'time)
#+END_SRC

*** Export settings

Allow setting certain headlines not to be exported.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package org-contrib)
    (require 'ox-extra)
    (ox-extras-activate '(ignore-headlines)))
#+END_SRC

Add a couple of classes for LaTeX export.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (add-to-list 'org-latex-classes
                 '("article-std"
                   "\\documentclass{article}
    [NO-DEFAULT-PACKAGES]
    \\input{$HOME/.emacs.d/header.tex} %$\n% latexbib"
                   ("\\section{%s}" . "\\section*{%s}")
                   ("\\subsection{%s}" . "\\subsection*{%s}")
                   ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
    (add-to-list 'org-latex-classes
                 '("memoir"
                   "\\documentclass[11pt,a5paper,extrafontsizes]{memoir}
    [NO-DEFAULT-PACKAGES]
    \\usepackage[namechapters]{optional}
    \\input{$HOME/.emacs.d/fic-export-files/header.tex} %$"
                   ("\\chapter{%s}" . "\\chapter*{%s}")
                   ("\\section{%s}" . "\\section*{%s}")
                   ("\\subsection{%s}" . "\\subsection*{%s}")
                   ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))))
#+END_SRC

General export settings:

#+BEGIN_SRC emacs-lisp
  (setq org-export-headline-levels 6)
  (setq org-html-head-include-default-style nil)
  (setq org-html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://tre.praze.net/main.css\" />")
  (setq org-footnote-define-inline t)
  (setq org-export-with-creator nil)
  (setq org-export-with-toc nil)
  (setq org-export-time-stamp-file nil)
  (unless (string-equal system-type "android")
    (if (string-equal user-login-name "3055822")
        (progn
          (setq org-export-with-author nil)
          (setq org-latex-default-class "article-std"))
      (if workhours
          (progn
            (setq org-export-with-author nil)
            (setq org-latex-default-class "article-std"))
        (setq org-latex-default-class "memoir")))
    (setq org-latex-compiler "xelatex"))
  (setq org-html-validation-link nil)
  (setq org-html-doctype "html5")
#+END_SRC

Export non-breaking spaces properly; from, believe it or not, [[https://orgmode.org/manual/Advanced-Export-Configuration.html][the Org Manual]].

#+BEGIN_SRC emacs-lisp
  (defun my-html-filter-nobreaks (text backend info)
    "Keep non-breaking spaces in HTML org export"
    (when (org-export-derived-backend-p backend 'html)
      (replace-regexp-in-string " " "&nbsp;" text)))
  (if (string-equal system-type "android")
      (setq org-export-filter-plain-text-functions
            'my-html-filter-nobreaks)
    (add-to-list 'org-export-filter-plain-text-functions
                 'my-html-filter-nobreaks))
  (unless (string-equal system-type "android")
    (defun my-latex-filter-nobreaks (text backend info)
      "Keep non-breaking spaces in LaTeX org export"
      (when (org-export-derived-backend-p backend 'latex)
        (replace-regexp-in-string " " "~" text)))
    (add-to-list 'org-export-filter-plain-text-functions
                 'my-latex-filter-nobreaks))
#+END_SRC

Export external links as ~target= “_blank”~, from [[https://emacs.stackexchange.com/a/48869][here]]:

#+BEGIN_SRC emacs-lisp
  (defun my-org-export-add-target-blank-to-http-links (text backend info)
    "Add target=\"_blank\" to external links."
    (when (and
           (org-export-derived-backend-p backend 'html)
           (string-match "href=\"http[^\"]+" text)
           (not (string-match "target=\"" text)))
      (string-match "<a " text)
      (replace-match "<a target=\"_blank\" " nil nil text)))

  (add-to-list 'org-export-filter-link-functions
               'my-org-export-add-target-blank-to-http-links)
#+END_SRC

*** Packages

**** =org-agenda-property=

Let properties be inherited by subheadings. I use this a lot for =:LOCATION:= on recurring events.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package org-agenda-property))
#+END_SRC

**** =org-journal=

Automate a tiny part of something I was previously doing manually.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (if (string-equal user-login-name "3055822")
        (progn
          (use-package org-journal
            :bind
            ("C-c j" . org-journal-new-entry)
            :config
            (setq org-journal-dir "~/Documents/drive/org")
            (setq org-journal-file-type 'yearly)
            (setq org-journal-file-format "journal-dump-%Y.org")
            (setq org-journal-find-file 'find-file)
            (setq org-journal-date-format "%Y-%m-%d")
            (setq org-journal-time-format "%H:%M\n")))
      (progn
        (defun org-journal-file-header-func (time)
          "Set the header for org-journal files"
          (concat "<" (format-time-string "%Y-%m-%d %a") ">\n\n"))
        (use-package org-journal
          :bind
          ("C-c j" . org-journal-new-entry)
          :config
          (setq org-journal-dir "~/Documents/drive/org/journal")
          (setq org-journal-file-format "%Y/%m/%Y-%m-%d.org")
          (setq org-journal-find-file 'find-file)
          (setq org-journal-date-format "journal")
          (setq org-journal-time-format "%H:%M\n")
          (setq org-journal-file-header 'org-journal-file-header-func)))))
#+END_SRC

**** =org-modern=

Use =org-modern=. [[https://github.com/minad/org-modern/issues/5#issuecomment-1318003940][Fix for issue with table widths]].

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package org-modern
      :hook
      (org-mode . org-modern-mode))
    (set-face-attribute 'org-table nil :inherit 'fixed-pitch)
    (custom-set-variables '(org-modern-table nil)))
#+END_SRC

**** =org-noter=

Annotate PDFs (kind of) in org-mode.

  #+BEGIN_SRC emacs-lisp
    (unless (string-equal system-type "android")
      (use-package org-noter
        :config
        (setq org-noter-property-doc-file "INTERLEAVE_PDF"
              org-noter-property-note-location "INTERLEAVE_PAGE_NOTE")))
#+END_SRC

**** =org-sidebar=

Display the file outline in a sidebar.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package org-sidebar
      :bind
      ("C-c C-x s" . org-sidebar-tree)))
#+END_SRC

**** =org-wc=

Display word counts next to org headings.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package org-wc
      :bind
      ("C-c C-x w" . org-wc-display)))
#+END_SRC

*** Agenda settings

Set the keybinding, set the week to start on Monday because I’m not the University of Oxford.

#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-c a") 'org-agenda)

  (setq calendar-week-start-day 1)
  (setq org-agenda-start-on-weekday nil)
#+END_SRC

Set the files to be included.

#+BEGIN_SRC emacs-lisp
  (if (string-equal system-type "android")
      (if workhours
          (setq org-agenda-files '("/storage/emulated/0/Sync/org/calendar/admin.org" "/storage/emulated/0/Sync/org/calendar/music.org" "/storage/emulated/0/Sync/org/calendar/work.org" "/storage/emulated/0/Sync/org/calendar/acwri.org"))
        (setq org-agenda-files '("/storage/emulated/0/Sync/org/calendar/admin.org" "/storage/emulated/0/Sync/org/calendar/music.org" "/storage/emulated/0/Sync/org/calendar/personal.org")))
    (progn
      (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/music.org")
      (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/admin.org")
      (if (string-equal user-login-name "3055822")
          (progn
            (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/work.org")
            (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/acwri.org"))
        (progn
          (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/home.org")
          (if workhours
              (progn
                (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/work.org")
                (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/acwri.org"))
            (add-to-list 'org-agenda-files "~/Documents/drive/org/calendar/personal.org"))))))
#+END_SRC

Set how the agenda looks.

#+BEGIN_SRC emacs-lisp
  (setq org-agenda-prefix-format
        '((todo . "%-2c %b")
          (tags . "%-2c %b")
          (agenda . "%-2c %?-12t%?-12s")))
  (setq org-use-property-inheritance (quote ("LOCATION")))
  (setq org-agenda-todo-ignore-scheduled 'future)
#+END_SRC

Add period information to the agenda header (this has a very weird output, completely different when you insert a function from just using text, utterly bizarre).

#+BEGIN_SRC emacs-lisp
  (setq org-agenda-custom-commands
        '(("a" "Slightly modified agenda view"
           ((agenda ""
                    ((org-agenda-overriding-header (periodise))))))))
  #+END_SRC

Use a horizontal line to divide each day from the next.
  
#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (setq org-agenda-format-date (lambda (date) (concat "\n"
                                                        (make-string (window-width) 9472)
                                                        "\n"
                                                        (org-agenda-format-date-aligned date)))))
#+END_SRC

Set up habit display.

#+BEGIN_SRC emacs-lisp
  (add-to-list 'org-modules 'org-habit t)
  (setq org-habit-show-all-today t)
#+END_SRC

Set the calendar day headers to the same language as the agenda.

#+BEGIN_SRC emacs-lisp
  (setq calendar-day-header-array ["Sl" "Ln" "Mt" "Mr" "Yw" "Gw" "Sd"])
#+END_SRC

*** Refile

#+BEGIN_SRC emacs-lisp
  (when (string-equal system-type "gnu/linux")
    (setq org-refile-use-outline-path 'file))
#+END_SRC
** =paren=

Highlights matching bracket.

#+BEGIN_SRC emacs-lisp
    (show-paren-mode +1)
#+END_SRC

** =pdf-tools= and =doc-view=

Use the superior package for viewing PDFs on the superior operating system, and use a less reliable one otherwise. Ghostscript has to be installed on Windows, but it’s indispensable anyway.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (if (string-equal system-type "windows-nt")
        (use-package doc-view
          :config
          (setq doc-view-ghostscript-program "gswin32c"))
      (use-package pdf-tools
        :config
        (pdf-tools-install)
        (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
        (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))
        (setq pdf-view-resize-factor 1.1))))
#+END_SRC

** =recentf=

Gives me a dialog with recently opened files. Package management stuff has to be manually excluded for obvious reasons. Surely I don’t have to call =add-to-list= separately every time, but I haven’t found a more sensible way of doing it.

#+BEGIN_SRC emacs-lisp
  (recentf-mode 1)
  (setq recentf-max-menu-items 20)
  (setq recentf-max-saved-items 20)
  (global-set-key (kbd "C-x C-r") 'recentf-open-files)
  (add-to-list 'recentf-exclude
               (expand-file-name "~/.emacs.d/elpa/*"))
  (add-to-list 'recentf-exclude
               (expand-file-name "~/.emacs.d/bookmarks"))
#+END_SRC

** =tex=

Probably the default settings.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package tex
      :ensure auctex
      :mode ("\\.tex\\'" . latex-mode)
      :init
      (add-hook 'LaTeX-mode-hook 'turn-on-auto-fill)
      (add-hook 'TeX-after-compilation-finished-functions
                #'TeX-revert-document-buffer)
      :config
      (setq TeX-auto-save t)
      (setq TeX-parse-self t)
      (setq-default TeX-master nil)
      (setq-default TeX-engine 'xetex)
      (setq-default TeX-PDF-mode t)
      (setq TeX-view-program-selection '((output-pdf "PDF Tools"))
            TeX-source-correlate-start-server t)))
#+END_SRC

** =typo=

Automatically use smart quotes. (Can’t be set to =text-mode-hook=, unfortunately, as this messes things up in LaTeX; but the only other text-modes I use are =org= and Markdown, I think.) Also, best to /unset/ this mode in source blocks in =org=, [[https://emacs.stackexchange.com/questions/55944/disable-minor-mode-inside-source-blocks][hook taken from here]].

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package typo
      :custom
      (typo-global-mode 1)
      :hook
      (org-mode . typo-mode)
      (markdown-mode . typo-mode))
    (defun unsmart-hook ()
      "Turn off smart quotes for source blocks within org mode"
      (add-hook 'typo-disable-electricity-functions 'org-in-src-block-p nil :local))
    (add-hook 'org-mode-hook 'unsmart-hook))
#+END_SRC

** =web-mode=

This is good for auto indentation, folding, killing elements, apparently XPath?? but I’ve failed to make faces work like they do in normal =html-mode=.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package web-mode
      :mode (("\\.html?\\'" . web-mode)
             ("\\.css" . web-mode))
      :config
      (setq web-mode-markup-indent-offset 2)
      (setq web-mode-css-indent-offset 2)
      (setq web-mode-enable-html-entities-fontification t)
      (setq web-mode-enable-current-element-highlight t)
      :bind
      ("C-c /" . web-mode-element-close)))
#+END_SRC

** =yasnippet=

Per-mode text expansion.

#+BEGIN_SRC emacs-lisp
    (unless (string-equal system-type "android")
      (use-package yasnippet
        :config
        (setq yas-snippet-dirs '("~/.emacs.d/snippets"))
        (setq yas-triggers-in-field t))
      (yas-global-mode 1))
#+END_SRC

* Aesthetics

** Packages

*** =all-the-icons=

Shows nice icons in the modeline and in =neotree=. Fonts need to be installed manually on Windows, possibly because of permissions issues or because of where the Emacs binary lives or maybe both those things.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package all-the-icons
      :config
      (unless (string-equal system-type "windows-nt")
        (when (not (member "all-the-icons" (font-family-list)))
          (all-the-icons-install-fonts t)))))
#+END_SRC

*** =emojify=

Support for various types of emoge.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package emojify
      :hook
      (text-mode . emojify-mode)
      (org-agenda-mode . emojify-mode)))
#+END_SRC

*** =hl-line=

Highlights current line.

#+BEGIN_SRC emacs-lisp
  (global-hl-line-mode 1)
#+END_SRC

** Theme/colours

Set a theme from =modus-themes=. This is built in for version 28 and above.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package modus-themes))
  (setq modus-themes-bold-constructs t)
  (setq modus-themes-italic-constructs t)
  (setq modus-themes-mixed-fonts t)
  (setq modus-themes-org-blocks 'gray-background)
  (load-theme 'modus-operandi-tinted t)
  #+END_SRC

** Fonts

Use Noto fonts to match my system fonts on Linux. This has to be done differently on Windows for some reason.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (if (string-equal system-type "windows-nt")
        (custom-set-faces
         '(default ((t (:family "Noto Mono" :foundry "outline" :slant normal :weight normal :height 98 :width normal))))
         '(italic ((t (:slant italic))))
         '(variable-pitch ((t (:family "Noto Sans" :height 90))))
         '(fixed-pitch ((t (:family "Noto Mono" :height 90)))))
      (custom-set-faces
       '(italic ((t (:slant italic))))
       '(variable-pitch ((t (:family "Noto Sans" :height 90))))
       '(fixed-pitch ((t (:family "Noto Mono" :height 100))))
       '(modus-themes-fixed-pitch ((t (:family "Noto Mono" :height 100)))))))
#+END_SRC

Use the =mixed-pitch= package to determine the font intelligently in modes that contain both text and prog elements.

#+BEGIN_SRC emacs-lisp
  (unless (string-equal system-type "android")
    (use-package mixed-pitch
      :hook
      (LaTeX-mode . mixed-pitch-mode)
      (org-mode . mixed-pitch-mode)
      (markdown-mode . mixed-pitch-mode)))
#+END_SRC

* Startup

Set the =*scratch*= buffer to =org-mode=.

#+BEGIN_SRC emacs-lisp
  (setq initial-major-mode 'org-mode)
#+END_SRC

Tell me what version of Emacs I’m using so I know if there are packages I can’t use.

#+BEGIN_SRC emacs-lisp
  (setq initial-scratch-message
        (concat "# emacs " (number-to-string emacs-major-version) " on " (symbol-name system-type) "\n\n"))
#+END_SRC

Finally, because =org= gets very confused by all these settings, give it a friendly reload.

#+BEGIN_SRC emacs-lisp
  (org-reload)
#+END_SRC