This emacs.d setup uses a literate programming style. A term coined by Donald Knuth.
- In order to generate a init.el file, run org tangle C-c v t and the different Babel code blocks will create Alex.el. I then create a symlink for init.el from that in my .emacs.d folder.
Inspired by Sacha Chua’s literate .emacs.d.
I like EXWM as a WM.
(setq user-full-name "Alex Scott"
user-mail-address "[email protected]")
Here’s how we start:
;; This sets up the load path so that we can override it
(package-initialize)
;; (add-to-list 'load-path "/usr/local/share/emacs/site-lisp")
;; (add-to-list 'load-path "~/vendor/org-mode/lisp")
;; (add-to-list 'load-path "~/vendor/org-mode/contrib/lisp")
;; (require 'org)
(setq custom-file "~/.emacs.d/custom-settings.el")
(setq use-package-always-ensure t)
(load custom-file t)
(unless (assoc-default "melpa" package-archives)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t))
(unless (assoc-default "org" package-archives)
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t))
Use M-x package-refresh-contents
to reload the list of packages
after adding these for the first time.
(add-to-list 'load-path "~/elisp")
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(setq use-package-verbose t)
(setq use-package-always-ensure t)
(require 'use-package)
(use-package quelpa)
(use-package quelpa-use-package)
(use-package auto-compile
:config (auto-compile-on-load-mode))
(setq load-prefer-newer t)
It would be nice if we could set the default sync already set. Maybe loading timing.
So just use keys that pulse audio provides. C-x / i set sync m mute/unmute v volume
(use-package pulseaudio-control
:ensure t)
(pulseaudio-control-default-keybindings)
;; (setq pulseaudio-control-default-source "0")
;; (pulse-audio-control-select-sink-by-index)
;; (pulseaudio-control-toggle-current-sink-mute)
;; (pulseaudio-control-set-volume "70%")
(use-package dash :ensure t)
(use-package diminish :ensure t)
Enable y/n answers
(fset 'yes-or-no-p 'y-or-n-p)
Bind to Alt Space
(global-set-key "\M- " 'hippie-expand)
(global-set-key (kbd "C-c e") 'er/expand-region)
;; (use-package ace-jump
;; :ensure t
;; :config
;; (define-key global-map (kbd "C-c SPC") 'ace-jump-mode)
;; )
;; (use-package ace-window
;; :config
;; (global-set-key (kbd "M-o") 'ace-window)
;; :ensure t)
(use-package winum
:init
(winum-mode)
:ensure t)
(use-package multiple-cursors
:config
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C-S-q") 'mc/keyboard-quit)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
:ensure t)
(require 'recentf)
(setq recentf-max-saved-items 200
recentf-max-menu-items 15)
(recentf-mode)
(display-time-mode 1)
winner-mode
lets you use C-c <left>
and C-c <right>
to switch between window configurations. This is handy when something has popped up a buffer that you want to look at briefly before returning to whatever you were working on. When you’re done, press C-c <left>
.
;; (use-package winner
;; :defer t)
(use-package keychain-environment
:ensure t
:config (keychain-refresh-environment))
;; Avoid repetition?
(keychain-refresh-environment)
(use-package ox-gfm
:ensure t)
(use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.mdx\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "multimarkdown"))
(use-package exwm)
(use-package exwm-firefox-core
:ensure t)
(require 'exwm)
(require 'exwm-config)
(exwm-config-example)
(require 'exwm-firefox-core) ; Would be nice to defer loading this. :defer ?
Useful when in other applications. Build on defaults by adding cut and paste. Exwm input simulation keys Logout and in again to take affect.
(setq exwm-input-simulation-keys
'(
;; movement
([?\C-b] . [left])
([?\M-b] . [C-left])
([?\C-f] . [right])
([?\M-f] . [C-right])
([?\C-p] . [up])
([?\C-n] . [down])
([?\C-a] . [home])
([?\C-e] . [end])
([?\M-v] . [prior])
([?\C-v] . [next])
([?\C-d] . [delete])
([?\C-k] . [S-end delete])
;; cut/paste.
([?\C-w] . [?\C-x])
([?\M-w] . [?\C-c])
([?\C-y] . [?\C-v])
;; Search
([?\C-s] . [?\C-f])))
(exwm-input-set-key (kbd "s-p") 'exwm-input-toggle-keyboard)
For this to have worked you will need to be able to suspend without a password:
(exwm-input-set-key (kbd "s-<f12>")
(lambda () (interactive) (start-process "" nil "sudo" "pm-suspend")))
https://elmord.org/blog/?entry=20180214-exwm-org-capture
(defun elmord-exwm-get-firefox-url ()
(exwm-input--fake-key ?\C-l)
(sleep-for 0.05) ; Wait a bit for the browser to respond.
(exwm-input--fake-key ?\C-c)
(sleep-for 0.05)
(gui-backend-get-selection 'CLIPBOARD 'STRING))
(defun elmord-exwm-org-store-link ()
(when (and (equal major-mode 'exwm-mode)
(member exwm-class-name '("Firefox")))
(org-store-link-props
:type "http"
:link (elmord-exwm-get-firefox-url)
:description exwm-title)))
;; (org-link-set-parameters "firefox" :store 'elmord-exwm-org-store-link)
When you call org-capture and use a template the includes a link and a description, then both will be added to the capture results.
(defalias 'oc 'org-capture)
(defalias 'oa 'org-agenda)
(defalias 'lp 'list-processes)
(defalias 'ogc 'org-cliplink)
(defalias 'gf 'grep-find)
(defalias 'fd 'find-dired)
(defalias 'ff 'find-file)
(defalias 'ms 'magit-status)
;; What does it take to make this work
(defalias 'fnd 'find-name-dired)
(if (file-exists-p "~/super.el")
(load "~/super.el"))
(if (file-exists-p "~/elisp/js-react-redux-yasnippets.el")
(load "~/elisp/js-react-redux-yasnippets.el"))
This is one of the things people usually want to change right away. By default, Emacs saves backup files in the current directory. These are the files ending in ~
that are cluttering up your directory lists. The following code stashes them all in ~/.config/emacs/backups
, where I can find them with C-x C-f
(find-file
) if I really need to.
(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
(setq create-lockfiles nil) ;; No lock files.
(setq delete-old-versions -1)
(setq version-control t)
(setq vc-make-backup-files t)
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)))
Do we need ORG mode?
;; (use-package org-tempo)
(setq org-confirm-babel-evaluate nil)
; languages for org-babel support
(org-babel-do-load-languages
'org-babel-load-languages
'(
(shell . t)
(dot . t)
(latex .t)
(clojure . t)
(scheme . t)
(C . t)
(js . t)
(lisp . t)
(ruby . t)
(org . t)
(python . t)
(sql . t)
))
(use-package magit
:ensure t
:bind
("C-c g" . magit-file-dispatch))
(use-package forge
:ensure t
:after magit)
(use-package orgit-forge
:ensure t
:after magit)
(use-package ag
:ensure t)
;; https://www.manueluberti.eu/emacs/2019/11/16/helm/
;; https://github.com/emacs-helm/helm-ls-git
(use-package helm-ls-git
:ensure t)
(global-set-key (kbd "C-c h P") 'helm-browse-project)
(global-set-key (kbd "C-c h H") 'helm-projects-history)
(global-set-key (kbd "C-x C-d") 'helm-browse-project)
https://emacs-helm.github.io/helm/
(use-package helm
:diminish helm-mode
:init
(progn
(require 'helm-config)
(require 'helm-for-files)
(setq helm-candidate-number-limit 100)
(setq helm-completing-read-handlers-alist
'((describe-function)
(consult-bookmark)
(consult-outline)
(org-refile)
(consult-line)
(consult-mark)
(consult-multi-occur)
(describe-variable)
(execute-extended-command)
(consult-yank)))
;; From https://gist.github.com/antifuchs/9238468
(setq helm-idle-delay 0.0 ; update fast sources immediately (doesn't).
helm-input-idle-delay 0.01 ; this actually updates things
; reeeelatively quickly.
helm-yas-display-key-on-candidate t
helm-quick-update t
helm-ff-file-name-history-use-recentf t
helm-M-x-requires-pattern nil
helm-ff-skip-boring-files t)
(helm-mode))
:config
(defadvice helm-files-insert-as-org-links (around sacha activate)
(insert (mapconcat (lambda (candidate)
(org-link-make-string candidate))
(helm-marked-candidates)
"\n")))
:bind (("C-c h" . helm-command-prefix)))
(ido-mode -1) ;; Turn off ido mode in case I enabled it accidentally
(use-package helm-ls-git)
(setq helm-mini-default-sources '(helm-source-buffers-list
helm-source-recentf
helm-source-bookmarks
helm-source-buffer-not-found))
(global-set-key (kbd "M-x") 'helm-M-x)
(global-set-key (kbd "M-y") 'helm-show-kill-ring)
(setq global-auto-revert-mode t)
(use-package helm-ag
:ensure t)
This promises to be a fast way to find things. Let’s bind it to Ctrl-Shift-S
to see if I can get used to that…
(use-package helm-swoop
:bind
(("C-S-s" . helm-swoop)
("M-i" . helm-swoop)
("M-s s" . helm-swoop)
("M-s M-s" . helm-swoop)
("M-I" . helm-swoop-back-to-last-point)
("C-c M-i" . helm-multi-swoop)
("C-x M-i" . helm-multi-swoop-all)
)
:config
(progn
(define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch)
(define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop))
)
(use-package pdf-tools
:ensure t
:magic ("%PDF" . pdf-view-mode)
:config
(pdf-tools-install :no-query))
(use-package org-noter
:ensure t)
Set EWW readable.
(use-package ob-async
:ensure t)
Visual line mode for wrapping lines in org mode.
(with-eval-after-load 'org
;;(setq org-startup-indented t)
(add-hook 'org-mode-hook #'visual-line-mode))
(add-hook 'text-mode-hook #'visual-line-mode)
(use-package org-pomodoro
:ensure t
:config
(global-set-key (kbd "<f12>") 'org-pomodoro))
(use-package org-roam
:ensure t
:hook
(after-init . org-roam-mode)
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n g" . org-roam-graph))
:map org-mode-map
(("C-c n i" . org-roam-insert))
(("C-c n I" . org-roam-insert-immediate))))
(use-package org-brain :ensure t
:config
(bind-key "C-c b" 'org-brain-prefix-map org-mode-map);; binds in org mode.
;; (push '("b" "Brain" plain (function org-brain-goto-end)
;; "* %i%?" :empty-lines 1)
;; org-capture-templates)
(setq org-brain-title-max-length 16))
(add-hook 'org-mode-hook 'org-indent-mode)
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook #'org-bullets-mode))
;; (use-package polymode
;; :ensure t
;; :config
;; (add-hook 'org-brain-visualize-mode-hook #'org-brain-polymode))
(setq dired-dwim-target t)
I like js and js2-modes.
(setq js-indent-level 2)
(setq js-switch-indent-offset 2)
(use-package tagedit
:ensure t)
(eval-after-load 'sgml-mode
'(progn
(require 'tagedit)
(tagedit-add-paredit-like-keybindings)
(add-hook 'html-mode-hook (lambda () (tagedit-mode 1)))))
(define-key html-mode-map (kbd "C-<right>") 'tagedit-forward-slurp-tag)
(define-key html-mode-map (kbd "C-<left>") 'tagedit-forward-barf-tag)
(define-key html-mode-map (kbd "M-r") 'tagedit-raise-tag)
(define-key html-mode-map (kbd "M-s") 'tagedit-splice-tag)
(define-key html-mode-map (kbd "M-J") 'tagedit-join-tags)
(define-key html-mode-map (kbd "M-S") 'tagedit-split-tag)
(define-key html-mode-map (kbd "M-?") 'tagedit-convolute-tags)
(define-key html-mode-map (kbd "C-k") 'tagedit-kill)
(define-key html-mode-map (kbd "s-k") 'tagedit-kill-attribute)
(add-to-list 'auto-mode-alist '("\\.js\\'\\|\\.json\\'" . js2-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . js2-mode))
(eval-after-load "sgml-mode"
'(progn
(require 'tagedit)
(tagedit-add-paredit-like-keybindings)
(add-hook 'html-mode-hook (lambda () (tagedit-mode 1)))))
(add-hook 'js2-mode-hook
(lambda () (flycheck-mode t)))
;; js2 refactor
(use-package js2-refactor
:ensure t)
(js2r-add-keybindings-with-prefix "C-c C-m")
(add-hook 'js2-mode-hook #'js2-refactor-mode)
(use-package flycheck
:ensure t)
Handy shortcuts:
(use-package js2-mode
:mode "\\.js\\'")
(use-package json-mode
:mode "\\.json\\'")
JS comint
(use-package js-comint
:ensure t)
(use-package paredit
:ensure t
:init
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'ielm-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-mode-hook #'enable-paredit-mode)
;; (add-hook 'js-mode-hook #'enable-paredit-mode) Messes with JXS
(add-hook 'js2-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook #'enable-paredit-mode)
;; eldoc-mode shows documentation in the minibuffer when writing code
;; http://www.emacswiki.org/emacs/ElDoc
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode))
;; (use-package autopairs
;; :ensure t)
;; Built into emacs.
(electric-pair-mode t)
(defun ais-paredit-nonlisp ()
"Turn on paredit mode for non-lisps."
(interactive)
(set (make-local-variable 'paredit-space-for-delimiter-predicates)
'((lambda (endp delimiter) nil)))
(paredit-mode 1))
(add-hook 'js2-mode-hook 'ais-paredit-nonlisp)
(add-hook 'before-save-hook #'whitespace-cleanup)
(setq-default indent-tabs-mode nil)
;; (setq custom-theme-directory "~/.emacs.d/poet")
;; (add-hook 'text-mode-hook
;; (lambda ()
;; (variable-pitch-mode 1)))
;; (load-theme 'poet-dark t)
;; Decent font size.
;; (set-face-attribute 'default nil :height 140)
(use-package clojure-mode
:ensure t)
(use-package cider
:ensure t)
;; Enable paredit for Clojure
(add-hook 'clojure-mode-hook 'enable-paredit-mode)
;; This is useful for working with camel-case tokens, like names of
;; Java classes (e.g. JavaClassName)
(add-hook 'clojure-mode-hook 'subword-mode)
;; A little more syntax highlighting
;; (require 'clojure-mode-extra-font-locking)
;; syntax hilighting for midje
(add-hook 'clojure-mode-hook
(lambda ()
(setq inferior-lisp-program "lein repl")
(font-lock-add-keywords
nil
'(("(\\(facts?\\)"
(1 font-lock-keyword-face))
("(\\(background?\\)"
(1 font-lock-keyword-face))))
(define-clojure-indent (fact 1))
(define-clojure-indent (facts 1))
(rainbow-delimiters-mode)))
;;;;
;; Cider
;;;;
;; provides minibuffer documentation for the code you're typing into the repl
(add-hook 'cider-mode-hook 'eldoc-mode)
;; go right to the REPL buffer when it's finished connecting
(setq cider-repl-pop-to-buffer-on-connect t)
;; When there's a cider error, show its buffer and switch to it
(setq cider-show-error-buffer t)
(setq cider-auto-select-error-buffer t)
;; Where to store the cider history.
(setq cider-repl-history-file "~/.emacs.d/cider-history")
;; Wrap when navigating history.
(setq cider-repl-wrap-history t)
;; enable paredit in your REPL
(add-hook 'cider-repl-mode-hook 'paredit-mode)
;; Use clojure mode for other extensions
(add-to-list 'auto-mode-alist '("\\.edn$" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.boot$" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.cljs.*$" . clojure-mode))
(add-to-list 'auto-mode-alist '("lein-env" . enh-ruby-mode))
;; key bindings
;; these help me out with the way I usually develop web apps
(defun cider-start-http-server ()
(interactive)
(cider-load-current-buffer)
(let ((ns (cider-current-ns)))
(cider-repl-set-ns ns)
(cider-interactive-eval (format "(println '(def server (%s/start))) (println 'server)" ns))
(cider-interactive-eval (format "(def server (%s/start)) (println server)" ns))))
(defun cider-refresh ()
(interactive)
(cider-interactive-eval (format "(user/reset)")))
(defun cider-user-ns ()
(interactive)
(cider-repl-set-ns "user"))
(eval-after-load 'cider
'(progn
(define-key clojure-mode-map (kbd "C-c C-v") 'cider-start-http-server)
(define-key clojure-mode-map (kbd "C-M-r") 'cider-refresh)
(define-key clojure-mode-map (kbd "C-c u") 'cider-user-ns)
(define-key cider-mode-map (kbd "C-c u") 'cider-user-ns)))
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; (add-hook 'ediff-prepare-buffer-hook #'show-all)
Will need the file added as elisp.
https://github.com/DEADB17/ob-racket/
;; (use-package ob-racket
;; :ensure t
;; :after org
;; :pin manual
;; :config
;; (append '((racket . t) (scribble . t)) org-babel-load-languages))
(use-package yasnippet
:ensure t
:init
(yas-global-mode))
(setq exwm-input-global-keys
`(
;; Move around
(,(kbd "s-<up>") . windmove-up)
(,(kbd "s-<down>") . windmove-down)
(,(kbd "s-<left>") . windmove-left)
(,(kbd "s-<right>") . windmove-right)
(,(kbd "s-o") . 'ace-window)
;; 's-r': Reset (to line-mode).
([?\s-r] . exwm-reset)
;; 's-w': Switch workspace.
([?\s-w] . exwm-workspace-switch)
;; 's-&': Launch application.
([?\s-&] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; 's-N': Switch to certain workspace.
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))))