From 91ddb83cbe0dfe03e9d2d3ea3984fc824407e5f9 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Wed, 2 Aug 2017 10:21:30 +0200 Subject: Emacs: Use smartparens from melpa-stable Recommended by author: https://github.com/Fuco1/smartparens/issues/775#issuecomment-315853084 --- nix/.config/nixpkgs/emacs.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/.config/nixpkgs/emacs.nix b/nix/.config/nixpkgs/emacs.nix index 02b7496..cf697c7 100644 --- a/nix/.config/nixpkgs/emacs.nix +++ b/nix/.config/nixpkgs/emacs.nix @@ -51,6 +51,7 @@ in diminish bind-key use-package + smartparens ]) ++ (with epkgs.melpaPackages; [ ace-link ace-window @@ -140,7 +141,6 @@ in shrink-whitespace slime smart-tabs-mode - smartparens smex suggest swiper -- cgit 1.4.1 From efa975ed49a33accf3d8c0d674320f26c9ec1cca Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 11:37:31 +0200 Subject: Emacs: Fix building emacs config files on macOS --- emacs/.emacs.d/Makefile | 7 +++++-- zsh/.config/zsh/.zshenv | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/emacs/.emacs.d/Makefile b/emacs/.emacs.d/Makefile index 7741ef3..9f086ff 100644 --- a/emacs/.emacs.d/Makefile +++ b/emacs/.emacs.d/Makefile @@ -1,5 +1,6 @@ define EMACS_TANGLE (progn\ + (require 'package)\ (package-refresh-contents nil)\ (setq vc-follow-symlinks nil)\ (find-file \"init.org\")\ @@ -7,6 +8,8 @@ define EMACS_TANGLE (org-babel-tangle nil \"init.el\")) endef +EMACS := ${NIX_LINK}/bin/emacs + # The first target is the default. `all` is typically defined here. all: init.elc @@ -14,10 +17,10 @@ all: init.elc .PHONY: all clean init.el: - @emacs --batch --no-init-file --eval "$(EMACS_TANGLE)" --kill + $(EMACS) --batch --no-init-file --eval "$(EMACS_TANGLE)" --kill init.elc: init.el - @emacs --batch --no-init-file --funcall batch-byte-compile init.el + $(EMACS) --batch --no-init-file --funcall batch-byte-compile init.el clean: rm init.el init.elc diff --git a/zsh/.config/zsh/.zshenv b/zsh/.config/zsh/.zshenv index 87dda38..f82d0a2 100644 --- a/zsh/.config/zsh/.zshenv +++ b/zsh/.config/zsh/.zshenv @@ -18,6 +18,7 @@ then if [[ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]] then . $HOME/.nix-profile/etc/profile.d/nix.sh; + export NIX_LINK fi case $OSTYPE in -- cgit 1.4.1 From 8c97e999adee892e046ecfaa611193b47497d6fc Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:08:01 +0200 Subject: Emacs: Switch from org-babel to lentic-mode --- emacs/.emacs.d/init.el | 2869 +++++++++++++++++++++++++++++++++++++++++ emacs/.emacs.d/init.org | 369 +++--- nix/.config/nixpkgs/emacs.nix | 2 +- 3 files changed, 3037 insertions(+), 203 deletions(-) create mode 100644 emacs/.emacs.d/init.el diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el new file mode 100644 index 0000000..902e5b5 --- /dev/null +++ b/emacs/.emacs.d/init.el @@ -0,0 +1,2869 @@ +;;; emacs-config --- Summary +;; #+TITLE: Emacs Configuration for Alan Pearce +;; #+OPTIONS: ^:nil +;; #+PROPERTY: results silent +;; #+PROPERTY: eval no-export +;; #+PROPERTY: header-args :comments link +;;; Header: +;; This is a living document, detailing my Emacs configuration using org-mode +;;; Code: +;; ** Basics +;; *** Startup +;; Open Emacs with just a plain window. No graphics or messages, please! +;; #+BEGIN_SRC emacs-lisp +(put 'inhibit-startup-echo-area-message 'saved-value + (setq inhibit-startup-echo-area-message (user-login-name))) +(setq inhibit-startup-screen t) +(setq gc-cons-threshold 100000000) +(defvar file-name-handler-alist-backup file-name-handler-alist) +(setq file-name-handler-alist nil) +(remove-hook 'find-file-hooks #'vc-refresh-state) +;; #+END_SRC + +;; Are we running on Windows via the WSL? + +;; #+BEGIN_SRC emacs-lisp +(when (file-exists-p "/proc/sys/kernel/osrelease") + (with-temp-buffer + (insert-file-contents-literally "/proc/sys/kernel/osrelease") + (decode-coding-region (point-min) (point-max) 'utf-8 t) + (when (string-match "Microsoft$" (buffer-string)) + (setq system-type 'gnu/linux/windows)))) +;; #+END_SRC + +;; *** Compatibility + +;; #+BEGIN_SRC emacs-lisp +(if (version< emacs-version "25.0") + (defmacro with-eval-after-load (file &rest body) + `(eval-after-load ,file (lambda () ,@body)))) +;; #+END_SRC + +;; *** Scratch buffers +;; I usually use scratch buffers for any sort of text. If I need a +;; programming mode in one, then I’ll just call it manually. I also like +;; the buffer to be empty. +;; #+BEGIN_SRC emacs-lisp +(setq initial-scratch-message "" + initial-major-mode 'text-mode) +;; #+END_SRC + +;; *** Personal Information +;; #+BEGIN_SRC emacs-lisp +(setq user-mail-address "alan@alanpearce.eu" + user-full-name "Alan Pearce") +;; #+end_src + +;; ** Packaging + +;; *** Use-package + +;; #+BEGIN_SRC emacs-lisp +(eval-and-compile + (require 'seq) + (defvar nix-emacs (and (string-match "^/nix/store" invocation-directory) + (not (null (seq-some (lambda (dir) (string-match "^/nix/store" dir)) load-path))))) + + (setq tls-checktrust t + gnutls-verify-error t + package-menu-async t + package-user-dir (concat "~/.emacs.d/packages/" emacs-version "/elpa") + package-menu-hide-low-priority t) + (if nix-emacs + (progn (setq package-archives nil) + (package-initialize)) + (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") + ("melpa-stable" . "https://stable.melpa.org/packages/") + ("melpa" . "https://melpa.org/packages/")) + package-pinned-packages '(("use-package" . melpa-stable) + ("diminish" . melpa-stable) + ("bind-key" . melpa-stable)) + package-archive-priorities '(("melpa" . 10) + ("gnu" . 10) + ("melpa-stable" . 5) + ("marmalade" . 0)))) + (when (eq system-type 'darwin) + (with-eval-after-load "gnutls" + (add-to-list 'gnutls-trustfiles "/etc/ssl/cert.pem"))) + (unless nix-emacs + (package-initialize) + (unless (package-installed-p 'use-package) + (package-refresh-contents) + (package-install 'use-package)))) +(eval-when-compile (require 'use-package)) +(unless (featurep 'use-package) + (require 'diminish) + (require 'bind-key) + (use-package use-package + :commands (use-package-autoload-keymap) + :defer 5)) +(setq use-package-always-ensure (not nix-emacs) + use-package-always-demand (daemonp) + package-enable-at-startup nil) +;; #+END_SRC + +;; *** Helpers + +;; **** Hook Helpers + +;; An improvement over add-hook with lamda functions that allows +;; modification and removal, without the boilerplate of an extra function +;; definition. + +;; #+BEGIN_SRC emacs-lisp +(eval-and-compile + (use-package hook-helpers)) +;; #+END_SRC + +;; ** Customize +;; I don’t really like using customize for normal configuration. +;; Instead, I use it for things that get saved automatically. That’s why +;; I use a different file, which is ignored by the VCS. It also means +;; that it’s not important whether the file exists or not, which is why I +;; pass =:noerror= to =load= + +;; #+BEGIN_SRC emacs-lisp +(setq custom-file "~/.emacs.d/custom.el") +(load custom-file :noerror :nomessage) +;; #+END_SRC + +;; ** Styles + +;; I prefer an always-visible cursor. Feels less distracting. +;; #+BEGIN_SRC emacs-lisp +(when (fboundp #'blink-cursor-mode) + (blink-cursor-mode -1)) +;; #+END_SRC + +;; Disable all the bars, unless on OSX, in which case, keep the menu bar. + +;; #+BEGIN_SRC emacs-lisp +(when (and menu-bar-mode (not (eq window-system 'ns))) + (menu-bar-mode -1)) +(with-eval-after-load 'scroll-bar + (set-scroll-bar-mode nil)) +(with-eval-after-load 'tooltip + (tooltip-mode -1)) +(with-eval-after-load 'tool-bar + (tool-bar-mode -1)) +;; #+END_SRC + +;; Ring the bell sometimes, but not so often +;; #+BEGIN_SRC emacs-lisp +(setq ring-bell-function + (lambda () + (unless (memq this-command + '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit undo-tree-undo)) + (ding)))) +;; #+END_SRC + +;; *** Colours + +;; Eziam looks nice, too, except for the non-white background. I prefer +;; white because most other application backgrounds are that colour. + +;; #+BEGIN_SRC emacs-lisp +(use-package eziam-light-theme + :ensure eziam-theme + :disabled t + :if (or window-system + (daemonp)) + :defines (eziam-scale-headings) + :config (progn + (setq eziam-scale-headings nil) + (load-theme 'eziam-light t) + (custom-theme-set-faces 'user + '(default ((t (:background "#ffffff")))) + '(js2-function-call ((t (:underline nil)))) + '(js2-object-property ((t (:slant normal)))) + '(font-lock-keyword-face ((t (:weight normal)))) + '(git-gutter-fr:added ((t (:foreground "#96a4ab")))) + '(git-gutter-fr:modified ((t (:foreground "#96a4ab")))) + '(git-gutter-fr:deleted ((t (:foreground "#96a4ab"))))))) +;; #+END_SRC + +;; White-theme. Sounds like a good idea. + +;; #+BEGIN_SRC emacs-lisp +(use-package white-theme + :if (or window-system + (daemonp)) + :config (progn + (load-theme 'white t) + (custom-theme-set-faces 'user + '(git-gutter-fr:added ((t (:foreground "#b8b8b8")))) + '(git-gutter-fr:modified ((t (:foreground "#b8b8b8")))) + '(git-gutter-fr:deleted ((t (:foreground "#b8b8b8")))) + '(font-lock-string-face ((t (:slant normal))))))) +;; #+END_SRC + +;; Base16 theming allows me have a consistent style between applications +;; quite easily. + +;; #+BEGIN_SRC emacs-lisp +(use-package base16-theme + :if (or window-system + (daemonp))) +;; #+END_SRC + +;; Highlighting quasi-quoted expressions in lisps is quite useful, but I +;; don't need it all the time. I'll keep it around for a while so that I +;; can enable it if needed. +;; #+BEGIN_SRC emacs-lisp +(use-package highlight-stages + :diminish highlight-stages-mode) +;; #+END_SRC + +;; *** Fonts + +;; When possible, set up fonts. I don’t have any settings here for X11, +;; because I manage those in my [[file:~/projects/dotfiles/tag-xresources/xresources/main][XResources file]]. +;; #+BEGIN_SRC emacs-lisp +(when (or (display-graphic-p) + (daemonp)) + + (defun use-variable-fonts () + (interactive) + (variable-pitch-mode) + (setq cursor-type '(bar . 1))) + + (defun ap/set-fonts (mono-face mono-font-size variable-face variable-font-size antialias &optional new-line-spacing) + (if (boundp 'ns-antialias-text) + (setq ns-antialias-text antialias)) + (if (boundp 'new-line-spacing) + (setq line-spacing new-line-spacing)) + (when mono-face + (let ((default-font (font-spec :family mono-face :size mono-font-size))) + (add-to-list 'default-frame-alist `(font . ,(format "%s %s" mono-face mono-font-size))) + (set-face-font 'fixed-pitch default-font) + (set-frame-font default-font t t))) + (when variable-face + (set-face-font 'variable-pitch (font-spec :name variable-face :size variable-font-size)))) + + (defun ap/set-fonts-according-to-system () + (interactive) + (cond + ((eq window-system 'w32) + (ap/set-fonts "Liberation Mono" 11 "Segoe UI" 11 t)) + ((or (eq window-system 'mac) + (eq window-system 'ns)) + (let ((displays (string-to-number (shell-command-to-string "system_profiler SPDisplaysDataType | grep \"Online: Yes\" | wc -l")))) + (if (eq displays 1) + (ap/set-fonts "Fira Code" 14 "Lucida Grande" 14 t nil) + (ap/set-fonts "Monoid" 12 "Helvetica Neue" 12 t 0.1)))) + ((and (eq window-system 'x) + (not (eq system-type 'gnu/linux/windows))) + (set-fontset-font "fontset-default" 'unicode (font-spec :name "PT Mono" :size 17)) + (ap/set-fonts "PT Mono" 17 "Noto Sans" 14 nil)) + ((and (eq window-system 'x) + (eq system-type 'gnu/linux/windows)) + (ap/set-fonts "Noto Mono" 12 "Sans" 12 nil)))) + + (ap/set-fonts-according-to-system)) +;; #+END_SRC + +;; Reduce font decoration. I’m trying to see whether this helps me focus +;; on the right things. +;; #+BEGIN_SRC emacs-lisp +(setq font-lock-maximum-decoration '((dired-mode . 1) + (t . 1))) +;; #+END_SRC + +;; Make symbols prettier. Turns out, in many cases, this is already +;; configured, just not enabled. If using the mac-port version of Emacs, +;; it has it's own, more extensive version. + +;; #+BEGIN_SRC emacs-lisp +(if (eq window-system 'mac) + (mac-auto-operator-composition-mode +1) + (global-prettify-symbols-mode +1)) +;; #+END_SRC + +;; *** Page Breaks + +;; By default, Emacs displays page breaks as ^L. Lines look much nicer. +;; On Windows, Emacs incorrectly detects that U+2500 (Box Drawings Light +;; Horizontal) can only be displayed with a different font, which is not +;; correct, at least for Liberation Mono. + +;; #+BEGIN_SRC emacs-lisp +(use-package page-break-lines + :defer 5 + :diminish page-break-lines-mode + :config (progn + (global-page-break-lines-mode) + (unless (eq (char-displayable-p ?─) (char-displayable-p ?a)) + (set-fontset-font "fontset-default" + (cons page-break-lines-char page-break-lines-char) + (face-attribute 'default :family))))) +;; #+END_SRC +;; *** Modeline + +;; #+BEGIN_SRC emacs-lisp +(column-number-mode -1) +(line-number-mode -1) +(size-indication-mode t) + + +(require 'f) +(setq frame-title-format (list "Emacs" + (if (and nix-emacs invocation-directory) + (list " (Nix Generation " + (cadr + (split-string (f-base + (car + (last (seq-take-while + (lambda (s) (s-contains? "profile" s)) + (split-string + (s-chomp (shell-command-to-string (concat "nix-store -q --roots " invocation-directory))) + "\n"))))) + "-")) + " " + (s-left 6 (nth 3 (f-split invocation-directory))) + "..." + (s-right 6 (car (split-string (nth 3 (f-split invocation-directory)) "-"))) + ")")) + '(buffer-file-name " — %f") + '(dired-directory (" — " dired-directory)))) +;; #+END_SRC + +;; *** Chrome + +;; Sometimes I like to hide clutter. Other times, it's useful. + +;; #+BEGIN_SRC emacs-lisp +(defvar mode-line-default-format mode-line-format) +(defvar mode-line-default-hidden nil + "Whether to hide the mode line by default") + +(defun show-mode-line () + (interactive) + (setq mode-line-format mode-line-default-format) + (when (called-interactively-p 'interactive) + (setq-default mode-line-format mode-line-default-format) + (setq mode-line-default-hidden nil))) +(defun hide-mode-line () + (interactive) + (setq mode-line-format nil) + (when (called-interactively-p 'interactive) + (setq-default mode-line-format nil) + (setq mode-line-default-hidden t))) + +(setq-default cursor-in-non-selected-windows nil) + +(defun hide-clutter () + (interactive) + (hide-mode-line)) + +(defun show-clutter () + (interactive) + (show-mode-line)) + +(when mode-line-default-hidden + (call-interactively #'hide-mode-line)) + +(setq-default indicate-buffer-boundaries nil) +(fringe-mode '(4 . 4)) + +(defun hide-mode-line-if-default-hidden () + (if mode-line-default-hidden + (hide-mode-line) + (show-mode-line))) + +(add-to-list 'default-frame-alist '(border-width . 0)) +(add-to-list 'default-frame-alist '(internal-border-width . 0)) +(when (or (eq window-system 'x) + (eq window-system 'mac)) + (setq window-divider-default-bottom-width 1 + window-divider-default-right-width 1 + window-divider-default-places t) + (window-divider-mode +1)) + +(add-hook 'after-change-major-mode-hook #'hide-mode-line-if-default-hidden) + +(add-hook 'minibuffer-setup-hook #'show-mode-line) +(add-hook 'minibuffer-exit-hook #'hide-mode-line) +;; #+END_SRC + +;; *** Highlight Changes + +;; Highlight what just changed when I undo, yank, and so on. + +;; #+BEGIN_SRC emacs-lisp +(use-package volatile-highlights + :diminish volatile-highlights-mode + :config (progn + (volatile-highlights-mode t))) +;; #+END_SRC + +;; *** Beacon + +;; I was against the idea of having flashy animations inside Emacs, but +;; this one is useful. It highlights the cursor when scrolling or +;; switching windows. + +;; #+BEGIN_SRC emacs-lisp +(use-package beacon + :diminish beacon-mode + :config (progn + (beacon-mode +1) + (setq beacon-blink-delay 0.25 + beacon-blink-duration 0.25 + beacon-size 20 + beacon-color "#a1b56c"))) +;; #+END_SRC + +;; *** Renaming major modes + +;; Diminishing major modes does not happen in the same manner as minor +;; modes. + +;; #+BEGIN_SRC emacs-lisp +(unless (version<= emacs-version "24.4") + (use-package cyphejor + :defer 2 + :config (progn + (setq cyphejor-rules `(("emacs" "ε") + ("diff" "Δ") + ("js2" "js") + ("magit-status" ,(char-to-string (seq-find #'char-displayable-p '(11942 5848 177)))) + ("inferior" "i" :prefix) + ("interaction" "i" :prefix) + ("interactive" "i" :prefix) + ("menu" "▤" :postfix) + ("ledger" "Ledger") + ("mode" "") + ("shell" "sh" :postfix))) + (cyphejor-mode 1)))) +;; #+END_SRC + + +;; ** Environment Variables + +;; MacOS doesn’t have a reasonable way to set environment variables and +;; read them automatically any more. So, let’s use the +;; [[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] package to set up ~exec-path~ and similar +;; variables from whatever my shell configuration is. + +;; On Windows, I like to run Emacs from the system tray menu of VcXsrv. +;; It starts up without an environment in this case as well. + +;; #+BEGIN_SRC emacs-lisp +(use-package exec-path-from-shell + :if (or (eq system-type 'darwin) + (eq system-type 'gnu/linux/windows) + (and (eq system-type 'gnu/linux) + (daemonp))) + :config (progn + (setq exec-path-from-shell-arguments '("-l")) + (exec-path-from-shell-initialize))) +;; #+END_SRC + +;; *** NixOS sandboxes + +;; I'm currently exploring using nix to create sandboxes for +;; development. This package allows using tools from inside sandboxes, +;; and some convenience commands for building packages and launching shells. + +;; #+BEGIN_SRC emacs-lisp +(use-package nix-sandbox + :config (progn + (with-eval-after-load 'flycheck + (setq flycheck-command-wrapper-function + (lambda (command) + (if (nix-current-sandbox) + (apply 'nix-shell-command (nix-current-sandbox) command) + command)) + flycheck-executable-find + (lambda (cmd) + (if (nix-current-sandbox) + (nix-executable-find (nix-current-sandbox) cmd) + (executable-find cmd))))))) +;; #+END_SRC + +;; ** Keybindings + +;; I think =set-keyboard-coding-system= stops OS X from doing something +;; annoying to add accents. The modifier setup is to match my +;; re-arrangement of modifiers on OSX: Cmd on the outside, then +;; Option/alt, then Control. + +;; #+BEGIN_SRC emacs-lisp +(when (eq system-type 'darwin) + (set-keyboard-coding-system nil) + (custom-set-variables + '(mac-option-modifier 'meta) + '(mac-right-option-modifier 'none) + '(mac-control-modifier 'control) + '(mac-right-control-modifier 'left) + '(mac-command-modifier 'super) + '(mac-right-command-modifier 'left) + '(mac-function-modifier 'hyper)) + (unbind-key "s-x")) +;; #+END_SRC + +;; #+BEGIN_SRC emacs-lisp +(unbind-key "") +(bind-key* "" #'compile) +(bind-key* "" #'kmacro-start-macro-or-insert-counter) +(bind-key* "" #'kmacro-end-or-call-macro) + +(bind-key* "" #'execute-extended-command) + +(unbind-key "C-z") +(bind-key* "C-" #'other-window) + +(bind-key* "C-x C-r" #'revert-buffer) +(bind-key* "C-x C-j" #'delete-indentation) +(unbind-key "C-x C-c") + +(bind-key* "C-c i" #'insert-char) +(bind-key* "M-/" #'hippie-expand) + +(unbind-key "s-h") +(unbind-key "s-n") +(unbind-key "s-p") +(unbind-key "s-w") +(bind-key* "s-k" #'kill-or-delete-this-buffer-dwim) + +(bind-key "C-M-a" #'backward-paragraph text-mode-map) +(bind-key "C-M-e" #'forward-paragraph text-mode-map) + +(bind-key* "s-x" (define-prefix-command 'super-x-map)) +(bind-key* "s-," #'switch-to-dotfiles) +(bind-key* "C-x M-x" #'execute-extended-command) +(set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) +;; #+END_SRC + +;; *** Crux + +;; I can replace most of the simple helper/wrapper functions in my +;; configuration with crux.el + +;; #+BEGIN_SRC emacs-lisp +(use-package crux + :bind (("M-o" . crux-smart-open-line-above) + ("C-o" . crux-smart-open-line) + + ("C-x 4 t" . crux-transpose-windows) + ("C-c e" . crux-eval-and-replace) + ("C-c D" . crux-delete-file-and-buffer) + ("C-c R" . crux-rename-file-and-buffer)) + :config (progn + (crux-reopen-as-root-mode +1)) + :init (progn + (defalias 'delete-current-buffer-file #'crux-delete-file-and-buffer) + (defalias 'rename-current-buffer-file #'crux-rename-file-and-buffer))) +;; #+END_SRC + +;; ** Projects + +;; #+BEGIN_SRC emacs-lisp +(defun switch-to-dotfiles () + (interactive) + (projectile-switch-project-by-name (car (split-string (shell-command-to-string "ghq list --full-path dotfiles"))))) +;; #+END_SRC + +;; *** The Silver Searcher + +;; #+BEGIN_SRC emacs-lisp +(use-package ag + :defer 30 + :config (setq ag-project-root-function #'projectile-project-root)) + +(use-package wgrep-ag + :after ag) +;; #+END_SRC + +;; *** Ripgrep + +;; Step over Silver Search, here comes a new challenger. + +;; #+BEGIN_SRC emacs-lisp +(use-package ripgrep + :if (executable-find "rg")) + +(use-package projectile-ripgrep + :after (ripgrep projectile) + :if (executable-find "rg") + :bind (("C-c p s r" . projectile-ripgrep))) +;; #+END_SRC + +;; *** Projectile + +;; Projectile is awesome for working in projects, especially VCS-backed +;; ones. + +;; #+BEGIN_SRC emacs-lisp +(use-package projectile + :bind (("s-p" . projectile-switch-project) + ("C-c C-f" . projectile-find-file) + ("s-x s-f" . projectile-find-file) + ("C-x g" . projectile-vc) + ("s-G" . projectile-vc)) + :demand t + :diminish projectile-mode + :config (progn + (projectile-global-mode +1) + (add-to-list 'projectile-globally-ignored-directories ".stversions") + + (defun yarn-install (&optional arg) + (interactive "P") + (projectile-with-default-dir (projectile-project-root) + (cmd-to-echo "yarn" "install"))) + + (defun yarn-add-dev (package) + (interactive "spackage: ") + (projectile-with-default-dir (projectile-project-root) + (cmd-to-echo "yarn" (concat "add --dev " package)))) + + (defun yarn-add (package) + (interactive "spackage: ") + (projectile-with-default-dir (projectile-project-root) + (cmd-to-echo "yarn" (concat "add " package)))) + + (defun yarn-run (cmd) + (interactive (list + (projectile-completing-read "command: " (alist-get 'scripts (json-read-file (expand-file-name "package.json" (projectile-project-root))))))) + (projectile-with-default-dir (projectile-project-root) + (cmd-to-echo "yarn" (concat "run " cmd)))) + + (defun ap/open-project (&optional arg) + (interactive "P") + (let ((project-dir (projectile-completing-read + "Open project: " + (ghq--find-projects)))) + (projectile-switch-project-by-name + (expand-file-name project-dir (ghq--find-root)) arg))) + + (setq projectile-switch-project-action #'projectile-commander + projectile-completion-system 'ivy + projectile-create-missing-test-files t) + + (defun ap/projectile-test-suffix (project-type) + (cond + ((member project-type '(node-yarn node-npm)) ".test") + (t (projectile-test-suffix project-type)))) + (setq projectile-test-suffix-function #'ap/projectile-test-suffix) + + (projectile-register-project-type 'node-yarn '("yarn.lock") "yarn start" "yarn test") + (projectile-register-project-type 'node '("package.json") "npm start" "npm test"))) + +(use-package counsel-projectile + :after (counsel projectile) + :config (progn + (counsel-projectile-on) + (def-projectile-commander-method ?A + "Find rg on project." + (call-interactively #'counsel-projectile-rg)) + (define-key projectile-mode-map [remap counsel-projectile-ag] #'counsel-projectile-rg))) +;; #+END_SRC + +;; *** vc + +;; This is nice for some things that magit doesn’t do, and for those rare +;; occasions that I’m working with something other than git. + +;; #+BEGIN_SRC emacs-lisp +(use-package vc + :defer t + :bind (("C-x v C" . vc-resolve-conflicts)) + :config (progn + (setq vc-follow-symlinks t) + (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" + vc-ignore-dir-regexp + tramp-file-name-regexp)))) +;; #+END_SRC + +;; *** git-gutter-fringe + +;; It’s nice to be able to see at a glance which lines of a file have +;; changed. This package colours the fringe. I have it set to the right +;; fringe so it doesn’t interfere with flycheck. + +;; #+BEGIN_SRC emacs-lisp +(eval-when-compile (require 'fringe-helper)) +(use-package git-gutter-fringe + :defer 2 + :diminish git-gutter-mode + :config (progn + (global-git-gutter-mode 1) + ;; places the git gutter outside the margins. + (setq-default fringes-outside-margins t) + ;; thin fringe bitmaps + (fringe-helper-define 'git-gutter-fr:added '(center repeated) + ".XXX....") + (fringe-helper-define 'git-gutter-fr:modified '(center repeated) + ".XXX....") + (fringe-helper-define 'git-gutter-fr:deleted 'bottom + ".......X" + "......XX" + ".....XXX" + "....XXXX") + (setq git-gutter-fr:side 'right-fringe))) +;; #+END_SRC + +;; *** magit + +;; Magit is my favourite way to use git. I use selective staging all the +;; time. Make sure to set it up with a nice =completing-read-function= + +;; #+BEGIN_SRC emacs-lisp +(use-package magit + :defer 5 + :commands (magit-status) + :config (progn (setq magit-completing-read-function #'ivy-completing-read + magit-popup-use-prefix-argument 'default + magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1 + global-magit-file-mode nil) + (add-to-list 'magit-no-confirm 'safe-with-wip)) + :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) +;; #+END_SRC + +;; *** git-messenger + +;; Popup the last commit that changed the line at point. + +;; #+BEGIN_SRC emacs-lisp +(use-package git-messenger + :bind* (("C-x v p" . git-messenger:popup-message)) + :config (progn + (setq git-messenger:use-magit-popup t))) +;; #+END_SRC + +;; *** git-timemachine + +;; This package allow me to go through a file’s history with just a few +;; keys. It makes it very easy to figure what what exactly was in a file +;; in the past. I often find it useful when I remember writing something +;; a particular way, but it changed later. + +;; #+BEGIN_SRC emacs-lisp +(use-package git-timemachine + :commands git-timemachine) +;; #+END_SRC + +;; *** ghq + +;; [[https://github.com/motemen/ghq][=ghq=]] clones VCS-backed projects to a common directory. It should +;; seem familiar to anyone who's used =go get= before. [[https://github.com/rcoedo/emacs-ghq][=emacs-ghq=]] is a +;; simple wrapper for it. + +;; #+BEGIN_SRC emacs-lisp +(use-package ghq + :if (executable-find "ghq")) +;; #+END_SRC + +;; ** Files + +;; *** Auto-saving + +;; Auto-save everything to a temporary directory, instead of cluttering +;; the filesystem. I don’t want emacs-specific lockfiles, either. + +;; #+BEGIN_SRC emacs-lisp +(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) + create-lockfiles nil) +;; #+END_SRC +;; *** Backups + +;; I like to keep my backups out of regular folders. I tell emacs to use +;; a subfolder of its configuration directory for that. Also, use the +;; trash for deleting on OS X. +;; #+BEGIN_SRC emacs-lisp +(let ((backup-dir (expand-file-name "~/.emacs.d/backups/"))) + (unless (file-directory-p backup-dir) + (make-directory backup-dir)) + (setq backup-directory-alist `((".*" . ,backup-dir)) + backup-by-copying-when-linked t + backup-by-copying-when-mismatch t)) +(if (eq system-type 'darwin) + (setq delete-by-moving-to-trash t) + (if (and (executable-find "trash") (not (fboundp #'system-move-file-to-trash))) + (defun system-move-file-to-trash (file) + (call-process (executable-find "trash") + nil 0 nil + file)))) +;; #+END_SRC + +;; *** autorevert + +;; #+BEGIN_SRC emacs-lisp +(use-package autorevert + :diminish auto-revert-mode + :init (progn + (global-auto-revert-mode 1) + (setq auto-revert-verbose nil + auto-revert-use-notify (not (eq system-type 'darwin))))) +;; #+END_SRC + +;; *** Encoding + +;; UTF-8 is usually appropriate. Note that =prefer-coding-system= expects +;; only a coding system, not a coding system and line ending combination. + +;; #+BEGIN_SRC emacs-lisp +(prefer-coding-system 'utf-8) +(setq-default buffer-file-coding-system 'utf-8-auto-unix) +;; #+END_SRC + +;; *** Buffer-file management + +;; Ask if I want to create a directory when it doesn’t exist. This is +;; especially nice when starting new projects. + +;; #+BEGIN_SRC emacs-lisp +(defun my-create-non-existent-directory () + (let ((parent-directory (file-name-directory buffer-file-name))) + (when (and (not (file-exists-p parent-directory)) + (y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory))) + (make-directory parent-directory t)))) +(add-to-list 'find-file-not-found-functions #'my-create-non-existent-directory) +;; #+END_SRC + +;; I often want to rename or delete the file that I’m currently visiting +;; with a buffer. + +;; #+BEGIN_SRC emacs-lisp +(defun kill-or-delete-this-buffer-dwim (&optional arg) + "Kills current buffer. With prefix arg, delete it." + (interactive "P") + (if (equal arg '(4)) + (delete-current-buffer-file) + (if server-buffer-clients + (server-edit) + (let ((buf (buffer-name))) + (when (equal buf "*HTTP Response*") + (other-window 1)) + (kill-buffer buf))))) +;; #+END_SRC + +;; *** Whitespace + +;; Show bad whitespace, so that I can fix it. + +;; #+BEGIN_SRC emacs-lisp +(defun show-trailing-whitespace-on () + (interactive) + (setq-local show-trailing-whitespace t)) +(defun show-trailing-whitespace-off () + (interactive) + (setq-local show-trailing-whitespace nil)) +(add-hook 'prog-mode-hook #'show-trailing-whitespace-on) +(add-hook 'text-mode-hook #'show-trailing-whitespace-on) +;; #+END_SRC + +;; *** shrink-whitespace + +;; DWIM whitespace removal. So I don’t need =M-SPC=, =M-\= and =C-x o= +;; for similar things any more. + +;; #+BEGIN_SRC emacs-lisp +(use-package shrink-whitespace + :bind ("M-SPC" . shrink-whitespace)) +;; #+END_SRC + +;; *** Tramp + +;; Tramp is awesome. It makes SSH feel Unix-y. The proxy setup is so +;; that I can sudo on remote machines + +;; #+BEGIN_SRC emacs-lisp +(use-package tramp + :defer 7 + :config (progn + (unless (getenv "SSH_AUTH_SOCK") + (setenv "SSH_AUTH_SOCK" (format "/run/user/%s/ssh-agent" (user-uid)))) + (setq tramp-default-method "ssh" + tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root")) + tramp-backup-directory-alist backup-directory-alist + tramp-completion-reread-directory-timeout 60 + tramp-ssh-controlmaster-options nil + backup-enable-predicate (lambda (name) + (and (normal-backup-enable-predicate name) + (not (let ((method (file-remote-p name 'method))) + (when (stringp method) + (member method '("su" "sudo"))))))) + tramp-shell-prompt-pattern "\\(?:^\\| \\)[^]#$%>\n]*#?[]#$%>❯›] *\\(\\[\\??[0-9;]*[a-zA-Z] *\\)*") + (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" (concat "/" tramp-default-method ":%h:"))) + (add-to-list 'tramp-default-proxies-alist `(,(regexp-quote (system-name)) nil nil)) + (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil)))) +;; #+END_SRC + +;; *** ediff + +;; I like a horizonal diff setup, with everything in one frame. + +;; #+BEGIN_SRC emacs-lisp +(use-package ediff + :defer t + :config (progn + (setq ediff-split-window-function 'split-window-horizontally + ediff-window-setup-function 'ediff-setup-windows-plain))) +;; #+END_SRC + +;; ** Indentation + +;; Ah, a complicated topic. One day we’ll all be using elastic +;; tabstops. I’ve recently switched to using two spaces, since elastic +;; tabstops is probably never going to happen. + +;; #+BEGIN_SRC emacs-lisp +(setq-default tab-width 2 + indent-tabs-mode nil) +(electric-indent-mode +1) +;; #+END_SRC + + +;; *** smart-tabs-mode + +;; Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns +;; with spaces. Perfect! + +;; #+BEGIN_SRC emacs-lisp +(use-package smart-tabs-mode + :defer 1 + :config (progn + (smart-tabs-insinuate 'c 'cperl 'python) + (define-hook-helper php-mode () + (smart-tabs-mode indent-tabs-mode)))) +;; #+END_SRC + +;; *** editorconfig + +;; #+BEGIN_SRC emacs-lisp +(use-package editorconfig + :diminish "EC" + :config (editorconfig-mode 1)) +;; #+END_SRC + +;; *** dtrt-indent-mode + +;; Sometimes people use different indentation settings. [[https://github.com/jscheid/dtrt-indent][dtrt-indent]] +;; guesses the correct settings for me. + +;; #+BEGIN_SRC emacs-lisp +(use-package dtrt-indent + :config (progn + (define-hook-helper after-change-major-mode () + (unless (and (boundp editorconfig-mode) + editorconfig-mode) + (dtrt-indent-adapt))) + (defadvice dtrt-indent-try-set-offset (after toggle-smart-tabs activate) + (smart-tabs-mode (or indent-tabs-mode -1))))) +;; #+END_SRC + +;; ** Security + +;; *** password-store + +;; This is a frontend to the GPG-powered =pass= program. +;; #+BEGIN_SRC emacs-lisp +(use-package password-store + :defer 15 + :config (progn + (setq password-store-password-length 16))) +;; #+END_SRC +;; ** Buffers + +;; *** Ibuffer +;; Ibuffer is quite nice for listing all buffers. + +;; #+BEGIN_SRC emacs-lisp +(use-package ibuffer + :bind (("C-x C-b" . ibuffer)) + :config (progn + (setq ibuffer-saved-filter-groups + (quote (("default" + ("org" (mode . org-mode)) + ("emacs" (mode . emacs-lisp-mode)) + ("zsh" (filename . "/zsh")) + ("server" (filename . "/su:root@server")))))) + + ;; Human-readable base-2 size column + (define-ibuffer-column size-h + (:name "Size" :inline t) + (cond + ((> (buffer-size) 1024) + (format "%7.2fK" (/ (buffer-size) 1024.0))) + ((> (buffer-size) 1048576) + (format "%7.2fM" (/ (buffer-size) 1048576.0))) + (t + (format "%8d" (buffer-size))))) + + (setq ibuffer-formats + '((mark modified read-only " " + (name 18 18 :left :elide) + " " + (size-h 9 -1 :right) + " " + (mode 16 16 :left :elide) + " " + filename-and-process))))) +;; #+END_SRC + +;; *** Relative Buffer names + +;; #+BEGIN_SRC emacs-lisp +(use-package relative-buffers + :defer 15 + :config (progn + (global-relative-buffers-mode))) +;; #+END_SRC +;; *** Narrowing + +;; Enable it without prompting + +;; #+BEGIN_SRC emacs-lisp +(put 'narrow-to-defun 'disabled nil) +(put 'narrow-to-page 'disabled nil) +(put 'narrow-to-region 'disabled nil) +;; #+END_SRC + +;; *** ace-window + +;; I don’t often have many windows open at once, but when I do, +;; =ace-window= is really nice to jump around them in the same way that +;; =ace-jump= or =avy= work. +;; #+BEGIN_SRC emacs-lisp +(use-package ace-window + :bind (("s-s" . ace-window)) + :config (progn + (setq aw-dispatch-always t + aw-dispatch-alist '((?k aw-delete-window " Ace - Delete Window") + (?K aw-delete-window) + (?m aw-swap-window " Ace - Swap Window") + (?f aw-flip-window) + (?v aw-split-window-vert " Ace - Split Vert Window") + (?b aw-split-window-horz " Ace - Split Horz Window") + (?m delete-other-windows " Ace - Maximize Window") + (?l delete-other-windows) + (?, winner-undo) + (?. winner-redo)) + aw-keys '(?a ?r ?s ?t ?n ?e ?i ?o)))) +;; #+END_SRC + +;; ** Windows + +;; Scrolling is tricky. I use this setup to help me keep track of the +;; point whilst I’m moving about. + +;; #+BEGIN_SRC emacs-lisp +(setq scroll-conservatively 100 + scroll-margin 1 + scroll-preserve-screen-position t + mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control))) + split-height-threshold 80 + split-width-threshold 160 + frame-resize-pixelwise nil) +(if (boundp 'ns-pop-up-frames) + (setq ns-pop-up-frames nil)) +;; #+END_SRC + +;; *** eyebrowse + +;; Workspaces, a bit like dwm. On Windows and Linux (at least the WMs +;; I'm likely to use), super+{0-9} are taken from the OS, so use meta +;; instead. On macOS, super makes a lot of sense, as it's used by most +;; programs to switch between program windows or views. + +;; #+BEGIN_SRC emacs-lisp +(use-package eyebrowse + :config (progn + (setq eyebrowse-new-workspace t) + (when (eq system-type 'darwin) + (bind-keys + ("s-0" . eyebrowse-switch-to-window-config-0) + ("s-1" . eyebrowse-switch-to-window-config-1) + ("s-2" . eyebrowse-switch-to-window-config-2) + ("s-3" . eyebrowse-switch-to-window-config-3) + ("s-4" . eyebrowse-switch-to-window-config-4) + ("s-5" . eyebrowse-switch-to-window-config-5) + ("s-6" . eyebrowse-switch-to-window-config-6) + ("s-7" . eyebrowse-switch-to-window-config-7) + ("s-8" . eyebrowse-switch-to-window-config-8) + ("s-9" . eyebrowse-switch-to-window-config-9))) + (bind-keys* + ("M-0" . eyebrowse-switch-to-window-config-0) + ("M-1" . eyebrowse-switch-to-window-config-1) + ("M-2" . eyebrowse-switch-to-window-config-2) + ("M-3" . eyebrowse-switch-to-window-config-3) + ("M-4" . eyebrowse-switch-to-window-config-4) + ("M-5" . eyebrowse-switch-to-window-config-5) + ("M-6" . eyebrowse-switch-to-window-config-6) + ("M-7" . eyebrowse-switch-to-window-config-7) + ("M-8" . eyebrowse-switch-to-window-config-8) + ("M-9" . eyebrowse-switch-to-window-config-9)) + (eyebrowse-mode +1))) +;; #+END_SRC + +;; ** Sessions + +;; *** Desktop +;; Save my Emacs session and restore it on startup. + +;; #+BEGIN_SRC emacs-lisp +(use-package desktop + :ensure nil + :config (progn + (setq desktop-dirname (expand-file-name "desktop/" user-emacs-directory) + desktop-base-file-name "emacs.desktop" + desktop-base-lock-name "lock" + desktop-path (list desktop-dirname) + desktop-save 'if-exists + desktop-files-not-to-save "^$" + desktop-load-locked-desktop nil) + (unless (file-directory-p desktop-dirname) + (make-directory desktop-dirname)) + (desktop-save-mode 1))) +;; #+END_SRC + +;; *** winner + +;; Undo, for window-based commands. + +;; #+BEGIN_SRC emacs-lisp +(use-package winner + :config (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")) + :init (progn + (winner-mode 1))) +;; #+END_SRC + +;; *** windmove + +;; Directional window movement + +;; #+BEGIN_SRC emacs-lisp +(use-package windmove + :bind (("S-" . windmove-left) + ("S-" . windmove-right) + ("S-" . windmove-up) + ("S-" . windmove-down))) +;; #+END_SRC +;; ** Blogging + +;; I have a [[https://alanpearce.uk][blog]] that I publish with hugo. + +;; #+BEGIN_SRC emacs-lisp +(use-package easy-hugo + :config (setq easy-hugo-basedir (car (split-string (shell-command-to-string "ghq list --full-path alanpearce.uk"))) + easy-hugo-url "https://alanpearce.uk" + easy-hugo-default-ext ".md")) +;; #+END_SRC + +;; ** Completion + +;; Make built-in completion a bit more intelligent, by adding substring +;; and initial-based completion and ignoring case. + +;; #+BEGIN_SRC emacs-lisp +(setq completion-styles '(basic initials partial-completion substring) + completion-ignore-case t + tab-always-indent 'complete) +;; #+END_SRC + +;; *** Company + +;; The main choices for automatic completion in Emacs are company and +;; auto-complete-mode. I’ve not tried auto-complete-mode as company +;; seems to work perfectly well for me. + +;; #+BEGIN_SRC emacs-lisp +(use-package company + :commands (company-mode) + :diminish "Cmpl" + :bind (("C-" . company-complete) + ("TAB" . company-indent-or-complete-common)) + :init (progn + (add-hook 'prog-mode-hook #'company-mode-on) + (setq company-backends '(company-bbdb company-web-html company-tern company-nxml company-css company-eclim company-semantic company-elisp + company-clang company-xcode company-cmake company-capf + company-files (company-gtags + company-etags company-keywords) company-oddmuse) + company-frontends '(company-pseudo-tooltip-unless-just-one-frontend + company-preview-frontend + company-echo-metadata-frontend) + company-idle-delay .3 + company-begin-commands '(self-insert-command) + company-auto-complete #'company-explicit-action-p + company-auto-complete-chars '(?\ ?\( ?\) ?.) + company-tooltip-align-annotations t + company-selection-wrap-around t))) +;; #+END_SRC + +;; #+BEGIN_SRC emacs-lisp +(use-package company-web + :after company) +;; #+END_SRC + +;;; * Dates: & Times + +;; *** Calendar + +;; Weeks start on Monday for me and I prefer ISO-style dates. +;; #+BEGIN_SRC emacs-lisp +(use-package calendar + :defer 1 + :config (progn + (setq calendar-week-start-day 1) + (calendar-set-date-style 'iso))) +;; #+END_SRC + +;; Sometimes I want to insert a date or time into a buffer. +;; #+BEGIN_SRC emacs-lisp +(defun insert-date (prefix) + "Insert the current date. With prefix-argument, use British format. With + two prefix arguments, write out the day and month name." + (interactive "P") + (let ((format (cond + ((not prefix) "%Y-%m-%d") + ((equal prefix '(4)) "%d/%m/%Y") + ((equal prefix '(16)) "%A, %d %B %Y")))) + (insert (format-time-string format)))) + +(defun insert-datetime (prefix) + "Insert the current date and time." + (interactive "P") + (let ((format (cond + ((not prefix) "%Y-%m-%d %H:%M:%S") + ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ")))) + (insert (format-time-string format)))) +;; #+END_SRC + +;; #+BEGIN_SRC emacs-lisp +(defun yesterday-time () + "Provide the date/time 24 hours before the time now in the format of current-time." + (timer-relative-time (current-time) -86400)) +;; #+END_SRC + +;; ** Directories + +;; Dired works quite nicely, but not always in the way I want. I don’t +;; like having so many prompts for recursive operations. Also, when I +;; have two dired windows open, assume that I’m going to be +;; copying/moving files between them. + +;; #+BEGIN_SRC emacs-lisp +(use-package dired + :defer 3 + :ensure nil + :config (progn + (bind-key "" #'dired-find-file dired-mode-map) + (bind-key "^" (lambda () (interactive) (find-alternate-file "..")) dired-mode-map) + (setq dired-dwim-target t + dired-recursive-copies 'top + dired-recursive-deletes (if delete-by-moving-to-trash + 'always + 'top) + dired-listing-switches "-alh") + (when (and (eq system-type 'darwin) (executable-find "gls")) + (setq insert-directory-program (executable-find "gls"))) + (put 'dired-find-alternate-file 'disabled nil))) +;; #+END_SRC + +;; Don’t show uninteresting files in dired listings. + +;; #+BEGIN_SRC emacs-lisp +(defun turn-on-dired-omit-mode () + (interactive) + (dired-omit-mode 1)) + +(use-package dired-x + :commands (dired-omit-mode + dired-expunge) + :ensure nil + :config (progn + (setq dired-omit-files "#\\|\\.$" + dired-omit-verbose nil + dired-find-subdir t + dired-bind-jump nil)) + :init (progn + (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode))) +;; #+END_SRC + +;; Expand subfolders like a tree inside the parent + +;; #+BEGIN_SRC emacs-lisp +(with-eval-after-load 'dired + (use-package dired-subtree + :functions (dired-subtree--get-ov + dired-subtree-maybe-up) + :init (progn + (setq dired-subtree-use-backgrounds nil) + (defun dired-subtree-maybe-up () + "Jump up one subtree or directory" + (interactive) + (let ((ov (dired-subtree--get-ov))) + (if ov + (progn (goto-char (overlay-start ov)) + (dired-previous-line 1)) + (dired-up-directory)))) + (bind-key "^" #'dired-subtree-maybe-up dired-mode-map) + (bind-key "i" #'dired-subtree-toggle dired-mode-map)))) +;; #+END_SRC + +;; *** Disk usage + +;; Combine dired and du (disk usage). + +;; #+BEGIN_SRC emacs-lisp +(use-package dired-du + :after dired + :config (progn + (setq dired-du-size-format t))) +;; #+END_SRC + +;; *** Dired-narrow +;; One can already use dired with wildcards to browse a filtered +;; directory listing, but it opens a new buffer. Dired-narrow is a +;; slightly nicer interface: with a currently-open dired buffer, use =/= +;; to start filtering, =RET= to complete the filter and =g= to refresh +;; the buffer, removing the filter. + +;; #+BEGIN_SRC emacs-lisp +(with-eval-after-load 'dired + (use-package dired-narrow + :bind (:map dired-mode-map + ("/" . dired-narrow)))) +;; #+END_SRC + +;; ** Documentation + +;; *** ehelp + +;; ehelp is a less well-known package that’s part of Emacs and slightly +;; improves the normal help commands, mostly by making quitting them easier. + +;; #+BEGIN_SRC emacs-lisp +(use-package ehelp + :bind-keymap ("C-h" . ehelp-map)) +;; #+END_SRC +;; *** counsel-dash + +;; Emacs’ documentation is great to read from inside Emacs. Counsel-dash +;; helps to make documentation for other languages easier to access + +;; #+BEGIN_SRC emacs-lisp +(defmacro ap/create-counsel-dash-hook (mode docsets) + (let* ((mode-s (symbol-name mode)) + (fun (intern (concat "counsel-dash-hook-" mode-s))) + (hook (intern (concat mode-s "-mode-hook")))) + `(progn + (defun ,fun () + (when (require 'counsel-dash nil :noerror) + (seq-map #'counsel-dash-install-docset + (seq-difference ',docsets + (helm-dash-installed-docsets))) + (setq-local counsel-dash-docsets ',docsets))) + (add-hook (quote ,hook) (function ,fun))))) + +(use-package counsel-dash + :defer 20 + :defines counsel-dash-docsets + :config (progn + (setq counsel-dash-browser-func #'eww) + (ap/create-counsel-dash-hook nginx ("Nginx")) + (ap/create-counsel-dash-hook ansible ("Ansible")) + (ap/create-counsel-dash-hook php ("PHP" "Symfony")) + (ap/create-counsel-dash-hook twig ("Twig")) + (ap/create-counsel-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express" "SailsJS" "Lo-Dash")) + (ap/create-counsel-dash-hook markdown ("Markdown")) + (ap/create-counsel-dash-hook saltstack ("SaltStack")) + (ap/create-counsel-dash-hook clojure ("Clojure")) + (ap/create-counsel-dash-hook sql ("PostgreSQL" "MySQL")))) +;; #+END_SRC + +;; *** discover-my-major + +;; A nicer way to browse keybindings for major modes. + +;; #+BEGIN_SRC emacs-lisp +(use-package discover-my-major + :bind ("" . discover-my-major)) +;; #+END_SRC + +;; *** which-key + +;; Popup keybindings following a prefix automatically. + +;; #+BEGIN_SRC emacs-lisp +(use-package which-key + :diminish which-key-mode + :config (progn + (which-key-mode 1) + (which-key-setup-side-window-right-bottom))) +;; #+END_SRC + +;; *** eldoc + +;; Documentation in the echo-area (where the minibuffer is displayed) is +;; rather useful. + +;; #+BEGIN_SRC emacs-lisp +(use-package eldoc + :commands (eldoc-mode) + :diminish eldoc-mode + :config (progn + (setq eldoc-idle-delay 0.1) + (eldoc-add-command 'paredit-backward-delete 'paredit-close-round))) +;; #+END_SRC +;; ** Mail + +;; *** Gnus + +;; At work, I use gnus for email. Some of the setup is specific to my +;; workplace, so I keep it in a host-specific, GPG-encrypted file. + +;; #+BEGIN_SRC emacs-lisp +(use-package gnus + :config (progn + (setq gnus-gcc-mark-as-read t + mml-secure-openpgp-encrypt-to-self t + send-mail-function #'smtpmail-send-it + message-send-mail-function #'smtpmail-send-it))) + +(with-eval-after-load "gnus-mime" + (define-key gnus-mime-button-map " " #'gnus-mime-view-part-externally)) + +(with-eval-after-load "mailcap" + (when (eq system-type 'darwin) + (mailcap-add-mailcap-entry "application" "pdf" '((viewer . "/usr/bin/qlmanage -p %s") (type . "application/pdf"))))) + +(with-eval-after-load "mm-decode" + (add-to-list 'mm-discouraged-alternatives "text/html") + (add-to-list 'mm-discouraged-alternatives "text/richtext")) +;; #+END_SRC + +;; *** BBDB + +;; As I'm using Emacs for email, it makes sense to have contact +;; information here as well. + +;; #+BEGIN_SRC emacs-lisp +(use-package bbdb + :config (progn + (bbdb-initialize 'gnus 'message 'pgp) + (bbdb-mua-auto-update-init 'gnus 'message) + (setq bbdb-send-mail-style 'gnus + bbdb-complete-mail-allow-cycling t + bbdb-mua-auto-update t + bbdb-mua-update-interactive-p '(query . create) + bbdb-message-all-addresses t + bbdb-offer-save t + bbdb-offer-to-create 1))) +;; #+END_SRC + +;; ** Misc + +;; #+BEGIN_SRC emacs-lisp +(defvar *init-file* + (let ((init-file (or user-init-file + (expand-file-name "init.el" user-emacs-directory)))) + (expand-file-name "init.el" + (file-name-directory (file-truename init-file)))) + "Where the emacs init file really is, passing through symlinks.") +(set-register ?e `(file . ,*init-file*)) + +(defun ap/remove-extra-cr () + "Remove extraneous CR codes from a file" + (interactive) + (save-excursion + (goto-char (point-min)) + (while (search-forward " + " nil t) + (replace-match "")))) + +(use-package rect + :ensure nil + :init (defun copy-rectangle (start end) + "Copy the region-rectangle." + (interactive "r") + (setq killed-rectangle (extract-rectangle start end)))) + +(defun shell-execute (to-current-buffer) + (interactive "P") + (let ((file-buffer (if (buffer-file-name) + (file-name-nondirectory (buffer-file-name)) + "")) + (command (read-shell-command "Shell command: " nil nil nil))) + (shell-command (replace-regexp-in-string "%" file-buffer command) to-current-buffer))) + +(defun process-exit-code (program &rest args) + "Run PROGRAM with ARGS and return the exit code" + (apply 'call-process program nil nil nil args)) + +(defun narrow-to-region-indirect (start end) + "Restrict editing in this buffer to the current region, indirectly." + (interactive "r") + (deactivate-mark) + (let ((buf (clone-indirect-buffer nil nil))) + (with-current-buffer buf + (narrow-to-region start end)) + (switch-to-buffer buf))) + +(bind-key* "M-!" #'shell-execute) +(bind-key* "C-x r M-w" #'copy-rectangle) +;; #+END_SRC + +;; *** Auxillary Configuration + +;; #+BEGIN_SRC emacs-lisp +(require 'pinentry) + +(defvar have-private-key + (file-exists-p (expand-file-name "secring.gpg" "~/.gnupg/"))) + +(defvar gpg-agent-ssh-sock + (or (getenv "GPG_AGENT_INFO") + (concat "/run/user/" (number-to-string (user-uid)) "/gnupg/S.gpg-agent.ssh"))) + +(defun read-gpg-file (file) + (let ((file-to-decrypt (expand-file-name file user-emacs-directory)) + (ctx (epg-make-context epa-protocol))) + (if (file-exists-p file-to-decrypt) + (epg-decrypt-file ctx file-to-decrypt nil) + (message "Decrypting %s...failed" file-to-decrypt) + (error "File %s does not exist" file-to-decrypt)))) + +(defun load-gpg (file) + (if have-private-key + (load file) + (message "WARNING: Couldn't load %s (No gpg key found)" file))) + +; load this in a post-frame hook because gpg-agent asks for a password on first +; startup and caches it. Don't want emacs daemon to hang because of gpg-agent. +(defun load-private-data () + (interactive) + (if (not (file-exists-p (expand-file-name (concat (system-name) ".el.gpg") user-emacs-directory))) + (message "No encrypted configuration matches system name `%s'" (system-name)) + (if (not have-private-key) + (message "ERROR: Private GPG key not found") + (unless (or (getenv "GPG_AGENT_INFO") + (getenv "SSH_AUTH_SOCK")) + (start-process "gpg-agent" nil "gpg-agent" "--daemon") + (setenv "SSH_AUTH_SOCK" gpg-agent-ssh-sock)) + (setq password-cache-expiry nil) + (unless (file-exists-p (concat pinentry--socket-dir "pinentry")) + (pinentry-start) + (add-hook 'kill-emacs-hook 'pinentry-stop)) + (add-to-list 'load-suffixes ".el.gpg") + (load-gpg (expand-file-name (system-name) user-emacs-directory))))) + +(defun first-frame-hook (frame) + (remove-hook 'after-make-frame-functions #'first-frame-hook) + (run-at-time nil nil 'load-private-data)) + +(if (eq 1 (length (frame-list))) + (add-hook 'after-init-hook #'load-private-data) + (add-hook 'after-make-frame-functions #'first-frame-hook)) +;; #+END_SRC + +;; ** Minibuffer + +;; Sometimes I want to use the minibuffer, but I’m already inside it. +;; Fortunately, this is possible. Of course, I need to know how many +;; minibuffers there are on the stack. + +;; #+BEGIN_SRC emacs-lisp +(setq enable-recursive-minibuffers t) +(minibuffer-depth-indicate-mode t) +;; #+END_SRC + +;; This avoids some issue with the minibuffer and the point being behind +;; the prompt. I don’t remember what exactly. +;; #+BEGIN_SRC emacs-lisp +(setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)) +;; #+END_SRC + +;; Occasionally, I exit emacs. I should probably reduce the frequency of this. +;; #+BEGIN_SRC emacs-lisp +(if (daemonp) + (defalias 'exit-emacs #'delete-frame) + (defalias 'exit-emacs #'save-buffers-kill-emacs)) +;; #+END_SRC + +;; *** swiper/ivy + +;; Ivy is the new kid on the completion block. It seems to be a strong +;; replacement for helm so far. + +;; #+BEGIN_SRC emacs-lisp +(use-package swiper + :bind (("C-s" . swiper) + ("C-r" . swiper) + ("C-=" . swiper)) + :diminish ivy-mode + :demand t + :config (progn + (ivy-mode 1) + (setq ivy-re-builders-alist '((t . ivy--regex-plus)) + ivy-extra-directories '("./")) + (ivy-set-actions 'ivy-switch-buffer '(("k" (lambda (x) + (kill-buffer x) + (ivy--reset-state ivy-last)) + "kill"))) + (add-to-list 'ivy-initial-inputs-alist '(counsel-M-x . "")))) +;; #+END_SRC + +;; *** counsel + +;; #+BEGIN_SRC emacs-lisp +(use-package counsel + :config (progn + (bind-key "M-x" #'counsel-M-x) + (bind-key "" #'counsel-M-x) + (bind-key "" #'counsel-M-x) + (bind-key "C-c M-x" #'execute-extended-command) + (bind-key "C-x C-f" #'counsel-find-file) + (bind-key "M-y" #'counsel-yank-pop) + (bind-key "C-x i" #'counsel-imenu) + (bind-key "M-y" #'ivy-next-line ivy-minibuffer-map) + (defadvice counsel-find-file (after find-file-sudo activate) + "Find file as root if necessary." + (when (and buffer-file-name + (not (file-writable-p buffer-file-name))) + (message "File not writable %s" buffer-file-name) + (find-alternate-file (concat "/sudo::" buffer-file-name)))) + (setq counsel-rg-base-command "rg -i --no-heading --line-number --hidden %s ."))) +;; #+END_SRC + + +;; *** smex + +;; Smex is my favourite way to use =M-x=. Counsel’s =counsel-M-x= +;; function uses it internally, so I’m keeping it around, even though I +;; don’t use it directly. + +;; #+BEGIN_SRC emacs-lisp +(use-package smex + :commands (smex + smex-update + smex-initialize) + :config (progn + (setq smex-key-advice-ignore-menu-bar t + smex-auto-update nil) + (defun smex-update-after-load (_unused) + (if (boundp 'smex-cache) + (smex-update))) + (add-hook 'after-load-functions 'smex-update-after-load)) + :init (progn + (setq smex-history-length 100 + smex-save-file (concat user-emacs-directory + "smex-items")))) +;; #+END_SRC + +;; *** cmd-to-echo + +;; I’ve been looking for some way to run programming projects (mostly +;; node.js) inside emacs. =cmd-to-echo= seems great for this, as new +;; output pops up in the echo area. + +;; #+BEGIN_SRC emacs-lisp +(use-package cmd-to-echo + :commands (cmd-to-echo) + :config (setq cmd-to-echo-add-output-to-process-buffers t)) +;; #+END_SRC +;; ** Modes + +;; Setup some modes for systemd files +;; #+BEGIN_SRC emacs-lisp +(add-to-list 'auto-mode-alist '("\\.service\\'" . conf-mode)) +(add-to-list 'auto-mode-alist '("\\.target\\'" . conf-mode)) +(add-to-list 'auto-mode-alist '("\\.socket\\'" . conf-mode)) +;; #+END_SRC + +;; =direnv=’s files are basically shell scripts, it’s a nice way to +;; set environment variables for projects. +;; #+BEGIN_SRC emacs-lisp +(add-to-list 'auto-mode-alist '("\\.envrc\\'" . sh-mode)) +;; #+END_SRC + +;; Some modes that I don’t really customise much, mostly for +;; configuration files. +;; #+BEGIN_SRC emacs-lisp +(use-package haskell-mode + :mode (("\\.hs\\'" . haskell-mode))) + +(use-package dockerfile-mode + :mode (("Dockerfile\\'" . dockerfile-mode))) + +(use-package nix-mode + :mode (("\\.nix\\'" . nix-mode))) + +(define-derived-mode xmonad-mode haskell-mode "XM") +(add-to-list 'auto-mode-alist '("xmobarrc\\'" . xmonad-mode)) +(add-to-list 'auto-mode-alist '("xmonad.hs\\'" . xmonad-mode)) + +(use-package nginx-mode + :defer t + :mode (("/nginx/servers/" . nginx-mode) + ("/nginx/.*\\.d/" . nginx-mode))) + +(use-package lua-mode + :defer t) + +(use-package ruby-mode + :mode (("\\.rb\\'" . ruby-mode) + ("\\.cap\\'" . ruby-mode))) + +(use-package go-mode + :mode (("\\.go\\'" . go-mode))) + +(use-package jinja2-mode + :mode (("\\.j2\\'" . jinja2-mode) + ("\\.jinja\\'" . jinja2-mode))) + +(use-package scss-mode + :defer t + :config (progn + (setq scss-compile-at-save nil))) + +(use-package toml-mode + :mode ("\\.toml\\'" . toml-mode)) + +(use-package yaml-mode + :mode (("/group_vars/.*" . yaml-mode) + ("/host_vars/.*" . yaml-mode))) + +(define-derived-mode ansible-mode yaml-mode "Ansible") +(add-to-list 'auto-mode-alist '("\\(?:ansible.+\\|roles/.+/\\(?:tasks\\|handlers\\)\\)/.+\\.yml\\'" . ansible-mode)) + +(define-derived-mode saltstack-mode yaml-mode "Salt") +(add-to-list 'auto-mode-alist '("\\.sls\\'" . saltstack-mode)) +;; #+END_SRC + +;; *** ledger + +;; I use [[http://ledger-cli.org/][=ledger=]] to manage my finances. It has an Emacs mode, which +;; works really nicely. + +;; #+BEGIN_SRC emacs-lisp +(use-package ledger-mode + :mode ("\\.ledger\\'" . ledger-mode) + :init (progn + (defun open-budget () + (interactive) + (projectile-switch-project-by-name "~/Sync/Default") + (find-file (expand-file-name "ledger/my.ledger" (projectile-project-root))) + (ledger-report "Budget (Cumulative)" nil))) + :config (progn + (setq ledger-use-iso-dates t + ledger-post-use-completion-engine :ido + ledger-reconcile-default-commodity "€" + ledger-clear-whole-transactions t + ledger-narrow-on-reconcile t + ledger-reports `(("Monthly Expenses" "ledger -f %(ledger-file) reg -M \\^Flex --real -X EUR -l \"payee != 'Opening Balances'\"") + ("Average Monthly Expenses (Past 12 Months)" ,(concat "ledger -f %(ledger-file) -b " + (format-time-string "%Y-%m" (time-add (current-time) (days-to-time -365))) + " --monthly --average balance ^Flex")) + ("Expenses:This Month" "ledger -f %(ledger-file) bal \\^Flex -p \"this month\"") + ("On-budget Balances" "ledger -f %(ledger-file) bal --current -R :Budget: Assets:Receivable Liabilities:Personal") + ("All Account Balances" "ledger -f %(ledger-file) bal --current -R \\^Assets \\^Liabilities") + ("Budget Values (Current Month)" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds") + ("Budget (Cumulative)" "ledger -f %(ledger-file) bal -E \\^Funds \\^Assets:Budget$") + ("Budget Allocation" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds --format \"\\ + %-17((depth_spacer)+(partial_account))\\ + %10(percent(market(display_total), market(parent.total)))\\ + %16(market(display_total))\n%/\"") + ("bal" "ledger -f %(ledger-file) bal") + ("reg" "ledger -f %(ledger-file) reg") + ("equity" "ledger -f %(ledger-file) equity") + ("payee" "ledger -f %(ledger-file) reg @%(payee)") + ("account" "ledger -f %(ledger-file) reg %(account)"))))) +;; #+END_SRC + +;; *** Markdown + +;; #+BEGIN_SRC emacs-lisp +(use-package markdown-mode + :defer t + :config (progn + (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) +;; #+END_SRC + +;; *** Lentic + +;; Multiple different views of the same file. Can be used for a kind of +;; inverse literate programming. + +;; #+BEGIN_SRC emacs-lisp +(use-package lentic + :config (global-lentic-mode)) +;; #+END_SRC + +;; *** Org + +;; Org is wünderbar. + +;; #+BEGIN_SRC emacs-lisp +(use-package org + :bind (("C-c C-a" . org-agenda-list) + ("C-c a" . org-agenda) + ("C-c l" . org-store-link)) + :defer 8 + :init (setq org-replace-disputed-keys t + org-ellipsis "…") + :config (progn + (setq org-directory "~/Sync/org" + org-agenda-files `(,(concat org-directory "/agenda")) + + org-default-notes-file (concat org-directory "/notes") + + ;; ‘Remember’: new items at top + org-reverse-note-order t + + org-modules '(org-protocol) + + ;; Add time done to ‘done’ tasks + org-log-done 'time + + org-list-allow-alphabetical t + + org-adapt-indentation nil + + org-pretty-entities t + + org-table-duration-custom-format 'seconds + + org-src-fontify-natively nil + + org-export-have-math t + + org-blank-before-new-entry '((heading . t) + (plain-list-item . auto)) + org-fontify-done-headline t + + org-goto-interface 'outline-path-completion + + org-outline-path-complete-in-steps nil + + org-todo-keywords '((sequence "BACKLOG(b)" "TODO(t)" "WAIT(w@/!)" "STARTED(s!)" "|" "DONE(d!)") + (sequence "|" "CANCELLED(c@)")) + org-log-into-drawer "LOGBOOK") + (set-register ?o `(file . ,(expand-file-name "organiser.org" org-directory))) + (add-hook 'org-mode-hook #'turn-on-auto-fill) + (org-load-modules-maybe t))) + +(use-package org-src + :ensure nil + :after org + :config (progn + (bind-key "C-x C-s" #'org-edit-src-exit org-src-mode-map))) +;; #+END_SRC + +;; ***** org-babel + +;; Org’s babel feature is really nice. I use it for this file, and I can +;; use it to communicate between programming languages. Sometime I hope +;; to have my =ledger= setup in an org file with some graph processing +;; with R or something. + +;; #+BEGIN_SRC emacs-lisp +(use-package ob-core + :defer t + :ensure nil + :config (progn + (org-babel-do-load-languages 'org-babel-load-languages + '((ledger . t) + (sh . t))) + (setq org-src-tab-acts-natively t + org-edit-src-content-indentation 0 + org-src-preserve-indentation t))) +;; #+END_SRC + +;; ***** org-journal + +;; I can use this to keep a journal. I should use it. + +;; #+BEGIN_SRC emacs-lisp +(use-package org-journal + :bind ("s-j" . org-journal-new-entry) + :defer 20 + :config (progn + (setq org-journal-date-format "%A, %d %B %Y" + org-journal-dir "~/Sync/Default/Documents/journal") + + (define-hook-helper org-journal-mode () + (use-variable-fonts) + (text-scale-adjust 4) + (if smartparens-strict-mode + (smartparens-strict-mode -1)) + (if show-smartparens-mode + (show-smartparens-mode -1))) + (defun org-journal-display-entry-yesterday () + "Show org-journal entry for yesterday" + (interactive) + (org-journal-read-or-display-entry (yesterday-time))))) +;; #+END_SRC + + +;; ** Programming +;; *** flycheck + +;; On-the-fly error checking in programming modes? Yes please. + +;; #+BEGIN_SRC emacs-lisp +(use-package flycheck + :diminish " ✓" + :defer 5 + :config (progn + (global-flycheck-mode) + (setq flycheck-check-syntax-automatically '(save mode-enabled)) + (setq flycheck-indication-mode 'left-fringe) + (with-eval-after-load 'git-gutter-fringe + (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated) + ".XXX....")) + (if (executable-find "eslint_d") + (setq flycheck-javascript-eslint-executable "eslint_d")))) +;; #+END_SRC + +;; **** flycheck-pos-tip + +;; Show flycheck errors in a little popup, so I don't lose my place + +;; #+BEGIN_SRC emacs-lisp +(use-package flycheck-pos-tip + :after flycheck + :config (progn + (setq flycheck-display-errors-delay 0.5) + (flycheck-pos-tip-mode 1))) +;; #+END_SRC + +;; **** flycheck-flow + +;; #+BEGIN_SRC emacs-lisp +(use-package flycheck-flow + :after js2-mode + :if (executable-find "flow") + :config (progn + (flycheck-add-next-checker 'javascript-eslint 'javascript-flow))) +;; #+END_SRC + +;; *** golang + +;; Go has a few packages to inter-operate with other emacs packages. + +;; #+BEGIN_SRC emacs-lisp +(use-package company-go + :commands company-go + :config (progn + (setq company-go-show-annotation t)) + :init (progn + (define-hook-helper go-mode () + (set (make-local-variable 'company-backends) + '(company-go))))) + +(use-package go-eldoc + :commands go-eldoc-setup + :init (progn + (add-hook 'go-mode-hook #'go-eldoc-setup))) + +(use-package go-projectile + :defer t + :config (progn + (setq go-projectile-switch-gopath 'maybe))) + + +;; #+END_SRC + +;; *** ggtags + +;; A nice completion backend for programming modes. + +;; #+BEGIN_SRC emacs-lisp +(use-package ggtags + :if (executable-find "gtags") + :commands turn-on-ggtags-mode + :functions (ggtags-navigation-mode-abort) + :config (progn + (bind-key "q" #'ggtags-navigation-mode-abort ggtags-navigation-mode-map)) + :init (progn + (defun turn-on-ggtags-mode () + (interactive) + (ggtags-mode 1)) + (add-hook 'c-mode-common-hook #'turn-on-ggtags-mode))) +;; #+END_SRC + +;; *** dumb-jump + +;; A "clever" way of implementing go-to-definition across languages: use +;; a project-wide text search and apply heuristics to the results to +;; guess a definition. + +;; #+BEGIN_SRC emacs-lisp +(use-package dumb-jump + :bind (("M-g o" . dumb-jump-go-other-window) + ("M-g j" . dumb-jump-go) + ("M-g x" . dumb-jump-go-prefer-external) + ("M-g z" . dumb-jump-go-prefer-external-other-window)) + :config (setq dumb-jump-selector 'ivy)) +;; #+END_SRC + +;; *** imenu-anywhere + +;; This is like imenu, but shows functions (or similar top-level +;; entities) across buffers in the same project. Neat! + +;; #+BEGIN_SRC emacs-lisp +(use-package imenu-anywhere + :bind ("C-x C-." . ivy-imenu-anywhere)) +;; #+END_SRC +;; *** Lisps + +;; **** All + +;; Lisp modes don’t seem to have a common ancestor. So I made a custom +;; hook which I trigger in every lispy-mode. + +;; #+BEGIN_SRC emacs-lisp +(defcustom lisp-mode-common-hook nil + "Hook run when entering any Lisp mode." + :type 'hook + :group 'lisp) + +(create-hook-helper lisp-mode-setup () + :hooks (emacs-lisp-mode-hook + scheme-mode-hook + lisp-mode-hook + clojure-mode-hook) + (run-hooks 'lisp-mode-common-hook)) +;; #+END_SRC + +;; ***** Redshank + +;; Lisp syntax allows for really easy refactoring. Redshank gives some +;; operations that aren’t part of paredit, like extracting variables into +;; let bindings. +;; #+BEGIN_SRC emacs-lisp +(use-package redshank + :diminish " Λ" + :after (paredit) + :config (progn + (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode))) +;; #+END_SRC + +;; **** Emacs Lisp + +;; Customise the modeline-display of =emacs-lisp-mode=. Then make sure +;; it runs the common lisp hooks. + +;; #+BEGIN_SRC emacs-lisp +(add-hook 'emacs-lisp-mode-hook #'eldoc-mode) +;; #+END_SRC + +;; Go-to function for elisp. Except it works through the entire Emacs ecosystem. + +;; #+BEGIN_SRC emacs-lisp +(use-package elisp-slime-nav + :commands elisp-slime-nav-mode + :diminish elisp-slime-nav-mode + :init (progn + (add-hook 'emacs-lisp-mode-hook #'elisp-slime-nav-mode))) +;; #+END_SRC + +;; Interactive elisp + +;; #+BEGIN_SRC emacs-lisp +(use-package ielm + :defer t + :ensure nil + :config (progn + (define-hook-helper ielm-mode () + (run-hooks 'lisp-mode-common-hook)))) +;; #+END_SRC + +;; **** Scheme & Lisp + +;; I don’t work with these as often as I would like + +;; #+BEGIN_SRC emacs-lisp +(define-hook-helper lisp-mode () + (set (make-local-variable 'lisp-indent-function) + #'common-lisp-indent-function)) +;; #+END_SRC + +;; ***** geiser + +;; A REPL thing for Scheme. Hopefully I’ll get to use it more in the +;; future. + +;; #+BEGIN_SRC emacs-lisp +(use-package geiser + :commands (geiser-mode + geiser + run-geiser + run-racket)) +;; #+END_SRC + +;; ***** slime + +;; A REPL thing (and more) for Lisp. + +;; #+BEGIN_SRC emacs-lisp +(use-package slime + :commands (slime) + :config (progn + (let ((ql-slime-helper (expand-file-name "~/quicklisp/slime-helper.el"))) + (if (file-exists-p ql-slime-helper) + (load ql-slime-helper)) + (slime-setup '(slime-fancy slime-asdf))) + (setq common-lisp-hyperspec-root "file://opt/local/share/doc/lisp/HyperSpec-7-0/" + inferior-lisp-program (or (executable-find "sbcl") + (executable-find "ccl64"))))) +;; #+END_SRC + +;; **** Clojure + +;; #+BEGIN_SRC emacs-lisp +(use-package clojure-mode + :defer t + :init (progn + (define-hook-helper cider-repl-mode () + (highlight-changes-mode -1)))) + +(use-package clj-refactor + :defer t + :functions (clj-refactor-mode cljr-add-keybindings-with-prefix) + :config (progn + (cljr-add-keybindings-with-prefix "C-c C-m")) + :init (progn + (define-hook-helper clojure-mode () + (clj-refactor-mode 1)))) +;; #+END_SRC + +;; ***** cider + +;; A REPL thing for Clojure + +;; #+BEGIN_SRC emacs-lisp +(use-package cider + :defer t + :config (progn + (setq nrepl-hide-special-buffers t) + (unbind-key "C-c C-f" cider-mode-map) + (add-hook 'cider-mode-hook #'eldoc-mode))) +;; #+END_SRC + +;; *** Auto-compile + +;; Auto-compile emacs lisp when saving. +;; #+BEGIN_SRC emacs-lisp +(use-package auto-compile + :defer t + :init (add-hook 'emacs-lisp-mode-hook #'auto-compile-on-save-mode)) +;; #+END_SRC + +;; *** cc-mode + +;; Although I don’t use C or C++, setting up the mode is helpful because +;; quite a few other modes are derived from it. + +;; #+BEGIN_SRC emacs-lisp +(use-package cc-mode + :defer 5 + :config (progn + (setq c-default-style '((java-mode . "java") + (awk-mode . "awk") + (other . "k&r")) + c-basic-offset 4) + (c-set-offset 'case-label '+))) +;; #+END_SRC + +;; *** quickrun + +;; It’s nice to be able to quickly evaluate some code. Although I don’t +;; really seem to use it. +;; #+BEGIN_SRC emacs-lisp +(use-package quickrun + :bind (("C-c C-e" . quickrun))) +;; #+END_SRC + +;; *** Scala + +;; Let’s try using Scala. + +;; #+BEGIN_SRC emacs-lisp +(use-package scala-mode) +;; #+END_SRC + +;; And add ensime, an IDE-style environment. + +;; #+BEGIN_SRC emacs-lisp +(use-package ensime) +;; #+END_SRC + +;; *** Web development + +;; **** js2-mode + +;; This mode is really great for editing Javascript. It turns code into +;; an AST internally, so it can work with it almost like a lisp. + +;; #+BEGIN_SRC emacs-lisp +(use-package js2-mode + :mode (("\\.js\\'" . js2-mode)) + :interpreter ("node" . js2-mode) + :functions js2-next-error + :config (progn + (define-key js2-mode-map [menu-bar Javascript] nil) + (defun js2--imenu-around (do-it name) + "Don't create a menu from js2-mode" + (if (and (not (string-equal name "IM-Javascript-IDE")) + (fboundp #'do-it)) + (do-it name))) + (add-hook 'js2-mode-hook #'js2-imenu-extras-mode) + (advice-add 'imenu-add-to-menubar :around #'js2--imenu-around) + (defun ap/js2-prev-error () + (interactive) + (js2-next-error -1)) + (bind-key "M-g M-n" #'js2-next-error js2-mode-map) + (bind-key "M-g M-p" #'ap/js2-prev-error js2-mode-map) + (setq js2-basic-offset 2 + js-switch-indent-offset 2 + js2-include-node-externs t + js2-highlight-level 1 + js2-strict-missing-semi-warning nil))) +;; #+END_SRC + +;; ***** rjsx-mode + +;; A set of advice for js2-jsx-mode to work better with React. + +;; #+BEGIN_SRC emacs-lisp +(use-package rjsx-mode + :after js2-mode + :if (fboundp #'js2--struct-put) + :mode (("\\.jsx\\'" . rjsx-mode))) +;; #+END_SRC + +;; ***** js2-refactor + +;; Thanks to the AST provided by js2-mode, refactoring is possible. This +;; library implements some refactorings. + +;; #+BEGIN_SRC emacs-lisp +(use-package js2-refactor + :after js2-mode + :config (progn + (bind-key "C-k" #'js2r-kill js2-mode-map) + (add-hook 'js2-mode-hook #'js2-refactor-mode) + (js2r-add-keybindings-with-prefix "C-c C-m"))) +;; #+END_SRC + +;; ***** add-node-modules-path + +;; Inside a javascript project, it's common to install tools locally to +;; the project. This will allows emacs to find their executables. + +;; #+BEGIN_SRC emacs-lisp +(use-package add-node-modules-path + :config (progn + (add-hook 'js2-mode-hook #'add-node-modules-path))) +;; #+END_SRC + +;; ***** Flow + +;; #+BEGIN_SRC emacs-lisp +(use-package flow-minor-mode + :after js2-mode + :config (progn + (add-hook 'js2-mode-hook #'flow-minor-enable-automatically))) +;; #+END_SRC + +;; ***** Indium + +;; Javascript with an inferior node.js process and a debugger? Awesome. + +;; To debug with node, use version 6.9.1 or later of node and run it with +;; ~--inspect~ and, to break on the first line, ~--debug-brk~. + +;; For Chrom*, it needs to be launched with +;; ~--remote-debugging-port=9222~ + +;; Node will tell you to open an URL in Chrome: + +;; ~chrome-devtools://inspector.html?...&ws=127.0.0.1:PORT/PATH~ + +;; Instead, do this: + +;; ~M-x indium-connect-to-nodejs RET 127.0.0.1 RET PORT RET~ + +;; #+BEGIN_SRC emacs-lisp +(use-package indium + :diminish (indium-interaction-mode . "In") + :config (progn + (add-hook 'js2-mode-hook #'indium-interaction-mode))) +;; #+END_SRC + +;; **** coffee-mode + +;; #+BEGIN_SRC emacs-lisp +(use-package coffee-mode + :mode ("\\.coffee\\'" . coffee-mode) + :config (progn + (setq coffee-indent-like-python-mode t))) +;; #+END_SRC + +;; **** tern + +;; Tern understands javascript. It adds really clever documented +;; completions, besides other IDE-like things. + +;; #+BEGIN_SRC emacs-lisp +(use-package tern + :diminish tern-mode + :if (executable-find "tern") + :defer 5 + :config (progn + (setq tern-command (list (executable-find "tern"))) + (create-hook-helper tern-mode-on () + :hooks (web-mode-hook + js2-mode-hook) + (tern-mode +1)))) + +(with-eval-after-load 'tern + (use-package company-tern)) +;; #+END_SRC + +;; **** json-mode + +;; #+BEGIN_SRC emacs-lisp +(use-package json-mode + :mode (("\\.json\\'" . json-mode) + ("\\.sailsrc\\'" . json-mode) + ("composer\\.lock\\'" . json-mode) + ("\\.tern-project\\'" . json-mode))) +;; #+END_SRC + +;; **** restclient + +;; Restclient is really nice. It’s like a scratchpad for HTTP api +;; calls. Feels a bit like using =org-babel=. I wonder if there’s an +;; integration between the two yet. + +;; #+BEGIN_SRC emacs-lisp +(use-package restclient + :mode ("\\.api\\'" . restclient-mode) + :config (progn + (defun imenu-restclient-sections () + (setq imenu-prev-index-position-function nil) + (add-to-list 'imenu-generic-expression '("Services" "^## ?\\(.+\\)$" 1) t) + (add-to-list 'imenu-generic-expression '("Calls" "^# ?\\(.+\\)$" 1) t)) + (add-hook 'restclient-mode-hook #'imenu-restclient-sections))) + +(use-package company-restclient + :after (company restclient) + :init (add-to-list 'company-backends #'company-restclient t)) +;; #+END_SRC + +;; **** sgml-mode + +;; This is for HTML, since old versions of HTML were derived from SGML. +;; #+BEGIN_SRC emacs-lisp +(use-package sgml-mode + :defer t + :config (setq sgml-basic-offset 2)) +;; #+END_SRC + +;; **** emmet-mode + +;; Emmet is really nice to write HTML quickly. Especially with +;; frameworks that require multiple nested elements to do anything useful. +;; #+BEGIN_SRC emacs-lisp +(use-package emmet-mode + :commands (emmet-mode) + :diminish (emmet-mode . " >") + :init (progn + (setq emmet-indentation 2 + emmet-self-closing-tag-style " /") + (add-hook 'sgml-mode-hook #'emmet-mode) + (add-hook 'web-mode-hook #'emmet-mode) + (add-hook 'css-mode-hook #'emmet-mode))) +;; #+END_SRC + +;; **** web-mode + +;; This mode handles just about every templating language out ther, which +;; is really nice, because it handles the HTML part the same way in all +;; of them as well. + +;; #+BEGIN_SRC emacs-lisp +(use-package web-mode + :mode (("/views/.*\\.php\\'" . web-mode) + ("\\.html\\'" . web-mode) + ("/templates/.*\\.php\\'" . web-mode) + ("\\.ejs\\'" . web-mode) + ("\\.njk\\'" . web-mode)) + :config (progn + (setq web-mode-code-indent-offset 2 + web-mode-css-indent-offset 2 + web-mode-markup-indent-offset 2 + web-mode-style-padding 0 + web-mode-script-padding 0 + web-mode-comment-style 2 + web-mode-enable-auto-pairing nil + web-mode-enable-auto-quoting nil) + (sp-local-pair '(web-mode) "<%" "%>"))) +;; #+END_SRC + +;; I derived a mode for twig, in order to use its =mode-hook=. + +;; #+BEGIN_SRC emacs-lisp +(define-derived-mode twig-mode web-mode "Twig") +(add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) +;; #+END_SRC + +;; *** Live coding + +;; Sometimes I might want to show off my emacs usage. + +;; #+BEGIN_SRC emacs-lisp +(defun live-coding () + (interactive) + (ap/set-fonts "SF Mono" 18 nil nil t 0.1) + (global-command-log-mode 1)) + +(defun live-coding-stop () + (interactive) + (ap/set-fonts-according-to-system) + (global-command-log-mode -1)) +;; #+END_SRC + +;; **** command-log-mode + +;; #+BEGIN_SRC emacs-lisp +(use-package command-log-mode + :defines command-log-mode-key-binding-open-log + :init (progn + (setq command-log-mode-key-binding-open-log nil + command-log-mode-auto-show t + command-log-mode-is-global t))) +;; #+END_SRC + +;; ** Spelling + +;; #+BEGIN_SRC emacs-lisp +(use-package ispell + :bind (("" . ispell-word)) + :config (progn + (cond + ((executable-find "aspell") (setq ispell-program-name "aspell" + ispell-dictionary "british" + ispell-really-aspell t + ispell-really-hunspell nil)) + ((executable-find "hunspell") (setq ispell-program-name "hunspell" + ispell-really-aspell nil + ispell-really-hunspell t))))) +;; #+END_SRC + +;; #+BEGIN_SRC emacs-lisp +(use-package flyspell + :diminish "﹏" + :config (progn + (defun flyspell-detect-ispell-args (&optional run-together) + "If RUN-TOGETHER is true, spell check the CamelCase words. + Please note RUN-TOGETHER will make aspell less capable. So it should only be used in prog-mode-hook." + (let (args) + (when ispell-program-name + (cond + ((string-match "aspell$" ispell-program-name) + (setq args (list "--sug-mode=ultra")) + (if run-together + (setq args (append args '("--run-together" "--run-together-limit=16" "--run-together-min=2"))))) + ((string-match "hunspell$" ispell-program-name) + (setq args nil)))) + args)) + ;; `ispell-extra-args' is *always* used when start CLI aspell process + (setq-default ispell-extra-args (flyspell-detect-ispell-args t)) + ;; (setq ispell-cmd-args (flyspell-detect-ispell-args)) + (defadvice ispell-word (around my-ispell-word activate) + (let ((old-ispell-extra-args ispell-extra-args)) + (ispell-kill-ispell t) + ;; use emacs original arguments + (setq ispell-extra-args (flyspell-detect-ispell-args)) + ad-do-it + ;; restore our own ispell arguments + (setq ispell-extra-args old-ispell-extra-args) + (ispell-kill-ispell t))) + + (defadvice flyspell-auto-correct-word (around my-flyspell-auto-correct-word activate) + (let* ((old-ispell-extra-args ispell-extra-args)) + (ispell-kill-ispell t) + ;; use emacs original arguments + (setq ispell-extra-args (flyspell-detect-ispell-args)) + ad-do-it + ;; restore our own ispell arguments + (setq ispell-extra-args old-ispell-extra-args) + (ispell-kill-ispell t))) + (setq flyspell-issue-message-flag nil) + + (defun fly-text-mode-hook-setup () + ;; Turn off RUN-TOGETHER option when spell check text-mode + (setq-local ispell-extra-args (flyspell-detect-ispell-args))) + (add-hook 'text-mode-hook 'fly-text-mode-hook-setup) + (add-hook 'prog-mode-hook #'flyspell-prog-mode))) +;; #+END_SRC + +;; *** Style checking + +;; [[https://github.com/ValeLint/vale][Vale]] is a linter, but for prose. Neat idea! Salesman is a bad term. + +;; #+BEGIN_SRC emacs-lisp +(use-package flycheck-vale + :if (executable-find "vale") + :config (progn + (add-to-list 'flycheck-vale-modes 'org-mode) + (add-to-list 'flycheck-vale-modes 'org-journal-mode) + (flycheck-vale-setup))) +;; #+END_SRC + +;; ** Scripting + +;; Make a shell-script buffer executable after saving it, if it has a shebang. + +;; #+BEGIN_SRC emacs-lisp +(add-hook 'after-save-hook + #'executable-make-buffer-file-executable-if-script-p) + +(use-package sh-script + :mode (("\\.zsh\\'" . shell-script-mode) + ("zshenv\\'" . shell-script-mode) + ("zshrc\\'" . shell-script-mode)) + :config (setq sh-shell-file "/usr/bin/env zsh" + sh-indentation 2 + sh-basic-offset 2)) +;; #+END_SRC + +;; #+BEGIN_SRC emacs-lisp +(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) +;; #+END_SRC + +;; *** eshell + +;; I should try to get into the habit of using this more. It’s really +;; nice, when I remember to use it. + +;; #+BEGIN_SRC emacs-lisp +(use-package eshell + :bind ("C-c s" . eshell) + :defer 10 + :functions (eshell/pwd) + :config (progn + (setq eshell-directory-name "~/.emacs.d/eshell" + eshell-prompt-function (lambda () + (concat + (eshell/pwd) + "\n$ "))) + (define-hook-helper eshell-load () + (bind-key "C-c C-l" #'counsel-esh-history eshell-mode-map)))) + +(use-package em-smart + :ensure nil + :commands eshell-smart-initialize + :init (progn + (add-hook 'eshell-load-hook #'eshell-smart-initialize)) + :config (progn + (setq eshell-where-to-jump 'begin + eshell-review-quick-commands nil + eshell-smart-space-goes-to-end t))) + +(autoload #'eshell/cd "em-dirs") +(defun eshell-goto-current-dir (&optional arg) + (interactive "P") + (let ((dir default-directory)) + (eshell arg) + (eshell/cd dir))) +(bind-key "C-c S" #'eshell-goto-current-dir) + + +;; #+END_SRC + +;; **** Shells + +;; #+BEGIN_SRC emacs-lisp +(use-package shell + :defer t + :ensure nil + :config (define-key shell-mode-map + (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer)) + +(use-package comint + :defer t + :ensure nil + :config (bind-key "C-c C-l" #'counsel-shell-history comint-mode-map)) + +(defun comint-delchar-or-eof-or-kill-buffer (arg) + (interactive "p") + (if (null (get-buffer-process (current-buffer))) + (kill-buffer) + (comint-delchar-or-maybe-eof arg))) +;; #+END_SRC + +;; ** Text editing + +;; Emacs has an editor within. + +;; #+BEGIN_SRC emacs-lisp +(put 'upcase-region 'disabled nil) +(put 'downcase-region 'disabled nil) +(setq sentence-end-double-space t + line-move-visual nil) +(setq-default truncate-lines t) +;; #+END_SRC + +;; *** align + +;; =Align= is a useful command to line things up, once given some rules. +;; The most important one for me is JSON property alignment. + +;; #+BEGIN_SRC emacs-lisp +(use-package align + :defer 10 + :ensure nil + :config (progn + (add-to-list 'align-rules-list + '(colon-key-value + (regexp . ":\\(\\s-*\\)") + (modes . '(js2-mode)))))) +;; #+END_SRC + +;; *** Clipboard + +;; I like to use the clipboard more than the primary selection in X11. + +;; #+BEGIN_SRC emacs-lisp +(setq select-enable-clipboard t + save-interprogram-paste-before-kill t) +(if (functionp 'x-cut-buffer-or-selection-value) + (setq interprogram-paste-function 'x-cut-buffer-or-selection-value)) +(when (boundp 'x-select-request-type) + (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) +;; #+END_SRC + +;; *** Selection + +;; I’m quite used to deleting text by selecting it and typing. Emacs has +;; a mode for that. + +;; #+BEGIN_SRC emacs-lisp +(use-package delsel + :config (delete-selection-mode t)) +;; #+END_SRC + +;; Sub-word movement is really nice for camel- and Pascal-case + +;; #+BEGIN_SRC emacs-lisp +(use-package subword + :diminish subword-mode + :init (global-subword-mode t)) +;; #+END_SRC + +;; I find that =zap-up-to-char= normally makes more sense to me than +;; =zap-to-char=. + +;; #+BEGIN_SRC emacs-lisp +(use-package misc + :ensure nil + :bind (("M-z" . zap-up-to-char) + ("M-Z" . zap-to-char))) +;; #+END_SRC + +;; Expanding the region by semantic units was something I quite liked +;; from Sublime Text. As always, there’s a mode for that. + +;; #+BEGIN_SRC emacs-lisp +(use-package expand-region + :bind ("C-M-SPC" . er/expand-region) + :config (setq expand-region-fast-keys-enabled nil)) +;; #+END_SRC + +;; *** avy + +;; Avy is a really nice way to move around files, like ace-jump-mode, but +;; somehow I prefer it. + +;; #+BEGIN_SRC emacs-lisp +(use-package avy + :defer 5 + :bind (("M-g g" . avy-goto-line) + ("M-g M-g" . avy-goto-line) + ("C-|" . avy-goto-line) + ("M-r" . avy-goto-word-1) + ("C-c SPC" . avy-goto-char-timer)) + :config (progn + (avy-setup-default) + (setq avy-all-windows nil + avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?\;)))) +;; #+END_SRC + +;; **** ace-link + +;; Visit any link. Despite the name, this works with avy. + +;; #+BEGIN_SRC emacs-lisp +(use-package ace-link + :after avy + :config (progn + (ace-link-setup-default) + (with-eval-after-load "gnus" + (bind-key "M-o" #'ace-link-gnus gnus-summary-mode-map) + (bind-key "M-o" #'ace-link-gnus gnus-article-mode-map)))) +;; #+END_SRC + +;; *** goto-chg + +;; This is like popping the mark, only it filters to only change areas +;; and doesn’t go back to the same place more than once. + +;; #+BEGIN_SRC emacs-lisp +(use-package goto-chg + :bind ("C-c C-SPC" . goto-last-change)) +;; #+END_SRC + +;; *** beginend + +;; In special buffers, I would rather have =M->= and =M-<= goto the +;; logical beginning/end rather than the physical ones. + +;; #+BEGIN_SRC emacs-lisp +(use-package beginend + :config (progn + (beginend-setup-all))) +;; #+END_SRC + +;; *** multiple-cursors + +;; I mentioned before that I’d used Sublime Text before. Multiple +;; cursors was one of my favourite features, so I was really happy when I +;; saw that multiple-cursors was released for Emacs. + +;; #+BEGIN_SRC emacs-lisp +(use-package multiple-cursors + :defer 1 + :bind* (("C-." . mc/mark-next-like-this) + ("C-," . mc/mark-previous-like-this) + ("M-" . mc/mark-all-like-this-dwim) + ("C-" . mc/mark-more-like-this-extended) + ("C-S-L" . mc/edit-lines))) +;; #+END_SRC + +;; *** paredit + +;; Balanced parentheses in lisps are nice, but all the refactoring and +;; movement commands are much more interesting. + +;; #+BEGIN_SRC emacs-lisp +(use-package paredit + :diminish "()" + :config (progn + (add-hook 'lisp-mode-common-hook #'enable-paredit-mode) + (put #'paredit-forward-delete 'delete-selection 'supersede) + (put #'paredit-backward-delete 'delete-selection 'supersede) + (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode))) +;; #+END_SRC + +;; *** smartparens + +;; I like to use smartparens where paredit isn’t already useful. Somehow +;; I didn’t find smartparens’ implementation of paredit style to be as +;; nice as the real version + +;; #+BEGIN_SRC emacs-lisp +(eval-when-compile (require 'smartparens nil :noerror)) +(use-package smartparens-config + :ensure smartparens + :config (progn + (sp-use-smartparens-bindings) + (setq sp-highlight-pair-overlay nil) + (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' + (bind-key "C-(" #'wrap-with-paren smartparens-mode-map) + (bind-key "C-)" #'sp-forward-slurp-sexp smartparens-mode-map) + (bind-key "M-" #'backward-kill-word smartparens-mode-map) + (bind-key "M-?" #'sp-convolute-sexp smartparens-mode-map) + (bind-key "C-M-t" #'sp-transpose-sexp smartparens-mode-map) + (bind-key "M-R" #'sp-raise-sexp smartparens-mode-map) + (bind-key "M-S" #'sp-splice-sexp smartparens-mode-map) + (bind-key "C-M-s" #'sp-split-sexp smartparens-mode-map) + (bind-key "M-J" #'sp-join-sexp smartparens-mode-map) + (bind-key "M-" #'sp-splice-sexp-killing-backward smartparens-mode-map) + (bind-key "M-" #'sp-splice-sexp-killing-forward smartparens-mode-map) + (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp smartparens-mode-map) + (bind-key "C-S-" #'sp-slurp-hybrid-sexp smartparens-mode-map) + (sp-with-modes '(twig-mode) + (sp-local-pair "{%" "%}") + (sp-local-pair "{{" "}}")) + (show-smartparens-global-mode t) + (smartparens-global-strict-mode t) + (add-hook 'lisp-mode-common-hook #'turn-off-smartparens-mode) + (add-hook 'coffee-mode-hook #'turn-off-smartparens-mode))) +;; #+END_SRC + + +;; *** move-text + +;; Transposing lines, made easier. + +;; #+BEGIN_SRC emacs-lisp +(use-package move-text + :config (move-text-default-bindings)) +;; #+END_SRC + +;; *** undo-tree + +;; Emacs’ default handling of undo is a bit confusing. Undo-tree makes +;; it much clearer. It’s especially helpful for protoyping and refactoring. + +;; #+BEGIN_SRC emacs-lisp +(use-package undo-tree + :config (progn + (global-undo-tree-mode) + ;; Keep region when undoing in region + (defadvice undo-tree-undo (around keep-region activate) + (if (use-region-p) + (let ((m (set-marker (make-marker) (mark))) + (p (set-marker (make-marker) (point)))) + ad-do-it + (goto-char p) + (set-mark m) + (set-marker p nil) + (set-marker m nil)) + ad-do-it))) + :diminish undo-tree-mode) +;; #+END_SRC + +;; *** replace + +;; #+BEGIN_SRC emacs-lisp +(with-eval-after-load "replace.el" + (setq case-replace nil)) +;; #+END_SRC + +;; *** visual-regexp + +;; I don’t always remember exactly how Emacs’ regular expressions work, +;; so this package is pretty useful because it highlights everything in +;; the buffer for me. + +;; #+BEGIN_SRC emacs-lisp +(use-package visual-regexp + :bind (("C-c r" . vr/replace) + ("C-c q" . vr/query-replace) + ("C-c m" . vc/mc-mark))) +;; #+END_SRC + +;; ** End + +;; Start a server if possible. A daemon is already a server. +;; #+BEGIN_SRC emacs-lisp +(use-package server + :defer 2 + :if (not (daemonp)) + :config (unless (server-running-p server-name) + (server-start))) +(setq gc-cons-threshold 800000 + file-name-handler-alist file-name-handler-alist-backup) +;; #+END_SRC + +;; Local Variables: +;; lentic-init: lentic-orgel-org-init +;; End: diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org index d15dcd6..d428bd8 100644 --- a/emacs/.emacs.d/init.org +++ b/emacs/.emacs.d/init.org @@ -1,12 +1,14 @@ +# # emacs-config --- Summary #+TITLE: Emacs Configuration for Alan Pearce #+OPTIONS: ^:nil #+PROPERTY: results silent #+PROPERTY: eval no-export #+PROPERTY: header-args :comments link -* Introduction +* Header This is a living document, detailing my Emacs configuration using org-mode -* Basics -** Startup +* Code +** Basics +*** Startup Open Emacs with just a plain window. No graphics or messages, please! #+BEGIN_SRC emacs-lisp (put 'inhibit-startup-echo-area-message 'saved-value @@ -29,7 +31,7 @@ Are we running on Windows via the WSL? (setq system-type 'gnu/linux/windows)))) #+END_SRC -** Compatibility +*** Compatibility #+BEGIN_SRC emacs-lisp (if (version< emacs-version "25.0") @@ -37,7 +39,7 @@ Are we running on Windows via the WSL? `(eval-after-load ,file (lambda () ,@body)))) #+END_SRC -** Scratch buffers +*** Scratch buffers I usually use scratch buffers for any sort of text. If I need a programming mode in one, then I’ll just call it manually. I also like the buffer to be empty. @@ -46,15 +48,15 @@ the buffer to be empty. initial-major-mode 'text-mode) #+END_SRC -** Personal Information +*** Personal Information #+BEGIN_SRC emacs-lisp (setq user-mail-address "alan@alanpearce.eu" user-full-name "Alan Pearce") #+end_src -* Packaging +** Packaging -** Use-package +*** Use-package #+BEGIN_SRC emacs-lisp (eval-and-compile @@ -100,9 +102,9 @@ the buffer to be empty. package-enable-at-startup nil) #+END_SRC -** Helpers +*** Helpers -*** Hook Helpers +**** Hook Helpers An improvement over add-hook with lamda functions that allows modification and removal, without the boilerplate of an extra function @@ -113,7 +115,7 @@ definition. (use-package hook-helpers)) #+END_SRC -* Customize +** Customize I don’t really like using customize for normal configuration. Instead, I use it for things that get saved automatically. That’s why I use a different file, which is ignored by the VCS. It also means @@ -125,7 +127,7 @@ pass =:noerror= to =load= (load custom-file :noerror :nomessage) #+END_SRC -* Styles +** Styles I prefer an always-visible cursor. Feels less distracting. #+BEGIN_SRC emacs-lisp @@ -155,7 +157,7 @@ Ring the bell sometimes, but not so often (ding)))) #+END_SRC -** Colours +*** Colours Eziam looks nice, too, except for the non-white background. I prefer white because most other application backgrounds are that colour. @@ -212,7 +214,7 @@ can enable it if needed. :diminish highlight-stages-mode) #+END_SRC -** Fonts +*** Fonts When possible, set up fonts. I don’t have any settings here for X11, because I manage those in my [[file:~/projects/dotfiles/tag-xresources/xresources/main][XResources file]]. @@ -277,7 +279,7 @@ it has it's own, more extensive version. (global-prettify-symbols-mode +1)) #+END_SRC -** Page Breaks +*** Page Breaks By default, Emacs displays page breaks as ^L. Lines look much nicer. On Windows, Emacs incorrectly detects that U+2500 (Box Drawings Light @@ -295,7 +297,7 @@ correct, at least for Liberation Mono. (cons page-break-lines-char page-break-lines-char) (face-attribute 'default :family))))) #+END_SRC -** Modeline +*** Modeline #+BEGIN_SRC emacs-lisp (column-number-mode -1) @@ -325,7 +327,7 @@ correct, at least for Liberation Mono. '(dired-directory (" — " dired-directory)))) #+END_SRC -** Chrome +*** Chrome Sometimes I like to hide clutter. Other times, it's useful. @@ -383,7 +385,7 @@ Sometimes I like to hide clutter. Other times, it's useful. (add-hook 'minibuffer-exit-hook #'hide-mode-line) #+END_SRC -** Highlight Changes +*** Highlight Changes Highlight what just changed when I undo, yank, and so on. @@ -394,7 +396,7 @@ Highlight what just changed when I undo, yank, and so on. (volatile-highlights-mode t))) #+END_SRC -** Beacon +*** Beacon I was against the idea of having flashy animations inside Emacs, but this one is useful. It highlights the cursor when scrolling or @@ -411,7 +413,7 @@ switching windows. beacon-color "#a1b56c"))) #+END_SRC -** Renaming major modes +*** Renaming major modes Diminishing major modes does not happen in the same manner as minor modes. @@ -436,7 +438,7 @@ modes. #+END_SRC -* Environment Variables +** Environment Variables MacOS doesn’t have a reasonable way to set environment variables and read them automatically any more. So, let’s use the @@ -457,7 +459,7 @@ It starts up without an environment in this case as well. (exec-path-from-shell-initialize))) #+END_SRC -** NixOS sandboxes +*** NixOS sandboxes I'm currently exploring using nix to create sandboxes for development. This package allows using tools from inside sandboxes, @@ -479,7 +481,7 @@ and some convenience commands for building packages and launching shells. (executable-find cmd))))))) #+END_SRC -* Keybindings +** Keybindings I think =set-keyboard-coding-system= stops OS X from doing something annoying to add accents. The modifier setup is to match my @@ -533,7 +535,7 @@ Option/alt, then Control. (set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) #+END_SRC -** Crux +*** Crux I can replace most of the simple helper/wrapper functions in my configuration with crux.el @@ -554,7 +556,7 @@ configuration with crux.el (defalias 'rename-current-buffer-file #'crux-rename-file-and-buffer))) #+END_SRC -* Projects +** Projects #+BEGIN_SRC emacs-lisp (defun switch-to-dotfiles () @@ -562,7 +564,7 @@ configuration with crux.el (projectile-switch-project-by-name (car (split-string (shell-command-to-string "ghq list --full-path dotfiles"))))) #+END_SRC -** The Silver Searcher +*** The Silver Searcher #+BEGIN_SRC emacs-lisp (use-package ag @@ -573,7 +575,7 @@ configuration with crux.el :after ag) #+END_SRC -** Ripgrep +*** Ripgrep Step over Silver Search, here comes a new challenger. @@ -587,7 +589,7 @@ Step over Silver Search, here comes a new challenger. :bind (("C-c p s r" . projectile-ripgrep))) #+END_SRC -** Projectile +*** Projectile Projectile is awesome for working in projects, especially VCS-backed ones. @@ -657,7 +659,7 @@ ones. (define-key projectile-mode-map [remap counsel-projectile-ag] #'counsel-projectile-rg))) #+END_SRC -** vc +*** vc This is nice for some things that magit doesn’t do, and for those rare occasions that I’m working with something other than git. @@ -673,7 +675,7 @@ occasions that I’m working with something other than git. tramp-file-name-regexp)))) #+END_SRC -** git-gutter-fringe +*** git-gutter-fringe It’s nice to be able to see at a glance which lines of a file have changed. This package colours the fringe. I have it set to the right @@ -701,7 +703,7 @@ fringe so it doesn’t interfere with flycheck. (setq git-gutter-fr:side 'right-fringe))) #+END_SRC -** magit +*** magit Magit is my favourite way to use git. I use selective staging all the time. Make sure to set it up with a nice =completing-read-function= @@ -718,7 +720,7 @@ time. Make sure to set it up with a nice =completing-read-function= :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) #+END_SRC -** git-messenger +*** git-messenger Popup the last commit that changed the line at point. @@ -729,7 +731,7 @@ Popup the last commit that changed the line at point. (setq git-messenger:use-magit-popup t))) #+END_SRC -** git-timemachine +*** git-timemachine This package allow me to go through a file’s history with just a few keys. It makes it very easy to figure what what exactly was in a file @@ -741,7 +743,7 @@ a particular way, but it changed later. :commands git-timemachine) #+END_SRC -** ghq +*** ghq [[https://github.com/motemen/ghq][=ghq=]] clones VCS-backed projects to a common directory. It should seem familiar to anyone who's used =go get= before. [[https://github.com/rcoedo/emacs-ghq][=emacs-ghq=]] is a @@ -752,9 +754,9 @@ simple wrapper for it. :if (executable-find "ghq")) #+END_SRC -* Files +** Files -** Auto-saving +*** Auto-saving Auto-save everything to a temporary directory, instead of cluttering the filesystem. I don’t want emacs-specific lockfiles, either. @@ -763,7 +765,7 @@ the filesystem. I don’t want emacs-specific lockfiles, either. (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) create-lockfiles nil) #+END_SRC -** Backups +*** Backups I like to keep my backups out of regular folders. I tell emacs to use a subfolder of its configuration directory for that. Also, use the @@ -784,7 +786,7 @@ trash for deleting on OS X. file)))) #+END_SRC -** autorevert +*** autorevert #+BEGIN_SRC emacs-lisp (use-package autorevert @@ -795,7 +797,7 @@ trash for deleting on OS X. auto-revert-use-notify (not (eq system-type 'darwin))))) #+END_SRC -** Encoding +*** Encoding UTF-8 is usually appropriate. Note that =prefer-coding-system= expects only a coding system, not a coding system and line ending combination. @@ -805,7 +807,7 @@ only a coding system, not a coding system and line ending combination. (setq-default buffer-file-coding-system 'utf-8-auto-unix) #+END_SRC -** Buffer-file management +*** Buffer-file management Ask if I want to create a directory when it doesn’t exist. This is especially nice when starting new projects. @@ -836,7 +838,7 @@ with a buffer. (kill-buffer buf))))) #+END_SRC -** Whitespace +*** Whitespace Show bad whitespace, so that I can fix it. @@ -851,7 +853,7 @@ Show bad whitespace, so that I can fix it. (add-hook 'text-mode-hook #'show-trailing-whitespace-on) #+END_SRC -** shrink-whitespace +*** shrink-whitespace DWIM whitespace removal. So I don’t need =M-SPC=, =M-\= and =C-x o= for similar things any more. @@ -861,7 +863,7 @@ for similar things any more. :bind ("M-SPC" . shrink-whitespace)) #+END_SRC -** Tramp +*** Tramp Tramp is awesome. It makes SSH feel Unix-y. The proxy setup is so that I can sudo on remote machines @@ -888,7 +890,7 @@ that I can sudo on remote machines (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil)))) #+END_SRC -** ediff +*** ediff I like a horizonal diff setup, with everything in one frame. @@ -900,7 +902,7 @@ I like a horizonal diff setup, with everything in one frame. ediff-window-setup-function 'ediff-setup-windows-plain))) #+END_SRC -* Indentation +** Indentation Ah, a complicated topic. One day we’ll all be using elastic tabstops. I’ve recently switched to using two spaces, since elastic @@ -913,7 +915,7 @@ tabstops is probably never going to happen. #+END_SRC -** smart-tabs-mode +*** smart-tabs-mode Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns with spaces. Perfect! @@ -927,7 +929,7 @@ with spaces. Perfect! (smart-tabs-mode indent-tabs-mode)))) #+END_SRC -** editorconfig +*** editorconfig #+BEGIN_SRC emacs-lisp (use-package editorconfig @@ -935,7 +937,7 @@ with spaces. Perfect! :config (editorconfig-mode 1)) #+END_SRC -** dtrt-indent-mode +*** dtrt-indent-mode Sometimes people use different indentation settings. [[https://github.com/jscheid/dtrt-indent][dtrt-indent]] guesses the correct settings for me. @@ -951,9 +953,9 @@ guesses the correct settings for me. (smart-tabs-mode (or indent-tabs-mode -1))))) #+END_SRC -* Security +** Security -** password-store +*** password-store This is a frontend to the GPG-powered =pass= program. #+BEGIN_SRC emacs-lisp @@ -962,9 +964,9 @@ This is a frontend to the GPG-powered =pass= program. :config (progn (setq password-store-password-length 16))) #+END_SRC -* Buffers +** Buffers -** Ibuffer +*** Ibuffer Ibuffer is quite nice for listing all buffers. #+BEGIN_SRC emacs-lisp @@ -1000,7 +1002,7 @@ Ibuffer is quite nice for listing all buffers. filename-and-process))))) #+END_SRC -** Relative Buffer names +*** Relative Buffer names #+BEGIN_SRC emacs-lisp (use-package relative-buffers @@ -1008,7 +1010,7 @@ Ibuffer is quite nice for listing all buffers. :config (progn (global-relative-buffers-mode))) #+END_SRC -** Narrowing +*** Narrowing Enable it without prompting @@ -1018,7 +1020,7 @@ Enable it without prompting (put 'narrow-to-region 'disabled nil) #+END_SRC -** ace-window +*** ace-window I don’t often have many windows open at once, but when I do, =ace-window= is really nice to jump around them in the same way that @@ -1041,7 +1043,7 @@ I don’t often have many windows open at once, but when I do, aw-keys '(?a ?r ?s ?t ?n ?e ?i ?o)))) #+END_SRC -* Windows +** Windows Scrolling is tricky. I use this setup to help me keep track of the point whilst I’m moving about. @@ -1058,7 +1060,7 @@ point whilst I’m moving about. (setq ns-pop-up-frames nil)) #+END_SRC -** eyebrowse +*** eyebrowse Workspaces, a bit like dwm. On Windows and Linux (at least the WMs I'm likely to use), super+{0-9} are taken from the OS, so use meta @@ -1095,9 +1097,9 @@ programs to switch between program windows or views. (eyebrowse-mode +1))) #+END_SRC -* Sessions +** Sessions -** Desktop +*** Desktop Save my Emacs session and restore it on startup. #+BEGIN_SRC emacs-lisp @@ -1116,7 +1118,7 @@ Save my Emacs session and restore it on startup. (desktop-save-mode 1))) #+END_SRC -** winner +*** winner Undo, for window-based commands. @@ -1127,7 +1129,7 @@ Undo, for window-based commands. (winner-mode 1))) #+END_SRC -** windmove +*** windmove Directional window movement @@ -1138,7 +1140,7 @@ Directional window movement ("S-" . windmove-up) ("S-" . windmove-down))) #+END_SRC -* Blogging +** Blogging I have a [[https://alanpearce.uk][blog]] that I publish with hugo. @@ -1149,7 +1151,7 @@ I have a [[https://alanpearce.uk][blog]] that I publish with hugo. easy-hugo-default-ext ".md")) #+END_SRC -* Completion +** Completion Make built-in completion a bit more intelligent, by adding substring and initial-based completion and ignoring case. @@ -1160,7 +1162,7 @@ and initial-based completion and ignoring case. tab-always-indent 'complete) #+END_SRC -** Company +*** Company The main choices for automatic completion in Emacs are company and auto-complete-mode. I’ve not tried auto-complete-mode as company @@ -1194,9 +1196,9 @@ seems to work perfectly well for me. :after company) #+END_SRC -* Dates & Times +;;; * Dates: & Times -** Calendar +*** Calendar Weeks start on Monday for me and I prefer ISO-style dates. #+BEGIN_SRC emacs-lisp @@ -1234,7 +1236,7 @@ Sometimes I want to insert a date or time into a buffer. (timer-relative-time (current-time) -86400)) #+END_SRC -* Directories +** Directories Dired works quite nicely, but not always in the way I want. I don’t like having so many prompts for recursive operations. Also, when I @@ -1300,7 +1302,7 @@ Expand subfolders like a tree inside the parent (bind-key "i" #'dired-subtree-toggle dired-mode-map)))) #+END_SRC -** Disk usage +*** Disk usage Combine dired and du (disk usage). @@ -1311,7 +1313,7 @@ Combine dired and du (disk usage). (setq dired-du-size-format t))) #+END_SRC -** Dired-narrow +*** Dired-narrow One can already use dired with wildcards to browse a filtered directory listing, but it opens a new buffer. Dired-narrow is a slightly nicer interface: with a currently-open dired buffer, use =/= @@ -1325,9 +1327,9 @@ the buffer, removing the filter. ("/" . dired-narrow)))) #+END_SRC -* Documentation +** Documentation -** ehelp +*** ehelp ehelp is a less well-known package that’s part of Emacs and slightly improves the normal help commands, mostly by making quitting them easier. @@ -1336,7 +1338,7 @@ improves the normal help commands, mostly by making quitting them easier. (use-package ehelp :bind-keymap ("C-h" . ehelp-map)) #+END_SRC -** counsel-dash +*** counsel-dash Emacs’ documentation is great to read from inside Emacs. Counsel-dash helps to make documentation for other languages easier to access @@ -1371,7 +1373,7 @@ helps to make documentation for other languages easier to access (ap/create-counsel-dash-hook sql ("PostgreSQL" "MySQL")))) #+END_SRC -** discover-my-major +*** discover-my-major A nicer way to browse keybindings for major modes. @@ -1380,7 +1382,7 @@ A nicer way to browse keybindings for major modes. :bind ("" . discover-my-major)) #+END_SRC -** which-key +*** which-key Popup keybindings following a prefix automatically. @@ -1392,7 +1394,7 @@ Popup keybindings following a prefix automatically. (which-key-setup-side-window-right-bottom))) #+END_SRC -** eldoc +*** eldoc Documentation in the echo-area (where the minibuffer is displayed) is rather useful. @@ -1405,9 +1407,9 @@ rather useful. (setq eldoc-idle-delay 0.1) (eldoc-add-command 'paredit-backward-delete 'paredit-close-round))) #+END_SRC -* Mail +** Mail -** Gnus +*** Gnus At work, I use gnus for email. Some of the setup is specific to my workplace, so I keep it in a host-specific, GPG-encrypted file. @@ -1432,7 +1434,7 @@ workplace, so I keep it in a host-specific, GPG-encrypted file. (add-to-list 'mm-discouraged-alternatives "text/richtext")) #+END_SRC -** BBDB +*** BBDB As I'm using Emacs for email, it makes sense to have contact information here as well. @@ -1451,7 +1453,7 @@ information here as well. bbdb-offer-to-create 1))) #+END_SRC -* Misc +** Misc #+BEGIN_SRC emacs-lisp (defvar *init-file* @@ -1503,7 +1505,7 @@ information here as well. (bind-key* "C-x r M-w" #'copy-rectangle) #+END_SRC -** Auxillary Configuration +*** Auxillary Configuration #+BEGIN_SRC emacs-lisp (require 'pinentry) @@ -1556,7 +1558,7 @@ information here as well. (add-hook 'after-make-frame-functions #'first-frame-hook)) #+END_SRC -* Minibuffer +** Minibuffer Sometimes I want to use the minibuffer, but I’m already inside it. Fortunately, this is possible. Of course, I need to know how many @@ -1580,7 +1582,7 @@ Occasionally, I exit emacs. I should probably reduce the frequency of this. (defalias 'exit-emacs #'save-buffers-kill-emacs)) #+END_SRC -** swiper/ivy +*** swiper/ivy Ivy is the new kid on the completion block. It seems to be a strong replacement for helm so far. @@ -1603,7 +1605,7 @@ replacement for helm so far. (add-to-list 'ivy-initial-inputs-alist '(counsel-M-x . "")))) #+END_SRC -** counsel +*** counsel #+BEGIN_SRC emacs-lisp (use-package counsel @@ -1626,7 +1628,7 @@ replacement for helm so far. #+END_SRC -** smex +*** smex Smex is my favourite way to use =M-x=. Counsel’s =counsel-M-x= function uses it internally, so I’m keeping it around, even though I @@ -1650,7 +1652,7 @@ don’t use it directly. "smex-items")))) #+END_SRC -** cmd-to-echo +*** cmd-to-echo I’ve been looking for some way to run programming projects (mostly node.js) inside emacs. =cmd-to-echo= seems great for this, as new @@ -1661,7 +1663,7 @@ output pops up in the echo area. :commands (cmd-to-echo) :config (setq cmd-to-echo-add-output-to-process-buffers t)) #+END_SRC -* Modes +** Modes Setup some modes for systemd files #+BEGIN_SRC emacs-lisp @@ -1730,7 +1732,7 @@ configuration files. (add-to-list 'auto-mode-alist '("\\.sls\\'" . saltstack-mode)) #+END_SRC -** ledger +*** ledger I use [[http://ledger-cli.org/][=ledger=]] to manage my finances. It has an Emacs mode, which works really nicely. @@ -1770,7 +1772,7 @@ works really nicely. ("account" "ledger -f %(ledger-file) reg %(account)"))))) #+END_SRC -** Markdown +*** Markdown #+BEGIN_SRC emacs-lisp (use-package markdown-mode @@ -1779,7 +1781,17 @@ works really nicely. (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) #+END_SRC -** Org +*** Lentic + +Multiple different views of the same file. Can be used for a kind of +inverse literate programming. + +#+BEGIN_SRC emacs-lisp +(use-package lentic + :config (global-lentic-mode)) +#+END_SRC + +*** Org Org is wünderbar. @@ -1839,7 +1851,7 @@ Org is wünderbar. (bind-key "C-x C-s" #'org-edit-src-exit org-src-mode-map))) #+END_SRC -**** org-babel +***** org-babel Org’s babel feature is really nice. I use it for this file, and I can use it to communicate between programming languages. Sometime I hope @@ -1859,7 +1871,7 @@ with R or something. org-src-preserve-indentation t))) #+END_SRC -**** org-journal +***** org-journal I can use this to keep a journal. I should use it. @@ -1885,8 +1897,8 @@ I can use this to keep a journal. I should use it. #+END_SRC -* Programming -** flycheck +** Programming +*** flycheck On-the-fly error checking in programming modes? Yes please. @@ -1905,7 +1917,7 @@ On-the-fly error checking in programming modes? Yes please. (setq flycheck-javascript-eslint-executable "eslint_d")))) #+END_SRC -*** flycheck-pos-tip +**** flycheck-pos-tip Show flycheck errors in a little popup, so I don't lose my place @@ -1917,7 +1929,7 @@ Show flycheck errors in a little popup, so I don't lose my place (flycheck-pos-tip-mode 1))) #+END_SRC -*** flycheck-flow +**** flycheck-flow #+BEGIN_SRC emacs-lisp (use-package flycheck-flow @@ -1927,7 +1939,7 @@ Show flycheck errors in a little popup, so I don't lose my place (flycheck-add-next-checker 'javascript-eslint 'javascript-flow))) #+END_SRC -** golang +*** golang Go has a few packages to inter-operate with other emacs packages. @@ -1954,7 +1966,7 @@ Go has a few packages to inter-operate with other emacs packages. #+END_SRC -** ggtags +*** ggtags A nice completion backend for programming modes. @@ -1972,7 +1984,7 @@ A nice completion backend for programming modes. (add-hook 'c-mode-common-hook #'turn-on-ggtags-mode))) #+END_SRC -** dumb-jump +*** dumb-jump A "clever" way of implementing go-to-definition across languages: use a project-wide text search and apply heuristics to the results to @@ -1987,7 +1999,7 @@ guess a definition. :config (setq dumb-jump-selector 'ivy)) #+END_SRC -** imenu-anywhere +*** imenu-anywhere This is like imenu, but shows functions (or similar top-level entities) across buffers in the same project. Neat! @@ -1996,9 +2008,9 @@ entities) across buffers in the same project. Neat! (use-package imenu-anywhere :bind ("C-x C-." . ivy-imenu-anywhere)) #+END_SRC -** Lisps +*** Lisps -*** All +**** All Lisp modes don’t seem to have a common ancestor. So I made a custom hook which I trigger in every lispy-mode. @@ -2017,7 +2029,7 @@ hook which I trigger in every lispy-mode. (run-hooks 'lisp-mode-common-hook)) #+END_SRC -**** Redshank +***** Redshank Lisp syntax allows for really easy refactoring. Redshank gives some operations that aren’t part of paredit, like extracting variables into @@ -2030,7 +2042,7 @@ let bindings. (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode))) #+END_SRC -*** Emacs Lisp +**** Emacs Lisp Customise the modeline-display of =emacs-lisp-mode=. Then make sure it runs the common lisp hooks. @@ -2060,7 +2072,7 @@ Interactive elisp (run-hooks 'lisp-mode-common-hook)))) #+END_SRC -*** Scheme & Lisp +**** Scheme & Lisp I don’t work with these as often as I would like @@ -2070,7 +2082,7 @@ I don’t work with these as often as I would like #'common-lisp-indent-function)) #+END_SRC -**** geiser +***** geiser A REPL thing for Scheme. Hopefully I’ll get to use it more in the future. @@ -2083,7 +2095,7 @@ future. run-racket)) #+END_SRC -**** slime +***** slime A REPL thing (and more) for Lisp. @@ -2100,7 +2112,7 @@ A REPL thing (and more) for Lisp. (executable-find "ccl64"))))) #+END_SRC -*** Clojure +**** Clojure #+BEGIN_SRC emacs-lisp (use-package clojure-mode @@ -2119,7 +2131,7 @@ A REPL thing (and more) for Lisp. (clj-refactor-mode 1)))) #+END_SRC -**** cider +***** cider A REPL thing for Clojure @@ -2132,7 +2144,7 @@ A REPL thing for Clojure (add-hook 'cider-mode-hook #'eldoc-mode))) #+END_SRC -** Auto-compile +*** Auto-compile Auto-compile emacs lisp when saving. #+BEGIN_SRC emacs-lisp @@ -2141,7 +2153,7 @@ Auto-compile emacs lisp when saving. :init (add-hook 'emacs-lisp-mode-hook #'auto-compile-on-save-mode)) #+END_SRC -** cc-mode +*** cc-mode Although I don’t use C or C++, setting up the mode is helpful because quite a few other modes are derived from it. @@ -2157,7 +2169,7 @@ quite a few other modes are derived from it. (c-set-offset 'case-label '+))) #+END_SRC -** quickrun +*** quickrun It’s nice to be able to quickly evaluate some code. Although I don’t really seem to use it. @@ -2166,7 +2178,7 @@ really seem to use it. :bind (("C-c C-e" . quickrun))) #+END_SRC -** Scala +*** Scala Let’s try using Scala. @@ -2180,9 +2192,9 @@ And add ensime, an IDE-style environment. (use-package ensime) #+END_SRC -** Web development +*** Web development -*** js2-mode +**** js2-mode This mode is really great for editing Javascript. It turns code into an AST internally, so it can work with it almost like a lisp. @@ -2213,16 +2225,18 @@ an AST internally, so it can work with it almost like a lisp. js2-strict-missing-semi-warning nil))) #+END_SRC -**** rjsx-mode +***** rjsx-mode A set of advice for js2-jsx-mode to work better with React. #+BEGIN_SRC emacs-lisp (use-package rjsx-mode + :after js2-mode + :if (fboundp #'js2--struct-put) :mode (("\\.jsx\\'" . rjsx-mode))) #+END_SRC -**** js2-refactor +***** js2-refactor Thanks to the AST provided by js2-mode, refactoring is possible. This library implements some refactorings. @@ -2236,7 +2250,7 @@ library implements some refactorings. (js2r-add-keybindings-with-prefix "C-c C-m"))) #+END_SRC -**** add-node-modules-path +***** add-node-modules-path Inside a javascript project, it's common to install tools locally to the project. This will allows emacs to find their executables. @@ -2247,7 +2261,7 @@ the project. This will allows emacs to find their executables. (add-hook 'js2-mode-hook #'add-node-modules-path))) #+END_SRC -**** Flow +***** Flow #+BEGIN_SRC emacs-lisp (use-package flow-minor-mode @@ -2256,7 +2270,7 @@ the project. This will allows emacs to find their executables. (add-hook 'js2-mode-hook #'flow-minor-enable-automatically))) #+END_SRC -**** Indium +***** Indium Javascript with an inferior node.js process and a debugger? Awesome. @@ -2281,7 +2295,7 @@ Instead, do this: (add-hook 'js2-mode-hook #'indium-interaction-mode))) #+END_SRC -*** coffee-mode +**** coffee-mode #+BEGIN_SRC emacs-lisp (use-package coffee-mode @@ -2290,7 +2304,7 @@ Instead, do this: (setq coffee-indent-like-python-mode t))) #+END_SRC -*** tern +**** tern Tern understands javascript. It adds really clever documented completions, besides other IDE-like things. @@ -2311,7 +2325,7 @@ completions, besides other IDE-like things. (use-package company-tern)) #+END_SRC -*** json-mode +**** json-mode #+BEGIN_SRC emacs-lisp (use-package json-mode @@ -2321,7 +2335,7 @@ completions, besides other IDE-like things. ("\\.tern-project\\'" . json-mode))) #+END_SRC -*** restclient +**** restclient Restclient is really nice. It’s like a scratchpad for HTTP api calls. Feels a bit like using =org-babel=. I wonder if there’s an @@ -2342,7 +2356,7 @@ integration between the two yet. :init (add-to-list 'company-backends #'company-restclient t)) #+END_SRC -*** sgml-mode +**** sgml-mode This is for HTML, since old versions of HTML were derived from SGML. #+BEGIN_SRC emacs-lisp @@ -2351,7 +2365,7 @@ This is for HTML, since old versions of HTML were derived from SGML. :config (setq sgml-basic-offset 2)) #+END_SRC -*** emmet-mode +**** emmet-mode Emmet is really nice to write HTML quickly. Especially with frameworks that require multiple nested elements to do anything useful. @@ -2367,7 +2381,7 @@ frameworks that require multiple nested elements to do anything useful. (add-hook 'css-mode-hook #'emmet-mode))) #+END_SRC -*** web-mode +**** web-mode This mode handles just about every templating language out ther, which is really nice, because it handles the HTML part the same way in all @@ -2399,7 +2413,7 @@ I derived a mode for twig, in order to use its =mode-hook=. (add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) #+END_SRC -** Live coding +*** Live coding Sometimes I might want to show off my emacs usage. @@ -2415,7 +2429,7 @@ Sometimes I might want to show off my emacs usage. (global-command-log-mode -1)) #+END_SRC -*** command-log-mode +**** command-log-mode #+BEGIN_SRC emacs-lisp (use-package command-log-mode @@ -2426,7 +2440,7 @@ Sometimes I might want to show off my emacs usage. command-log-mode-is-global t))) #+END_SRC -* Spelling +** Spelling #+BEGIN_SRC emacs-lisp (use-package ispell @@ -2490,7 +2504,7 @@ Sometimes I might want to show off my emacs usage. (add-hook 'prog-mode-hook #'flyspell-prog-mode))) #+END_SRC -** Style checking +*** Style checking [[https://github.com/ValeLint/vale][Vale]] is a linter, but for prose. Neat idea! Salesman is a bad term. @@ -2503,7 +2517,7 @@ Sometimes I might want to show off my emacs usage. (flycheck-vale-setup))) #+END_SRC -* Scripting +** Scripting Make a shell-script buffer executable after saving it, if it has a shebang. @@ -2524,7 +2538,7 @@ Make a shell-script buffer executable after saving it, if it has a shebang. (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) #+END_SRC -** eshell +*** eshell I should try to get into the habit of using this more. It’s really nice, when I remember to use it. @@ -2564,7 +2578,7 @@ nice, when I remember to use it. #+END_SRC -*** Shells +**** Shells #+BEGIN_SRC emacs-lisp (use-package shell @@ -2585,7 +2599,7 @@ nice, when I remember to use it. (comint-delchar-or-maybe-eof arg))) #+END_SRC -* Text editing +** Text editing Emacs has an editor within. @@ -2597,7 +2611,7 @@ Emacs has an editor within. (setq-default truncate-lines t) #+END_SRC -** align +*** align =Align= is a useful command to line things up, once given some rules. The most important one for me is JSON property alignment. @@ -2613,7 +2627,7 @@ The most important one for me is JSON property alignment. (modes . '(js2-mode)))))) #+END_SRC -** Clipboard +*** Clipboard I like to use the clipboard more than the primary selection in X11. @@ -2626,7 +2640,7 @@ I like to use the clipboard more than the primary selection in X11. (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) #+END_SRC -** Selection +*** Selection I’m quite used to deleting text by selecting it and typing. Emacs has a mode for that. @@ -2663,7 +2677,7 @@ from Sublime Text. As always, there’s a mode for that. :config (setq expand-region-fast-keys-enabled nil)) #+END_SRC -** avy +*** avy Avy is a really nice way to move around files, like ace-jump-mode, but somehow I prefer it. @@ -2682,7 +2696,7 @@ somehow I prefer it. avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?\;)))) #+END_SRC -*** ace-link +**** ace-link Visit any link. Despite the name, this works with avy. @@ -2696,7 +2710,7 @@ Visit any link. Despite the name, this works with avy. (bind-key "M-o" #'ace-link-gnus gnus-article-mode-map)))) #+END_SRC -** goto-chg +*** goto-chg This is like popping the mark, only it filters to only change areas and doesn’t go back to the same place more than once. @@ -2706,7 +2720,7 @@ and doesn’t go back to the same place more than once. :bind ("C-c C-SPC" . goto-last-change)) #+END_SRC -** beginend +*** beginend In special buffers, I would rather have =M->= and =M-<= goto the logical beginning/end rather than the physical ones. @@ -2717,7 +2731,7 @@ logical beginning/end rather than the physical ones. (beginend-setup-all))) #+END_SRC -** multiple-cursors +*** multiple-cursors I mentioned before that I’d used Sublime Text before. Multiple cursors was one of my favourite features, so I was really happy when I @@ -2733,7 +2747,7 @@ saw that multiple-cursors was released for Emacs. ("C-S-L" . mc/edit-lines))) #+END_SRC -** paredit +*** paredit Balanced parentheses in lisps are nice, but all the refactoring and movement commands are much more interesting. @@ -2748,7 +2762,7 @@ movement commands are much more interesting. (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode))) #+END_SRC -** smartparens +*** smartparens I like to use smartparens where paredit isn’t already useful. Somehow I didn’t find smartparens’ implementation of paredit style to be as @@ -2785,7 +2799,7 @@ nice as the real version #+END_SRC -** move-text +*** move-text Transposing lines, made easier. @@ -2794,7 +2808,7 @@ Transposing lines, made easier. :config (move-text-default-bindings)) #+END_SRC -** undo-tree +*** undo-tree Emacs’ default handling of undo is a bit confusing. Undo-tree makes it much clearer. It’s especially helpful for protoyping and refactoring. @@ -2817,14 +2831,14 @@ it much clearer. It’s especially helpful for protoyping and refactoring. :diminish undo-tree-mode) #+END_SRC -** replace +*** replace #+BEGIN_SRC emacs-lisp (with-eval-after-load "replace.el" (setq case-replace nil)) #+END_SRC -** visual-regexp +*** visual-regexp I don’t always remember exactly how Emacs’ regular expressions work, so this package is pretty useful because it highlights everything in @@ -2836,61 +2850,8 @@ the buffer for me. ("C-c q" . vr/query-replace) ("C-c m" . vc/mc-mark))) #+END_SRC -* Tangling - -Taken from [[https://github.com/larstvei/dot-emacs/blob/master/init.org][larstvei/dot-emacs]]. I changed it so that it would work with -my current dotfiles repository structure and work asynchronously, -thanks to [[https://github.com/jwiegley/emacs-async][jwiegley/emacs-async]]. - -We can use =C-c C-v t= to run =org-babel-tangle=, which extracts the -code blocks from the current file into a source-specific file (in this -case a =.el=-file). -To avoid doing this each time a change is made we can add a function -to the =after-save-hook= ensuring to always tangle and byte-compile -the =org=-document after changes. - -#+BEGIN_SRC emacs-lisp -(use-package async - :commands (async-start) - :defer 2) - -(defun tangle-if-init () - "If the current buffer is 'init.org' the code-blocks are - tangled, and the tangled file is compiled." - - (when (string-suffix-p "init.org" (buffer-file-name)) - (tangle-init))) - -(defun tangle-init-sync () - (interactive) - (message "Tangling init") - ;; Avoid running hooks when tangling. - (let ((prog-mode-hook nil) - (src (expand-file-name "init.org" user-emacs-directory)) - (dest (expand-file-name "init.el" user-emacs-directory))) - (require 'ob-tangle) - (org-babel-tangle-file src dest) - (if (byte-compile-file dest) - (byte-compile-dest-file dest) - (with-current-buffer byte-compile-log-buffer - (buffer-string))))) - -(defun tangle-init () - "Tangle init.org asynchronously." - - (interactive) - (message "Tangling init") - (async-start - (symbol-function #'tangle-init-sync) - (lambda (result) - (message "Init tangling completed: %s" result)))) -#+END_SRC - -# Local Variables: -# eval: (when (fboundp #'tangle-if-init) (add-hook 'after-save-hook #'tangle-if-init)) -# End: -* End +** End Start a server if possible. A daemon is already a server. #+BEGIN_SRC emacs-lisp @@ -2902,3 +2863,7 @@ Start a server if possible. A daemon is already a server. (setq gc-cons-threshold 800000 file-name-handler-alist file-name-handler-alist-backup) #+END_SRC + +Local Variables: +lentic-init: lentic-orgel-org-init +End: diff --git a/nix/.config/nixpkgs/emacs.nix b/nix/.config/nixpkgs/emacs.nix index cf697c7..aad4a78 100644 --- a/nix/.config/nixpkgs/emacs.nix +++ b/nix/.config/nixpkgs/emacs.nix @@ -52,12 +52,12 @@ in bind-key use-package smartparens + lentic ]) ++ (with epkgs.melpaPackages; [ ace-link ace-window add-node-modules-path ag - async auto-compile avy base16-theme -- cgit 1.4.1 From f4aa8c2484b2fc00afa5935e31164f0b4bb6c311 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:11:01 +0200 Subject: Emacs: Update Makefile to only byte-compile init --- emacs/.emacs.d/Makefile | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/emacs/.emacs.d/Makefile b/emacs/.emacs.d/Makefile index 9f086ff..71415d5 100644 --- a/emacs/.emacs.d/Makefile +++ b/emacs/.emacs.d/Makefile @@ -1,13 +1,3 @@ -define EMACS_TANGLE -(progn\ - (require 'package)\ - (package-refresh-contents nil)\ - (setq vc-follow-symlinks nil)\ - (find-file \"init.org\")\ - (require 'ob-tangle)\ - (org-babel-tangle nil \"init.el\")) -endef - EMACS := ${NIX_LINK}/bin/emacs # The first target is the default. `all` is typically defined here. @@ -16,11 +6,8 @@ all: init.elc # These targets don't pertain to files .PHONY: all clean -init.el: - $(EMACS) --batch --no-init-file --eval "$(EMACS_TANGLE)" --kill - init.elc: init.el $(EMACS) --batch --no-init-file --funcall batch-byte-compile init.el clean: - rm init.el init.elc + rm init.elc -- cgit 1.4.1 From 17750b72b3d5578f486c4a13901f552a93b7cdb0 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:16:21 +0200 Subject: Ignore .elc files With lentic-mode, these are now created inside the repository --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea33edf..b1a76a4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.zwc *.zwc.old .DS_Store +*.elc -- cgit 1.4.1 From 0c91555d5bab41fd2ce71ea0dee29eb7fb64484a Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:32:16 +0200 Subject: Emacs: Remove counsel-dash I don't seem to be using it, and it's currently not installable via nix --- emacs/.emacs.d/init.el | 34 ---------------------------------- emacs/.emacs.d/init.org | 34 ---------------------------------- 2 files changed, 68 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 902e5b5..9e8e109 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -1338,40 +1338,6 @@ (use-package ehelp :bind-keymap ("C-h" . ehelp-map)) ;; #+END_SRC -;; *** counsel-dash - -;; Emacs’ documentation is great to read from inside Emacs. Counsel-dash -;; helps to make documentation for other languages easier to access - -;; #+BEGIN_SRC emacs-lisp -(defmacro ap/create-counsel-dash-hook (mode docsets) - (let* ((mode-s (symbol-name mode)) - (fun (intern (concat "counsel-dash-hook-" mode-s))) - (hook (intern (concat mode-s "-mode-hook")))) - `(progn - (defun ,fun () - (when (require 'counsel-dash nil :noerror) - (seq-map #'counsel-dash-install-docset - (seq-difference ',docsets - (helm-dash-installed-docsets))) - (setq-local counsel-dash-docsets ',docsets))) - (add-hook (quote ,hook) (function ,fun))))) - -(use-package counsel-dash - :defer 20 - :defines counsel-dash-docsets - :config (progn - (setq counsel-dash-browser-func #'eww) - (ap/create-counsel-dash-hook nginx ("Nginx")) - (ap/create-counsel-dash-hook ansible ("Ansible")) - (ap/create-counsel-dash-hook php ("PHP" "Symfony")) - (ap/create-counsel-dash-hook twig ("Twig")) - (ap/create-counsel-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express" "SailsJS" "Lo-Dash")) - (ap/create-counsel-dash-hook markdown ("Markdown")) - (ap/create-counsel-dash-hook saltstack ("SaltStack")) - (ap/create-counsel-dash-hook clojure ("Clojure")) - (ap/create-counsel-dash-hook sql ("PostgreSQL" "MySQL")))) -;; #+END_SRC ;; *** discover-my-major diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org index d428bd8..78c1ede 100644 --- a/emacs/.emacs.d/init.org +++ b/emacs/.emacs.d/init.org @@ -1338,40 +1338,6 @@ improves the normal help commands, mostly by making quitting them easier. (use-package ehelp :bind-keymap ("C-h" . ehelp-map)) #+END_SRC -*** counsel-dash - -Emacs’ documentation is great to read from inside Emacs. Counsel-dash -helps to make documentation for other languages easier to access - -#+BEGIN_SRC emacs-lisp -(defmacro ap/create-counsel-dash-hook (mode docsets) - (let* ((mode-s (symbol-name mode)) - (fun (intern (concat "counsel-dash-hook-" mode-s))) - (hook (intern (concat mode-s "-mode-hook")))) - `(progn - (defun ,fun () - (when (require 'counsel-dash nil :noerror) - (seq-map #'counsel-dash-install-docset - (seq-difference ',docsets - (helm-dash-installed-docsets))) - (setq-local counsel-dash-docsets ',docsets))) - (add-hook (quote ,hook) (function ,fun))))) - -(use-package counsel-dash - :defer 20 - :defines counsel-dash-docsets - :config (progn - (setq counsel-dash-browser-func #'eww) - (ap/create-counsel-dash-hook nginx ("Nginx")) - (ap/create-counsel-dash-hook ansible ("Ansible")) - (ap/create-counsel-dash-hook php ("PHP" "Symfony")) - (ap/create-counsel-dash-hook twig ("Twig")) - (ap/create-counsel-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express" "SailsJS" "Lo-Dash")) - (ap/create-counsel-dash-hook markdown ("Markdown")) - (ap/create-counsel-dash-hook saltstack ("SaltStack")) - (ap/create-counsel-dash-hook clojure ("Clojure")) - (ap/create-counsel-dash-hook sql ("PostgreSQL" "MySQL")))) -#+END_SRC *** discover-my-major -- cgit 1.4.1 From d42c508a6c8d51ff9efa72cfcdd357cef3f0f9da Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:32:36 +0200 Subject: Ignore flycheck temp files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b1a76a4..e9fa055 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ *.zwc.old .DS_Store *.elc +flycheck_* -- cgit 1.4.1 From 0fa6a6ba99361ff513dfd93f24d605a07a5c9f07 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Thu, 3 Aug 2017 12:44:45 +0200 Subject: Emacs: Fix byte-compiler warnings --- emacs/.emacs.d/init.el | 12 ++++-------- emacs/.emacs.d/init.org | 5 ++--- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 9e8e109..ffde904 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -604,7 +604,7 @@ :demand t :diminish projectile-mode :config (progn - (projectile-global-mode +1) + (projectile-mode +1) (add-to-list 'projectile-globally-ignored-directories ".stversions") (defun yarn-install (&optional arg) @@ -1706,6 +1706,7 @@ ;; #+BEGIN_SRC emacs-lisp (use-package ledger-mode :mode ("\\.ledger\\'" . ledger-mode) + :functions ledger-report :init (progn (defun open-budget () (interactive) @@ -2169,16 +2170,11 @@ (use-package js2-mode :mode (("\\.js\\'" . js2-mode)) :interpreter ("node" . js2-mode) - :functions js2-next-error + :functions (js2-next-error + js2--struct-put) :config (progn (define-key js2-mode-map [menu-bar Javascript] nil) - (defun js2--imenu-around (do-it name) - "Don't create a menu from js2-mode" - (if (and (not (string-equal name "IM-Javascript-IDE")) - (fboundp #'do-it)) - (do-it name))) (add-hook 'js2-mode-hook #'js2-imenu-extras-mode) - (advice-add 'imenu-add-to-menubar :around #'js2--imenu-around) (defun ap/js2-prev-error () (interactive) (js2-next-error -1)) diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org index 78c1ede..da79d68 100644 --- a/emacs/.emacs.d/init.org +++ b/emacs/.emacs.d/init.org @@ -604,7 +604,7 @@ ones. :demand t :diminish projectile-mode :config (progn - (projectile-global-mode +1) + (projectile-mode -1) (add-to-list 'projectile-globally-ignored-directories ".stversions") (defun yarn-install (&optional arg) @@ -2174,8 +2174,7 @@ an AST internally, so it can work with it almost like a lisp. (define-key js2-mode-map [menu-bar Javascript] nil) (defun js2--imenu-around (do-it name) "Don't create a menu from js2-mode" - (if (and (not (string-equal name "IM-Javascript-IDE")) - (fboundp #'do-it)) + (if (not (string-equal name "IM-Javascript-IDE")) (do-it name))) (add-hook 'js2-mode-hook #'js2-imenu-extras-mode) (advice-add 'imenu-add-to-menubar :around #'js2--imenu-around) -- cgit 1.4.1 From 86fc398a1e808c73f5727f729460ccab01258dd8 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 10:17:36 +0200 Subject: Emacs: Move post-startup de-optimisation code to top of file --- emacs/.emacs.d/init.el | 6 ++++-- emacs/.emacs.d/init.org | 17 ++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index ffde904..fb5a75e 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -17,6 +17,10 @@ (setq gc-cons-threshold 100000000) (defvar file-name-handler-alist-backup file-name-handler-alist) (setq file-name-handler-alist nil) +(add-hook 'after-init-hook + #'(lambda () + (setq gc-cons-threshold 800000 + file-name-handler-alist file-name-handler-alist-backup))) (remove-hook 'find-file-hooks #'vc-refresh-state) ;; #+END_SRC @@ -2822,8 +2826,6 @@ :if (not (daemonp)) :config (unless (server-running-p server-name) (server-start))) -(setq gc-cons-threshold 800000 - file-name-handler-alist file-name-handler-alist-backup) ;; #+END_SRC ;; Local Variables: diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org index da79d68..6ca4f65 100644 --- a/emacs/.emacs.d/init.org +++ b/emacs/.emacs.d/init.org @@ -17,6 +17,10 @@ Open Emacs with just a plain window. No graphics or messages, please! (setq gc-cons-threshold 100000000) (defvar file-name-handler-alist-backup file-name-handler-alist) (setq file-name-handler-alist nil) +(add-hook 'after-init-hook + #'(lambda () + (setq gc-cons-threshold 800000 + file-name-handler-alist file-name-handler-alist-backup))) (remove-hook 'find-file-hooks #'vc-refresh-state) #+END_SRC @@ -604,7 +608,7 @@ ones. :demand t :diminish projectile-mode :config (progn - (projectile-mode -1) + (projectile-mode +1) (add-to-list 'projectile-globally-ignored-directories ".stversions") (defun yarn-install (&optional arg) @@ -1706,6 +1710,7 @@ works really nicely. #+BEGIN_SRC emacs-lisp (use-package ledger-mode :mode ("\\.ledger\\'" . ledger-mode) + :functions ledger-report :init (progn (defun open-budget () (interactive) @@ -2169,15 +2174,11 @@ an AST internally, so it can work with it almost like a lisp. (use-package js2-mode :mode (("\\.js\\'" . js2-mode)) :interpreter ("node" . js2-mode) - :functions js2-next-error + :functions (js2-next-error + js2--struct-put) :config (progn (define-key js2-mode-map [menu-bar Javascript] nil) - (defun js2--imenu-around (do-it name) - "Don't create a menu from js2-mode" - (if (not (string-equal name "IM-Javascript-IDE")) - (do-it name))) (add-hook 'js2-mode-hook #'js2-imenu-extras-mode) - (advice-add 'imenu-add-to-menubar :around #'js2--imenu-around) (defun ap/js2-prev-error () (interactive) (js2-next-error -1)) @@ -2825,8 +2826,6 @@ Start a server if possible. A daemon is already a server. :if (not (daemonp)) :config (unless (server-running-p server-name) (server-start))) -(setq gc-cons-threshold 800000 - file-name-handler-alist file-name-handler-alist-backup) #+END_SRC Local Variables: -- cgit 1.4.1 From 979a1c53860c2aa8705084ebaedba2ea8d85665e Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 15:28:28 +0200 Subject: Emacs: Use outshine instead of lentic --- emacs/.emacs.d/init.el | 24 +- emacs/.emacs.d/init.org | 2833 ----------------------------------------- nix/.config/nixpkgs/emacs.nix | 3 + 3 files changed, 22 insertions(+), 2838 deletions(-) delete mode 100644 emacs/.emacs.d/init.org diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index fb5a75e..5df1f8b 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -1200,7 +1200,7 @@ :after company) ;; #+END_SRC -;;; * Dates: & Times +;;; ** Dates & Times ;; *** Calendar @@ -1762,6 +1762,24 @@ :config (global-lentic-mode)) ;; #+END_SRC +;; *** Outshine + +;; Org-ified source code. I think this might work better than +;; lentic-mode, whilst also being more general. + +;; #+BEGIN_SRC emacs-lisp +(defvar outline-minor-mode-prefix "M-#") +(use-package outshine + :bind (:map outline-minor-mode-map + ("TAB" . outline-cycle) + ("" . outshine-cycle-buffer)) + :config (progn + (add-hook 'outline-minor-mode-hook #'outshine-hook-function) + (add-hook 'emacs-lisp-mode-hook #'outline-minor-mode) + (add-hook 'ledger-mode-hook #'outline-minor-mode) + (add-hook 'sh-mode-hook #'outline-minor-mode))) +;; #+END_SRC + ;; *** Org ;; Org is wünderbar. @@ -2827,7 +2845,3 @@ :config (unless (server-running-p server-name) (server-start))) ;; #+END_SRC - -;; Local Variables: -;; lentic-init: lentic-orgel-org-init -;; End: diff --git a/emacs/.emacs.d/init.org b/emacs/.emacs.d/init.org deleted file mode 100644 index 6ca4f65..0000000 --- a/emacs/.emacs.d/init.org +++ /dev/null @@ -1,2833 +0,0 @@ -# # emacs-config --- Summary -#+TITLE: Emacs Configuration for Alan Pearce -#+OPTIONS: ^:nil -#+PROPERTY: results silent -#+PROPERTY: eval no-export -#+PROPERTY: header-args :comments link -* Header -This is a living document, detailing my Emacs configuration using org-mode -* Code -** Basics -*** Startup -Open Emacs with just a plain window. No graphics or messages, please! -#+BEGIN_SRC emacs-lisp -(put 'inhibit-startup-echo-area-message 'saved-value - (setq inhibit-startup-echo-area-message (user-login-name))) -(setq inhibit-startup-screen t) -(setq gc-cons-threshold 100000000) -(defvar file-name-handler-alist-backup file-name-handler-alist) -(setq file-name-handler-alist nil) -(add-hook 'after-init-hook - #'(lambda () - (setq gc-cons-threshold 800000 - file-name-handler-alist file-name-handler-alist-backup))) -(remove-hook 'find-file-hooks #'vc-refresh-state) -#+END_SRC - -Are we running on Windows via the WSL? - -#+BEGIN_SRC emacs-lisp -(when (file-exists-p "/proc/sys/kernel/osrelease") - (with-temp-buffer - (insert-file-contents-literally "/proc/sys/kernel/osrelease") - (decode-coding-region (point-min) (point-max) 'utf-8 t) - (when (string-match "Microsoft$" (buffer-string)) - (setq system-type 'gnu/linux/windows)))) -#+END_SRC - -*** Compatibility - -#+BEGIN_SRC emacs-lisp -(if (version< emacs-version "25.0") - (defmacro with-eval-after-load (file &rest body) - `(eval-after-load ,file (lambda () ,@body)))) -#+END_SRC - -*** Scratch buffers -I usually use scratch buffers for any sort of text. If I need a -programming mode in one, then I’ll just call it manually. I also like -the buffer to be empty. -#+BEGIN_SRC emacs-lisp -(setq initial-scratch-message "" - initial-major-mode 'text-mode) -#+END_SRC - -*** Personal Information -#+BEGIN_SRC emacs-lisp -(setq user-mail-address "alan@alanpearce.eu" - user-full-name "Alan Pearce") -#+end_src - -** Packaging - -*** Use-package - -#+BEGIN_SRC emacs-lisp -(eval-and-compile - (require 'seq) - (defvar nix-emacs (and (string-match "^/nix/store" invocation-directory) - (not (null (seq-some (lambda (dir) (string-match "^/nix/store" dir)) load-path))))) - - (setq tls-checktrust t - gnutls-verify-error t - package-menu-async t - package-user-dir (concat "~/.emacs.d/packages/" emacs-version "/elpa") - package-menu-hide-low-priority t) - (if nix-emacs - (progn (setq package-archives nil) - (package-initialize)) - (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") - ("melpa-stable" . "https://stable.melpa.org/packages/") - ("melpa" . "https://melpa.org/packages/")) - package-pinned-packages '(("use-package" . melpa-stable) - ("diminish" . melpa-stable) - ("bind-key" . melpa-stable)) - package-archive-priorities '(("melpa" . 10) - ("gnu" . 10) - ("melpa-stable" . 5) - ("marmalade" . 0)))) - (when (eq system-type 'darwin) - (with-eval-after-load "gnutls" - (add-to-list 'gnutls-trustfiles "/etc/ssl/cert.pem"))) - (unless nix-emacs - (package-initialize) - (unless (package-installed-p 'use-package) - (package-refresh-contents) - (package-install 'use-package)))) -(eval-when-compile (require 'use-package)) -(unless (featurep 'use-package) - (require 'diminish) - (require 'bind-key) - (use-package use-package - :commands (use-package-autoload-keymap) - :defer 5)) -(setq use-package-always-ensure (not nix-emacs) - use-package-always-demand (daemonp) - package-enable-at-startup nil) -#+END_SRC - -*** Helpers - -**** Hook Helpers - -An improvement over add-hook with lamda functions that allows -modification and removal, without the boilerplate of an extra function -definition. - -#+BEGIN_SRC emacs-lisp -(eval-and-compile - (use-package hook-helpers)) -#+END_SRC - -** Customize -I don’t really like using customize for normal configuration. -Instead, I use it for things that get saved automatically. That’s why -I use a different file, which is ignored by the VCS. It also means -that it’s not important whether the file exists or not, which is why I -pass =:noerror= to =load= - -#+BEGIN_SRC emacs-lisp -(setq custom-file "~/.emacs.d/custom.el") -(load custom-file :noerror :nomessage) -#+END_SRC - -** Styles - -I prefer an always-visible cursor. Feels less distracting. -#+BEGIN_SRC emacs-lisp -(when (fboundp #'blink-cursor-mode) - (blink-cursor-mode -1)) -#+END_SRC - -Disable all the bars, unless on OSX, in which case, keep the menu bar. - -#+BEGIN_SRC emacs-lisp -(when (and menu-bar-mode (not (eq window-system 'ns))) - (menu-bar-mode -1)) -(with-eval-after-load 'scroll-bar - (set-scroll-bar-mode nil)) -(with-eval-after-load 'tooltip - (tooltip-mode -1)) -(with-eval-after-load 'tool-bar - (tool-bar-mode -1)) -#+END_SRC - -Ring the bell sometimes, but not so often -#+BEGIN_SRC emacs-lisp -(setq ring-bell-function - (lambda () - (unless (memq this-command - '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit undo-tree-undo)) - (ding)))) -#+END_SRC - -*** Colours - -Eziam looks nice, too, except for the non-white background. I prefer -white because most other application backgrounds are that colour. - -#+BEGIN_SRC emacs-lisp -(use-package eziam-light-theme - :ensure eziam-theme - :disabled t - :if (or window-system - (daemonp)) - :defines (eziam-scale-headings) - :config (progn - (setq eziam-scale-headings nil) - (load-theme 'eziam-light t) - (custom-theme-set-faces 'user - '(default ((t (:background "#ffffff")))) - '(js2-function-call ((t (:underline nil)))) - '(js2-object-property ((t (:slant normal)))) - '(font-lock-keyword-face ((t (:weight normal)))) - '(git-gutter-fr:added ((t (:foreground "#96a4ab")))) - '(git-gutter-fr:modified ((t (:foreground "#96a4ab")))) - '(git-gutter-fr:deleted ((t (:foreground "#96a4ab"))))))) -#+END_SRC - -White-theme. Sounds like a good idea. - -#+BEGIN_SRC emacs-lisp -(use-package white-theme - :if (or window-system - (daemonp)) - :config (progn - (load-theme 'white t) - (custom-theme-set-faces 'user - '(git-gutter-fr:added ((t (:foreground "#b8b8b8")))) - '(git-gutter-fr:modified ((t (:foreground "#b8b8b8")))) - '(git-gutter-fr:deleted ((t (:foreground "#b8b8b8")))) - '(font-lock-string-face ((t (:slant normal))))))) -#+END_SRC - -Base16 theming allows me have a consistent style between applications -quite easily. - -#+BEGIN_SRC emacs-lisp -(use-package base16-theme - :if (or window-system - (daemonp))) -#+END_SRC - -Highlighting quasi-quoted expressions in lisps is quite useful, but I -don't need it all the time. I'll keep it around for a while so that I -can enable it if needed. -#+BEGIN_SRC emacs-lisp -(use-package highlight-stages - :diminish highlight-stages-mode) -#+END_SRC - -*** Fonts - -When possible, set up fonts. I don’t have any settings here for X11, -because I manage those in my [[file:~/projects/dotfiles/tag-xresources/xresources/main][XResources file]]. -#+BEGIN_SRC emacs-lisp -(when (or (display-graphic-p) - (daemonp)) - - (defun use-variable-fonts () - (interactive) - (variable-pitch-mode) - (setq cursor-type '(bar . 1))) - - (defun ap/set-fonts (mono-face mono-font-size variable-face variable-font-size antialias &optional new-line-spacing) - (if (boundp 'ns-antialias-text) - (setq ns-antialias-text antialias)) - (if (boundp 'new-line-spacing) - (setq line-spacing new-line-spacing)) - (when mono-face - (let ((default-font (font-spec :family mono-face :size mono-font-size))) - (add-to-list 'default-frame-alist `(font . ,(format "%s %s" mono-face mono-font-size))) - (set-face-font 'fixed-pitch default-font) - (set-frame-font default-font t t))) - (when variable-face - (set-face-font 'variable-pitch (font-spec :name variable-face :size variable-font-size)))) - - (defun ap/set-fonts-according-to-system () - (interactive) - (cond - ((eq window-system 'w32) - (ap/set-fonts "Liberation Mono" 11 "Segoe UI" 11 t)) - ((or (eq window-system 'mac) - (eq window-system 'ns)) - (let ((displays (string-to-number (shell-command-to-string "system_profiler SPDisplaysDataType | grep \"Online: Yes\" | wc -l")))) - (if (eq displays 1) - (ap/set-fonts "Fira Code" 14 "Lucida Grande" 14 t nil) - (ap/set-fonts "Monoid" 12 "Helvetica Neue" 12 t 0.1)))) - ((and (eq window-system 'x) - (not (eq system-type 'gnu/linux/windows))) - (set-fontset-font "fontset-default" 'unicode (font-spec :name "PT Mono" :size 17)) - (ap/set-fonts "PT Mono" 17 "Noto Sans" 14 nil)) - ((and (eq window-system 'x) - (eq system-type 'gnu/linux/windows)) - (ap/set-fonts "Noto Mono" 12 "Sans" 12 nil)))) - - (ap/set-fonts-according-to-system)) -#+END_SRC - -Reduce font decoration. I’m trying to see whether this helps me focus -on the right things. -#+BEGIN_SRC emacs-lisp -(setq font-lock-maximum-decoration '((dired-mode . 1) - (t . 1))) -#+END_SRC - -Make symbols prettier. Turns out, in many cases, this is already -configured, just not enabled. If using the mac-port version of Emacs, -it has it's own, more extensive version. - -#+BEGIN_SRC emacs-lisp -(if (eq window-system 'mac) - (mac-auto-operator-composition-mode +1) - (global-prettify-symbols-mode +1)) -#+END_SRC - -*** Page Breaks - -By default, Emacs displays page breaks as ^L. Lines look much nicer. -On Windows, Emacs incorrectly detects that U+2500 (Box Drawings Light -Horizontal) can only be displayed with a different font, which is not -correct, at least for Liberation Mono. - -#+BEGIN_SRC emacs-lisp -(use-package page-break-lines - :defer 5 - :diminish page-break-lines-mode - :config (progn - (global-page-break-lines-mode) - (unless (eq (char-displayable-p ?─) (char-displayable-p ?a)) - (set-fontset-font "fontset-default" - (cons page-break-lines-char page-break-lines-char) - (face-attribute 'default :family))))) -#+END_SRC -*** Modeline - -#+BEGIN_SRC emacs-lisp -(column-number-mode -1) -(line-number-mode -1) -(size-indication-mode t) - - -(require 'f) -(setq frame-title-format (list "Emacs" - (if (and nix-emacs invocation-directory) - (list " (Nix Generation " - (cadr - (split-string (f-base - (car - (last (seq-take-while - (lambda (s) (s-contains? "profile" s)) - (split-string - (s-chomp (shell-command-to-string (concat "nix-store -q --roots " invocation-directory))) - "\n"))))) - "-")) - " " - (s-left 6 (nth 3 (f-split invocation-directory))) - "..." - (s-right 6 (car (split-string (nth 3 (f-split invocation-directory)) "-"))) - ")")) - '(buffer-file-name " — %f") - '(dired-directory (" — " dired-directory)))) -#+END_SRC - -*** Chrome - -Sometimes I like to hide clutter. Other times, it's useful. - -#+BEGIN_SRC emacs-lisp -(defvar mode-line-default-format mode-line-format) -(defvar mode-line-default-hidden nil - "Whether to hide the mode line by default") - -(defun show-mode-line () - (interactive) - (setq mode-line-format mode-line-default-format) - (when (called-interactively-p 'interactive) - (setq-default mode-line-format mode-line-default-format) - (setq mode-line-default-hidden nil))) -(defun hide-mode-line () - (interactive) - (setq mode-line-format nil) - (when (called-interactively-p 'interactive) - (setq-default mode-line-format nil) - (setq mode-line-default-hidden t))) - -(setq-default cursor-in-non-selected-windows nil) - -(defun hide-clutter () - (interactive) - (hide-mode-line)) - -(defun show-clutter () - (interactive) - (show-mode-line)) - -(when mode-line-default-hidden - (call-interactively #'hide-mode-line)) - -(setq-default indicate-buffer-boundaries nil) -(fringe-mode '(4 . 4)) - -(defun hide-mode-line-if-default-hidden () - (if mode-line-default-hidden - (hide-mode-line) - (show-mode-line))) - -(add-to-list 'default-frame-alist '(border-width . 0)) -(add-to-list 'default-frame-alist '(internal-border-width . 0)) -(when (or (eq window-system 'x) - (eq window-system 'mac)) - (setq window-divider-default-bottom-width 1 - window-divider-default-right-width 1 - window-divider-default-places t) - (window-divider-mode +1)) - -(add-hook 'after-change-major-mode-hook #'hide-mode-line-if-default-hidden) - -(add-hook 'minibuffer-setup-hook #'show-mode-line) -(add-hook 'minibuffer-exit-hook #'hide-mode-line) -#+END_SRC - -*** Highlight Changes - -Highlight what just changed when I undo, yank, and so on. - -#+BEGIN_SRC emacs-lisp -(use-package volatile-highlights - :diminish volatile-highlights-mode - :config (progn - (volatile-highlights-mode t))) -#+END_SRC - -*** Beacon - -I was against the idea of having flashy animations inside Emacs, but -this one is useful. It highlights the cursor when scrolling or -switching windows. - -#+BEGIN_SRC emacs-lisp -(use-package beacon - :diminish beacon-mode - :config (progn - (beacon-mode +1) - (setq beacon-blink-delay 0.25 - beacon-blink-duration 0.25 - beacon-size 20 - beacon-color "#a1b56c"))) -#+END_SRC - -*** Renaming major modes - -Diminishing major modes does not happen in the same manner as minor -modes. - -#+BEGIN_SRC emacs-lisp -(unless (version<= emacs-version "24.4") - (use-package cyphejor - :defer 2 - :config (progn - (setq cyphejor-rules `(("emacs" "ε") - ("diff" "Δ") - ("js2" "js") - ("magit-status" ,(char-to-string (seq-find #'char-displayable-p '(11942 5848 177)))) - ("inferior" "i" :prefix) - ("interaction" "i" :prefix) - ("interactive" "i" :prefix) - ("menu" "▤" :postfix) - ("ledger" "Ledger") - ("mode" "") - ("shell" "sh" :postfix))) - (cyphejor-mode 1)))) -#+END_SRC - - -** Environment Variables - -MacOS doesn’t have a reasonable way to set environment variables and -read them automatically any more. So, let’s use the -[[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] package to set up ~exec-path~ and similar -variables from whatever my shell configuration is. - -On Windows, I like to run Emacs from the system tray menu of VcXsrv. -It starts up without an environment in this case as well. - -#+BEGIN_SRC emacs-lisp -(use-package exec-path-from-shell - :if (or (eq system-type 'darwin) - (eq system-type 'gnu/linux/windows) - (and (eq system-type 'gnu/linux) - (daemonp))) - :config (progn - (setq exec-path-from-shell-arguments '("-l")) - (exec-path-from-shell-initialize))) -#+END_SRC - -*** NixOS sandboxes - -I'm currently exploring using nix to create sandboxes for -development. This package allows using tools from inside sandboxes, -and some convenience commands for building packages and launching shells. - -#+BEGIN_SRC emacs-lisp -(use-package nix-sandbox - :config (progn - (with-eval-after-load 'flycheck - (setq flycheck-command-wrapper-function - (lambda (command) - (if (nix-current-sandbox) - (apply 'nix-shell-command (nix-current-sandbox) command) - command)) - flycheck-executable-find - (lambda (cmd) - (if (nix-current-sandbox) - (nix-executable-find (nix-current-sandbox) cmd) - (executable-find cmd))))))) -#+END_SRC - -** Keybindings - -I think =set-keyboard-coding-system= stops OS X from doing something -annoying to add accents. The modifier setup is to match my -re-arrangement of modifiers on OSX: Cmd on the outside, then -Option/alt, then Control. - -#+BEGIN_SRC emacs-lisp -(when (eq system-type 'darwin) - (set-keyboard-coding-system nil) - (custom-set-variables - '(mac-option-modifier 'meta) - '(mac-right-option-modifier 'none) - '(mac-control-modifier 'control) - '(mac-right-control-modifier 'left) - '(mac-command-modifier 'super) - '(mac-right-command-modifier 'left) - '(mac-function-modifier 'hyper)) - (unbind-key "s-x")) -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(unbind-key "") -(bind-key* "" #'compile) -(bind-key* "" #'kmacro-start-macro-or-insert-counter) -(bind-key* "" #'kmacro-end-or-call-macro) - -(bind-key* "" #'execute-extended-command) - -(unbind-key "C-z") -(bind-key* "C-" #'other-window) - -(bind-key* "C-x C-r" #'revert-buffer) -(bind-key* "C-x C-j" #'delete-indentation) -(unbind-key "C-x C-c") - -(bind-key* "C-c i" #'insert-char) -(bind-key* "M-/" #'hippie-expand) - -(unbind-key "s-h") -(unbind-key "s-n") -(unbind-key "s-p") -(unbind-key "s-w") -(bind-key* "s-k" #'kill-or-delete-this-buffer-dwim) - -(bind-key "C-M-a" #'backward-paragraph text-mode-map) -(bind-key "C-M-e" #'forward-paragraph text-mode-map) - -(bind-key* "s-x" (define-prefix-command 'super-x-map)) -(bind-key* "s-," #'switch-to-dotfiles) -(bind-key* "C-x M-x" #'execute-extended-command) -(set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) -#+END_SRC - -*** Crux - -I can replace most of the simple helper/wrapper functions in my -configuration with crux.el - -#+BEGIN_SRC emacs-lisp -(use-package crux - :bind (("M-o" . crux-smart-open-line-above) - ("C-o" . crux-smart-open-line) - - ("C-x 4 t" . crux-transpose-windows) - ("C-c e" . crux-eval-and-replace) - ("C-c D" . crux-delete-file-and-buffer) - ("C-c R" . crux-rename-file-and-buffer)) - :config (progn - (crux-reopen-as-root-mode +1)) - :init (progn - (defalias 'delete-current-buffer-file #'crux-delete-file-and-buffer) - (defalias 'rename-current-buffer-file #'crux-rename-file-and-buffer))) -#+END_SRC - -** Projects - -#+BEGIN_SRC emacs-lisp -(defun switch-to-dotfiles () - (interactive) - (projectile-switch-project-by-name (car (split-string (shell-command-to-string "ghq list --full-path dotfiles"))))) -#+END_SRC - -*** The Silver Searcher - -#+BEGIN_SRC emacs-lisp -(use-package ag - :defer 30 - :config (setq ag-project-root-function #'projectile-project-root)) - -(use-package wgrep-ag - :after ag) -#+END_SRC - -*** Ripgrep - -Step over Silver Search, here comes a new challenger. - -#+BEGIN_SRC emacs-lisp -(use-package ripgrep - :if (executable-find "rg")) - -(use-package projectile-ripgrep - :after (ripgrep projectile) - :if (executable-find "rg") - :bind (("C-c p s r" . projectile-ripgrep))) -#+END_SRC - -*** Projectile - -Projectile is awesome for working in projects, especially VCS-backed -ones. - -#+BEGIN_SRC emacs-lisp -(use-package projectile - :bind (("s-p" . projectile-switch-project) - ("C-c C-f" . projectile-find-file) - ("s-x s-f" . projectile-find-file) - ("C-x g" . projectile-vc) - ("s-G" . projectile-vc)) - :demand t - :diminish projectile-mode - :config (progn - (projectile-mode +1) - (add-to-list 'projectile-globally-ignored-directories ".stversions") - - (defun yarn-install (&optional arg) - (interactive "P") - (projectile-with-default-dir (projectile-project-root) - (cmd-to-echo "yarn" "install"))) - - (defun yarn-add-dev (package) - (interactive "spackage: ") - (projectile-with-default-dir (projectile-project-root) - (cmd-to-echo "yarn" (concat "add --dev " package)))) - - (defun yarn-add (package) - (interactive "spackage: ") - (projectile-with-default-dir (projectile-project-root) - (cmd-to-echo "yarn" (concat "add " package)))) - - (defun yarn-run (cmd) - (interactive (list - (projectile-completing-read "command: " (alist-get 'scripts (json-read-file (expand-file-name "package.json" (projectile-project-root))))))) - (projectile-with-default-dir (projectile-project-root) - (cmd-to-echo "yarn" (concat "run " cmd)))) - - (defun ap/open-project (&optional arg) - (interactive "P") - (let ((project-dir (projectile-completing-read - "Open project: " - (ghq--find-projects)))) - (projectile-switch-project-by-name - (expand-file-name project-dir (ghq--find-root)) arg))) - - (setq projectile-switch-project-action #'projectile-commander - projectile-completion-system 'ivy - projectile-create-missing-test-files t) - - (defun ap/projectile-test-suffix (project-type) - (cond - ((member project-type '(node-yarn node-npm)) ".test") - (t (projectile-test-suffix project-type)))) - (setq projectile-test-suffix-function #'ap/projectile-test-suffix) - - (projectile-register-project-type 'node-yarn '("yarn.lock") "yarn start" "yarn test") - (projectile-register-project-type 'node '("package.json") "npm start" "npm test"))) - -(use-package counsel-projectile - :after (counsel projectile) - :config (progn - (counsel-projectile-on) - (def-projectile-commander-method ?A - "Find rg on project." - (call-interactively #'counsel-projectile-rg)) - (define-key projectile-mode-map [remap counsel-projectile-ag] #'counsel-projectile-rg))) -#+END_SRC - -*** vc - -This is nice for some things that magit doesn’t do, and for those rare -occasions that I’m working with something other than git. - -#+BEGIN_SRC emacs-lisp -(use-package vc - :defer t - :bind (("C-x v C" . vc-resolve-conflicts)) - :config (progn - (setq vc-follow-symlinks t) - (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" - vc-ignore-dir-regexp - tramp-file-name-regexp)))) -#+END_SRC - -*** git-gutter-fringe - -It’s nice to be able to see at a glance which lines of a file have -changed. This package colours the fringe. I have it set to the right -fringe so it doesn’t interfere with flycheck. - -#+BEGIN_SRC emacs-lisp -(eval-when-compile (require 'fringe-helper)) -(use-package git-gutter-fringe - :defer 2 - :diminish git-gutter-mode - :config (progn - (global-git-gutter-mode 1) - ;; places the git gutter outside the margins. - (setq-default fringes-outside-margins t) - ;; thin fringe bitmaps - (fringe-helper-define 'git-gutter-fr:added '(center repeated) - ".XXX....") - (fringe-helper-define 'git-gutter-fr:modified '(center repeated) - ".XXX....") - (fringe-helper-define 'git-gutter-fr:deleted 'bottom - ".......X" - "......XX" - ".....XXX" - "....XXXX") - (setq git-gutter-fr:side 'right-fringe))) -#+END_SRC - -*** magit - -Magit is my favourite way to use git. I use selective staging all the -time. Make sure to set it up with a nice =completing-read-function= - -#+BEGIN_SRC emacs-lisp -(use-package magit - :defer 5 - :commands (magit-status) - :config (progn (setq magit-completing-read-function #'ivy-completing-read - magit-popup-use-prefix-argument 'default - magit-display-buffer-function #'magit-display-buffer-fullcolumn-most-v1 - global-magit-file-mode nil) - (add-to-list 'magit-no-confirm 'safe-with-wip)) - :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) -#+END_SRC - -*** git-messenger - -Popup the last commit that changed the line at point. - -#+BEGIN_SRC emacs-lisp -(use-package git-messenger - :bind* (("C-x v p" . git-messenger:popup-message)) - :config (progn - (setq git-messenger:use-magit-popup t))) -#+END_SRC - -*** git-timemachine - -This package allow me to go through a file’s history with just a few -keys. It makes it very easy to figure what what exactly was in a file -in the past. I often find it useful when I remember writing something -a particular way, but it changed later. - -#+BEGIN_SRC emacs-lisp -(use-package git-timemachine - :commands git-timemachine) -#+END_SRC - -*** ghq - -[[https://github.com/motemen/ghq][=ghq=]] clones VCS-backed projects to a common directory. It should -seem familiar to anyone who's used =go get= before. [[https://github.com/rcoedo/emacs-ghq][=emacs-ghq=]] is a -simple wrapper for it. - -#+BEGIN_SRC emacs-lisp -(use-package ghq - :if (executable-find "ghq")) -#+END_SRC - -** Files - -*** Auto-saving - -Auto-save everything to a temporary directory, instead of cluttering -the filesystem. I don’t want emacs-specific lockfiles, either. - -#+BEGIN_SRC emacs-lisp -(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) - create-lockfiles nil) -#+END_SRC -*** Backups - -I like to keep my backups out of regular folders. I tell emacs to use -a subfolder of its configuration directory for that. Also, use the -trash for deleting on OS X. -#+BEGIN_SRC emacs-lisp -(let ((backup-dir (expand-file-name "~/.emacs.d/backups/"))) - (unless (file-directory-p backup-dir) - (make-directory backup-dir)) - (setq backup-directory-alist `((".*" . ,backup-dir)) - backup-by-copying-when-linked t - backup-by-copying-when-mismatch t)) -(if (eq system-type 'darwin) - (setq delete-by-moving-to-trash t) - (if (and (executable-find "trash") (not (fboundp #'system-move-file-to-trash))) - (defun system-move-file-to-trash (file) - (call-process (executable-find "trash") - nil 0 nil - file)))) -#+END_SRC - -*** autorevert - -#+BEGIN_SRC emacs-lisp -(use-package autorevert - :diminish auto-revert-mode - :init (progn - (global-auto-revert-mode 1) - (setq auto-revert-verbose nil - auto-revert-use-notify (not (eq system-type 'darwin))))) -#+END_SRC - -*** Encoding - -UTF-8 is usually appropriate. Note that =prefer-coding-system= expects -only a coding system, not a coding system and line ending combination. - -#+BEGIN_SRC emacs-lisp -(prefer-coding-system 'utf-8) -(setq-default buffer-file-coding-system 'utf-8-auto-unix) -#+END_SRC - -*** Buffer-file management - -Ask if I want to create a directory when it doesn’t exist. This is -especially nice when starting new projects. - -#+BEGIN_SRC emacs-lisp -(defun my-create-non-existent-directory () - (let ((parent-directory (file-name-directory buffer-file-name))) - (when (and (not (file-exists-p parent-directory)) - (y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory))) - (make-directory parent-directory t)))) -(add-to-list 'find-file-not-found-functions #'my-create-non-existent-directory) -#+END_SRC - -I often want to rename or delete the file that I’m currently visiting -with a buffer. - -#+BEGIN_SRC emacs-lisp -(defun kill-or-delete-this-buffer-dwim (&optional arg) - "Kills current buffer. With prefix arg, delete it." - (interactive "P") - (if (equal arg '(4)) - (delete-current-buffer-file) - (if server-buffer-clients - (server-edit) - (let ((buf (buffer-name))) - (when (equal buf "*HTTP Response*") - (other-window 1)) - (kill-buffer buf))))) -#+END_SRC - -*** Whitespace - -Show bad whitespace, so that I can fix it. - -#+BEGIN_SRC emacs-lisp -(defun show-trailing-whitespace-on () - (interactive) - (setq-local show-trailing-whitespace t)) -(defun show-trailing-whitespace-off () - (interactive) - (setq-local show-trailing-whitespace nil)) -(add-hook 'prog-mode-hook #'show-trailing-whitespace-on) -(add-hook 'text-mode-hook #'show-trailing-whitespace-on) -#+END_SRC - -*** shrink-whitespace - -DWIM whitespace removal. So I don’t need =M-SPC=, =M-\= and =C-x o= -for similar things any more. - -#+BEGIN_SRC emacs-lisp -(use-package shrink-whitespace - :bind ("M-SPC" . shrink-whitespace)) -#+END_SRC - -*** Tramp - -Tramp is awesome. It makes SSH feel Unix-y. The proxy setup is so -that I can sudo on remote machines - -#+BEGIN_SRC emacs-lisp -(use-package tramp - :defer 7 - :config (progn - (unless (getenv "SSH_AUTH_SOCK") - (setenv "SSH_AUTH_SOCK" (format "/run/user/%s/ssh-agent" (user-uid)))) - (setq tramp-default-method "ssh" - tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root")) - tramp-backup-directory-alist backup-directory-alist - tramp-completion-reread-directory-timeout 60 - tramp-ssh-controlmaster-options nil - backup-enable-predicate (lambda (name) - (and (normal-backup-enable-predicate name) - (not (let ((method (file-remote-p name 'method))) - (when (stringp method) - (member method '("su" "sudo"))))))) - tramp-shell-prompt-pattern "\\(?:^\\| \\)[^]#$%>\n]*#?[]#$%>❯›] *\\(\\[\\??[0-9;]*[a-zA-Z] *\\)*") - (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" (concat "/" tramp-default-method ":%h:"))) - (add-to-list 'tramp-default-proxies-alist `(,(regexp-quote (system-name)) nil nil)) - (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil)))) -#+END_SRC - -*** ediff - -I like a horizonal diff setup, with everything in one frame. - -#+BEGIN_SRC emacs-lisp -(use-package ediff - :defer t - :config (progn - (setq ediff-split-window-function 'split-window-horizontally - ediff-window-setup-function 'ediff-setup-windows-plain))) -#+END_SRC - -** Indentation - -Ah, a complicated topic. One day we’ll all be using elastic -tabstops. I’ve recently switched to using two spaces, since elastic -tabstops is probably never going to happen. - -#+BEGIN_SRC emacs-lisp -(setq-default tab-width 2 - indent-tabs-mode nil) -(electric-indent-mode +1) -#+END_SRC - - -*** smart-tabs-mode - -Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns -with spaces. Perfect! - -#+BEGIN_SRC emacs-lisp -(use-package smart-tabs-mode - :defer 1 - :config (progn - (smart-tabs-insinuate 'c 'cperl 'python) - (define-hook-helper php-mode () - (smart-tabs-mode indent-tabs-mode)))) -#+END_SRC - -*** editorconfig - -#+BEGIN_SRC emacs-lisp -(use-package editorconfig - :diminish "EC" - :config (editorconfig-mode 1)) -#+END_SRC - -*** dtrt-indent-mode - -Sometimes people use different indentation settings. [[https://github.com/jscheid/dtrt-indent][dtrt-indent]] -guesses the correct settings for me. - -#+BEGIN_SRC emacs-lisp -(use-package dtrt-indent - :config (progn - (define-hook-helper after-change-major-mode () - (unless (and (boundp editorconfig-mode) - editorconfig-mode) - (dtrt-indent-adapt))) - (defadvice dtrt-indent-try-set-offset (after toggle-smart-tabs activate) - (smart-tabs-mode (or indent-tabs-mode -1))))) -#+END_SRC - -** Security - -*** password-store - -This is a frontend to the GPG-powered =pass= program. -#+BEGIN_SRC emacs-lisp -(use-package password-store - :defer 15 - :config (progn - (setq password-store-password-length 16))) -#+END_SRC -** Buffers - -*** Ibuffer -Ibuffer is quite nice for listing all buffers. - -#+BEGIN_SRC emacs-lisp -(use-package ibuffer - :bind (("C-x C-b" . ibuffer)) - :config (progn - (setq ibuffer-saved-filter-groups - (quote (("default" - ("org" (mode . org-mode)) - ("emacs" (mode . emacs-lisp-mode)) - ("zsh" (filename . "/zsh")) - ("server" (filename . "/su:root@server")))))) - - ;; Human-readable base-2 size column - (define-ibuffer-column size-h - (:name "Size" :inline t) - (cond - ((> (buffer-size) 1024) - (format "%7.2fK" (/ (buffer-size) 1024.0))) - ((> (buffer-size) 1048576) - (format "%7.2fM" (/ (buffer-size) 1048576.0))) - (t - (format "%8d" (buffer-size))))) - - (setq ibuffer-formats - '((mark modified read-only " " - (name 18 18 :left :elide) - " " - (size-h 9 -1 :right) - " " - (mode 16 16 :left :elide) - " " - filename-and-process))))) -#+END_SRC - -*** Relative Buffer names - -#+BEGIN_SRC emacs-lisp -(use-package relative-buffers - :defer 15 - :config (progn - (global-relative-buffers-mode))) -#+END_SRC -*** Narrowing - -Enable it without prompting - -#+BEGIN_SRC emacs-lisp -(put 'narrow-to-defun 'disabled nil) -(put 'narrow-to-page 'disabled nil) -(put 'narrow-to-region 'disabled nil) -#+END_SRC - -*** ace-window - -I don’t often have many windows open at once, but when I do, -=ace-window= is really nice to jump around them in the same way that -=ace-jump= or =avy= work. -#+BEGIN_SRC emacs-lisp -(use-package ace-window - :bind (("s-s" . ace-window)) - :config (progn - (setq aw-dispatch-always t - aw-dispatch-alist '((?k aw-delete-window " Ace - Delete Window") - (?K aw-delete-window) - (?m aw-swap-window " Ace - Swap Window") - (?f aw-flip-window) - (?v aw-split-window-vert " Ace - Split Vert Window") - (?b aw-split-window-horz " Ace - Split Horz Window") - (?m delete-other-windows " Ace - Maximize Window") - (?l delete-other-windows) - (?, winner-undo) - (?. winner-redo)) - aw-keys '(?a ?r ?s ?t ?n ?e ?i ?o)))) -#+END_SRC - -** Windows - -Scrolling is tricky. I use this setup to help me keep track of the -point whilst I’m moving about. - -#+BEGIN_SRC emacs-lisp -(setq scroll-conservatively 100 - scroll-margin 1 - scroll-preserve-screen-position t - mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control))) - split-height-threshold 80 - split-width-threshold 160 - frame-resize-pixelwise nil) -(if (boundp 'ns-pop-up-frames) - (setq ns-pop-up-frames nil)) -#+END_SRC - -*** eyebrowse - -Workspaces, a bit like dwm. On Windows and Linux (at least the WMs -I'm likely to use), super+{0-9} are taken from the OS, so use meta -instead. On macOS, super makes a lot of sense, as it's used by most -programs to switch between program windows or views. - -#+BEGIN_SRC emacs-lisp -(use-package eyebrowse - :config (progn - (setq eyebrowse-new-workspace t) - (when (eq system-type 'darwin) - (bind-keys - ("s-0" . eyebrowse-switch-to-window-config-0) - ("s-1" . eyebrowse-switch-to-window-config-1) - ("s-2" . eyebrowse-switch-to-window-config-2) - ("s-3" . eyebrowse-switch-to-window-config-3) - ("s-4" . eyebrowse-switch-to-window-config-4) - ("s-5" . eyebrowse-switch-to-window-config-5) - ("s-6" . eyebrowse-switch-to-window-config-6) - ("s-7" . eyebrowse-switch-to-window-config-7) - ("s-8" . eyebrowse-switch-to-window-config-8) - ("s-9" . eyebrowse-switch-to-window-config-9))) - (bind-keys* - ("M-0" . eyebrowse-switch-to-window-config-0) - ("M-1" . eyebrowse-switch-to-window-config-1) - ("M-2" . eyebrowse-switch-to-window-config-2) - ("M-3" . eyebrowse-switch-to-window-config-3) - ("M-4" . eyebrowse-switch-to-window-config-4) - ("M-5" . eyebrowse-switch-to-window-config-5) - ("M-6" . eyebrowse-switch-to-window-config-6) - ("M-7" . eyebrowse-switch-to-window-config-7) - ("M-8" . eyebrowse-switch-to-window-config-8) - ("M-9" . eyebrowse-switch-to-window-config-9)) - (eyebrowse-mode +1))) -#+END_SRC - -** Sessions - -*** Desktop -Save my Emacs session and restore it on startup. - -#+BEGIN_SRC emacs-lisp -(use-package desktop - :ensure nil - :config (progn - (setq desktop-dirname (expand-file-name "desktop/" user-emacs-directory) - desktop-base-file-name "emacs.desktop" - desktop-base-lock-name "lock" - desktop-path (list desktop-dirname) - desktop-save 'if-exists - desktop-files-not-to-save "^$" - desktop-load-locked-desktop nil) - (unless (file-directory-p desktop-dirname) - (make-directory desktop-dirname)) - (desktop-save-mode 1))) -#+END_SRC - -*** winner - -Undo, for window-based commands. - -#+BEGIN_SRC emacs-lisp -(use-package winner - :config (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")) - :init (progn - (winner-mode 1))) -#+END_SRC - -*** windmove - -Directional window movement - -#+BEGIN_SRC emacs-lisp -(use-package windmove - :bind (("S-" . windmove-left) - ("S-" . windmove-right) - ("S-" . windmove-up) - ("S-" . windmove-down))) -#+END_SRC -** Blogging - -I have a [[https://alanpearce.uk][blog]] that I publish with hugo. - -#+BEGIN_SRC emacs-lisp -(use-package easy-hugo - :config (setq easy-hugo-basedir (car (split-string (shell-command-to-string "ghq list --full-path alanpearce.uk"))) - easy-hugo-url "https://alanpearce.uk" - easy-hugo-default-ext ".md")) -#+END_SRC - -** Completion - -Make built-in completion a bit more intelligent, by adding substring -and initial-based completion and ignoring case. - -#+BEGIN_SRC emacs-lisp -(setq completion-styles '(basic initials partial-completion substring) - completion-ignore-case t - tab-always-indent 'complete) -#+END_SRC - -*** Company - -The main choices for automatic completion in Emacs are company and -auto-complete-mode. I’ve not tried auto-complete-mode as company -seems to work perfectly well for me. - -#+BEGIN_SRC emacs-lisp -(use-package company - :commands (company-mode) - :diminish "Cmpl" - :bind (("C-" . company-complete) - ("TAB" . company-indent-or-complete-common)) - :init (progn - (add-hook 'prog-mode-hook #'company-mode-on) - (setq company-backends '(company-bbdb company-web-html company-tern company-nxml company-css company-eclim company-semantic company-elisp - company-clang company-xcode company-cmake company-capf - company-files (company-gtags - company-etags company-keywords) company-oddmuse) - company-frontends '(company-pseudo-tooltip-unless-just-one-frontend - company-preview-frontend - company-echo-metadata-frontend) - company-idle-delay .3 - company-begin-commands '(self-insert-command) - company-auto-complete #'company-explicit-action-p - company-auto-complete-chars '(?\ ?\( ?\) ?.) - company-tooltip-align-annotations t - company-selection-wrap-around t))) -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(use-package company-web - :after company) -#+END_SRC - -;;; * Dates: & Times - -*** Calendar - -Weeks start on Monday for me and I prefer ISO-style dates. -#+BEGIN_SRC emacs-lisp -(use-package calendar - :defer 1 - :config (progn - (setq calendar-week-start-day 1) - (calendar-set-date-style 'iso))) -#+END_SRC - -Sometimes I want to insert a date or time into a buffer. -#+BEGIN_SRC emacs-lisp -(defun insert-date (prefix) - "Insert the current date. With prefix-argument, use British format. With - two prefix arguments, write out the day and month name." - (interactive "P") - (let ((format (cond - ((not prefix) "%Y-%m-%d") - ((equal prefix '(4)) "%d/%m/%Y") - ((equal prefix '(16)) "%A, %d %B %Y")))) - (insert (format-time-string format)))) - -(defun insert-datetime (prefix) - "Insert the current date and time." - (interactive "P") - (let ((format (cond - ((not prefix) "%Y-%m-%d %H:%M:%S") - ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ")))) - (insert (format-time-string format)))) -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(defun yesterday-time () - "Provide the date/time 24 hours before the time now in the format of current-time." - (timer-relative-time (current-time) -86400)) -#+END_SRC - -** Directories - -Dired works quite nicely, but not always in the way I want. I don’t -like having so many prompts for recursive operations. Also, when I -have two dired windows open, assume that I’m going to be -copying/moving files between them. - -#+BEGIN_SRC emacs-lisp -(use-package dired - :defer 3 - :ensure nil - :config (progn - (bind-key "" #'dired-find-file dired-mode-map) - (bind-key "^" (lambda () (interactive) (find-alternate-file "..")) dired-mode-map) - (setq dired-dwim-target t - dired-recursive-copies 'top - dired-recursive-deletes (if delete-by-moving-to-trash - 'always - 'top) - dired-listing-switches "-alh") - (when (and (eq system-type 'darwin) (executable-find "gls")) - (setq insert-directory-program (executable-find "gls"))) - (put 'dired-find-alternate-file 'disabled nil))) -#+END_SRC - -Don’t show uninteresting files in dired listings. - -#+BEGIN_SRC emacs-lisp -(defun turn-on-dired-omit-mode () - (interactive) - (dired-omit-mode 1)) - -(use-package dired-x - :commands (dired-omit-mode - dired-expunge) - :ensure nil - :config (progn - (setq dired-omit-files "#\\|\\.$" - dired-omit-verbose nil - dired-find-subdir t - dired-bind-jump nil)) - :init (progn - (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode))) -#+END_SRC - -Expand subfolders like a tree inside the parent - -#+BEGIN_SRC emacs-lisp -(with-eval-after-load 'dired - (use-package dired-subtree - :functions (dired-subtree--get-ov - dired-subtree-maybe-up) - :init (progn - (setq dired-subtree-use-backgrounds nil) - (defun dired-subtree-maybe-up () - "Jump up one subtree or directory" - (interactive) - (let ((ov (dired-subtree--get-ov))) - (if ov - (progn (goto-char (overlay-start ov)) - (dired-previous-line 1)) - (dired-up-directory)))) - (bind-key "^" #'dired-subtree-maybe-up dired-mode-map) - (bind-key "i" #'dired-subtree-toggle dired-mode-map)))) -#+END_SRC - -*** Disk usage - -Combine dired and du (disk usage). - -#+BEGIN_SRC emacs-lisp -(use-package dired-du - :after dired - :config (progn - (setq dired-du-size-format t))) -#+END_SRC - -*** Dired-narrow -One can already use dired with wildcards to browse a filtered -directory listing, but it opens a new buffer. Dired-narrow is a -slightly nicer interface: with a currently-open dired buffer, use =/= -to start filtering, =RET= to complete the filter and =g= to refresh -the buffer, removing the filter. - -#+BEGIN_SRC emacs-lisp -(with-eval-after-load 'dired - (use-package dired-narrow - :bind (:map dired-mode-map - ("/" . dired-narrow)))) -#+END_SRC - -** Documentation - -*** ehelp - -ehelp is a less well-known package that’s part of Emacs and slightly -improves the normal help commands, mostly by making quitting them easier. - -#+BEGIN_SRC emacs-lisp -(use-package ehelp - :bind-keymap ("C-h" . ehelp-map)) -#+END_SRC - -*** discover-my-major - -A nicer way to browse keybindings for major modes. - -#+BEGIN_SRC emacs-lisp -(use-package discover-my-major - :bind ("" . discover-my-major)) -#+END_SRC - -*** which-key - -Popup keybindings following a prefix automatically. - -#+BEGIN_SRC emacs-lisp -(use-package which-key - :diminish which-key-mode - :config (progn - (which-key-mode 1) - (which-key-setup-side-window-right-bottom))) -#+END_SRC - -*** eldoc - -Documentation in the echo-area (where the minibuffer is displayed) is -rather useful. - -#+BEGIN_SRC emacs-lisp -(use-package eldoc - :commands (eldoc-mode) - :diminish eldoc-mode - :config (progn - (setq eldoc-idle-delay 0.1) - (eldoc-add-command 'paredit-backward-delete 'paredit-close-round))) -#+END_SRC -** Mail - -*** Gnus - -At work, I use gnus for email. Some of the setup is specific to my -workplace, so I keep it in a host-specific, GPG-encrypted file. - -#+BEGIN_SRC emacs-lisp -(use-package gnus - :config (progn - (setq gnus-gcc-mark-as-read t - mml-secure-openpgp-encrypt-to-self t - send-mail-function #'smtpmail-send-it - message-send-mail-function #'smtpmail-send-it))) - -(with-eval-after-load "gnus-mime" - (define-key gnus-mime-button-map " " #'gnus-mime-view-part-externally)) - -(with-eval-after-load "mailcap" - (when (eq system-type 'darwin) - (mailcap-add-mailcap-entry "application" "pdf" '((viewer . "/usr/bin/qlmanage -p %s") (type . "application/pdf"))))) - -(with-eval-after-load "mm-decode" - (add-to-list 'mm-discouraged-alternatives "text/html") - (add-to-list 'mm-discouraged-alternatives "text/richtext")) -#+END_SRC - -*** BBDB - -As I'm using Emacs for email, it makes sense to have contact -information here as well. - -#+BEGIN_SRC emacs-lisp -(use-package bbdb - :config (progn - (bbdb-initialize 'gnus 'message 'pgp) - (bbdb-mua-auto-update-init 'gnus 'message) - (setq bbdb-send-mail-style 'gnus - bbdb-complete-mail-allow-cycling t - bbdb-mua-auto-update t - bbdb-mua-update-interactive-p '(query . create) - bbdb-message-all-addresses t - bbdb-offer-save t - bbdb-offer-to-create 1))) -#+END_SRC - -** Misc - -#+BEGIN_SRC emacs-lisp -(defvar *init-file* - (let ((init-file (or user-init-file - (expand-file-name "init.el" user-emacs-directory)))) - (expand-file-name "init.el" - (file-name-directory (file-truename init-file)))) - "Where the emacs init file really is, passing through symlinks.") -(set-register ?e `(file . ,*init-file*)) - -(defun ap/remove-extra-cr () - "Remove extraneous CR codes from a file" - (interactive) - (save-excursion - (goto-char (point-min)) - (while (search-forward " - " nil t) - (replace-match "")))) - -(use-package rect - :ensure nil - :init (defun copy-rectangle (start end) - "Copy the region-rectangle." - (interactive "r") - (setq killed-rectangle (extract-rectangle start end)))) - -(defun shell-execute (to-current-buffer) - (interactive "P") - (let ((file-buffer (if (buffer-file-name) - (file-name-nondirectory (buffer-file-name)) - "")) - (command (read-shell-command "Shell command: " nil nil nil))) - (shell-command (replace-regexp-in-string "%" file-buffer command) to-current-buffer))) - -(defun process-exit-code (program &rest args) - "Run PROGRAM with ARGS and return the exit code" - (apply 'call-process program nil nil nil args)) - -(defun narrow-to-region-indirect (start end) - "Restrict editing in this buffer to the current region, indirectly." - (interactive "r") - (deactivate-mark) - (let ((buf (clone-indirect-buffer nil nil))) - (with-current-buffer buf - (narrow-to-region start end)) - (switch-to-buffer buf))) - -(bind-key* "M-!" #'shell-execute) -(bind-key* "C-x r M-w" #'copy-rectangle) -#+END_SRC - -*** Auxillary Configuration - -#+BEGIN_SRC emacs-lisp -(require 'pinentry) - -(defvar have-private-key - (file-exists-p (expand-file-name "secring.gpg" "~/.gnupg/"))) - -(defvar gpg-agent-ssh-sock - (or (getenv "GPG_AGENT_INFO") - (concat "/run/user/" (number-to-string (user-uid)) "/gnupg/S.gpg-agent.ssh"))) - -(defun read-gpg-file (file) - (let ((file-to-decrypt (expand-file-name file user-emacs-directory)) - (ctx (epg-make-context epa-protocol))) - (if (file-exists-p file-to-decrypt) - (epg-decrypt-file ctx file-to-decrypt nil) - (message "Decrypting %s...failed" file-to-decrypt) - (error "File %s does not exist" file-to-decrypt)))) - -(defun load-gpg (file) - (if have-private-key - (load file) - (message "WARNING: Couldn't load %s (No gpg key found)" file))) - -; load this in a post-frame hook because gpg-agent asks for a password on first -; startup and caches it. Don't want emacs daemon to hang because of gpg-agent. -(defun load-private-data () - (interactive) - (if (not (file-exists-p (expand-file-name (concat (system-name) ".el.gpg") user-emacs-directory))) - (message "No encrypted configuration matches system name `%s'" (system-name)) - (if (not have-private-key) - (message "ERROR: Private GPG key not found") - (unless (or (getenv "GPG_AGENT_INFO") - (getenv "SSH_AUTH_SOCK")) - (start-process "gpg-agent" nil "gpg-agent" "--daemon") - (setenv "SSH_AUTH_SOCK" gpg-agent-ssh-sock)) - (setq password-cache-expiry nil) - (unless (file-exists-p (concat pinentry--socket-dir "pinentry")) - (pinentry-start) - (add-hook 'kill-emacs-hook 'pinentry-stop)) - (add-to-list 'load-suffixes ".el.gpg") - (load-gpg (expand-file-name (system-name) user-emacs-directory))))) - -(defun first-frame-hook (frame) - (remove-hook 'after-make-frame-functions #'first-frame-hook) - (run-at-time nil nil 'load-private-data)) - -(if (eq 1 (length (frame-list))) - (add-hook 'after-init-hook #'load-private-data) - (add-hook 'after-make-frame-functions #'first-frame-hook)) -#+END_SRC - -** Minibuffer - -Sometimes I want to use the minibuffer, but I’m already inside it. -Fortunately, this is possible. Of course, I need to know how many -minibuffers there are on the stack. - -#+BEGIN_SRC emacs-lisp -(setq enable-recursive-minibuffers t) -(minibuffer-depth-indicate-mode t) -#+END_SRC - -This avoids some issue with the minibuffer and the point being behind -the prompt. I don’t remember what exactly. -#+BEGIN_SRC emacs-lisp -(setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)) -#+END_SRC - -Occasionally, I exit emacs. I should probably reduce the frequency of this. -#+BEGIN_SRC emacs-lisp -(if (daemonp) - (defalias 'exit-emacs #'delete-frame) - (defalias 'exit-emacs #'save-buffers-kill-emacs)) -#+END_SRC - -*** swiper/ivy - -Ivy is the new kid on the completion block. It seems to be a strong -replacement for helm so far. - -#+BEGIN_SRC emacs-lisp -(use-package swiper - :bind (("C-s" . swiper) - ("C-r" . swiper) - ("C-=" . swiper)) - :diminish ivy-mode - :demand t - :config (progn - (ivy-mode 1) - (setq ivy-re-builders-alist '((t . ivy--regex-plus)) - ivy-extra-directories '("./")) - (ivy-set-actions 'ivy-switch-buffer '(("k" (lambda (x) - (kill-buffer x) - (ivy--reset-state ivy-last)) - "kill"))) - (add-to-list 'ivy-initial-inputs-alist '(counsel-M-x . "")))) -#+END_SRC - -*** counsel - -#+BEGIN_SRC emacs-lisp -(use-package counsel - :config (progn - (bind-key "M-x" #'counsel-M-x) - (bind-key "" #'counsel-M-x) - (bind-key "" #'counsel-M-x) - (bind-key "C-c M-x" #'execute-extended-command) - (bind-key "C-x C-f" #'counsel-find-file) - (bind-key "M-y" #'counsel-yank-pop) - (bind-key "C-x i" #'counsel-imenu) - (bind-key "M-y" #'ivy-next-line ivy-minibuffer-map) - (defadvice counsel-find-file (after find-file-sudo activate) - "Find file as root if necessary." - (when (and buffer-file-name - (not (file-writable-p buffer-file-name))) - (message "File not writable %s" buffer-file-name) - (find-alternate-file (concat "/sudo::" buffer-file-name)))) - (setq counsel-rg-base-command "rg -i --no-heading --line-number --hidden %s ."))) -#+END_SRC - - -*** smex - -Smex is my favourite way to use =M-x=. Counsel’s =counsel-M-x= -function uses it internally, so I’m keeping it around, even though I -don’t use it directly. - -#+BEGIN_SRC emacs-lisp -(use-package smex - :commands (smex - smex-update - smex-initialize) - :config (progn - (setq smex-key-advice-ignore-menu-bar t - smex-auto-update nil) - (defun smex-update-after-load (_unused) - (if (boundp 'smex-cache) - (smex-update))) - (add-hook 'after-load-functions 'smex-update-after-load)) - :init (progn - (setq smex-history-length 100 - smex-save-file (concat user-emacs-directory - "smex-items")))) -#+END_SRC - -*** cmd-to-echo - -I’ve been looking for some way to run programming projects (mostly -node.js) inside emacs. =cmd-to-echo= seems great for this, as new -output pops up in the echo area. - -#+BEGIN_SRC emacs-lisp -(use-package cmd-to-echo - :commands (cmd-to-echo) - :config (setq cmd-to-echo-add-output-to-process-buffers t)) -#+END_SRC -** Modes - -Setup some modes for systemd files -#+BEGIN_SRC emacs-lisp -(add-to-list 'auto-mode-alist '("\\.service\\'" . conf-mode)) -(add-to-list 'auto-mode-alist '("\\.target\\'" . conf-mode)) -(add-to-list 'auto-mode-alist '("\\.socket\\'" . conf-mode)) -#+END_SRC - -=direnv=’s files are basically shell scripts, it’s a nice way to -set environment variables for projects. -#+BEGIN_SRC emacs-lisp -(add-to-list 'auto-mode-alist '("\\.envrc\\'" . sh-mode)) -#+END_SRC - -Some modes that I don’t really customise much, mostly for -configuration files. -#+BEGIN_SRC emacs-lisp -(use-package haskell-mode - :mode (("\\.hs\\'" . haskell-mode))) - -(use-package dockerfile-mode - :mode (("Dockerfile\\'" . dockerfile-mode))) - -(use-package nix-mode - :mode (("\\.nix\\'" . nix-mode))) - -(define-derived-mode xmonad-mode haskell-mode "XM") -(add-to-list 'auto-mode-alist '("xmobarrc\\'" . xmonad-mode)) -(add-to-list 'auto-mode-alist '("xmonad.hs\\'" . xmonad-mode)) - -(use-package nginx-mode - :defer t - :mode (("/nginx/servers/" . nginx-mode) - ("/nginx/.*\\.d/" . nginx-mode))) - -(use-package lua-mode - :defer t) - -(use-package ruby-mode - :mode (("\\.rb\\'" . ruby-mode) - ("\\.cap\\'" . ruby-mode))) - -(use-package go-mode - :mode (("\\.go\\'" . go-mode))) - -(use-package jinja2-mode - :mode (("\\.j2\\'" . jinja2-mode) - ("\\.jinja\\'" . jinja2-mode))) - -(use-package scss-mode - :defer t - :config (progn - (setq scss-compile-at-save nil))) - -(use-package toml-mode - :mode ("\\.toml\\'" . toml-mode)) - -(use-package yaml-mode - :mode (("/group_vars/.*" . yaml-mode) - ("/host_vars/.*" . yaml-mode))) - -(define-derived-mode ansible-mode yaml-mode "Ansible") -(add-to-list 'auto-mode-alist '("\\(?:ansible.+\\|roles/.+/\\(?:tasks\\|handlers\\)\\)/.+\\.yml\\'" . ansible-mode)) - -(define-derived-mode saltstack-mode yaml-mode "Salt") -(add-to-list 'auto-mode-alist '("\\.sls\\'" . saltstack-mode)) -#+END_SRC - -*** ledger - -I use [[http://ledger-cli.org/][=ledger=]] to manage my finances. It has an Emacs mode, which -works really nicely. - -#+BEGIN_SRC emacs-lisp -(use-package ledger-mode - :mode ("\\.ledger\\'" . ledger-mode) - :functions ledger-report - :init (progn - (defun open-budget () - (interactive) - (projectile-switch-project-by-name "~/Sync/Default") - (find-file (expand-file-name "ledger/my.ledger" (projectile-project-root))) - (ledger-report "Budget (Cumulative)" nil))) - :config (progn - (setq ledger-use-iso-dates t - ledger-post-use-completion-engine :ido - ledger-reconcile-default-commodity "€" - ledger-clear-whole-transactions t - ledger-narrow-on-reconcile t - ledger-reports `(("Monthly Expenses" "ledger -f %(ledger-file) reg -M \\^Flex --real -X EUR -l \"payee != 'Opening Balances'\"") - ("Average Monthly Expenses (Past 12 Months)" ,(concat "ledger -f %(ledger-file) -b " - (format-time-string "%Y-%m" (time-add (current-time) (days-to-time -365))) - " --monthly --average balance ^Flex")) - ("Expenses:This Month" "ledger -f %(ledger-file) bal \\^Flex -p \"this month\"") - ("On-budget Balances" "ledger -f %(ledger-file) bal --current -R :Budget: Assets:Receivable Liabilities:Personal") - ("All Account Balances" "ledger -f %(ledger-file) bal --current -R \\^Assets \\^Liabilities") - ("Budget Values (Current Month)" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds") - ("Budget (Cumulative)" "ledger -f %(ledger-file) bal -E \\^Funds \\^Assets:Budget$") - ("Budget Allocation" "ledger -f %(ledger-file) bal -p \"this month\" --limit \"payee=~/budget/\" \\^Funds --format \"\\ - %-17((depth_spacer)+(partial_account))\\ - %10(percent(market(display_total), market(parent.total)))\\ - %16(market(display_total))\n%/\"") - ("bal" "ledger -f %(ledger-file) bal") - ("reg" "ledger -f %(ledger-file) reg") - ("equity" "ledger -f %(ledger-file) equity") - ("payee" "ledger -f %(ledger-file) reg @%(payee)") - ("account" "ledger -f %(ledger-file) reg %(account)"))))) -#+END_SRC - -*** Markdown - -#+BEGIN_SRC emacs-lisp -(use-package markdown-mode - :defer t - :config (progn - (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) -#+END_SRC - -*** Lentic - -Multiple different views of the same file. Can be used for a kind of -inverse literate programming. - -#+BEGIN_SRC emacs-lisp -(use-package lentic - :config (global-lentic-mode)) -#+END_SRC - -*** Org - -Org is wünderbar. - -#+BEGIN_SRC emacs-lisp -(use-package org - :bind (("C-c C-a" . org-agenda-list) - ("C-c a" . org-agenda) - ("C-c l" . org-store-link)) - :defer 8 - :init (setq org-replace-disputed-keys t - org-ellipsis "…") - :config (progn - (setq org-directory "~/Sync/org" - org-agenda-files `(,(concat org-directory "/agenda")) - - org-default-notes-file (concat org-directory "/notes") - - ;; ‘Remember’: new items at top - org-reverse-note-order t - - org-modules '(org-protocol) - - ;; Add time done to ‘done’ tasks - org-log-done 'time - - org-list-allow-alphabetical t - - org-adapt-indentation nil - - org-pretty-entities t - - org-table-duration-custom-format 'seconds - - org-src-fontify-natively nil - - org-export-have-math t - - org-blank-before-new-entry '((heading . t) - (plain-list-item . auto)) - org-fontify-done-headline t - - org-goto-interface 'outline-path-completion - - org-outline-path-complete-in-steps nil - - org-todo-keywords '((sequence "BACKLOG(b)" "TODO(t)" "WAIT(w@/!)" "STARTED(s!)" "|" "DONE(d!)") - (sequence "|" "CANCELLED(c@)")) - org-log-into-drawer "LOGBOOK") - (set-register ?o `(file . ,(expand-file-name "organiser.org" org-directory))) - (add-hook 'org-mode-hook #'turn-on-auto-fill) - (org-load-modules-maybe t))) - -(use-package org-src - :ensure nil - :after org - :config (progn - (bind-key "C-x C-s" #'org-edit-src-exit org-src-mode-map))) -#+END_SRC - -***** org-babel - -Org’s babel feature is really nice. I use it for this file, and I can -use it to communicate between programming languages. Sometime I hope -to have my =ledger= setup in an org file with some graph processing -with R or something. - -#+BEGIN_SRC emacs-lisp -(use-package ob-core - :defer t - :ensure nil - :config (progn - (org-babel-do-load-languages 'org-babel-load-languages - '((ledger . t) - (sh . t))) - (setq org-src-tab-acts-natively t - org-edit-src-content-indentation 0 - org-src-preserve-indentation t))) -#+END_SRC - -***** org-journal - -I can use this to keep a journal. I should use it. - -#+BEGIN_SRC emacs-lisp -(use-package org-journal - :bind ("s-j" . org-journal-new-entry) - :defer 20 - :config (progn - (setq org-journal-date-format "%A, %d %B %Y" - org-journal-dir "~/Sync/Default/Documents/journal") - - (define-hook-helper org-journal-mode () - (use-variable-fonts) - (text-scale-adjust 4) - (if smartparens-strict-mode - (smartparens-strict-mode -1)) - (if show-smartparens-mode - (show-smartparens-mode -1))) - (defun org-journal-display-entry-yesterday () - "Show org-journal entry for yesterday" - (interactive) - (org-journal-read-or-display-entry (yesterday-time))))) -#+END_SRC - - -** Programming -*** flycheck - -On-the-fly error checking in programming modes? Yes please. - -#+BEGIN_SRC emacs-lisp -(use-package flycheck - :diminish " ✓" - :defer 5 - :config (progn - (global-flycheck-mode) - (setq flycheck-check-syntax-automatically '(save mode-enabled)) - (setq flycheck-indication-mode 'left-fringe) - (with-eval-after-load 'git-gutter-fringe - (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated) - ".XXX....")) - (if (executable-find "eslint_d") - (setq flycheck-javascript-eslint-executable "eslint_d")))) -#+END_SRC - -**** flycheck-pos-tip - -Show flycheck errors in a little popup, so I don't lose my place - -#+BEGIN_SRC emacs-lisp -(use-package flycheck-pos-tip - :after flycheck - :config (progn - (setq flycheck-display-errors-delay 0.5) - (flycheck-pos-tip-mode 1))) -#+END_SRC - -**** flycheck-flow - -#+BEGIN_SRC emacs-lisp -(use-package flycheck-flow - :after js2-mode - :if (executable-find "flow") - :config (progn - (flycheck-add-next-checker 'javascript-eslint 'javascript-flow))) -#+END_SRC - -*** golang - -Go has a few packages to inter-operate with other emacs packages. - -#+BEGIN_SRC emacs-lisp -(use-package company-go - :commands company-go - :config (progn - (setq company-go-show-annotation t)) - :init (progn - (define-hook-helper go-mode () - (set (make-local-variable 'company-backends) - '(company-go))))) - -(use-package go-eldoc - :commands go-eldoc-setup - :init (progn - (add-hook 'go-mode-hook #'go-eldoc-setup))) - -(use-package go-projectile - :defer t - :config (progn - (setq go-projectile-switch-gopath 'maybe))) - - -#+END_SRC - -*** ggtags - -A nice completion backend for programming modes. - -#+BEGIN_SRC emacs-lisp -(use-package ggtags - :if (executable-find "gtags") - :commands turn-on-ggtags-mode - :functions (ggtags-navigation-mode-abort) - :config (progn - (bind-key "q" #'ggtags-navigation-mode-abort ggtags-navigation-mode-map)) - :init (progn - (defun turn-on-ggtags-mode () - (interactive) - (ggtags-mode 1)) - (add-hook 'c-mode-common-hook #'turn-on-ggtags-mode))) -#+END_SRC - -*** dumb-jump - -A "clever" way of implementing go-to-definition across languages: use -a project-wide text search and apply heuristics to the results to -guess a definition. - -#+BEGIN_SRC emacs-lisp -(use-package dumb-jump - :bind (("M-g o" . dumb-jump-go-other-window) - ("M-g j" . dumb-jump-go) - ("M-g x" . dumb-jump-go-prefer-external) - ("M-g z" . dumb-jump-go-prefer-external-other-window)) - :config (setq dumb-jump-selector 'ivy)) -#+END_SRC - -*** imenu-anywhere - -This is like imenu, but shows functions (or similar top-level -entities) across buffers in the same project. Neat! - -#+BEGIN_SRC emacs-lisp -(use-package imenu-anywhere - :bind ("C-x C-." . ivy-imenu-anywhere)) -#+END_SRC -*** Lisps - -**** All - -Lisp modes don’t seem to have a common ancestor. So I made a custom -hook which I trigger in every lispy-mode. - -#+BEGIN_SRC emacs-lisp -(defcustom lisp-mode-common-hook nil - "Hook run when entering any Lisp mode." - :type 'hook - :group 'lisp) - -(create-hook-helper lisp-mode-setup () - :hooks (emacs-lisp-mode-hook - scheme-mode-hook - lisp-mode-hook - clojure-mode-hook) - (run-hooks 'lisp-mode-common-hook)) -#+END_SRC - -***** Redshank - -Lisp syntax allows for really easy refactoring. Redshank gives some -operations that aren’t part of paredit, like extracting variables into -let bindings. -#+BEGIN_SRC emacs-lisp -(use-package redshank - :diminish " Λ" - :after (paredit) - :config (progn - (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode))) -#+END_SRC - -**** Emacs Lisp - -Customise the modeline-display of =emacs-lisp-mode=. Then make sure -it runs the common lisp hooks. - -#+BEGIN_SRC emacs-lisp -(add-hook 'emacs-lisp-mode-hook #'eldoc-mode) -#+END_SRC - -Go-to function for elisp. Except it works through the entire Emacs ecosystem. - -#+BEGIN_SRC emacs-lisp -(use-package elisp-slime-nav - :commands elisp-slime-nav-mode - :diminish elisp-slime-nav-mode - :init (progn - (add-hook 'emacs-lisp-mode-hook #'elisp-slime-nav-mode))) -#+END_SRC - -Interactive elisp - -#+BEGIN_SRC emacs-lisp -(use-package ielm - :defer t - :ensure nil - :config (progn - (define-hook-helper ielm-mode () - (run-hooks 'lisp-mode-common-hook)))) -#+END_SRC - -**** Scheme & Lisp - -I don’t work with these as often as I would like - -#+BEGIN_SRC emacs-lisp -(define-hook-helper lisp-mode () - (set (make-local-variable 'lisp-indent-function) - #'common-lisp-indent-function)) -#+END_SRC - -***** geiser - -A REPL thing for Scheme. Hopefully I’ll get to use it more in the -future. - -#+BEGIN_SRC emacs-lisp -(use-package geiser - :commands (geiser-mode - geiser - run-geiser - run-racket)) -#+END_SRC - -***** slime - -A REPL thing (and more) for Lisp. - -#+BEGIN_SRC emacs-lisp -(use-package slime - :commands (slime) - :config (progn - (let ((ql-slime-helper (expand-file-name "~/quicklisp/slime-helper.el"))) - (if (file-exists-p ql-slime-helper) - (load ql-slime-helper)) - (slime-setup '(slime-fancy slime-asdf))) - (setq common-lisp-hyperspec-root "file://opt/local/share/doc/lisp/HyperSpec-7-0/" - inferior-lisp-program (or (executable-find "sbcl") - (executable-find "ccl64"))))) -#+END_SRC - -**** Clojure - -#+BEGIN_SRC emacs-lisp -(use-package clojure-mode - :defer t - :init (progn - (define-hook-helper cider-repl-mode () - (highlight-changes-mode -1)))) - -(use-package clj-refactor - :defer t - :functions (clj-refactor-mode cljr-add-keybindings-with-prefix) - :config (progn - (cljr-add-keybindings-with-prefix "C-c C-m")) - :init (progn - (define-hook-helper clojure-mode () - (clj-refactor-mode 1)))) -#+END_SRC - -***** cider - -A REPL thing for Clojure - -#+BEGIN_SRC emacs-lisp -(use-package cider - :defer t - :config (progn - (setq nrepl-hide-special-buffers t) - (unbind-key "C-c C-f" cider-mode-map) - (add-hook 'cider-mode-hook #'eldoc-mode))) -#+END_SRC - -*** Auto-compile - -Auto-compile emacs lisp when saving. -#+BEGIN_SRC emacs-lisp -(use-package auto-compile - :defer t - :init (add-hook 'emacs-lisp-mode-hook #'auto-compile-on-save-mode)) -#+END_SRC - -*** cc-mode - -Although I don’t use C or C++, setting up the mode is helpful because -quite a few other modes are derived from it. - -#+BEGIN_SRC emacs-lisp -(use-package cc-mode - :defer 5 - :config (progn - (setq c-default-style '((java-mode . "java") - (awk-mode . "awk") - (other . "k&r")) - c-basic-offset 4) - (c-set-offset 'case-label '+))) -#+END_SRC - -*** quickrun - -It’s nice to be able to quickly evaluate some code. Although I don’t -really seem to use it. -#+BEGIN_SRC emacs-lisp -(use-package quickrun - :bind (("C-c C-e" . quickrun))) -#+END_SRC - -*** Scala - -Let’s try using Scala. - -#+BEGIN_SRC emacs-lisp -(use-package scala-mode) -#+END_SRC - -And add ensime, an IDE-style environment. - -#+BEGIN_SRC emacs-lisp -(use-package ensime) -#+END_SRC - -*** Web development - -**** js2-mode - -This mode is really great for editing Javascript. It turns code into -an AST internally, so it can work with it almost like a lisp. - -#+BEGIN_SRC emacs-lisp -(use-package js2-mode - :mode (("\\.js\\'" . js2-mode)) - :interpreter ("node" . js2-mode) - :functions (js2-next-error - js2--struct-put) - :config (progn - (define-key js2-mode-map [menu-bar Javascript] nil) - (add-hook 'js2-mode-hook #'js2-imenu-extras-mode) - (defun ap/js2-prev-error () - (interactive) - (js2-next-error -1)) - (bind-key "M-g M-n" #'js2-next-error js2-mode-map) - (bind-key "M-g M-p" #'ap/js2-prev-error js2-mode-map) - (setq js2-basic-offset 2 - js-switch-indent-offset 2 - js2-include-node-externs t - js2-highlight-level 1 - js2-strict-missing-semi-warning nil))) -#+END_SRC - -***** rjsx-mode - -A set of advice for js2-jsx-mode to work better with React. - -#+BEGIN_SRC emacs-lisp -(use-package rjsx-mode - :after js2-mode - :if (fboundp #'js2--struct-put) - :mode (("\\.jsx\\'" . rjsx-mode))) -#+END_SRC - -***** js2-refactor - -Thanks to the AST provided by js2-mode, refactoring is possible. This -library implements some refactorings. - -#+BEGIN_SRC emacs-lisp -(use-package js2-refactor - :after js2-mode - :config (progn - (bind-key "C-k" #'js2r-kill js2-mode-map) - (add-hook 'js2-mode-hook #'js2-refactor-mode) - (js2r-add-keybindings-with-prefix "C-c C-m"))) -#+END_SRC - -***** add-node-modules-path - -Inside a javascript project, it's common to install tools locally to -the project. This will allows emacs to find their executables. - -#+BEGIN_SRC emacs-lisp -(use-package add-node-modules-path - :config (progn - (add-hook 'js2-mode-hook #'add-node-modules-path))) -#+END_SRC - -***** Flow - -#+BEGIN_SRC emacs-lisp -(use-package flow-minor-mode - :after js2-mode - :config (progn - (add-hook 'js2-mode-hook #'flow-minor-enable-automatically))) -#+END_SRC - -***** Indium - -Javascript with an inferior node.js process and a debugger? Awesome. - -To debug with node, use version 6.9.1 or later of node and run it with -~--inspect~ and, to break on the first line, ~--debug-brk~. - -For Chrom*, it needs to be launched with -~--remote-debugging-port=9222~ - -Node will tell you to open an URL in Chrome: - -~chrome-devtools://inspector.html?...&ws=127.0.0.1:PORT/PATH~ - -Instead, do this: - -~M-x indium-connect-to-nodejs RET 127.0.0.1 RET PORT RET~ - -#+BEGIN_SRC emacs-lisp -(use-package indium - :diminish (indium-interaction-mode . "In") - :config (progn - (add-hook 'js2-mode-hook #'indium-interaction-mode))) -#+END_SRC - -**** coffee-mode - -#+BEGIN_SRC emacs-lisp -(use-package coffee-mode - :mode ("\\.coffee\\'" . coffee-mode) - :config (progn - (setq coffee-indent-like-python-mode t))) -#+END_SRC - -**** tern - -Tern understands javascript. It adds really clever documented -completions, besides other IDE-like things. - -#+BEGIN_SRC emacs-lisp -(use-package tern - :diminish tern-mode - :if (executable-find "tern") - :defer 5 - :config (progn - (setq tern-command (list (executable-find "tern"))) - (create-hook-helper tern-mode-on () - :hooks (web-mode-hook - js2-mode-hook) - (tern-mode +1)))) - -(with-eval-after-load 'tern - (use-package company-tern)) -#+END_SRC - -**** json-mode - -#+BEGIN_SRC emacs-lisp -(use-package json-mode - :mode (("\\.json\\'" . json-mode) - ("\\.sailsrc\\'" . json-mode) - ("composer\\.lock\\'" . json-mode) - ("\\.tern-project\\'" . json-mode))) -#+END_SRC - -**** restclient - -Restclient is really nice. It’s like a scratchpad for HTTP api -calls. Feels a bit like using =org-babel=. I wonder if there’s an -integration between the two yet. - -#+BEGIN_SRC emacs-lisp -(use-package restclient - :mode ("\\.api\\'" . restclient-mode) - :config (progn - (defun imenu-restclient-sections () - (setq imenu-prev-index-position-function nil) - (add-to-list 'imenu-generic-expression '("Services" "^## ?\\(.+\\)$" 1) t) - (add-to-list 'imenu-generic-expression '("Calls" "^# ?\\(.+\\)$" 1) t)) - (add-hook 'restclient-mode-hook #'imenu-restclient-sections))) - -(use-package company-restclient - :after (company restclient) - :init (add-to-list 'company-backends #'company-restclient t)) -#+END_SRC - -**** sgml-mode - -This is for HTML, since old versions of HTML were derived from SGML. -#+BEGIN_SRC emacs-lisp -(use-package sgml-mode - :defer t - :config (setq sgml-basic-offset 2)) -#+END_SRC - -**** emmet-mode - -Emmet is really nice to write HTML quickly. Especially with -frameworks that require multiple nested elements to do anything useful. -#+BEGIN_SRC emacs-lisp -(use-package emmet-mode - :commands (emmet-mode) - :diminish (emmet-mode . " >") - :init (progn - (setq emmet-indentation 2 - emmet-self-closing-tag-style " /") - (add-hook 'sgml-mode-hook #'emmet-mode) - (add-hook 'web-mode-hook #'emmet-mode) - (add-hook 'css-mode-hook #'emmet-mode))) -#+END_SRC - -**** web-mode - -This mode handles just about every templating language out ther, which -is really nice, because it handles the HTML part the same way in all -of them as well. - -#+BEGIN_SRC emacs-lisp -(use-package web-mode - :mode (("/views/.*\\.php\\'" . web-mode) - ("\\.html\\'" . web-mode) - ("/templates/.*\\.php\\'" . web-mode) - ("\\.ejs\\'" . web-mode) - ("\\.njk\\'" . web-mode)) - :config (progn - (setq web-mode-code-indent-offset 2 - web-mode-css-indent-offset 2 - web-mode-markup-indent-offset 2 - web-mode-style-padding 0 - web-mode-script-padding 0 - web-mode-comment-style 2 - web-mode-enable-auto-pairing nil - web-mode-enable-auto-quoting nil) - (sp-local-pair '(web-mode) "<%" "%>"))) -#+END_SRC - -I derived a mode for twig, in order to use its =mode-hook=. - -#+BEGIN_SRC emacs-lisp -(define-derived-mode twig-mode web-mode "Twig") -(add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) -#+END_SRC - -*** Live coding - -Sometimes I might want to show off my emacs usage. - -#+BEGIN_SRC emacs-lisp -(defun live-coding () - (interactive) - (ap/set-fonts "SF Mono" 18 nil nil t 0.1) - (global-command-log-mode 1)) - -(defun live-coding-stop () - (interactive) - (ap/set-fonts-according-to-system) - (global-command-log-mode -1)) -#+END_SRC - -**** command-log-mode - -#+BEGIN_SRC emacs-lisp -(use-package command-log-mode - :defines command-log-mode-key-binding-open-log - :init (progn - (setq command-log-mode-key-binding-open-log nil - command-log-mode-auto-show t - command-log-mode-is-global t))) -#+END_SRC - -** Spelling - -#+BEGIN_SRC emacs-lisp -(use-package ispell - :bind (("" . ispell-word)) - :config (progn - (cond - ((executable-find "aspell") (setq ispell-program-name "aspell" - ispell-dictionary "british" - ispell-really-aspell t - ispell-really-hunspell nil)) - ((executable-find "hunspell") (setq ispell-program-name "hunspell" - ispell-really-aspell nil - ispell-really-hunspell t))))) -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(use-package flyspell - :diminish "﹏" - :config (progn - (defun flyspell-detect-ispell-args (&optional run-together) - "If RUN-TOGETHER is true, spell check the CamelCase words. - Please note RUN-TOGETHER will make aspell less capable. So it should only be used in prog-mode-hook." - (let (args) - (when ispell-program-name - (cond - ((string-match "aspell$" ispell-program-name) - (setq args (list "--sug-mode=ultra")) - (if run-together - (setq args (append args '("--run-together" "--run-together-limit=16" "--run-together-min=2"))))) - ((string-match "hunspell$" ispell-program-name) - (setq args nil)))) - args)) - ;; `ispell-extra-args' is *always* used when start CLI aspell process - (setq-default ispell-extra-args (flyspell-detect-ispell-args t)) - ;; (setq ispell-cmd-args (flyspell-detect-ispell-args)) - (defadvice ispell-word (around my-ispell-word activate) - (let ((old-ispell-extra-args ispell-extra-args)) - (ispell-kill-ispell t) - ;; use emacs original arguments - (setq ispell-extra-args (flyspell-detect-ispell-args)) - ad-do-it - ;; restore our own ispell arguments - (setq ispell-extra-args old-ispell-extra-args) - (ispell-kill-ispell t))) - - (defadvice flyspell-auto-correct-word (around my-flyspell-auto-correct-word activate) - (let* ((old-ispell-extra-args ispell-extra-args)) - (ispell-kill-ispell t) - ;; use emacs original arguments - (setq ispell-extra-args (flyspell-detect-ispell-args)) - ad-do-it - ;; restore our own ispell arguments - (setq ispell-extra-args old-ispell-extra-args) - (ispell-kill-ispell t))) - (setq flyspell-issue-message-flag nil) - - (defun fly-text-mode-hook-setup () - ;; Turn off RUN-TOGETHER option when spell check text-mode - (setq-local ispell-extra-args (flyspell-detect-ispell-args))) - (add-hook 'text-mode-hook 'fly-text-mode-hook-setup) - (add-hook 'prog-mode-hook #'flyspell-prog-mode))) -#+END_SRC - -*** Style checking - -[[https://github.com/ValeLint/vale][Vale]] is a linter, but for prose. Neat idea! Salesman is a bad term. - -#+BEGIN_SRC emacs-lisp -(use-package flycheck-vale - :if (executable-find "vale") - :config (progn - (add-to-list 'flycheck-vale-modes 'org-mode) - (add-to-list 'flycheck-vale-modes 'org-journal-mode) - (flycheck-vale-setup))) -#+END_SRC - -** Scripting - -Make a shell-script buffer executable after saving it, if it has a shebang. - -#+BEGIN_SRC emacs-lisp -(add-hook 'after-save-hook - #'executable-make-buffer-file-executable-if-script-p) - -(use-package sh-script - :mode (("\\.zsh\\'" . shell-script-mode) - ("zshenv\\'" . shell-script-mode) - ("zshrc\\'" . shell-script-mode)) - :config (setq sh-shell-file "/usr/bin/env zsh" - sh-indentation 2 - sh-basic-offset 2)) -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) -#+END_SRC - -*** eshell - -I should try to get into the habit of using this more. It’s really -nice, when I remember to use it. - -#+BEGIN_SRC emacs-lisp -(use-package eshell - :bind ("C-c s" . eshell) - :defer 10 - :functions (eshell/pwd) - :config (progn - (setq eshell-directory-name "~/.emacs.d/eshell" - eshell-prompt-function (lambda () - (concat - (eshell/pwd) - "\n$ "))) - (define-hook-helper eshell-load () - (bind-key "C-c C-l" #'counsel-esh-history eshell-mode-map)))) - -(use-package em-smart - :ensure nil - :commands eshell-smart-initialize - :init (progn - (add-hook 'eshell-load-hook #'eshell-smart-initialize)) - :config (progn - (setq eshell-where-to-jump 'begin - eshell-review-quick-commands nil - eshell-smart-space-goes-to-end t))) - -(autoload #'eshell/cd "em-dirs") -(defun eshell-goto-current-dir (&optional arg) - (interactive "P") - (let ((dir default-directory)) - (eshell arg) - (eshell/cd dir))) -(bind-key "C-c S" #'eshell-goto-current-dir) - - -#+END_SRC - -**** Shells - -#+BEGIN_SRC emacs-lisp -(use-package shell - :defer t - :ensure nil - :config (define-key shell-mode-map - (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer)) - -(use-package comint - :defer t - :ensure nil - :config (bind-key "C-c C-l" #'counsel-shell-history comint-mode-map)) - -(defun comint-delchar-or-eof-or-kill-buffer (arg) - (interactive "p") - (if (null (get-buffer-process (current-buffer))) - (kill-buffer) - (comint-delchar-or-maybe-eof arg))) -#+END_SRC - -** Text editing - -Emacs has an editor within. - -#+BEGIN_SRC emacs-lisp -(put 'upcase-region 'disabled nil) -(put 'downcase-region 'disabled nil) -(setq sentence-end-double-space t - line-move-visual nil) -(setq-default truncate-lines t) -#+END_SRC - -*** align - -=Align= is a useful command to line things up, once given some rules. -The most important one for me is JSON property alignment. - -#+BEGIN_SRC emacs-lisp -(use-package align - :defer 10 - :ensure nil - :config (progn - (add-to-list 'align-rules-list - '(colon-key-value - (regexp . ":\\(\\s-*\\)") - (modes . '(js2-mode)))))) -#+END_SRC - -*** Clipboard - -I like to use the clipboard more than the primary selection in X11. - -#+BEGIN_SRC emacs-lisp -(setq select-enable-clipboard t - save-interprogram-paste-before-kill t) -(if (functionp 'x-cut-buffer-or-selection-value) - (setq interprogram-paste-function 'x-cut-buffer-or-selection-value)) -(when (boundp 'x-select-request-type) - (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) -#+END_SRC - -*** Selection - -I’m quite used to deleting text by selecting it and typing. Emacs has -a mode for that. - -#+BEGIN_SRC emacs-lisp -(use-package delsel - :config (delete-selection-mode t)) -#+END_SRC - -Sub-word movement is really nice for camel- and Pascal-case - -#+BEGIN_SRC emacs-lisp -(use-package subword - :diminish subword-mode - :init (global-subword-mode t)) -#+END_SRC - -I find that =zap-up-to-char= normally makes more sense to me than -=zap-to-char=. - -#+BEGIN_SRC emacs-lisp -(use-package misc - :ensure nil - :bind (("M-z" . zap-up-to-char) - ("M-Z" . zap-to-char))) -#+END_SRC - -Expanding the region by semantic units was something I quite liked -from Sublime Text. As always, there’s a mode for that. - -#+BEGIN_SRC emacs-lisp -(use-package expand-region - :bind ("C-M-SPC" . er/expand-region) - :config (setq expand-region-fast-keys-enabled nil)) -#+END_SRC - -*** avy - -Avy is a really nice way to move around files, like ace-jump-mode, but -somehow I prefer it. - -#+BEGIN_SRC emacs-lisp -(use-package avy - :defer 5 - :bind (("M-g g" . avy-goto-line) - ("M-g M-g" . avy-goto-line) - ("C-|" . avy-goto-line) - ("M-r" . avy-goto-word-1) - ("C-c SPC" . avy-goto-char-timer)) - :config (progn - (avy-setup-default) - (setq avy-all-windows nil - avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?\;)))) -#+END_SRC - -**** ace-link - -Visit any link. Despite the name, this works with avy. - -#+BEGIN_SRC emacs-lisp -(use-package ace-link - :after avy - :config (progn - (ace-link-setup-default) - (with-eval-after-load "gnus" - (bind-key "M-o" #'ace-link-gnus gnus-summary-mode-map) - (bind-key "M-o" #'ace-link-gnus gnus-article-mode-map)))) -#+END_SRC - -*** goto-chg - -This is like popping the mark, only it filters to only change areas -and doesn’t go back to the same place more than once. - -#+BEGIN_SRC emacs-lisp -(use-package goto-chg - :bind ("C-c C-SPC" . goto-last-change)) -#+END_SRC - -*** beginend - -In special buffers, I would rather have =M->= and =M-<= goto the -logical beginning/end rather than the physical ones. - -#+BEGIN_SRC emacs-lisp -(use-package beginend - :config (progn - (beginend-setup-all))) -#+END_SRC - -*** multiple-cursors - -I mentioned before that I’d used Sublime Text before. Multiple -cursors was one of my favourite features, so I was really happy when I -saw that multiple-cursors was released for Emacs. - -#+BEGIN_SRC emacs-lisp -(use-package multiple-cursors - :defer 1 - :bind* (("C-." . mc/mark-next-like-this) - ("C-," . mc/mark-previous-like-this) - ("M-" . mc/mark-all-like-this-dwim) - ("C-" . mc/mark-more-like-this-extended) - ("C-S-L" . mc/edit-lines))) -#+END_SRC - -*** paredit - -Balanced parentheses in lisps are nice, but all the refactoring and -movement commands are much more interesting. - -#+BEGIN_SRC emacs-lisp -(use-package paredit - :diminish "()" - :config (progn - (add-hook 'lisp-mode-common-hook #'enable-paredit-mode) - (put #'paredit-forward-delete 'delete-selection 'supersede) - (put #'paredit-backward-delete 'delete-selection 'supersede) - (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode))) -#+END_SRC - -*** smartparens - -I like to use smartparens where paredit isn’t already useful. Somehow -I didn’t find smartparens’ implementation of paredit style to be as -nice as the real version - -#+BEGIN_SRC emacs-lisp -(eval-when-compile (require 'smartparens nil :noerror)) -(use-package smartparens-config - :ensure smartparens - :config (progn - (sp-use-smartparens-bindings) - (setq sp-highlight-pair-overlay nil) - (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' - (bind-key "C-(" #'wrap-with-paren smartparens-mode-map) - (bind-key "C-)" #'sp-forward-slurp-sexp smartparens-mode-map) - (bind-key "M-" #'backward-kill-word smartparens-mode-map) - (bind-key "M-?" #'sp-convolute-sexp smartparens-mode-map) - (bind-key "C-M-t" #'sp-transpose-sexp smartparens-mode-map) - (bind-key "M-R" #'sp-raise-sexp smartparens-mode-map) - (bind-key "M-S" #'sp-splice-sexp smartparens-mode-map) - (bind-key "C-M-s" #'sp-split-sexp smartparens-mode-map) - (bind-key "M-J" #'sp-join-sexp smartparens-mode-map) - (bind-key "M-" #'sp-splice-sexp-killing-backward smartparens-mode-map) - (bind-key "M-" #'sp-splice-sexp-killing-forward smartparens-mode-map) - (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp smartparens-mode-map) - (bind-key "C-S-" #'sp-slurp-hybrid-sexp smartparens-mode-map) - (sp-with-modes '(twig-mode) - (sp-local-pair "{%" "%}") - (sp-local-pair "{{" "}}")) - (show-smartparens-global-mode t) - (smartparens-global-strict-mode t) - (add-hook 'lisp-mode-common-hook #'turn-off-smartparens-mode) - (add-hook 'coffee-mode-hook #'turn-off-smartparens-mode))) -#+END_SRC - - -*** move-text - -Transposing lines, made easier. - -#+BEGIN_SRC emacs-lisp -(use-package move-text - :config (move-text-default-bindings)) -#+END_SRC - -*** undo-tree - -Emacs’ default handling of undo is a bit confusing. Undo-tree makes -it much clearer. It’s especially helpful for protoyping and refactoring. - -#+BEGIN_SRC emacs-lisp -(use-package undo-tree - :config (progn - (global-undo-tree-mode) - ;; Keep region when undoing in region - (defadvice undo-tree-undo (around keep-region activate) - (if (use-region-p) - (let ((m (set-marker (make-marker) (mark))) - (p (set-marker (make-marker) (point)))) - ad-do-it - (goto-char p) - (set-mark m) - (set-marker p nil) - (set-marker m nil)) - ad-do-it))) - :diminish undo-tree-mode) -#+END_SRC - -*** replace - -#+BEGIN_SRC emacs-lisp -(with-eval-after-load "replace.el" - (setq case-replace nil)) -#+END_SRC - -*** visual-regexp - -I don’t always remember exactly how Emacs’ regular expressions work, -so this package is pretty useful because it highlights everything in -the buffer for me. - -#+BEGIN_SRC emacs-lisp -(use-package visual-regexp - :bind (("C-c r" . vr/replace) - ("C-c q" . vr/query-replace) - ("C-c m" . vc/mc-mark))) -#+END_SRC - -** End - -Start a server if possible. A daemon is already a server. -#+BEGIN_SRC emacs-lisp -(use-package server - :defer 2 - :if (not (daemonp)) - :config (unless (server-running-p server-name) - (server-start))) -#+END_SRC - -Local Variables: -lentic-init: lentic-orgel-org-init -End: diff --git a/nix/.config/nixpkgs/emacs.nix b/nix/.config/nixpkgs/emacs.nix index aad4a78..fe661b7 100644 --- a/nix/.config/nixpkgs/emacs.nix +++ b/nix/.config/nixpkgs/emacs.nix @@ -124,6 +124,9 @@ in nginx-mode nix-mode nix-sandbox + outorg + outshine + navi-mode org-journal page-break-lines paredit -- cgit 1.4.1 From 5029163e7d68416c9b04124467b3084c50f19bb7 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 15:29:00 +0200 Subject: Emacs: Fix smartparens not being disabled in lisp modes --- emacs/.emacs.d/init.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 5df1f8b..9a93ab2 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -2778,7 +2778,9 @@ (sp-local-pair "{{" "}}")) (show-smartparens-global-mode t) (smartparens-global-strict-mode t) - (add-hook 'lisp-mode-common-hook #'turn-off-smartparens-mode) + (define-hook-helper lisp-mode-common () + (smartparens-strict-mode -1) + (smartparens-mode -1)) (add-hook 'coffee-mode-hook #'turn-off-smartparens-mode))) ;; #+END_SRC -- cgit 1.4.1 From 75a8eebea057167476ca9cb1653524b20760868d Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 15:29:17 +0200 Subject: Emacs: Make bbdb popup window smaller --- emacs/.emacs.d/init.el | 1 + 1 file changed, 1 insertion(+) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 9a93ab2..d6f5a82 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -1417,6 +1417,7 @@ (setq bbdb-send-mail-style 'gnus bbdb-complete-mail-allow-cycling t bbdb-mua-auto-update t + bbdb-mua-pop-up-window-size 3 bbdb-mua-update-interactive-p '(query . create) bbdb-message-all-addresses t bbdb-offer-save t -- cgit 1.4.1 From 14a8c8a386663a969f72fbd6cfb67ea0f475c43c Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 15:29:27 +0200 Subject: Emacs: Fix startup issue opening encrypted config --- emacs/.emacs.d/init.el | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index d6f5a82..924100a 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -15,12 +15,9 @@ (setq inhibit-startup-echo-area-message (user-login-name))) (setq inhibit-startup-screen t) (setq gc-cons-threshold 100000000) -(defvar file-name-handler-alist-backup file-name-handler-alist) -(setq file-name-handler-alist nil) (add-hook 'after-init-hook - #'(lambda () - (setq gc-cons-threshold 800000 - file-name-handler-alist file-name-handler-alist-backup))) + (lambda () + (setq gc-cons-threshold 800000))) (remove-hook 'find-file-hooks #'vc-refresh-state) ;; #+END_SRC -- cgit 1.4.1 From cd060d4e5ecd0f53e14d698e8a76f28d2415a20c Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 15:29:47 +0200 Subject: Emacs: Simplify search for init file --- emacs/.emacs.d/init.el | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 924100a..ef66d64 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -1425,10 +1425,7 @@ ;; #+BEGIN_SRC emacs-lisp (defvar *init-file* - (let ((init-file (or user-init-file - (expand-file-name "init.el" user-emacs-directory)))) - (expand-file-name "init.el" - (file-name-directory (file-truename init-file)))) + (file-truename user-init-file) "Where the emacs init file really is, passing through symlinks.") (set-register ?e `(file . ,*init-file*)) -- cgit 1.4.1 From 9a1e539df2bafab894bde33c39feee8c5ac4cb59 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 16:37:06 +0200 Subject: Emacs: Remove coffee mode Unused --- emacs/.emacs.d/init.el | 12 +----------- nix/.config/nixpkgs/emacs.nix | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index ef66d64..78e4919 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -2274,15 +2274,6 @@ (add-hook 'js2-mode-hook #'indium-interaction-mode))) ;; #+END_SRC -;; **** coffee-mode - -;; #+BEGIN_SRC emacs-lisp -(use-package coffee-mode - :mode ("\\.coffee\\'" . coffee-mode) - :config (progn - (setq coffee-indent-like-python-mode t))) -;; #+END_SRC - ;; **** tern ;; Tern understands javascript. It adds really clever documented @@ -2775,8 +2766,7 @@ (smartparens-global-strict-mode t) (define-hook-helper lisp-mode-common () (smartparens-strict-mode -1) - (smartparens-mode -1)) - (add-hook 'coffee-mode-hook #'turn-off-smartparens-mode))) + (smartparens-mode -1)))) ;; #+END_SRC diff --git a/nix/.config/nixpkgs/emacs.nix b/nix/.config/nixpkgs/emacs.nix index fe661b7..ad77ff5 100644 --- a/nix/.config/nixpkgs/emacs.nix +++ b/nix/.config/nixpkgs/emacs.nix @@ -67,7 +67,6 @@ in clj-refactor clojure-mode cmd-to-echo - coffee-mode command-log-mode company company-go -- cgit 1.4.1 From 4c61a4a89c0a1613d6979a4df64ea1c2498eddaa Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 4 Aug 2017 16:40:56 +0200 Subject: Emacs: Remove twig-mode I don't use PHP any more --- emacs/.emacs.d/init.el | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 78e4919..5411adb 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -2376,13 +2376,6 @@ (sp-local-pair '(web-mode) "<%" "%>"))) ;; #+END_SRC -;; I derived a mode for twig, in order to use its =mode-hook=. - -;; #+BEGIN_SRC emacs-lisp -(define-derived-mode twig-mode web-mode "Twig") -(add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) -;; #+END_SRC - ;; *** Live coding ;; Sometimes I might want to show off my emacs usage. @@ -2758,10 +2751,7 @@ (bind-key "M-" #'sp-splice-sexp-killing-backward smartparens-mode-map) (bind-key "M-" #'sp-splice-sexp-killing-forward smartparens-mode-map) (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp smartparens-mode-map) - (bind-key "C-S-" #'sp-slurp-hybrid-sexp smartparens-mode-map) - (sp-with-modes '(twig-mode) - (sp-local-pair "{%" "%}") - (sp-local-pair "{{" "}}")) + (bind-key "C-S-" #'sp-slurp-hybrid-sexp smartparens-mode-map) (show-smartparens-global-mode t) (smartparens-global-strict-mode t) (define-hook-helper lisp-mode-common () -- cgit 1.4.1