Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/henryleach/emacs

My emacs configuration files
https://github.com/henryleach/emacs

emacs emacs-configuration

Last synced: about 7 hours ago
JSON representation

My emacs configuration files

Awesome Lists containing this project

README

        

#+TITLE: Henry's Emacs Config File

Setting configuration in an complied org file for better organisation.

* Basic Customisation

#+begin_src emacs-lisp
(setq
inhibit-startup-screen t
;; Get rid of all noises
ring-bell-function 'ignore
;; I might be a beginner, but I know what the scratch buffer is.
initial-scratch-message nil
;; One space should be enough for anyone
sentence-end-double-space nil
;; Delete the whole line and following newline
kill-whole-line t
)

;; Accept 'y' in lieu of 'yes'.
(defalias 'yes-or-no-p 'y-or-n-p)
;; Overwrite selected text
(delete-selection-mode t)
;; Line numbers everywhere
(global-display-line-numbers-mode t)
;; Soft line wrapping - only in text modes?
(global-visual-line-mode 1)
;; Show the matching brackets
(show-paren-mode)
;; Also show the column/character position in the modeline
(column-number-mode)
;; No need for tool or menu bar
(menu-bar-mode -1)
(tool-bar-mode -1)

;; Prefer a cursor bar to block, guess it's what I'm used to.
(setq-default cursor-type 'bar)

#+end_src

It can get confusing if emacs saves some custom variable without you expecting it, then changes in your config file don't seem to work. So send these changes to nowhere

#+BEGIN_SRC emacs-lisp
(setq custom-file null-device)
#+END_SRC

Some performance tweaks: add more memory, the default limits are very low and stop very long lines from hanging emacs.

#+BEGIN_SRC emacs-lisp
(setq gc-cons-threshold 100000000)
(setq read-process-output-max (* 1024 1024)) ;; 1mb
;; Avoid performance issues in files with very long lines.
;;(global-so-long-mode 1) only native from V27 onwards
(if (<= emacs-major-version 27)
(use-package so-long
:config (global-so-long-mode 1))
(setq global-so-long-mode 1))
#+END_SRC

** Keybindings

General keybindings that aren't linked to any specific packages.

#+begin_src emacs-lisp
;; When moving forward I want to be at the start of a word, not the end.
(global-set-key (kbd "M-f") 'forward-to-word)
;; Backspace and Del are a long reach
(global-set-key (kbd "C-z") 'backward-kill-word)
#+end_src

Various characters that aren't reliably on all keyboards I use.

#+begin_src emacs-lisp
(global-set-key (kbd "C-c e") "€")
(global-set-key (kbd "C-c u") "ü")
(global-set-key (kbd "C-c o") "ö")
(global-set-key (kbd "C-c s") "ß")
#+end_src

** Remap Caps Lock

If you don't spend much time shouting when you type, it's worth remapping the Caps Lock key to being Control, as it's in a much nicer position than the normal control key.

*MacOS*
System Preferences > Keyboard > Modifier Keys

*Windows 10*
You have to edit the register, because...Windows? Copy the following into a text file, save with a ~.reg~ extension, then double click. This requires admin privileges. (From [[https://superuser.com/questions/949385/map-capslock-to-control-in-windows-10][StackExchange]]).

#+begin_src
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00
#+end_src

*Linux*
None persistently with:
: setxkbmap -option ctrl:nocaps

but that won't survive a reboot. To make the change more permanent we need to add the option "ctrl:nocaps" to /etc/default/keyboard in the XKBOPTIONS="" part.

Steps from [[https://thesynack.com/posts/persistent-capslock-behavior/][here]].

** MacOS Options

If you have a UK Keyboard on a Mac, and want to type a hash symbol you need [[https://stackoverflow.com/questions/3977069/emacs-question-hash-key][this]].

#+begin_src emacs-lisp
;; Allow hash to be entered
(cond ((eq system-type 'darwin)
(global-set-key (kbd "M-3") #'(lambda () (interactive) (insert "#")))
))
#+end_src

** Windows 10 Options

To get emacs working 'normally' there are a couple of steps you should do, [[http://ergoemacs.org/emacs/emacs_mswin.html][Xah tips]]

1. Set a 'HOME' variable. WinKey + search for 'Environment Variables', then create a new one called 'HOME' and set it to your home directory, probably =c:\Users\username=.

** UTF-8 Everywhere

#+begin_src emacs-lisp
(set-charset-priority 'unicode)
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setq default-process-coding-system '(utf-8-unix . utf-8-unix))
#+end_src

** Backup File Location

It's crazy to have them scattered everywhere, instead put them in one place:

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

** Set Frame Title

#+begin_src emacs-lisp
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))
(:eval (if (buffer-modified-p)
" •"))
" - Emacs")
)
#+end_src

** TODO Tabs

Tabs are a [[https://www.emacswiki.org/emacs/TabsAreEvil][bit of a mess]] and it should probably be fixed once I've understood it.

** Bookmarks and Recent Files

Seeing recent files is helpful, and especially when you open Emacs, and then can carry on from where you left off.

#+begin_src emacs-lisp
(recentf-mode 1)
(setq recentf-max-saved-items 25) ;Otherwise it gets very slow
(global-set-key "\C-x\ \C-r" 'recentf-open-files)
(add-hook 'after-init-hook 'recentf-open-files)
#+end_src

* Appearance
** Theme

[[https://github.com/bbatsov/solarized-emacs][Solarized]] is relatively sedate. 'material-theme' is also nice, but has ugly looking blocks around headings in org-mode. The cool kids these days are mostly using [[https://github.com/hlissner/emacs-doom-themes][Doom Themes]].

#+begin_src emacs-lisp
(use-package solarized-theme
:ensure t
:config
(load-theme 'solarized-dark t))
#+end_src

** Fonts and Text Appearance

We want proprtional fonts in a number of places, but not others.

Could probably pick a specific font too if I wanted, something more serify. To see which fonts are available, run =(font-family-list)= in scratch, and see the result. Can also use =(x-list-fonts "Font Name")= but that might be for X-based systems only, e.g. not Windows.

To list monospaced fonts, filter with the below, as found on SO.
#+BEGIN_SRC emacs-lisp :tangle no
(seq-filter (lambda (font)
(when-let ((info (font-info font)))
(string-match-p "spacing=100" (aref info 1))))
(font-family-list))
#+END_SRC

Fonts are very dependant on what's installed on each system, so there's a list of preferences and we work through those, picking the first installed one. Sizes can render a bit differently between OSs, with MacOS appearing slightly smaller, so we make that system dependent.

#+BEGIN_SRC emacs-lisp
(defun font-candidate (&rest fonts)
"Return existing font which first match."
(cl-find-if (lambda (f) (find-font (font-spec :name f))) fonts))

;; Only run when in a windowing system
(when (display-graphic-p)
;; Choose fonts in order of preference here
;; Must have at least one font that works on each system; 'nix, MacOS and Windows
(setq var-pitch-fonts '("DejaVu Serif" "Georgia"))
(setq fix-pitch-fonts '("Calling Code" "DejaVu Sans Mono" "Menlo" "Courier New"))

;; Adjust sizes depending on the OS
(setq var-pitch-font
(concat
(apply 'font-candidate var-pitch-fonts) "-"
(cond ((eq system-type 'darwin) "13")
((eq system-type 'berkeley-unix) "9")
(t "12")) ;; Fallback
))

(setq fix-pitch-font
(concat
(apply 'font-candidate fix-pitch-fonts) "-"
(cond ((eq system-type 'darwin) "12")
((eq system-type 'berkeley-unix) "8")
(t "11")) ;; Fallback
))

(set-face-attribute 'variable-pitch nil :font var-pitch-font)
(set-face-attribute 'fixed-pitch nil :font fix-pitch-font)

;; Default font for most things
(set-frame-font fix-pitch-font nil t)
)

(defun set-buffer-variable-pitch ()
(interactive)
(variable-pitch-mode t)
(setq line-spacing 3)
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-code nil :inherit 'fixed-pitch)
(set-face-attribute 'org-block nil :inherit 'fixed-pitch)
)
;; Specify where the proportional fonts should be used.
(add-hook 'org-mode-hook 'set-buffer-variable-pitch)
(add-hook 'eww-mode-hook 'set-buffer-variable-pitch)
(add-hook 'Info-mode-hook 'set-buffer-variable-pitch)
#+END_SRC

** Mode Line

A fancier modeline. Also run ~M-x nerd-icons-install-fonts~ to make sure all the relevant fonts are installed.

#+begin_src emacs-lisp
;; Needed for multiple mode-line
;; themes
(use-package all-the-icons
:ensure t
)
;; Don't forget to run M-x all-the-icons-install-fonts

;; now uses
(use-package doom-modeline
:ensure t
:config (doom-modeline-mode 1))
#+end_src

** Dimmer

Dims the modeline of the inactive buffers.

#+begin_src emacs-lisp
(use-package dimmer
:ensure t
:custom (dimmer-fraction 0.1)
:config (dimmer-mode))
#+end_src

** Rainbow Delimiters

Pretty and helpful for any bracket heavy languages.

#+begin_src emacs-lisp
(use-package rainbow-delimiters
:ensure t
:config
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
)
#+end_src

** Emoji

Guide on setting up [[https://github.com/iqbalansari/emacs-emojify][emacs-emojify]] by [[https://ianyepan.github.io/posts/emacs-emojis/][Ian YE Pan]]. For Windows there's the Segoe UI Emoji, for other systems you can download the [[https://fonts.google.com/noto/specimen/Noto+Color+Emoji][Noto Colour Emoji]] and install them. For Linux that's adding to a ~~/.fonts~ dir and running ~fc-cache -v ~/.fonts~ to add them.

#+begin_src emacs-lisp
(setq emoji-font (cond
((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji")
((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji")))

(use-package emojify
:ensure t
:config
(when emoji-font (set-fontset-font
t 'symbol (font-spec :family emoji-font) nil 'prepend))
(setq emojify-display-style 'unicode)
(setq emojify-emoji-styles '(unicode))
:hook
(after-init . global-emojify-mode))
#+end_src

(Yes, there's a better way of doing the above, code, I just don't have the brainpower right now 😕.)

Then the easiest way to find and insert an emoji is to call ~emojify-apropos-emoji~.

** Xah Colour Colour Codes

Highlights RGB values in their colours, using the following function from [[http://xahlee.info/emacs/emacs/emacs_CSS_colors.html][Xah Lee]].

#+begin_src emacs-lisp
(defun xah-syntax-color-hex ()
"Syntax color text of the form 「#ff1100」 and 「#abc」 in current buffer.
URL `http://xahlee.info/emacs/emacs/emacs_CSS_colors.html'
Version 2017-03-12"
(interactive)
(font-lock-add-keywords
nil
'(("#[[:xdigit:]]\\{3\\}"
(0 (put-text-property
(match-beginning 0)
(match-end 0)
'face (list :background
(let* (
(ms (match-string-no-properties 0))
(r (substring ms 1 2))
(g (substring ms 2 3))
(b (substring ms 3 4)))
(concat "#" r r g g b b))))))
("#[[:xdigit:]]\\{6\\}"
(0 (put-text-property
(match-beginning 0)
(match-end 0)
'face (list :background (match-string-no-properties 0)))))))
(font-lock-flush))

(add-hook 'css-mode-hook 'xah-syntax-color-hex)
(add-hook 'php-mode-hook 'xah-syntax-color-hex)
(add-hook 'html-mode-hook 'xah-syntax-color-hex)

#+end_src

* Packages
** Own Functions

Load any personal functions.

#+begin_src emacs-lisp
(add-to-list 'load-path "~/.emacs.d/private_functions/")
(load-library "hl_functions")
#+end_src

** Dired

Want to reduce the clutter mostly by hiding hidden files and extended information, which can be done via ~dired-omit-mode~ that hides certain files, a function that comes from the additional, built in, dired-x package, and ~dired-hide-details-mode~ that list only file and directory names, and nothing else. Toggle it on and off with ~"("~.

Perhaps package dired+ or dired-subtree is interesting? also other [[https://github.com/Fuco1/dired-hacks][dired hacks]]. There's also something in [[https://github.com/patrickt/emacs/blob/master/readme.org][this]] about dired opening multiple windows, which mine does and is very annoying. Looks like I should be using =a= instead of =RET=. Also =i= opens a directory in the same buffer below.

Also hiding details by default needs to be enabled somehow.
#+begin_src emacs-lisp
(add-hook 'dired-mode-hook (lambda () (dired-hide-details-mode)))
#+end_src

#+begin_src emacs-lisp
(with-eval-after-load 'dired
(require 'dired-x)
;; Set dired-x global variables here. For example:
(setq-default dired-omit-mode t)
(setq-default dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$\\|^\\.")
(define-key dired-mode-map (kbd "C-o") 'dired-omit-mode)
)
(add-hook 'dired-mode-hook
(lambda ()
;; Set dired-x buffer-local variables here. For example:
;; (dired-omit-mode 1)
))
#+end_src

~dired-narrow~ allows you to quickly filter the files in a dired buffer, hit the keybinding and start typing

#+begin_src emacs-lisp
(use-package dired-narrow
:ensure t
:bind (:map dired-mode-map
("/" . dired-narrow)))
#+end_src

** Which Key

Shows possible completitions. Also use which-key-postframe?

#+begin_src emacs-lisp
(use-package which-key
:ensure t
:init
(which-key-mode t)
)
#+end_src

** Undo-Tree

Naturally bound to =C-/=, =n= and =p= navigate up and down, =f= and =b= switch branches. =q= (or =C-q=) will quit with changes matching the point you selected.

Also make =C-z= simple undo, I can't get that muscle memory out of my fingers.

[[http://pragmaticemacs.com/emacs/advanced-undoredo-with-undo-tree]]

#+begin_src emacs-lisp
(use-package undo-tree
:ensure t
:diminish undo-tree-mode
:config
(progn
(global-undo-tree-mode)
(setq undo-tree-visualizer-timestamps t)
(setq undo-tree-visualizer-diff t)
;;(global-unset-key "\C-z") ;; remove other bindings
;;(global-set-key "\C-\/" 'undo-tree-undo)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))
))
#+end_src

** Ido

Better suggestion customisation. Is the list better vertical, or horizontal?

#+begin_src emacs-lisp
(use-package ido
:ensure t
:config
(progn
(setq ido-enable-flex-matching t)
(setq ido-everywhere t)
(ido-mode 1)
;; Display ido results vertically, rather than horizontally
;; (setq ido-decorations (quote ("\n-> " "" "\n " "\n ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
))
#+end_src

** Regex

/Default Commands Reminder/
- =C-s= isearch-forward
- =C-r= iseach-backward
- =C-M-s= isearch-forward-regexp
- =C-M-r= isearch-backward-regexp
- =M-%= query-replace
- =C-M-%= query-replace-regexp - remapped to visual-regexp

#+begin_src emacs-lisp
(use-package visual-regexp
:ensure t
:config
(progn
(define-key global-map (kbd "C-M-%") 'vr/query-replace)
))

#+end_src

** Avy

[[https://github.com/abo-abo/avy][Avy]] is a fast way of jumping around the visible screen, and it can [[https://karthinks.com/software/avy-can-do-anything/][do lots of other useful things too]].

#+begin_src emacs-lisp
(use-package avy
:ensure t
:bind ("C-c C-SPC" . avy-goto-char-timer)
)
#+end_src

If you define avy-actions (see them with ~?~ once you've narrowed your selection) you can type the character for that action (which won't be used as an option in the narrowing process) before typing the characters that select your candidate. Then, once you've selected your candidate that action will be applied.

Must also remember to use ~global-pop-mark~ (~C-x C-SPC~) to jump back to where you were previously after a little excursion.

** Spell Checking

Enable flyspell in all text modes and in those places in source where you write comments. This uses either ispell or aspell on Linux. For Windows and MacOS it seems to be easiest to use [[https://hunspell.github.io][Hunspell]] (MacOS: =brew install hunspell=). Then you need to download the dictionaries you want, useful note from brew:

#+begin_quote
Dictionary files (*.aff and *.dic) should be placed in ~/Library/Spelling/ or /Library/Spelling/. Homebrew itself provides no dictionaries for Hunspell, but you can download compatible dictionaries from other sources, such as https://wiki.openoffice.org/wiki/Dictionaries .
#+end_quote

Also emacs on MacOS can't find hunspell dictionaries unless you start it in the home folder, or use this [[https://passingcuriosity.com/2017/emacs-hunspell-and-dictionaries/][tip]] to fix that.

Working on mutli-language support:
https://200ok.ch/posts/2020-08-22_setting_up_spell_checking_with_multiple_dictionaries.html
https://www.monotux.tech/posts/2021/02/hunspell-multi-lang/
https://stackoverflow.com/questions/42159012/emacs-spell-check-on-fly-for-2-languages

For OpenBSD install hunspell and dicts with:

#+begin_src sh
pkg_add hunspell mozilla-dicts-ca
#+end_src

#+BEGIN_SRC emacs-lisp
;; set up hunspell dictionary for windows and macos
(cond ((eq system-type 'windows-nt)
(add-to-list 'exec-path "~/.emacs.d/Hunspell/bin/")
(setenv "DICTDIR" (expand-file-name "~/.emacs.d/Hunspell/"))

(setq ispell-program-name (locate-file "hunspell"
exec-path exec-suffixes 'file-executable-p))
(setq ispell-list-command "--list")
(setq ispell-local-dictionary "en_GB")
;; Added below to try and get multilanguage to work.
;; (setq ispell-dictionary "en_GB,de_DE_frami")
;; (ispell-set-spellchecker-params)
;; (ispell-hunspell-add-multi-dic "en_GB,de_DE_frami")
)
((eq system-type 'darwin)
;; Set $DICPATH to "$HOME/Library/Spelling" for hunspell.
(setenv
"DICPATH"
(concat (getenv "HOME") "/Library/Spelling"))
(setenv "DICTIONARY" "en_GB")
;; Assuming this is where "brew install hunspell" puts it.
(setq ispell-program-name "/usr/local/bin/hunspell")
(setq ispell-list-command "--list")
(setq ispell-local-dictionary "en_GB")
)
((eq system-type 'berkeley-unix) ;; for OpenBSD, same for other BSDs?
(setenv "DICTDIR" "/usr/local/share/mozilla-dicts")
(setenv "DICTIONARY" "en-GB")
(setq ispell-progam-name "hunspell")
(setq ispell-list-command "--list")
(setq ispell-local-dictionary "en-GB")
)
)
#+END_SRC

#+BEGIN_SRC emacs-lisp
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; On big org files this can get very slow, so use it only when not typing
(use-package flyspell-lazy
:ensure t
:config
(flyspell-lazy-mode 1)
)
#+END_SRC

** Move Buffer

Allows for quick switching of buffers between windows within a frame, bound to =C-S-=.

#+begin_src emacs-lisp
(use-package buffer-move
:ensure t
:config
(progn
(global-set-key (kbd "") 'buf-move-up)
(global-set-key (kbd "") 'buf-move-down)
(global-set-key (kbd "") 'buf-move-left)
(global-set-key (kbd "") 'buf-move-right))
)
#+end_src

** Expand Region

#+begin_src emacs-lisp
(use-package expand-region
:ensure t
:bind ("C-=" . er/expand-region))
#+end_src

* Org-Mode

Basic changes.

#+begin_src emacs-lisp
;; show inline images as a default.
(setq org-startup-with-inline-images t)

;; Store links from anywhere
(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
#+end_src

More to do states, and their colours (not always theme compatible, should probably update that later).

#+begin_src emacs-lisp
;; TODO list sequence, add 'IN PROGRESS' and 'WAITING' to default options
(setq org-todo-keywords
'((sequence "TODO" "IN PROGRESS" "WAITING" "|" "DONE")))

;; Colour the todo keywords
(setq org-todo-keyword-faces
'(("TODO" . (:foreground "white" :background "OrangeRed3"))
("IN PROGRESS" . (:foreground "white" :background "firebrick"))
("WAITING" . (:background "pink"))
("DONE" . (:background "OliveDrab3"))))
#+end_src

With long ToDo items names, the list can get messy and wrap in unpleasant ways, then a column view is nicer. Can access this from the agenda ToDo view ~C-c a t~ using ~C-c C-x C-c~. Note that you have to use this to sequence to refresh the column view as well, pressing ~g~ as usual refreshes, but jumps out of the column view. There's probably a way to fix that.

#+BEGIN_SRC emacs-lisp
;; Set the column view for the todo list
;; see in agenda view with C-c C-x C-c
(setq org-columns-default-format
"%35ITEM %TODO %15DEADLINE %ALLTAGS")
#+end_src

Appearance, based a lot [[https://zzamboni.org/post/beautifying-org-mode-in-emacs/][on this]]. Some useful info [[https://protesilaos.com/codelog/2020-07-17-emacs-mixed-fonts-org/][here too]].

#+BEGIN_SRC emacs-lisp
;; Means * / = ~ etc. will be hidden.
(setq org-hide-emphasis-markers t)
(setq org-startup-folded t)
;; Pretty bullets instead of lots of stars
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
#+END_SRC

Keep the agenda files in a separate file. Partly because we disabled writing customisation info into the init.el file, but also it means you can have a text file per installation with the org files for that installation in it. Either add a whole file path, or a folder (ending in ' / ') to add all .org files in it.

If you give the following only a relative path or a file name, it looks in the directory of the currently open buffer. If emacs can't find it, then any function relating the agenda don't work (e.g. can't clock in). If you add files to your agenda list with =C-[=, or remove them, with =C-]=) they will be added and removed in this file.

The agenda view will also mess around with your windows/buffer views. With the last option set it will return you to your previous layout when hitting =q=.

#+BEGIN_SRC emacs-lisp
(setq org-agenda-files "~/.emacs.d/agenda_files.txt")

;; The agenda view can mess with your layout
(setq org-agenda-restore-windows-after-quit t)
#+END_SRC

For the clock table I don't want it to jump to days, but keep hours as the biggest unit, otherwise it's harder to compare tasks quickly.

#+begin_src emacs-lisp
;;Keep the clock table in hours, and not count days
(setq org-duration-format (quote h:mm))
#+end_src

** Templates and Skeletons

Use a basic org-mode template for new files. More details at [[https://www.gnu.org/software/emacs/manual/html_node/autotype/index.html][AutoType]].

#+begin_src emacs-lisp
(auto-insert-mode)
(setq auto-insert-query nil)
(define-auto-insert '("\.org" . "Org Skeleton")
'("Short description: "
"#+TITLE: " (my/create-org-title (buffer-name)) \n
"#+DATE: "(format-time-string "<%Y-%m-%d %a>") \n
"#+FILETAGS: " \n \n _))
#+end_src

#+begin_src emacs-lisp
(define-skeleton html-det-sum
"Insert the escaped HTML code to create a detail/summary field"
nil
>"@@html:@@\n"
>"@@html:@@"_"@@html:@@\n
@@html:@@\n")
#+end_src

** Exporting

Normally I just want to export a small section as HTML to copy into an e-mail, never the whole file. This setting doesn't seem to stick though.

#+BEGIN_SRC emacs-lisp
(setq org-export-initial-scope 'subtree)
#+END_SRC

*** HTMLIZE

This helps to syntax colour exported code blocks, needed by org-mode's html export module.
#+BEGIN_SRC emacs-lisp
(use-package htmlize
:ensure t
)
#+END_SRC

** Archiving

Make the archive match the hierarchy in the main org document. Using the [[https://gist.github.com/kepi/2f4acc3cc93403c75fbba5684c5d852d][org-archive-subtree function]]. Replaces the usual function, under the same command =C-c C-x C-a=. This does keep the hierarchy, but not the sequence.

#+begin_src emacs-lisp
(require 'org-archive-subtree-hierarchical)
(setq org-archive-default-command 'org-archive-subtree-hierarchical)
#+end_src

* Programming

** Smart Parentheses

A better way of dealing with brackets. [[https://github.com/Fuco1/smartparens][github page]], and a [[https://ebzzry.com/en/emacs-pairs/][user guide]].

#+begin_src emacs-lisp
(use-package smartparens-config
:ensure smartparens
:config (progn (show-smartparens-global-mode t)) ;; High list current pair
)
;;(add-hook 'prog-mode-hook 'turn-on-smartparens-strict-mode)
#+end_src

** Projectile

[[https://docs.projectile.mx/projectile/index.html][Documents]] for project interaction library. To mark a folder as a project, add a empty '.projectile' file to it.

#+begin_src emacs-lisp
(use-package projectile
:ensure t
:init
(projectile-mode +1)
:bind (:map projectile-mode-map
("C-c p" . projectile-command-map)))
#+end_src

** Treemacs

For better overviews in projects. [[https://github.com/Alexander-Miller/treemacs#installation][Documentation]]

#+begin_src emacs-lisp
(use-package treemacs
:ensure t
:defer t
)

(use-package treemacs-projectile
:after (treemacs projectile)
:ensure t)
#+end_src

** Company Mode

Company completion can be used in anything, but I only want to use it for coding. Still seems active in comments, which I don't really want.

#+begin_src emacs-lisp
(use-package company
:ensure t
:defer t
:diminish
:config
(setq company-dabbrev-other-buffers t
company-dabbrev-code-other-buffers t)
:hook (;;(text-mode . company-mode)
(prog-mode . company-mode)))
#+end_src

** TODO Python

I want a consistent configuration between Windows, MacOS and Linux; so I suspect this is going to be limited by what I can get work on Windows.

For working with different python environments. This is also loaded/integrated with Elpy, but here we set the WORKON_HOME directory so it's easier to find them in =M-x pyvenv-workon=.

#+begin_src emacs-lisp
(use-package pyvenv
:ensure t
:init
(cond ((eq system-type 'windows-nt)
(setenv "WORKON_HOME" "c:/ProgramData/Anaconda3/envs")))
)
#+end_src

Slightly nicer than Flymake. For Python, make sure it's calling whatever the current envs python is.

#+begin_src emacs-lisp
(use-package flycheck
:ensure t
:config
:hook (sh-mode . flycheck-mode)
)
#+end_src

LSP Mode is all fancy and modern, but Elpy gets the job done.

For Windows where python is installed via Anaconda, I can only get it to work reliably if I activate the environment I want to work in /first/ in the Anaconda prompt, then launch Emacs. This means installing all the dependencies in each environment first (e.g. jedi, flake8 etc.), but anything else eventually causes a failure as some different version of Python is launched in parallel which is missing the right packages.

#+begin_src emacs-lisp
(use-package elpy
:ensure t
:defer t
:init
(advice-add 'python-mode :before 'elpy-enable)
:config
(setq elpy-rpc-python-command "python")
(setq elpy-rpc-virtualenv-path 'current)
(setq elpy-get-info-from-shell t)
(when (load "flycheck" t t) ;; is the 3rd value nil or t? depends who you ask.
(setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
(add-hook 'elpy-mode-hook 'flycheck-mode))
(setq python-shell-interpreter "ipython"
python-shell-interpreter-args "-i --simple-prompt")
)

;; This ensures that the python shell buffer scrolls
;; down to show the output of the last run code.
(advice-add 'elpy-shell-send-region-or-buffer
:before (lambda (&optional rest)
(let ((curbuf (current-buffer)))
(elpy-shell-switch-to-shell)
(goto-char (point-max))
(recenter -10)
(elpy-shell-switch-to-buffer)))
'((name . "elpy-shell-scroll-to-bottom")))

#+end_src

** Markdown
#+begin_src emacs-lisp
(use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "multimarkdown"))
#+end_src

** YAML

#+begin_src emacs-lisp
(use-package yaml-mode
:mode "\\.yaml\\'"
:ensure t)
#+end_src

** Web

If [[https://www.web-mode.org][Web-Mode]] doesn't automatically detect the correct engine for templates, you can force the correct one with =M-x web-mode-set-engine RET ENGINE_NAME RET=, e.g. "go".

If that gets tiresome it is also possible to add:
: -*- engine:ENGINE_NAME -*-
into a comment on the page.

#+begin_src emacs-lisp
(use-package web-mode
:ensure t
:mode ("\\.html\\'"
"\\.php\\'")
:config
(progn
(setq web-mode-code-indent-offset 2)
(setq web-mode-enable-engine-detection t)
(setq web-mode-enable-auto-quoting nil)))
#+end_src

** TODO CSV

[[https://elpa.gnu.org/packages/csv-mode.html][CSV-mode docs]], default separators are tabs and commas, add semi-colon for all languages that use a comma as a decimal place separator.

The docs say that editing =csv-separators= should be enough to set the possible separators, but this doesn't seem to be working correctly, when opening a semi-colon separated file it doesn't split on the semi-colons.

=csv-separator-chars= should not be set directly, but trying to set that with ='(44 59 9)= didn't make any difference. How does csv-mode know /which/ separator it should use in a file? Even reducing the separators to /only/ being ";" didn't make it work.

#+begin_src emacs-lisp
(use-package csv-mode
:ensure t
:config
(progn
;; Below seems to set the separators correctly, but
;; then CSV mode ignores semi-colons when opening files.
(setq csv-separators '("," ";" " "))
)
)
#+end_src

** Tex/Latex

For editing LaTex documents [[https://www.gnu.org/software/auctex/documentation.html][AucTeX]] appears the most integrated option, defaults below from the AucTex manual.

#+begin_src emacs-lisp
(use-package tex
:ensure auctex)
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)
#+end_src

** Lilypond

[[https://www.lilypond.org][Lilypond]] is a LaTeX like way of marking up musical notation, and then generating the engraving, normally as a PDF file. There is [[https://lilypond.org/doc/v2.23/Documentation/usage/text-editor-support#emacs-mode][official documentation]] for it, but that didn't quite work, this had [[https://francopasut.netlify.app/post/emacs_write_lilypond/][more details]] to get Emacs to actually find the lilypond-mode.el file which is automatically installed with lilypond, but not automatically found.. This depends on where it's been installed, and there must be a good way of doing that. Here I'm just limiting to where it's installed on a Mac with brew.sh, and only checking it then. There is also an integration with [[https://melpa.org/#/flycheck-lilypond][flycheck]] that might be worth checking out.

#+begin_src emacs-lisp
(cond ((eq system-type 'darwin)
(setq load-path (append (list
(expand-file-name "/usr/local/Cellar/lilypond/2.22.2/share/emacs/site-lisp/lilypond"))
load-path))))

(autoload 'LilyPond-mode "lilypond-mode")
(setq auto-mode-alist
(cons '("\\.ly$" . LilyPond-mode) auto-mode-alist))

(add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
#+end_src

** Magit

For working with Git, and related EDiff settings. Could probably customise the faces of the diffs a bit more.

#+begin_src emacs-lisp
(use-package magit
:ensure t)

;; Somewhat related EDiff settings
;; Don't use the little pop-up window, and split horizontally by default.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
(setq ediff-split-window-function 'split-window-horizontally)
#+end_src
* Interesting Packages to be investigated

- expand region
- treemacs
- [[https://github.com/bbatsov/projectile][projectile]]
- dired subtree
- [[https://github.com/tlh/workgroups.el][Workspace]]
- [[https://github.com/nex3/perspective-el][perspective]] to manage a collection of buffers?

LSP mode for Python development environment instead of Elpy?

- [[https://emacs-lsp.github.io/lsp-mode/page/installation/][lsp-mode docs]]
- [[https://ddavis.io/posts/emacs-python-lsp/][ddavis.io]]
- [[https://vxlabs.com/2018/06/08/python-language-server-with-emacs-and-lsp-mode/][vxLabs]]

* References/other config files of interest

[[https://zzamboni.org/post/my-emacs-configuration-with-commentary/]]
[[https://github.com/zzamboni/dot-emacs/blob/master/init.org]]

[[https://pages.sachachua.com/.emacs.d/Sacha.html#org955a0ab]]

[[https://github.com/patrickt/emacs/blob/master/readme.org]] (and the [[https://github.com/patrickt/emacs/blob/master/init.el][init.el]] file)

[[http://www.howardism.org/Technical/Emacs/emacs-init.html]]

[[https://github.com/cocreature/dotfiles/blob/master/emacs/.emacs.d/emacs.org]]

[[https://blog.sumtypeofway.com/posts/emacs-config.html]]

[[https://github.com/PythonNut/quark-emacs]]

[[https://github.com/jwiegley/use-package][Use Package Docs]]

Ideas?
https://zzamboni.org/post/my-blogging-setup-with-emacs-org-mode-ox-hugo-hugo-gitlab-and-netlify/

** Useful Commands I always forget

=C-h k= Describes keybindings
=M-;= Comment region
=