I use Emacs and its literate programming features.
The content of both the Makefile
and the files
directory
is generated out of this org file, so do not edit these directly
but work on this document instead!
Then:
- Run
C-c C-v t
- Commit all the changes
- Run
make
- Clone this repository (or pull the latest changes)
- Run
make
These are the files that will be copied over your home directory
install: $(HOME)/.gitconfig \
$(HOME)/.gitconfig-local \
$(HOME)/.gitignore \
$(HOME)/.emacs.d/init.el
My global Git configuration file will be installed in my home directory:
$(HOME)/.gitconfig: files/.gitconfig
cp -f $^ $@
It will make provision for local additions that can’t be checked in for whatever reason (e.g. work stuff).
[include]
path = ~/.gitconfig-local
That file also lives in my home directory:
$(HOME)/.gitconfig-local:; touch $(HOME)/.gitconfig-local
These are the things I always want Git to ignore:
*~
.DS_Store
.\#*
.clj-kondo
.cljs_node_repl
.cpcache
.hgignore
.lsp
.nrepl-port
\#*\#
dist
node_modules
out
resources
target
These patterns live in a file in my home directory:
$(HOME)/.gitignore: files/.gitignore
cp -f $^ $@
And that file is referenced in my global Git configuration file:
[core]
excludesFile = ~/.gitignore
Open Emacs maximised:
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
Remember that what we usually refer to as a window is called a frame in Emacs parlance.
I don’t find both Emacs toolbar & scrollbar very useful so I disable them:
(tool-bar-mode -1)
(scroll-bar-mode -1)
Disable default left and right margins:
(set-fringe-mode 0)
I always want to see line numbers so I enable that feature globally:
(global-display-line-numbers-mode t)
I need this as other I cannot type that character :)
(global-set-key (kbd "M-3") (lambda ()
(interactive)
(insert "#")))
This seems to be frowned upon but I find using Shift
and the arrow keys
really handy to navigate the windows:
(windmove-default-keybindings)
This allows a “circular” navigation e.g. if you reach the last window
then Shift-<Arrow Left>
get you back to the first window.
(setq windmove-wrap-around t)
Indentation
(electric-indent-mode -1)
(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(setq-default js-indent-level 2)
I need this to avoid choking lsp-mode: https://emacs-lsp.github.io/lsp-mode/page/performance/
(setq read-process-output-max (* 1024 1024)) ;; 1mb
(setq gc-cons-threshold 100000000)
I use straight.el as my package manager.
This is what is needed to bootstrap it:
(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))
;; tell `use-package` to use `straight.el` as the package manager
(setq straight-use-package-by-default t)
(straight-use-package 'use-package)
First, make sure Fira Code is installed!
(set-frame-font "Fira Code:size=14")
(use-package ligature
:init
;; Enable the www ligature in every possible major mode
(ligature-set-ligatures 't '("www"))
;; Enable ligatures in programming modes
(ligature-set-ligatures 'prog-mode '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\" "{-" "::"
":::" ":=" "!!" "!=" "!==" "-}" "----" "-->" "->" "->>"
"-<" "-<<" "-~" "#{" "#[" "##" "###" "####" "#(" "#?" "#_"
"#_(" ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*" "/**"
"/=" "/==" "/>" "//" "///" "&&" "||" "||=" "|=" "|>" "^=" "$>"
"++" "+++" "+>" "=:=" "==" "===" "==>" "=>" "=>>" "<="
"=<<" "=/=" ">-" ">=" ">=>" ">>" ">>-" ">>=" ">>>" "<*"
"<*>" "<|" "<|>" "<$" "<$>" "<!--" "<-" "<--" "<->" "<+"
"<+>" "<=" "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<"
"<~" "<~~" "</" "</>" "~@" "~-" "~>" "~~" "~~>" "%%"))
(global-ligature-mode 't)
)
(use-package vertico
:ensure t
:init
(vertico-mode t)
:custom
(vertico-cycle t) ; goes back to the top when reaching the end of minibuffer
)
(use-package marginalia
:ensure t
:init
(marginalia-mode t))
Provide fuzzy search:
(use-package orderless
:ensure t
:config
(setq completion-styles '(orderless basic)))
consult-xref
is nice alternative to a plain *xref*
buffer, especially
when combined with lsp-mode
!
(use-package consult
:init
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:bind (("C-x b" . consult-buffer)
("C-s" . consult-line)))
(use-package which-key
:init
(which-key-mode t))
Install and use ef-themes from Prot.
(use-package ef-themes
:init (ef-themes-select 'ef-maris-dark))
Not sure exactly what those are but that came with Emacs 29 apparentlty and I need those as otherwise I get annoying Warning buffer all the time.
See https://www.masteringemacs.org/article/how-to-get-started-tree-sitter
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(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")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
(mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
(use-package lsp-mode
:commands (lsp lsp-deferred)
:init
(setq lsp-keymap-prefix "C-c l")
:config
(lsp-enable-which-key-integration t))
(use-package corfu
:init
(global-corfu-mode)
:bind
(:map corfu-map
("RET" . (lambda ()
(interactive)
(corfu-quit)
(newline-and-indent))))
:config
(setq corfu-auto t))
Make sure Emacs can see the environment variables I have in my usual shell:
(use-package exec-path-from-shell
:init
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))
Prevents org-mode from adding extra indentation:
(setq org-src-preserve-indentation t)
Let’s start with some basic project management stuff:
(use-package magit
:init
(with-eval-after-load 'project
(keymap-set project-prefix-map "m" #'magit-project-status)
(keymap-set project-prefix-map "g" #'consult-ripgrep)
(setq project-switch-commands '((magit-project-status "Magit")
(project-find-file "Find file")
(consult-ripgrep "Find rg")
(project-find-dir "Find dir")
(project-shell "Shell")))))
(use-package embark
:straight t
:bind
(("C-." . embark-act)
("C-h B" . embark-bindings))
:init
(setq prefix-help-command #'embark-prefix-help-command))
(use-package embark-consult)
(use-package wgrep)
Web development.
The major mode `tsx-ts-mode` comes with Emacs 29.1 and is what I will use for both JavaScript and TypeScript source files. React is also supported.
New entries are added at the beginning of the list and so will take precedence over any default entries from Emacs.
(add-to-list 'auto-mode-alist '("\\.[jt]s[x]?\\'" . tsx-ts-mode))
Activate lsp
(add-hook 'tsx-ts-mode-hook 'lsp-deferred)
This might be occasionally useful:
(use-package add-node-modules-path
:hook ((tsx-ts-mode . #'add-node-modules-path)))
Some projects insist on using Prettier and even go out of their way to integrate it with Git hooks.
I need to support those projects as otherwise I will have a really tough time.
(use-package prettier-js
:hook ((tsx-ts-mode . prettier-js-mode)))
Things I need when I do Clojure(Script) development:
(use-package cider)
(use-package clojure-mode
:mode (("\\.cljc?\\'" . clojure-mode)
("\\.cljs\\'" . clojurescript-mode)))
(use-package rainbow-delimiters
:hook ((clojure-mode . rainbow-delimiters-mode)
(clojurescript-mode . rainbow-delimiters-mode)
(emacs-lisp-mode . rainbow-delimiters-mode)))
(use-package paredit
:hook ((clojure-mode . paredit-mode)
(clojurescript-mode . paredit-mode)
(emacs-lisp-mode . paredit-mode)))
Support for the Janet programming language:
You need to install Janet first:
brew install janet
(use-package janet-mode
:mode (("\\.janet\\'" . janet-mode))
:hook ((janet-mode . paredit-mode)
(janet-mode . rainbow-delimiters-mode)))
Check this paredit guide out!
The restclient package is a nice alternative to Postman
(use-package restclient)
I use this package to execute restclient source blocks in org-mode.
Note: you can add a jq filter via a source header e.g. ==:jq .==
(use-package ob-restclient
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((restclient . t))))
This package also provides org-babel support for jq
(use-package jq-mode
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((jq . t))))
My Emacs configuration file will be put in a standard location:
$(HOME)/.emacs.d/init.el: files/init.el
mkdir -p $(@D)
cp $^ $@
See https://emacsredux.com/blog/2024/03/11/tracking-world-time-with-emacs/
(setq world-clock-list
'(("Europe/London" "London")
("Europe/Brussels" "Brussels")
("Europe/Kiev" "Kiev")
("Asia/Seoul" "Seoul")))