From 5d343fb5f08129137c69ef56c97ff1a6e0e886bf Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Tue, 14 Jul 2015 14:21:28 +0200 Subject: Move emacs configuration to org-babel --- tag-emacs/emacs.d/init.el | 1636 ----------------------------- tag-emacs/emacs.d/init.org | 2506 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2506 insertions(+), 1636 deletions(-) delete mode 100644 tag-emacs/emacs.d/init.el create mode 100644 tag-emacs/emacs.d/init.org diff --git a/tag-emacs/emacs.d/init.el b/tag-emacs/emacs.d/init.el deleted file mode 100644 index df3c821..0000000 --- a/tag-emacs/emacs.d/init.el +++ /dev/null @@ -1,1636 +0,0 @@ -;; -*- lexical-binding: t; -*- -;;;; Startup -;; Do not merge echo-area-message sexp -(setq inhibit-startup-echo-area-message "alan") -(setq inhibit-startup-screen t - initial-scratch-message "" - initial-major-mode 'text-mode - user-mail-address "alan@alanpearce.co.uk" - user-full-name "Alan Pearce" - custom-file "~/.emacs.d/custom.el") - -(load custom-file :noerror) - -;;;; Helper Macros -(defmacro rename-modeline (mode new-name) - `(defadvice ,mode (after rename-modeline activate) - (setq mode-name ,new-name))) - -;;; Allow lisps to use a common setup. I don't know why they don't have some lispy mode as their parent, but this is close enough -(defcustom lisp-mode-common-hook nil - "Hook run when entering any Lisp mode." - :type 'hook - :group 'lisp) - -;;;; Environment & Location - -(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.") - -(defvar work-project-directory "~/work") -(defvar home-project-directory "~/projects") - -;;;; Package Management -(add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory)) - -(eval-and-compile - (add-to-list 'load-path (expand-file-name "~/.cask")) - (require 'cask) - (cask-initialize)) - -(unless (package-installed-p 'req-package) - (package-refresh-contents) - (package-install 'req-package)) -(require 'req-package) -(setq use-package-verbose t) -(req-package pallet - :defer 5 - :config (pallet-mode 1)) - -;;;; Style - -(req-package whitespace - :defer t - :config (setq whitespace-style - '(face - space - tabs - trailing - newline - empty - tab-mark - space-before-tab - indentation - indentation::space - indentation::tabs))) - -(global-font-lock-mode t) -;; Allow font-lock-mode to do background parsing -(setq jit-lock-stealth-time 1 - jit-lock-stealth-load 100 - jit-lock-chunk-size 1000 - jit-lock-defer-time 0.01) - -(when (fboundp #'blink-cursor-mode) - (blink-cursor-mode -1)) - -(setq x-underline-at-descent-line t) - -(setq ring-bell-function - (lambda () - (unless (memq this-command - '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit undo-tree-undo)) - (ding)))) - -(req-package solarized-theme - :config (progn - (load-theme 'solarized-light t))) - -(when (or (display-graphic-p) - (daemonp)) - - (defun use-variable-fonts () - (interactive) - (variable-pitch-mode) - (setq cursor-type 'bar)) - - (defun ap/set-fonts (mono-face variable-face font-size) - (when mono-face - (let ((default-font (concat mono-face "-" (number-to-string font-size)))) - (add-to-list 'default-frame-alist `(font . ,default-font)) - (set-face-font 'fixed-pitch default-font) - (set-frame-font default-font t t))) - (when variable-face - (set-face-font 'variable-pitch (concat variable-face "-" - (number-to-string (1+ font-size)))))) - - (cond - ((eq window-system 'w32) - (ap/set-fonts "Consolas" "Segoe UI" 10)) - ((eq system-type 'darwin) - (ap/set-fonts "Monaco" "Helvetica" 12)))) - -(req-package rainbow-mode - :commands (rainbow-turn-on - rainbow-turn-off) - :config (progn - (add-hook 'xmonad-mode-hook #'rainbow-turn-on))) - -(req-package highlight-stages - :defer t - :diminish highlight-stages-mode - :init (progn - (add-hook 'lisp-mode-common-hook #'highlight-stages-mode))) - -;;;; Autosaves & Backups -(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)) - auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) - backup-by-copying-when-linked t - backup-by-copying-when-mismatch t)) - -;;;; Buffers - -(req-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))))) - -(req-package uniquify - :config (progn - (setq uniquify-buffer-name-style 'reverse - uniquify-separator "/" - uniquify-after-kill-buffer-p t - uniquify-ignore-buffers-re "^\\*"))) - -(req-package fancy-narrow - :diminish fancy-narrow-mode - :config (fancy-narrow-mode 1)) - -;;;; Communication - -(setq gnutls-min-prime-bits nil) - -;;;; Completion - -(setq completion-styles '(basic initials partial-completion substring) - completion-ignore-case t) - -(req-package smart-tab - :commands (global-smart-tab-mode) - :init (global-smart-tab-mode) - :config (progn - (nconc smart-tab-completion-functions-alist '((php-mode . php-complete-function))) - (diminish 'smart-tab-mode ""))) - -(req-package company - :commands (company-mode) - :diminish "Cmpl" - :bind (("C-" . company-complete)) - :init (progn - (add-hook 'prog-mode-hook #'company-mode) - (setq company-backends '(company-tern (php-extras-company company-elisp company-bbdb company-nxml company-css company-eclim company-semantic company-clang company-xcode company-cmake company-capf company-gtags company-dabbrev-code company-etags company-keywords) - company-oddmuse company-files company-dabbrev) - 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-dabbrev-downcase nil))) - -;;;; Dates & Times - -(req-package calendar - :defer t - :config (progn - (setq calendar-week-start-day 1) - (calendar-set-date-style 'iso))) - -(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)))) - -;;;; Directory browsing -(req-package dired - :defer t - :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 'top - dired-listing-switches "-alh" - dired-bind-jump nil) - (when (and (eq system-type 'darwin) (executable-find "gls")) - (setq insert-directory-program (executable-find "gls"))) - (put 'dired-find-alternate-file 'disabled nil))) - -(req-package dired-k - :require dired - :init (progn - (add-hook 'dired-initial-position-hook #'dired-k)) - :config (progn - (setq dired-k-human-readable t) - (bind-key "g" #'dired-k dired-mode-map))) - -(req-package dired-x - :require dired) - -(req-package dired+ - :require dired - :config (progn - (diredp-toggle-find-file-reuse-dir 1) - (unbind-key "C-h C-m" dired-mode-map) - (bind-key "." #'diredp-describe-file dired-mode-map) - (defun turn-on-dired-omit-mode () - (interactive) - (dired-omit-mode 1)) - (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode) - (setq dired-omit-files "#\\|\\.$" - dired-omit-verbose nil - dired-find-subdir t))) - -(req-package dired-subtree - :defer t - :require dired - :config (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)) - :init (progn - (bind-key "i" #'dired-subtree-toggle dired-mode-map))) - -;;;; Documentation - -(req-package helm-dash - :defer t - :init (progn - (defmacro ap/create-helm-dash-hook (mode docsets) - (let* ((mode-s (symbol-name mode)) - (fun (intern (concat "helm-dash-hook-" mode-s))) - (hook (intern (concat mode-s "-mode-hook")))) - `(progn - (defun ,fun () - (when (require 'helm-dash nil :noerror) - (-each (-difference ',docsets - (helm-dash-installed-docsets)) - #'helm-dash-install-docset) - (setq-local helm-dash-docsets ',docsets))) - (add-hook (quote ,hook) (function ,fun))))) - (ap/create-helm-dash-hook nginx ("Nginx")) - (ap/create-helm-dash-hook ansible ("Ansible")) - (ap/create-helm-dash-hook php ("PHP" "Symfony")) - (ap/create-helm-dash-hook twig ("Twig")) - (ap/create-helm-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express")) - (ap/create-helm-dash-hook markdown ("Markdown")) - (ap/create-helm-dash-hook saltstack ("SaltStack")) - (ap/create-helm-dash-hook clojure ("Clojure")) - (ap/create-helm-dash-hook sql ("PostgreSQL" "MySQL")))) - -(req-package which-func - :init (which-function-mode) - :config (setq which-func-modes t)) - -(req-package discover-my-major - :bind ("C-h C-m" . discover-my-major)) - -;;;; Files - -(prefer-coding-system 'utf-8-auto-unix) -(set-default-coding-systems 'utf-8-auto-unix) -(setq-default buffer-file-coding-system 'utf-8-auto-unix) -(setq create-lockfiles nil) -(if (eq system-type 'darwin) - (setq delete-by-moving-to-trash t)) - -(req-package autorevert - :init (progn - (global-auto-revert-mode 1) - (setq auto-revert-verbose nil))) - -(defun rename-current-buffer-file () - "Renames current buffer and file it is visiting." - (interactive) - (let ((name (buffer-name)) - (filename (buffer-file-name))) - (if (not (and filename (file-exists-p filename))) - (error "Buffer '%s' is not visiting a file!" name) - (let ((new-name (read-file-name "New name: " filename))) - (if (get-buffer new-name) - (error "A buffer named '%s' already exists!" new-name) - (cond - ((vc-backend filename) (vc-rename-file filename new-name)) - (t (rename-file filename new-name t) - (rename-buffer new-name) - (set-visited-file-name new-name) - (set-buffer-modified-p nil) - (message "File '%s' successfully renamed to '%s'" - name (file-name-nondirectory new-name))))))))) - -(defun delete-current-buffer-file () - "Removes file connected to current buffer and kills buffer." - (interactive) - (let ((filename (buffer-file-name))) - (if (not (and filename (file-exists-p filename))) - (kill-this-buffer) - (when (yes-or-no-p "Are you sure you want to remove this file? ") - (delete-file filename) - (kill-this-buffer) - (message "File '%s' successfully removed" filename))))) - -(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) - -(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 (equalp buf "*HTTP Response*") - (other-window 1)) - (kill-buffer buf))))) - -(req-package ws-butler - :if window-system - :config (ws-butler-global-mode 1)) -(if (daemonp) - (add-hook #'before-make-frame-hook (lambda () (ws-butler-global-mode 1)))) - -(req-package fasd - :bind ("C-x C-/" . fasd-find-file) - :init (progn - (global-fasd-mode 1))) - -(req-package recentf - :init (progn (setq recentf-auto-cleanup 'never - recentf-save-file (expand-file-name "recentf" user-emacs-directory)) - (recentf-mode 1))) - -(req-package password-store - :config (progn - (setq password-store-password-length 16))) - -(req-package saveplace - :config (progn (setq-default save-place t) - (setq save-place-file (expand-file-name ".saveplace" user-emacs-directory)))) - -(req-package tramp - :defer t - :config (progn - (setq tramp-default-method (if (eq system-type 'windows-nt) "plinkx" "ssh") - tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root")) - tramp-backup-directory-alist backup-directory-alist - 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)) - (add-to-list 'tramp-default-proxies-alist '("router" nil nil)))) - -(req-package tramp-sh - :require tramp - :defer t - :config (progn - (add-to-list 'tramp-remote-path "/usr/local/sbin") - (add-to-list 'tramp-remote-path "~/bin"))) - -(req-package ediff - :defer t - :config (progn - (setq ediff-split-window-function 'split-window-horizontally - ediff-window-setup-function 'ediff-setup-windows-plain))) - -;;;; Indentation - -(setq-default tab-width 4 - indent-tabs-mode t) -(setq tab-stop-list - ;; (mapcar (lambda (x) - ;; (* 4 x)) - ;; (number-sequence 1 (/ 120 4))) - '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120) - tab-always-indent 'complete) - -(req-package auto-indent-mode - :config (progn - (setq auto-indent-key-for-end-of-line-then-newline "" - auto-indent-key-for-end-of-line-insert-char-then-newline "" - auto-indent-blank-lines-on-move nil - auto-indent-assign-indent-level 4 - auto-indent-backward-delete-char-behavior nil - auto-indent-delete-trailing-whitespace-on-save-file t - auto-indent-mode-untabify-on-yank-or-paste nil - auto-indent-known-indent-level-variables - (remq 'lisp-body-indent auto-indent-known-indent-level-variables)) - (add-to-list 'auto-indent-disabled-modes-list 'jinja2-mode) - (add-to-list 'auto-indent-disabled-modes-list 'yaml-mode) - (add-to-list 'auto-indent-disabled-modes-list 'saltstack-mode) - (add-to-list 'auto-indent-disabled-modes-list 'nix-mode) - (auto-indent-global-mode))) - -(req-package smart-tabs-mode - :commands (smart-tabs-mode - smart-tabs-mode-enable - smart-tabs-advice) - :config (progn - (add-hook 'php-mode-hook (lambda () - (smart-tabs-mode indent-tabs-mode))) - (smart-tabs-insinuate 'c 'javascript 'cperl 'python))) - -;;;; Keybindings - -(when (eq system-type 'darwin) - (set-keyboard-coding-system nil) - (setq mac-option-modifier 'meta - mac-right-option-modifier 'left - mac-control-modifier 'control - mac-right-control-modifier 'left - mac-command-modifier 'super - mac-right-command-modifier 'left - mac-function-modifier 'hyper)) - -(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 "s-x" (define-prefix-command 'super-x-map)) - -(defun switch-to-dotfiles () - (interactive) - (projectile-persp-switch-project (expand-file-name "dotfiles" home-project-directory))) -(bind-key "s-," #'switch-to-dotfiles) -(set-register ?e `(file . ,*init-file*)) -(set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) - -(req-package discover - :config (global-discover-mode)) - -;; Enable narrowing functions C-x n -(put 'narrow-to-defun 'disabled nil) -(put 'narrow-to-page 'disabled nil) -(put 'narrow-to-region 'disabled nil) - -;;;; Minibuffer - -(setq enable-recursive-minibuffers t) -(setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)) -(minibuffer-depth-indicate-mode t) - -(if (daemonp) - (defalias 'exit-emacs #'delete-frame) - (defalias 'exit-emacs #'save-buffers-kill-emacs)) - -(req-package helm-config - :demand t - :ensure helm - :bind (("C-x i" . helm-semantic-or-imenu)) - :config (progn - (setq helm-idle-delay .1 - helm-input-idle-delay 0) - (when (fboundp #'helm-adaptive-mode) - (helm-adaptive-mode 1)))) - -(req-package helm-files - :defer t - :config (progn - (define-key helm-read-file-map (kbd "") #'helm-execute-persistent-action) - (define-key helm-read-file-map (kbd "TAB") #'helm-execute-persistent-action) - (define-key helm-read-file-map (kbd "C-i") #'helm-execute-persistent-action) - (define-key helm-read-file-map (kbd "C-z") #'helm-select-action))) - -(req-package ido - :bind (("C-x b" . ido-switch-buffer)) - :init (progn - (setq ido-save-directory-list-file (expand-file-name "ido-state" user-emacs-directory)) - (bind-key* "C-x C-f" #'ido-find-file) - (ido-mode 1) - (ido-everywhere 1)) - :config (progn - (setq ido-auto-merge-delay-time 99999 - ido-enable-flex-matching t) - - (ido-init-completion-maps) - (defadvice ido-find-file (after find-file-sudo activate) - "Find file as root if necessary." - (unless (and buffer-file-name - (file-writable-p buffer-file-name)) - (find-alternate-file (concat "/sudo::" buffer-file-name)))) - (defun ido-manual-merge () - (interactive) - (ido-initiate-auto-merge (current-buffer))) - (bind-key "C-c C-s" #'ido-manual-merge ido-file-dir-completion-map))) - -(req-package ido-completing-read+ - :require ido - :config (progn - (setq ido-cr+-fallback-function #'helm-completing-read - ido-cr+-max-items 2000))) - -(defun ap/ido-projectile-switch-buffer-dwim (force-ido) - (interactive "p") - (if (and (projectile-project-p) (eq force-ido 1)) - (call-interactively #'projectile-switch-to-buffer) - (call-interactively #'ido-switch-buffer))) - -(bind-key "s-x b" #'ap/ido-projectile-switch-buffer-dwim) -(bind-key "s-x s-b" #'ap/ido-projectile-switch-buffer-dwim) - -(req-package ido-vertical-mode - :require ido - :init (progn - (setq ido-vertical-decorations '("\n❯ " - "" - "\n " - "\n …" - "[" - "]" - " [No match]" - " [Matched]" - " [Not readable]" - " [Too big]" - " [Confirm]" - "\n❯ " - "") - ido-vertical-define-keys 'C-n-C-p-up-down-left-right)) - :config (ido-vertical-mode 1)) - -(req-package flx-ido - :require ido - :init (progn - (flx-ido-mode 1) - (setq flx-ido-threshhold 1000))) - -(req-package smex - :require ido - :bind (("M-x" . smex) - ("" . smex) - ("" . smex) - ("M-X" . smex-major-mode-commands) - ("C-c M-x" . execute-extended-command)) - :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")) - (smex-initialize))) - -;;;; Modeline - -(column-number-mode t) -(size-indication-mode t) - -(defun fill-line-format (line-format) - (max 0 - (- (window-width) - (length (format-mode-line line-format))))) - -(defvar mode-line-size - `((size-indication-mode - ((-3 ,(propertize - "%p" - 'local-map mode-line-column-line-number-mode-map - 'mouse-face 'mode-line-highlight - ;; XXX needs better description - 'help-echo "Size indication mode\n\ -mouse-1: Display Line and Column Mode Menu")) - " " - (-4 "%I"))))) - -(setq-default - mode-line-modes (let ((recursive-edit-help-echo "Recursive edit, type C-M-c to get out")) - (list (propertize "%[" 'help-echo recursive-edit-help-echo) - `(:propertize ("" mode-name) - help-echo "Major mode\n\ -mouse-1: Display major mode menu\n\ -mouse-2: Show help for major mode\n\ -mouse-3: Toggle minor modes" - mouse-face mode-line-highlight - local-map ,mode-line-major-mode-keymap) - '("" mode-line-process) - `(:propertize ("" minor-mode-alist) - mouse-face mode-line-highlight - help-echo "Minor mode\n\ -mouse-1: Display minor mode menu\n\ -mouse-2: Show help for minor mode\n\ -mouse-3: Toggle minor modes" - local-map ,mode-line-minor-mode-keymap) - (propertize "%n" 'help-echo "mouse-2: Remove narrowing from buffer" - 'mouse-face 'mode-line-highlight - 'local-map (make-mode-line-mouse-map - 'mouse-2 #'mode-line-widen)) - (propertize "%]" 'help-echo recursive-edit-help-echo) - " ")) - mode-line-buffer-identification (list (propertize "%b" - 'face 'mode-line-buffer-id)) - - mode-line-position `((line-number-mode - ((column-number-mode - ,(propertize - "%l:%c" - 'local-map mode-line-column-line-number-mode-map - 'mouse-face 'mode-line-highlight - 'help-echo "Line number and Column number\n\ -mouse-1: Display Line and Column Mode Menu") - (6 ,(propertize - "L%l" - 'local-map mode-line-column-line-number-mode-map - 'mouse-face 'mode-line-highlight - 'help-echo "Line Number\n\ -mouse-1: Display Line and Column Mode Menu")))) - ((column-number-mode - (5 ,(propertize - "C%c" - 'local-map mode-line-column-line-number-mode-map - 'mouse-face 'mode-line-highlight - 'help-echo "Column number\n\ -mouse-1: Display Line and Column Mode Menu")))))) - mode-line-format `("%e" - " " - mode-line-modes - mode-line-misc-info - (vc-mode vc-mode) - mode-line-end-spaces) - header-line-format `("%e" - mode-line-front-space - mode-line-mule-info - mode-line-client - mode-line-modified - mode-line-auto-compile - mode-line-remote " " - mode-line-position " " - mode-line-size - " ⎸ " - mode-line-buffer-identification - )) - -;;;; Modes - -;;;; systemd files -(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)) - -(add-to-list 'auto-mode-alist '("\\.envrc\\'" . sh-mode)) - -(req-package xrdb-mode - :mode (("\\.Xdefaults\\'" . xrdb-mode) - ("\\.Xresources\\'" . xrdb-mode))) - -(req-package haskell-mode - :mode (("\\.hs\\'" . haskell-mode))) - -(req-package nix-mode - :mode (("\\.nix\\'" . nix-mode)) - :config (progn - (setq-local indent-tabs-mode nil))) - -(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)) - -(req-package nginx-mode - :defer t - :mode (("/nginx/servers/" . nginx-mode) - ("/nginx/.*\\.d/" . nginx-mode)) - :config (progn - (setq nginx-indent-tabs-mode t))) - -(req-package lua-mode - :defer t) - -(req-package ledger-mode - :mode ("\\.ledger\\'" . ledger-mode) - :config (progn - (defun setup-ledger-mode () - (setq-local indent-tabs-mode nil)) - (add-hook 'ledger-mode-hook #'setup-ledger-mode) - (add-to-list 'smart-tab-disabled-major-modes 'ledger-mode) - (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-default-date-format "%Y-%m-%d"))) - -(req-package ruby-mode - :mode (("\\.rb\\'" . ruby-mode) - ("\\.cap\\'" . ruby-mode))) - -(req-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)) - -;;;; Planning - -(req-package org - :bind (("C-c C-a" . org-agenda-list) - ("C-c a" . org-agenda) - ("C-c l" . org-store-link)) - :init (setq org-replace-disputed-keys t) - :config (progn - (setq org-directory "~/org" - org-agenda-files `(,org-directory) - - org-default-notes-file (concat org-directory "/notes") - - ;; ‘Remember’: new items at top - org-reverse-note-order t - - org-modules '(org-habit - org-checklist) - - ;; Add time done to ‘done’ tasks - org-log-done 'time - - ;; Allow refiling into any org file - org-refile-targets '((org-agenda-files :maxlevel . 3)) - - org-list-allow-alphabetical t - - org-pretty-entities t - - org-table-duration-custom-format 'seconds - - org-src-fontify-natively t - - org-export-have-math t - - org-blank-before-new-entry '((heading . t) - (plain-list-item . auto)) - org-fontify-done-headline t - - org-todo-keywords '((sequence "TODO" "STARTED" "|" "DONE") - (sequence "TOLEARN" "LEARNING" "LEARNED" "|" "MASTERED") - (sequence "|" "CANCELLED"))) - (set-register ?o `(file . ,(expand-file-name "organiser.org" org-directory))) - (add-hook 'org-mode-hook #'turn-on-auto-fill) - (defadvice org-clock-in (after wicked activate) - "Mark STARTED when clocked in" - (save-excursion - (catch 'exit - (org-back-to-heading t) - (if (looking-at org-outline-regexp) (goto-char (1- (match-end 0)))) - (if (looking-at (concat " +" org-todo-regexp "\\( +\\|[ \t]*$\\)")) - (org-todo "STARTED"))))))) - -(req-package org-babel - :require org - :defer t - :config (org-babel-do-load-languages - 'org-babel-load-languages - '((ledger . t) - (sh . t)))) - -(req-package org-journal - :require org - :defer t - :config (progn - (setq org-journal-date-format "%A, %d %B %Y"))) - -(req-package org-mobile - :require org - :defer t - :config (progn - (setq org-mobile-directory "~/Mobile/Org"))) - -;;;; Programming - -(req-package cedet - :disabled t - :config (progn - (semantic-load-enable-code-helpers) - (global-semantic-idle-completions-mode t) - (global-semantic-highlight-func-mode t) - (global-semantic-show-unmatched-syntax-mode t) - (global-semantic-decoration-mode t))) - -(req-package flycheck - :diminish " ✓" - :init (global-flycheck-mode)) - -(req-package go-mode - :mode (("\\.go\\'" . go-mode))) - -(when (file-exists-p "src/code.google.com/p/go.tools/cmd/oracle/oracle.el") - (req-package oracle - :load-path ,(expand-file-name "src/code.google.com/p/go.tools/cmd/oracle/oracle.el" (getenv "GOPATH")) - :init (progn - (add-hook 'go-mode-hook #'go-oracle-mode)))) - -(req-package company-go - :require go-mode - :config (progn - (setq company-go-show-annotation t) - (defun ap/company-go-setup () - (set (make-local-variable 'company-backends) - '(company-go))) - (add-hook 'go-mode-hook #'ap/company-go-setup))) - -(req-package go-eldoc - :require go-mode - :config (progn - (add-hook 'go-mode-hook #'go-eldoc-setup))) - -(req-package go-projectile - :require (go-mode go-eldoc projectile) - :config (progn - (setq go-projectile-switch-gopath 'maybe))) - -(req-package ggtags - :commands turn-on-ggtags-mode - :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))) - -(req-package auto-compile - :defer t - :init (add-hook 'emacs-lisp-mode-hook #'auto-compile-on-save-mode)) - -(req-package cc-mode - :defer t - :init (progn - (add-hook 'c-mode-common-hook #'electric-indent-mode)) - :config (progn - (setq c-default-style '((java-mode . "java") - (awk-mode . "awk") - (other . "k&r")) - c-basic-offset 4) - (c-set-offset 'case-label '+))) - -(req-package quickrun - :bind (("C-c C-e" . quickrun))) - -;;;; Projects - -(req-package dash - :demand t - :init (setq dash-enable-fontlock t) - :config (progn - (dash--enable-fontlock 'dash-enable-font-lock t))) - -(req-package projectile - :bind (("C-c C-f" . projectile-find-file) - ("s-x s-f" . projectile-find-file) - ("C-x g" . projectile-vc) - ("s-G" . projectile-vc)) - :init (projectile-global-mode) - :diminish projectile-mode - :config (progn - (defun ap/subfolder-projects (dir) - (--map (file-relative-name it dir) - (-filter (lambda (subdir) - (--reduce-from (or acc (funcall it subdir)) nil - projectile-project-root-files-functions)) - (-filter #'file-directory-p (directory-files dir t "\\<"))))) - - (defun ap/-add-known-subfolder-projects (dir) - (-map #'projectile-add-known-project (--map (concat (file-name-as-directory dir) it) (ap/subfolder-projects dir)))) - - (defun ap/add-known-subfolder-projects () - (interactive) - (ap/-add-known-subfolder-projects (ido-read-directory-name "Add projects under: "))) - - (defun ap/open-subfolder-project (from-dir &optional arg) - (let ((project-dir (projectile-completing-read "Open project: " - (ap/subfolder-projects from-dir)))) - (projectile-switch-project-by-name (expand-file-name project-dir from-dir) arg))) - - (defun ap/open-work-project (&optional arg) - (interactive "P") - (ap/open-subfolder-project work-project-directory arg)) - - (defun ap/open-home-project (&optional arg) - (interactive "P") - (ap/open-subfolder-project home-project-directory arg)) - - - (setq projectile-switch-project-action #'projectile-dired - projectile-remember-window-configs t - projectile-completion-system 'helm))) - -(req-package helm-projectile - :ensure projectile - :require projectile - :defer t) - -(req-package projector - :require projectile - :bind (("s-z" . projector-open-project-shell))) - -(req-package perspective - :bind (("s-p" . persp-switch)) - :init (progn - (persp-mode))) - -(req-package persp-projectile - :require (projectile perspective)) - -(req-package vc - :defer t - :bind (("C-x v C" . vc-resolve-conflicts)) - :config (progn - (setq vc-follow-symlinks t))) - -(req-package diff-hl - :init (progn - (global-diff-hl-mode) - (add-hook 'magit-refresh-file-buffer-hook #'diff-hl-update))) - -(req-package magit - :commands (magit-status) - :config (progn (rename-modeline magit-status-mode (char-to-string (-find #'char-displayable-p '(11942 5848 177)))) - (setq magit-last-seen-setup-instructions "1.4.0" - magit-completing-read-function #'magit-ido-completing-read)) - :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) - -;;;; Spelling -(req-package ispell - :bind (("" . ispell-word)) - :config (progn - (setq ispell-program-name "aspell" - ispell-dictionary "british"))) - -;;;; Scripting - -(add-hook 'after-save-hook - #'executable-make-buffer-file-executable-if-script-p) - -(req-package sh-script - :mode (("\\.zsh\\'" . shell-script-mode)) - :config (setq sh-shell-file "/usr/bin/env zsh")) - -;;;; Shells & REPLs - -(req-package eshell - :bind ("C-c s" . eshell) - :config (progn - (setq eshell-directory-name "~/.emacs.d/eshell") - (add-hook 'eshell-load-hook (lambda () - (bind-key "C-c C-l" #'helm-eshell-history eshell-mode-map))) - (req-package em-smart - :config (progn - (setq eshell-where-to-jump 'begin - eshell-review-quick-commands nil - eshell-smart-space-goes-to-end t) - (eshell-smart-initialize))))) - -(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) - -(req-package shell - :defer t - :config (define-key shell-mode-map - (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer)) - -(req-package comint - :defer t - :config (bind-key "C-c C-l" #'helm-comint-input-ring comint-mode-map)) - -(req-package multi-term - :if (not (eq system-type 'windows-nt)) - :bind ("C-`" . multi-term-dedicated-toggle)) - -(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))) - -;;;; Text editing - -(bind-key "C-M-a" #'backward-paragraph text-mode-map) -(bind-key "C-M-e" #'forward-paragraph text-mode-map) - -;; Enable upcase and downcase-region -(put 'upcase-region 'disabled nil) -(put 'downcase-region 'disabled nil) -(setq sentence-end-double-space t - line-move-visual nil) - -(req-package align - :config (progn - (add-to-list 'align-rules-list - '(colon-key-value - (regexp . ":\\(\\s-*\\)") - (modes . '(js2-mode)))))) - -(setq x-select-enable-clipboard t) -(if (functionp 'x-cut-buffer-or-selection-value) - (setq interprogram-paste-function 'x-cut-buffer-or-selection-value)) - -;; replace highlighted text rather than just inserting at point -(delete-selection-mode t) - -(bind-key "S-SPC" #'set-mark-command) - -(defun fc/isearch-yank-symbol () - "Yank the symbol at point into the isearch minibuffer. - -C-w does something similar in isearch, but it only looks for -the rest of the word. I want to look for the whole string. And -symbol, not word, as I need this for programming the most." - (interactive) - (isearch-yank-string - (save-excursion - (when (and (not isearch-forward) - isearch-other-end) - (goto-char isearch-other-end)) - (thing-at-point 'symbol)))) -(bind-key "C-d" #'fc/isearch-yank-symbol isearch-mode-map) - -(req-package subword - :init (global-subword-mode t)) - -(req-package misc - :bind (("M-z" . zap-up-to-char) - ("M-Z" . zap-to-char))) - -(req-package typopunct - :config (progn - (typopunct-change-language 'english t) - (defconst typopunct-minus (decode-char 'ucs #x2212)) - (defadvice typopunct-insert-typographical-dashes - (around minus-or-pm activate) - (cond - ((or (eq (char-before) typopunct-em-dash) - (looking-back "\\([[:blank:]]\\|^\\)\\^")) - (delete-char -1) - (insert typopunct-minus)) - ((looking-back "[^[:blank:]]\\^") - (insert typopunct-minus)) - (t ad-do-it))) - - (defconst typopunct-ellipsis (decode-char 'ucs #x2026)) - (defconst typopunct-middot (decode-char 'ucs #xB7)) ; or 2219 - (defun typopunct-insert-ellipsis-or-middot (arg) - "Change three consecutive dots to a typographical ellipsis mark." - (interactive "p") - (cond - ((and (= 1 arg) - (eq (char-before) ?^)) - (delete-char -1) - (insert typopunct-middot)) - ((and (= 1 arg) - (eq this-command last-command) - (looking-back "\\.\\.")) - (replace-match "") - (insert typopunct-ellipsis)) - (t - (self-insert-command arg)))) - (define-key typopunct-map "." 'typopunct-insert-ellipsis-or-middot) - - (defconst typopunct-times (decode-char 'ucs #xD7)) - (defun typopunct-insert-times (arg) - (interactive "p") - (if (and (= 1 arg) (looking-back "\\([[:blank:]]\\|^\\)\\^")) - (progn (delete-char -1) - (insert typopunct-times)) - (self-insert-command arg))) - (define-key typopunct-map "x" 'typopunct-insert-times) - - (defadvice typopunct-insert-quotation-mark (around wrap-region activate) - (let* ((lang (or (get-text-property (point) 'typopunct-language) - typopunct-buffer-language)) - (omark (if single - (typopunct-opening-single-quotation-mark lang) - (typopunct-opening-quotation-mark lang))) - (qmark (if single - (typopunct-closing-single-quotation-mark lang) - (typopunct-closing-quotation-mark lang)))) - (cond - (mark-active - (let ((skeleton-end-newline nil) - (singleo (typopunct-opening-single-quotation-mark lang)) - (singleq (typopunct-closing-single-quotation-mark lang))) - (if (> (point) (mark)) - (exchange-point-and-mark)) - (save-excursion - (while (re-search-forward (regexp-quote (string omark)) (mark) t) - (replace-match (regexp-quote (string singleo)) nil nil))) - (save-excursion - (while (re-search-forward (regexp-quote (string qmark)) (mark) t) - (replace-match (regexp-quote (string singleq)) nil nil))) - (skeleton-insert (list nil omark '_ qmark) -1))) - ((looking-at (regexp-opt (list (string omark) (string qmark)))) - (forward-char 1)) - (t ad-do-it))))) - :init (progn - (add-hook 'text-mode-hook #'typopunct-mode))) - -(req-package ap-functions - :commands (ap/remove-extra-cr) - :bind (("C-x r M-w" . copy-rectangle) - ("M-!" . shell-execute))) - -(when (boundp 'x-select-request-type) - (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))) - -(req-package markdown-mode - :defer t - :config (progn - (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) - -(req-package avy - :bind* (("M-g g" . avy-goto-line) - ("M-g M-g" . avy-goto-line) - ("C-|" . avy-goto-line) - ("C-c SPC" . avy-goto-char)) - :config (progn - (avy-setup-default) - (setq avy-all-windows nil))) - -(use-package ace-jump-buffer - :bind ("s-b" . ace-jump-buffer)) - -(req-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)))) - -(req-package expand-region - :bind ("C-M-SPC" . er/expand-region)) - -(req-package goto-chg - :bind ("C-x SPC" . goto-last-change)) - -(req-package helm-swoop - :bind (("C-=" . helm-swoop) - ("C-c C-=" . helm-multi-swoop)) - :init (progn - (bind-key "C-=" #'helm-swoop isearch-mode-map) - (bind-key "C-=" #'helm-multi-swoop-all-from-helm-swoop))) - -(req-package multiple-cursors - :defer 1 - :config (progn - (bind-key "C-." #'mc/mark-next-like-this) - (bind-key "C-," #'mc/mark-previous-like-this) - (bind-key "M-" #'mc/mark-all-like-this-dwim) - (bind-key "C-" #'mc/mark-more-like-this-extended) - (bind-key "C-S-L" #'mc/edit-lines))) - -(req-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))) - -(req-package paredit - :diminish "()" - :commands (paredit-mode) - :init (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 'minibuffer-setup-hook #'conditionally-enable-paredit-mode) - (defun conditionally-enable-paredit-mode () - "enable paredit-mode during eval-expression" - (if (eq this-command 'eval-expression) - (paredit-mode 1))))) - -(req-package smartparens-config - :config (progn - (sp-use-smartparens-bindings) - (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' - (bind-key "C-(" #'wrap-with-paren sp-keymap) - (bind-key "C-)" #'sp-forward-slurp-sexp sp-keymap) - (bind-key "M-" #'backward-kill-word sp-keymap) - (bind-key "M-?" #'sp-convolute-sexp sp-keymap) - (bind-key "C-M-t" #'sp-transpose-sexp sp-keymap) - (bind-key "M-r" #'sp-raise-sexp sp-keymap) - (bind-key "M-s" #'sp-splice-sexp sp-keymap) - (bind-key "M-S" #'sp-split-sexp sp-keymap) - (bind-key "M-J" #'sp-join-sexp sp-keymap) - (bind-key "M-" #'sp-splice-sexp-killing-backward sp-keymap) - (bind-key "M-" #'sp-splice-sexp-killing-forward sp-keymap) - (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp sp-keymap) - (bind-key "C-S-" #'sp-slurp-hybrid-sexp sp-keymap) - (sp-with-modes '(web-mode 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))) - -(req-package move-text - :config (move-text-default-bindings)) - -(req-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) - -(req-package visual-regexp - :bind (("C-c r" . vr/replace) - ("C-c q" . vr/query-replace) - ("C-c m" . vc/mc-mark))) - -;;;; Lisps - -(defun ap/lisp-setup () - (run-hooks 'lisp-mode-common-hook) - (setq indent-tabs-mode nil)) - -(defun set-common-lisp-indentation () - (set (make-local-variable 'lisp-indent-function) - #'common-lisp-indent-function)) - -(rename-modeline emacs-lisp-mode "ξ") -(add-to-list 'auto-mode-alist '("/Cask\\'" . emacs-lisp-mode)) -(add-hook 'emacs-lisp-mode-hook #'ap/lisp-setup) -(add-hook 'emacs-lisp-mode-hook #'eldoc-mode) - -(add-hook 'scheme-mode-hook #'ap/lisp-setup) -(add-hook 'lisp-mode-hook #'ap/lisp-setup) -(add-hook 'lisp-mode-hook #'set-common-lisp-indentation) - -(req-package elisp-slime-nav - :commands elisp-slime-nav-mode - :diminish elisp-slime-nav-mode) - -(req-package geiser - :commands (geiser-mode - geiser - run-geiser - run-racket)) - -(req-package clojure-mode - :defer t - :init (progn - (add-hook 'cider-repl-mode-hook (lambda () (highlight-changes-mode -1))) - (add-hook 'clojure-mode-hook #'ap/lisp-setup))) - -(req-package clj-refactor - :defer t - :require clojure-mode - :config (progn - (cljr-add-keybindings-with-prefix "C-c C-m")) - :init (progn - (defun turn-on-clj-refactor-mode () - (clj-refactor-mode 1)) - (add-hook 'clojure-mode-hook #'turn-on-clj-refactor-mode))) - -(req-package cider - :require clojure-mode - :defer t - :config (progn - (setq nrepl-hide-special-buffers t) - (unbind-key "C-c C-f" cider-mode-map) - (add-hook 'cider-mode-hook #'cider-turn-on-eldoc-mode))) - -(req-package redshank - :diminish " Λ" - :defer t - :init (progn - (add-hook 'lisp-mode-common-hook #'turn-on-redshank-mode))) - -(req-package ielm - :defer t - :config (progn - (add-hook 'ielm-mode-hook (lambda () - (run-hooks 'lisp-mode-common-hook))))) - -(req-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)) - (setq inferior-lisp-program (executable-find "sbcl")))) - -(defun imenu-elisp-sections () - (setq imenu-prev-index-position-function nil) - (add-to-list 'imenu-generic-expression '("Sections" "^;;;; \\(.+\\)$" 1) t) - (add-to-list 'imenu-generic-expression '("Packages" "^(req-package\\s-+\\(\\(\\sw\\|\\s_\\)+\\)$" 1) t)) - -(defun init-narrow-to-section () - (interactive) - (save-excursion - (beginning-of-line) - (unless (looking-at "^;;;;") - (re-search-backward "^;;;;" nil t)) - (push-mark) - (forward-line) - (re-search-forward "^;;;;" nil t) - (forward-line -1) - (narrow-to-region (region-beginning) (region-end)))) - -(defun init-imenu (p) - (interactive "P") - (find-file-existing *init-file*) - (widen) - (helm-imenu) - (if p (init-narrow-to-section))) - -(add-hook 'emacs-lisp-mode-hook 'imenu-elisp-sections) - -(defun eval-and-replace () - "Replace the preceding sexp with its value." - (interactive) - (backward-kill-sexp) - (condition-case nil - (prin1 (eval (read (current-kill 0))) - (current-buffer)) - (error (message "Invalid expression") - (insert (current-kill 0))))) - -(bind-key "C-c e" #'eval-and-replace) - -;;;; Web Development - -(req-package skewer-mode - :defer t - :init (progn - (add-hook 'js2-mode-hook #'skewer-mode) - (add-hook 'html-mode-hook #'skewer-html-mode) - (add-hook 'css-mode-hook #'skewer-css-mode))) - -(req-package js2-mode - :mode ("\\.js\\'" . js2-mode) - :config (progn - (defun ap/javascript-setup () - (autopair-mode -1) - (auto-indent-mode -1)) - (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) - (add-hook 'js2-mode-hook #'ap/javascript-setup) - (setq js2-basic-offset 4 - js2-include-node-externs t))) - -(req-package json-mode - :mode ("\\.json\\'" . json-mode)) - -(req-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))) - -(req-package tern - :commands ap/enable-tern - :config (progn - (setq tern-command (list (executable-find "tern"))) - (defun ap/enable-tern () - (tern-mode 1)) - (add-hook 'js2-mode-hook #'ap/enable-tern))) - -(req-package tern-company - :require (tern company)) - -(add-to-list 'auto-mode-alist '("composer\\.lock" . js-mode)) - -(req-package scss-mode - :defer t - :config (progn - (setq scss-compile-at-save nil))) - -(req-package jinja2-mode - :mode (("\\.j2\\'" . jinja2-mode) - ("\\.jinja\\'" . jinja2-mode))) - -(req-package php-mode - :mode ("\\.php\\'" . php-mode) - :config (progn - (setq php-template-compatibility nil) - (bind-key "C-h C-f" #'php-search-documentation php-mode-map) - (unbind-key "C-c C-f" php-mode-map) - (unbind-key "C-." php-mode-map) - (setq php-mode-coding-style "Symfony2") - (add-hook 'php-mode-hook #'turn-on-eldoc-mode) - (add-hook 'php-mode-hook #'php-enable-symfony2-coding-style))) - -(req-package sgml-mode - :defer t - :config (setq sgml-basic-offset 4)) - -(req-package emmet-mode - :commands (emmet-mode) - :diminish (emmet-mode . " >") - :init (progn - (if (functionp 'web-mode) - (add-hook 'web-mode-hook #'emmet-mode)))) - -(req-package web-mode - :mode (("/views/.*\\.php\\'" . web-mode) - ("/layouts/.*\\.html\\'" . web-mode) - ("/templates/.*\\.php\\'" . web-mode) - ("\\.ejs\\'" . web-mode)) - :config (setq web-mode-code-indent-offset 4 - web-mode-css-indent-offset 4 - web-mode-markup-indent-offset 4 - web-mode-style-padding 0 - web-mode-script-padding 0 - web-mode-comment-style 2 - web-mode-enable-auto-pairing nil)) - -(define-derived-mode twig-mode web-mode "Twig") -(add-to-list 'auto-mode-alist '("\\.html\\.twig\\'" . twig-mode)) - -(req-package mmm-auto - :config (progn - (mmm-add-classes - '((php-sql - :submode sql-mode - :front "<<= emacs-major-version 24) - (> emacs-minor-version 3)) - :config (progn - (popwin-mode 1) - (add-to-list 'popwin:special-display-config '("^*helm.+*$" :regexp t :height 20)))) - -(req-package winner - :init (progn - (winner-mode 1) - (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))) - -(req-package windmove - :bind (("S-" . windmove-left) - ("S-" . windmove-right) - ("S-" . windmove-up) - ("S-" . windmove-down))) - -(if (eq system-type 'darwin) - (setq ns-pop-up-frames nil)) - -(req-package-finish) - -(unless (daemonp) - (require 'server) - (if (server-running-p server-name) - (message "Server already appears to be running") - (server-start))) diff --git a/tag-emacs/emacs.d/init.org b/tag-emacs/emacs.d/init.org new file mode 100644 index 0000000..8cfb1c9 --- /dev/null +++ b/tag-emacs/emacs.d/init.org @@ -0,0 +1,2506 @@ +#+STARTUP: noindent showstars content +#+TITLE: Emacs Configuration for Alan Pearce +#+PROPERTY: results silent +#+PROPERTY: eval no-export +#+PROPERTY: header-args :tangle yes :comments link +* Introduction +This is a living document, detailing my Emacs configuration using org-mode +* Emacs Configuration + +** Basics +*** Startup +Open Emacs with just a plain window. No graphics or messages, please! +#+BEGIN_SRC emacs-lisp + (setq inhibit-startup-echo-area-message "alan") + (setq inhibit-startup-screen t) +#+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.co.uk" + user-full-name "Alan Pearce") +#+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 + + +** Packaging + +I still use a couple of [[file:elisp/][elisp files]] that don’t appear to be in any package +archives. +#+BEGIN_SRC emacs-lisp +(add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory)) +#+END_SRC + +*** TODO Move [[file:elisp/ap-functions.el][=ap-functions=]] into this file and delete above + +*** Cask + +For most packages, I use [[https://github.com/cask/cask][cask]] +#+BEGIN_SRC emacs-lisp + (add-to-list 'load-path (expand-file-name "~/.cask")) + (require 'cask) + (cask-initialize) +#+END_SRC + +**** Cask commands + +Installing +#+BEGIN_SRC sh :tangle no +curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python +#+END_SRC + +Install all packages specified in the Caskfile +#+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ +cask install +#+END_SRC + +List packages with new versions +#+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ :results output +cask outdated +#+END_SRC + +Update old packages +#+BEGIN_SRC sh :tangle no :dir ~/.emacs.d/ +cask update +#+END_SRC + +*** Req-package + +#+BEGIN_SRC emacs-lisp + (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") + ("marmalade" . "http://marmalade-repo.org/packages/") + ("melpa" . "http://melpa.org/packages/") + ("melpa-stable" . "http://stable.melpa.org/packages/") + ("org" . "http://orgmode.org/elpa/"))) + (package-initialize) + (unless (package-installed-p 'req-package) + (package-refresh-contents) + (package-install 'req-package)) + (require 'req-package) + (setq use-package-verbose t) +#+END_SRC + +*** Pallet + +I use [[https://github.com/rdallasgray/pallet][pallet]] to keep my [[file:Cask][Caskfile]] up-to-date with packages installed +from inside Emacs. I don’t need it on startup, so I tell +=req-package= to initialise it when Emacs is idle. + +#+BEGIN_SRC emacs-lisp +(req-package pallet + :defer 5 + :config (pallet-mode 1)) +#+END_SRC + + +** Helpers + I like to rename modeline lighters. This macro works for major modes. +#+BEGIN_SRC emacs-lisp +(defmacro rename-modeline (mode new-name) + `(defadvice ,mode (after rename-modeline activate) + (setq mode-name ,new-name))) +#+END_SRC + +** Projects + + #+BEGIN_SRC emacs-lisp + (defvar work-project-directory "~/work") + (defvar home-project-directory "~/projects") + #+END_SRC + +#+BEGIN_SRC emacs-lisp +(defun switch-to-dotfiles () + (interactive) + (projectile-persp-switch-project (expand-file-name "dotfiles" home-project-directory))) +#+END_SRC + +*** Projectile + +Projectile is awesome for working in projects, especially VCS-backed +ones. I added a couple of functions to allow me to open new projects +based upon some folder conventions I use. + +#+BEGIN_SRC emacs-lisp +(req-package projectile + :bind (("C-c C-f" . projectile-find-file) + ("s-x s-f" . projectile-find-file) + ("C-x g" . projectile-vc) + ("s-G" . projectile-vc)) + :init (projectile-global-mode) + :diminish projectile-mode + :config (progn + (defun ap/subfolder-projects (dir) + (--map (file-relative-name it dir) + (-filter (lambda (subdir) + (--reduce-from (or acc (funcall it subdir)) nil + projectile-project-root-files-functions)) + (-filter #'file-directory-p (directory-files dir t "\\<"))))) + + (defun ap/-add-known-subfolder-projects (dir) + (-map #'projectile-add-known-project (--map (concat (file-name-as-directory dir) it) (ap/subfolder-projects dir)))) + + (defun ap/add-known-subfolder-projects () + (interactive) + (ap/-add-known-subfolder-projects (ido-read-directory-name "Add projects under: "))) + + (defun ap/open-subfolder-project (from-dir &optional arg) + (let ((project-dir (projectile-completing-read "Open project: " + (ap/subfolder-projects from-dir)))) + (projectile-switch-project-by-name (expand-file-name project-dir from-dir) arg))) + + (defun ap/open-work-project (&optional arg) + (interactive "P") + (ap/open-subfolder-project work-project-directory arg)) + + (defun ap/open-home-project (&optional arg) + (interactive "P") + (ap/open-subfolder-project home-project-directory arg)) + + + (setq projectile-switch-project-action #'projectile-dired + projectile-remember-window-configs t + projectile-completion-system 'helm))) +#+END_SRC + +*** projector + +Project-based shell buffers sounds like a good idea, but for some +reason I haven’t found a use for it. + +#+BEGIN_SRC emacs-lisp +(req-package projector + :require projectile + :bind (("s-z" . projector-open-project-shell))) +#+END_SRC + +*** perspective + +This package makes buffer-switching inside of projects make sense, by +filtering the candidates to those within the project. For it to work, +it needs hooking into projectile and a key bound to switch between projects. + +#+BEGIN_SRC emacs-lisp + (req-package perspective + :bind (("s-p" . persp-switch)) + :init (progn + (persp-mode))) + + (req-package persp-projectile + :require (projectile perspective)) +#+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 +(req-package vc + :defer t + :bind (("C-x v C" . vc-resolve-conflicts)) + :config (progn + (setq vc-follow-symlinks t))) +#+END_SRC + +*** diff-hl + +It’s nice to be able to see at a glance which lines of a file have +changed. This package colours the fringe + +#+BEGIN_SRC emacs-lisp +(req-package diff-hl + :init (progn + (global-diff-hl-mode) + (add-hook 'magit-refresh-file-buffer-hook #'diff-hl-update))) +#+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 +(req-package magit + :commands (magit-status) + :config (progn (rename-modeline magit-status-mode (char-to-string (-find #'char-displayable-p '(11942 5848 177)))) + (setq magit-last-seen-setup-instructions "1.4.0" + magit-completing-read-function #'magit-ido-completing-read)) + :init (add-hook 'magit-mode-hook #'magit-load-config-extensions)) +#+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)) + (when scroll-bar-mode + (scroll-bar-mode -1) + (tooltip-mode -1) + (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 + +When I’m using dash in emacs lisp, it’s nice to have proper font +locking for it. +#+BEGIN_SRC emacs-lisp +(req-package dash + :demand t + :init (setq dash-enable-fontlock t) + :config (progn + (dash--enable-fontlock 'dash-enable-font-lock t))) +#+END_SRC + +*** Colours + +I quite like solarized. I don’t think it’s perfect, but it supports a +lot of modes. +#+BEGIN_SRC emacs-lisp + (req-package solarized-theme + :config (progn + (load-theme 'solarized-light t))) +#+END_SRC + +Colourise colour names in certain types of buffer. I don’t use this +in modes for webdev because [[web-mode]] includes that functionality. +#+BEGIN_SRC emacs-lisp +(req-package rainbow-mode + :commands (rainbow-turn-on + rainbow-turn-off) + :config (progn + (add-hook 'xmonad-mode-hook #'rainbow-turn-on))) +#+END_SRC + +Highlighting quasi-quoted expressions in lisps is quite useful. +#+BEGIN_SRC emacs-lisp +(req-package highlight-stages + :defer t + :diminish highlight-stages-mode + :init (progn + (add-hook 'lisp-mode-common-hook #'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)) + + (defun ap/set-fonts (mono-face variable-face font-size) + (when mono-face + (let ((default-font (concat mono-face "-" (number-to-string font-size)))) + (add-to-list 'default-frame-alist `(font . ,default-font)) + (set-face-font 'fixed-pitch default-font) + (set-frame-font default-font t t))) + (when variable-face + (set-face-font 'variable-pitch (concat variable-face "-" + (number-to-string (1+ font-size)))))) + + (cond + ((eq window-system 'w32) + (ap/set-fonts "Consolas" "Segoe UI" 10)) + ((eq system-type 'darwin) + (ap/set-fonts "Monaco" "Helvetica" 12)))) +#+END_SRC + +Allow font-lock-mode to do background parsing. I’m not really sure if +these settings are particularly useful +#+BEGIN_SRC emacs-lisp +(setq jit-lock-stealth-time 1 + jit-lock-stealth-load 100 + jit-lock-chunk-size 1000 + jit-lock-defer-time 0.01) +#+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)) +#+END_SRC + +*** autorevert + +#+BEGIN_SRC emacs-lisp +(req-package autorevert + :init (progn + (global-auto-revert-mode 1) + (setq auto-revert-verbose nil))) +#+END_SRC + +*** Encoding + +#+BEGIN_SRC emacs-lisp +(prefer-coding-system 'utf-8-auto-unix) +(set-default-coding-systems 'utf-8-auto-unix) +(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 rename-current-buffer-file () + "Renames current buffer and file it is visiting." + (interactive) + (let ((name (buffer-name)) + (filename (buffer-file-name))) + (if (not (and filename (file-exists-p filename))) + (error "Buffer '%s' is not visiting a file!" name) + (let ((new-name (read-file-name "New name: " filename))) + (if (get-buffer new-name) + (error "A buffer named '%s' already exists!" new-name) + (cond + ((vc-backend filename) (vc-rename-file filename new-name)) + (t (rename-file filename new-name t) + (rename-buffer new-name) + (set-visited-file-name new-name) + (set-buffer-modified-p nil) + (message "File '%s' successfully renamed to '%s'" + name (file-name-nondirectory new-name))))))))) + + (defun delete-current-buffer-file () + "Removes file connected to current buffer and kills buffer." + (interactive) + (let ((filename (buffer-file-name))) + (if (not (and filename (file-exists-p filename))) + (kill-this-buffer) + (when (yes-or-no-p "Are you sure you want to remove this file? ") + (delete-file filename) + (kill-this-buffer) + (message "File '%s' successfully removed" filename))))) + + (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 (equalp buf "*HTTP Response*") + (other-window 1)) + (kill-buffer buf))))) +#+END_SRC + +*** Whitespace Butler + +I don’t like it when editors change an entire file’s layout when I +open it. Whitespace butler fixes whitespace only for lines that I’m editing. + +#+BEGIN_SRC emacs-lisp +(req-package ws-butler + :if window-system + :config (ws-butler-global-mode 1)) +(if (daemonp) + (add-hook #'before-make-frame-hook (lambda () (ws-butler-global-mode 1)))) +#+END_SRC + +*** fasd + +Fasd is a nice shell plugin that remembers file and folder arguments, +making it easy to re-visit them later. This package hooks into that. +I don’t seem to use it much though. + +#+BEGIN_SRC emacs-lisp +(req-package fasd + :bind ("C-x C-/" . fasd-find-file) + :init (progn + (global-fasd-mode 1))) +#+END_SRC + +*** recentf + +I only use this occasionally, but it’s nice for files outside of projects. + +#+BEGIN_SRC emacs-lisp +(req-package recentf + :init (progn (setq recentf-auto-cleanup 'never + recentf-save-file (expand-file-name "recentf" user-emacs-directory)) + (recentf-mode 1))) +#+END_SRC + +*** saveplace + +It.. saves the position I visited a file at last. Might try turning +it off to see if I notice it. + +#+BEGIN_SRC emacs-lisp +(req-package saveplace + :config (progn (setq-default save-place t) + (setq save-place-file (expand-file-name ".saveplace" user-emacs-directory)))) +#+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 + (req-package tramp + :defer t + :config (progn + (setq tramp-default-method (if (eq system-type 'windows-nt) "plinkx" "ssh") + tramp-default-user-alist '(("\\`su\\(do\\)?\\'" nil "root")) + tramp-backup-directory-alist backup-directory-alist + 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)) + (add-to-list 'tramp-default-proxies-alist '("router" nil nil)))) + + (req-package tramp-sh + :require tramp + :defer t + :config (progn + (add-to-list 'tramp-remote-path "/usr/local/sbin") + (add-to-list 'tramp-remote-path "~/bin"))) +#+END_SRC + +*** ediff + +I like a horizonal diff setup, with everything in one frame. + +#+BEGIN_SRC emacs-lisp +(req-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. Until then, I want 4-wide tabs, and make them real tabs! + +#+BEGIN_SRC emacs-lisp +(setq-default tab-width 4 + indent-tabs-mode t) +(setq tab-stop-list + ;; (mapcar (lambda (x) + ;; (* 4 x)) + ;; (number-sequence 1 (/ 120 4))) + '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120)) +#+END_SRC + +*** auto-indent-mode + +Don’t make me think, just indent it! Unless it’s a +whitespace-sensitive language, of course. + +#+BEGIN_SRC emacs-lisp +(req-package auto-indent-mode + :config (progn + (setq auto-indent-key-for-end-of-line-then-newline "" + auto-indent-key-for-end-of-line-insert-char-then-newline "" + auto-indent-blank-lines-on-move nil + auto-indent-assign-indent-level 4 + auto-indent-backward-delete-char-behavior nil + auto-indent-delete-trailing-whitespace-on-save-file t + auto-indent-mode-untabify-on-yank-or-paste nil + auto-indent-known-indent-level-variables + (remq 'lisp-body-indent auto-indent-known-indent-level-variables)) + (add-to-list 'auto-indent-disabled-modes-list 'jinja2-mode) + (add-to-list 'auto-indent-disabled-modes-list 'yaml-mode) + (add-to-list 'auto-indent-disabled-modes-list 'saltstack-mode) + (add-to-list 'auto-indent-disabled-modes-list 'nix-mode) + (auto-indent-global-mode))) +#+END_SRC + +**** TODO Check for auto-indentation of whitespace-sensitive languages. + +*** smart-tabs-mode + +Not related to [[smart-tab][=smart-tab=]], this mode indents with tabs and aligns +with spaces. Perfect! + +#+BEGIN_SRC emacs-lisp +(req-package smart-tabs-mode + :commands (smart-tabs-mode + smart-tabs-mode-enable + smart-tabs-advice) + :config (progn + (add-hook 'php-mode-hook (lambda () + (smart-tabs-mode indent-tabs-mode))) + (smart-tabs-insinuate 'c 'javascript 'cperl 'python))) +#+END_SRC + +** Security + +*** password-store + +This is a frontend to the GPG-powered =pass= program. +#+BEGIN_SRC emacs-lisp +(req-package password-store + :config (progn + (setq password-store-password-length 16))) +#+END_SRC +** Buffers + +*** Ibuffer +Ibuffer is quite nice for listing all buffers. I don’t use it very +often though, as it doesn’t really work with perspectives. + +#+BEGIN_SRC emacs-lisp +(req-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 + +*** Uniqify + +Sometimes projects have files with the same name. This gives them +unique names, by adding enough path elements to make them unambiguous. + +#+BEGIN_SRC emacs-lisp +(req-package uniquify + :config (progn + (setq uniquify-buffer-name-style 'forward + uniquify-separator "/" + uniquify-after-kill-buffer-p t + uniquify-ignore-buffers-re "^\\*"))) +#+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 + +*** Fancy Narrow + +Sometimes I like to be able to focus on one block of code at a time. +Normally narrowing hides everything else completely, which I don’t +like. This package just makes everything else lower-contrast. +#+BEGIN_SRC emacs-lisp +(req-package fancy-narrow + :diminish fancy-narrow-mode + :config (fancy-narrow-mode 1)) +#+END_SRC + +*** ace-jump-buffer + +#+BEGIN_SRC emacs-lisp +(use-package ace-jump-buffer + :bind ("s-b" . ace-jump-buffer)) +#+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 +(req-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 100) +(if (eq system-type 'darwin) + (setq ns-pop-up-frames nil)) +#+END_SRC + +A dedicated window always keeps the same buffer in view. + +#+BEGIN_SRC emacs-lisp +(defun toggle-window-dedicated () + "Toggle whether the current active window is dedicated or not" + (interactive) + (message + "Window '%s' is %s" + (current-buffer) + (if (let ((window (get-buffer-window (current-buffer)))) + (set-window-dedicated-p window + (not (window-dedicated-p window)))) + "dedicated" + "normal"))) +#+END_SRC + +*** popwin + +This works really nicely wiht helm. I should think about whether it +might be useful elsewhere + +#+BEGIN_SRC emacs-lisp +(req-package popwin + :if (and (>= emacs-major-version 24) + (> emacs-minor-version 3)) + :config (progn + (popwin-mode 1) + (add-to-list 'popwin:special-display-config '("^*helm.+*$" :regexp t :height 20)))) +#+END_SRC + +*** winner + +Undo, for window-based commands. + +#+BEGIN_SRC emacs-lisp +(req-package winner + :init (progn + (winner-mode 1) + (setq winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))) +#+END_SRC + +*** windmove + +Directional window movement + +#+BEGIN_SRC emacs-lisp +(req-package windmove + :bind (("S-" . windmove-left) + ("S-" . windmove-right) + ("S-" . windmove-up) + ("S-" . windmove-down))) +#+END_SRC +** Completion + +Make built-in completion a bit more intelligent, by adding substring +and initial-based completion and ignoring case. + +** TODO With =tab-always-indent=, do I need smart-tab anymore? + +#+BEGIN_SRC emacs-lisp + (setq completion-styles '(basic initials partial-completion substring) + completion-ignore-case t + tab-always-indent 'complete) +#+END_SRC + +*** Smart-tab + +Most editors use tab for both completion and indentation. Smart-tab +tries to do the right thing depending on the location of the point and +the line’s current indentation. + +#+BEGIN_SRC emacs-lisp +(req-package smart-tab + :commands (global-smart-tab-mode) + :init (global-smart-tab-mode) + :diminish smart-tab-mode + :config (progn + (nconc smart-tab-completion-functions-alist '((php-mode . php-complete-function))) + (diminish 'smart-tab-mode ""))) +#+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 +(req-package company + :commands (company-mode) + :diminish "Cmpl" + :bind (("C-" . company-complete)) + :init (progn + (add-hook 'prog-mode-hook #'company-mode) + (setq company-backends '(company-tern (php-extras-company company-elisp company-bbdb company-nxml company-css company-eclim company-semantic company-clang company-xcode company-cmake company-capf company-gtags company-dabbrev-code company-etags company-keywords) + company-oddmuse company-files company-dabbrev) + 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-dabbrev-downcase nil))) +#+END_SRC + +** Dates & Times + +*** Calendar + +Weeks start on Monday for me and I prefer ISO-style dates. +#+BEGIN_SRC emacs-lisp +(req-package calendar + :defer t + :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 + +** 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 +(req-package dired + :defer t + :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 'top + dired-listing-switches "-alh" + dired-bind-jump nil) + (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 + +I work with a lot of git projects. Dired-k adds colours based upon +the file’s git status. +#+BEGIN_SRC emacs-lisp +(req-package dired-k + :require dired + :init (progn + (add-hook 'dired-initial-position-hook #'dired-k)) + :config (progn + (setq dired-k-human-readable t) + (bind-key "g" #'dired-k dired-mode-map))) +#+END_SRC + + +Don’t show uninteresting files in dired listings. + +#+BEGIN_SRC emacs-lisp + (req-package dired-x + :require dired + :config (progn + (defun turn-on-dired-omit-mode () + (interactive) + (dired-omit-mode 1)) + (add-hook 'dired-mode-hook #'turn-on-dired-omit-mode) + (setq dired-omit-files "#\\|\\.$" + dired-omit-verbose nil + dired-find-subdir t))) +#+END_SRC + +#+BEGIN_SRC emacs-lisp + (req-package dired+ + :require dired + :config (progn + (diredp-toggle-find-file-reuse-dir 1) + (unbind-key "C-h C-m" dired-mode-map) + (bind-key "." #'diredp-describe-file dired-mode-map))) +#+END_SRC + +Expand subfolders like a tree inside the parent + +#+BEGIN_SRC emacs-lisp +(req-package dired-subtree + :defer t + :require dired + :config (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)) + :init (progn + (bind-key "i" #'dired-subtree-toggle dired-mode-map))) +#+END_SRC + +** Documentation + +*** helm-dash + +Emacs’ documentation is great to read from inside Emacs. Helm-dash +helps to make documentation for other languages easier to access + +#+BEGIN_SRC emacs-lisp +(req-package helm-dash + :defer t + :init (progn + (defmacro ap/create-helm-dash-hook (mode docsets) + (let* ((mode-s (symbol-name mode)) + (fun (intern (concat "helm-dash-hook-" mode-s))) + (hook (intern (concat mode-s "-mode-hook")))) + `(progn + (defun ,fun () + (when (require 'helm-dash nil :noerror) + (-each (-difference ',docsets + (helm-dash-installed-docsets)) + #'helm-dash-install-docset) + (setq-local helm-dash-docsets ',docsets))) + (add-hook (quote ,hook) (function ,fun))))) + (ap/create-helm-dash-hook nginx ("Nginx")) + (ap/create-helm-dash-hook ansible ("Ansible")) + (ap/create-helm-dash-hook php ("PHP" "Symfony")) + (ap/create-helm-dash-hook twig ("Twig")) + (ap/create-helm-dash-hook js2 ("JavaScript" "NodeJS" "jQuery" "Express")) + (ap/create-helm-dash-hook markdown ("Markdown")) + (ap/create-helm-dash-hook saltstack ("SaltStack")) + (ap/create-helm-dash-hook clojure ("Clojure")) + (ap/create-helm-dash-hook sql ("PostgreSQL" "MySQL")))) +#+END_SRC + +*** which-func + +Use the modeline to show which function definition the point is in. + +#+BEGIN_SRC emacs-lisp +(req-package which-func + :init (which-function-mode) + :config (setq which-func-modes t)) +#+END_SRC + +*** discover-my-major + +A nicer way to browse keybindings for major modes. + +#+BEGIN_SRC emacs-lisp +(req-package discover-my-major + :bind ("C-h C-m" . discover-my-major)) +#+END_SRC + +*** discover + +Makes some context menus for dired and other things, similarly to the +way magit’s popups work. + +#+BEGIN_SRC emacs-lisp +(req-package discover + :config (global-discover-mode)) +#+END_SRC + +*** eldoc + +Documentation in the echo-area (where the minibuffer is displayed) is +rather useful. + +#+BEGIN_SRC emacs-lisp +(req-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 +** 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) + (setq mac-option-modifier 'meta + mac-right-option-modifier 'left + mac-control-modifier 'control + mac-right-control-modifier 'left + mac-command-modifier 'super + mac-right-command-modifier 'left + mac-function-modifier 'hyper)) +#+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) + (set-register ?z `(file . ,(expand-file-name ".config/zsh/zshrc" "~"))) +#+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*)) + + (req-package whitespace + :defer t + :config (setq whitespace-style + '(face + space + tabs + trailing + newline + empty + tab-mark + space-before-tab + indentation + indentation::space + indentation::tabs))) + + (req-package ap-functions + :commands (ap/remove-extra-cr) + :bind (("C-x r M-w" . copy-rectangle) + ("M-!" . shell-execute))) +#+END_SRC + +Some stuff for getting around my =init.el=. Now that I’m using +=org-mode=, I’ll probably need to write something else, or fiddle with +org’s navigation commands. + +#+BEGIN_SRC emacs-lisp +(defun imenu-elisp-sections () + (setq imenu-prev-index-position-function nil) + (add-to-list 'imenu-generic-expression '("Sections" "^;;;; \\(.+\\)$" 1) t) + (add-to-list 'imenu-generic-expression '("Packages" "^(req-package\\s-+\\(\\(\\sw\\|\\s_\\)+\\)$" 1) t)) + +(defun init-narrow-to-section () + (interactive) + (save-excursion + (beginning-of-line) + (unless (looking-at "^;;;;") + (re-search-backward "^;;;;" nil t)) + (push-mark) + (forward-line) + (re-search-forward "^;;;;" nil t) + (forward-line -1) + (narrow-to-region (region-beginning) (region-end)))) + +(defun init-imenu (p) + (interactive "P") + (find-file-existing *init-file*) + (widen) + (helm-imenu) + (if p (init-narrow-to-section))) + +(add-hook 'emacs-lisp-mode-hook 'imenu-elisp-sections) +#+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 + +*** helm + +I like to use =helm= for some completions, especially when there are +lots of candidates. + +#+BEGIN_SRC emacs-lisp + (req-package helm-config + :demand t + :ensure helm + :bind (("C-x i" . helm-semantic-or-imenu)) + :config (progn + (setq helm-idle-delay .1 + helm-input-idle-delay 0) + (when (fboundp #'helm-adaptive-mode) + (helm-adaptive-mode 1)))) + + (req-package helm-files + :defer t + :config (progn + (define-key helm-read-file-map (kbd "") #'helm-execute-persistent-action) + (define-key helm-read-file-map (kbd "TAB") #'helm-execute-persistent-action) + (define-key helm-read-file-map (kbd "C-i") #'helm-execute-persistent-action) + (define-key helm-read-file-map (kbd "C-z") #'helm-select-action))) +#+END_SRC + +*** ido + +I really like ido. It’s part of emacs, it does flex matching nicely +and it’s pretty configurable. + +#+BEGIN_SRC emacs-lisp +(req-package ido + :bind (("C-x b" . ido-switch-buffer)) + :init (progn + (setq ido-save-directory-list-file (expand-file-name "ido-state" user-emacs-directory)) + (bind-key* "C-x C-f" #'ido-find-file) + (ido-mode 1) + (ido-everywhere 1)) + :config (progn + (setq ido-auto-merge-delay-time 99999 + ido-enable-flex-matching t) + + (ido-init-completion-maps) + (defadvice ido-find-file (after find-file-sudo activate) + "Find file as root if necessary." + (unless (and buffer-file-name + (file-writable-p buffer-file-name)) + (find-alternate-file (concat "/sudo::" buffer-file-name)))) + (defun ido-manual-merge () + (interactive) + (ido-initiate-auto-merge (current-buffer))) + (bind-key "C-c C-s" #'ido-manual-merge ido-file-dir-completion-map))) +#+END_SRC + +**** TODO Figure out whether the merge stuff is useful. + +**** ido-completing-read+ + +This is mostly a dependency of =magit=. +#+BEGIN_SRC emacs-lisp +(req-package ido-completing-read+ + :require ido + :config (progn + (setq ido-cr+-fallback-function #'helm-completing-read + ido-cr+-max-items 2000))) +#+END_SRC + +***** TODO See if I can use ido-completing-read+ in ido places +This would be good for finding files in projects. + +***** Buffer switching within projects + +#+BEGIN_SRC emacs-lisp +(defun ap/ido-projectile-switch-buffer-dwim (force-ido) + (interactive "p") + (if (and (projectile-project-p) (eq force-ido 1)) + (call-interactively #'projectile-switch-to-buffer) + (call-interactively #'ido-switch-buffer))) + +(bind-key "s-x b" #'ap/ido-projectile-switch-buffer-dwim) +(bind-key "s-x s-b" #'ap/ido-projectile-switch-buffer-dwim) +#+END_SRC + +**** ido-vertical-mode + +I find ido’s default horizonal presentation of completion candidates +to be a little difficult to follow. Of course, there’s always a +package for that. + +#+BEGIN_SRC emacs-lisp +(req-package ido-vertical-mode + :require ido + :init (progn + (setq ido-vertical-decorations '("\n❯ " + "" + "\n " + "\n …" + "[" + "]" + " [No match]" + " [Matched]" + " [Not readable]" + " [Too big]" + " [Confirm]" + "\n❯ " + "") + ido-vertical-define-keys 'C-n-C-p-up-down-left-right)) + :config (ido-vertical-mode 1)) +#+END_SRC + +**** flx-ido + +I think ido’s flex matching could be a bit better, so I use =flx-ido= +for that. It can be slow on large collectinos, but fortunately it can +disable itself at that point + +#+BEGIN_SRC emacs-lisp +(req-package flx-ido + :require ido + :init (progn + (flx-ido-mode 1) + (setq flx-ido-threshold 1000))) +#+END_SRC + +*** smex + +Smex is my favourite way to use =M-x=. I might try setting up =helm= +again, to see whether it’s any better or not. + +#+BEGIN_SRC emacs-lisp +(req-package smex + :require ido + :bind (("M-x" . smex) + ("" . smex) + ("" . smex) + ("M-X" . smex-major-mode-commands) + ("C-c M-x" . execute-extended-command)) + :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")) + (smex-initialize))) +#+END_SRC + +** Modeline + +I modified the mode-line format to show me less information. Instead, +I put some of it in the frame-line at the top. + +#+BEGIN_SRC emacs-lisp + (column-number-mode t) + (size-indication-mode t) + + (defun fill-line-format (line-format) + (max 0 + (- (window-width) + (length (format-mode-line line-format))))) + + (defvar mode-line-size + `((size-indication-mode + ((-3 ,(propertize + "%p" + 'local-map mode-line-column-line-number-mode-map + 'mouse-face 'mode-line-highlight + ;; XXX needs better description + 'help-echo "Size indication mode\n\ + mouse-1: Display Line and Column Mode Menu")) + " " + (-4 "%I"))))) + + (setq-default + mode-line-modes (let ((recursive-edit-help-echo "Recursive edit, type C-M-c to get out")) + (list (propertize "%[" 'help-echo recursive-edit-help-echo) + `(:propertize ("" mode-name) + help-echo "Major mode\n\ + mouse-1: Display major mode menu\n\ + mouse-2: Show help for major mode\n\ + mouse-3: Toggle minor modes" + mouse-face mode-line-highlight + local-map ,mode-line-major-mode-keymap) + '("" mode-line-process) + `(:propertize ("" minor-mode-alist) + mouse-face mode-line-highlight + help-echo "Minor mode\n\ + mouse-1: Display minor mode menu\n\ + mouse-2: Show help for minor mode\n\ + mouse-3: Toggle minor modes" + local-map ,mode-line-minor-mode-keymap) + (propertize "%n" 'help-echo "mouse-2: Remove narrowing from buffer" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map + 'mouse-2 #'mode-line-widen)) + (propertize "%]" 'help-echo recursive-edit-help-echo) + " ")) + mode-line-buffer-identification (list (propertize "%b" + 'face 'mode-line-buffer-id)) + + mode-line-position `((line-number-mode + ((column-number-mode + ,(propertize + "%l:%c" + 'local-map mode-line-column-line-number-mode-map + 'mouse-face 'mode-line-highlight + 'help-echo "Line number and Column number\n\ + mouse-1: Display Line and Column Mode Menu") + (6 ,(propertize + "L%l" + 'local-map mode-line-column-line-number-mode-map + 'mouse-face 'mode-line-highlight + 'help-echo "Line Number\n\ + mouse-1: Display Line and Column Mode Menu")))) + ((column-number-mode + (5 ,(propertize + "C%c" + 'local-map mode-line-column-line-number-mode-map + 'mouse-face 'mode-line-highlight + 'help-echo "Column number\n\ + mouse-1: Display Line and Column Mode Menu")))))) + mode-line-format `("%e" + " " + mode-line-modes + mode-line-misc-info + (vc-mode vc-mode) + mode-line-end-spaces) + header-line-format `("%e" + mode-line-front-space + mode-line-mule-info + mode-line-client + mode-line-modified + mode-line-auto-compile + mode-line-remote " " + mode-line-position " " + mode-line-size + " ⎸ " + mode-line-buffer-identification + )) + + (setq frame-title-format + '((:eval (if (and (fboundp #'projectile-project-p) + (projectile-project-p)) + (projectile-project-name))) + ": " + (:eval (if (buffer-file-name) + (buffer-name) + "%b")))) +#+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 + (req-package xrdb-mode + :mode (("\\.Xdefaults\\'" . xrdb-mode) + ("\\.Xresources\\'" . xrdb-mode))) + + (req-package haskell-mode + :mode (("\\.hs\\'" . haskell-mode))) + + (req-package nix-mode + :mode (("\\.nix\\'" . nix-mode)) + :config (progn + (setq-local indent-tabs-mode nil))) + + (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)) + + (req-package nginx-mode + :defer t + :mode (("/nginx/servers/" . nginx-mode) + ("/nginx/.*\\.d/" . nginx-mode)) + :config (progn + (setq nginx-indent-tabs-mode t))) + + (req-package lua-mode + :defer t) + + (req-package ruby-mode + :mode (("\\.rb\\'" . ruby-mode) + ("\\.cap\\'" . ruby-mode))) + + (req-package go-mode + :mode (("\\.go\\'" . go-mode))) + + (req-package jinja2-mode + :mode (("\\.j2\\'" . jinja2-mode) + ("\\.jinja\\'" . jinja2-mode))) + + (req-package scss-mode + :defer t + :config (progn + (setq scss-compile-at-save nil))) + + (req-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 +(req-package ledger-mode + :mode ("\\.ledger\\'" . ledger-mode) + :config (progn + (defun setup-ledger-mode () + (setq-local indent-tabs-mode nil)) + (add-hook 'ledger-mode-hook #'setup-ledger-mode) + (add-to-list 'smart-tab-disabled-major-modes 'ledger-mode) + (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-default-date-format "%Y-%m-%d"))) +#+END_SRC + +**** Markdown + +#+BEGIN_SRC emacs-lisp +(req-package markdown-mode + :defer t + :config (progn + (add-hook 'markdown-mode-hook #'turn-on-auto-fill))) +#+END_SRC + +*** Org + +Org is wünderbar. + +**** TODO Check whether all this configuration is necessary or helpful. + +#+BEGIN_SRC emacs-lisp +(req-package org + :bind (("C-c C-a" . org-agenda-list) + ("C-c a" . org-agenda) + ("C-c l" . org-store-link)) + :init (setq org-replace-disputed-keys t) + :config (progn + (setq org-directory "~/org" + org-agenda-files `(,org-directory) + + org-default-notes-file (concat org-directory "/notes") + + ;; ‘Remember’: new items at top + org-reverse-note-order t + + org-modules '(org-habit + org-checklist) + + ;; Add time done to ‘done’ tasks + org-log-done 'time + + ;; Allow refiling into any org file + org-refile-targets '((org-agenda-files :maxlevel . 3)) + + org-list-allow-alphabetical t + + org-pretty-entities t + + org-table-duration-custom-format 'seconds + + org-src-fontify-natively t + + org-export-have-math t + + org-blank-before-new-entry '((heading . t) + (plain-list-item . auto)) + org-fontify-done-headline t + + org-todo-keywords '((sequence "TODO" "STARTED" "|" "DONE") + (sequence "TOLEARN" "LEARNING" "LEARNED" "|" "MASTERED") + (sequence "|" "CANCELLED"))) + (set-register ?o `(file . ,(expand-file-name "organiser.org" org-directory))) + (add-hook 'org-mode-hook #'turn-on-auto-fill) + (defadvice org-clock-in (after wicked activate) + "Mark STARTED when clocked in" + (save-excursion + (catch 'exit + (org-back-to-heading t) + (if (looking-at org-outline-regexp) (goto-char (1- (match-end 0)))) + (if (looking-at (concat " +" org-todo-regexp "\\( +\\|[ \t]*$\\)")) + (org-todo "STARTED"))))))) +#+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 +(req-package org-babel + :require org + :defer t + :config (org-babel-do-load-languages + 'org-babel-load-languages + '((ledger . t) + (sh . t)))) +#+END_SRC + +***** org-journal + +I can use this to keep a journal. I should use it. + +#+BEGIN_SRC emacs-lisp +(req-package org-journal + :require org + :defer t + :config (progn + (setq org-journal-date-format "%A, %d %B %Y"))) +#+END_SRC + +***** org-mobile + +****** TODO Setup org-mobile +#+BEGIN_SRC emacs-lisp +(req-package org-mobile + :require org + :defer t + :config (progn + (setq org-mobile-directory "~/Mobile/Org"))) +#+END_SRC + +** Programming +*** cedet + +**** TODO Setup cedet and see whether it’s useful + +#+BEGIN_SRC emacs-lisp +(req-package cedet + :disabled t + :config (progn + (semantic-load-enable-code-helpers) + (global-semantic-idle-completions-mode t) + (global-semantic-highlight-func-mode t) + (global-semantic-show-unmatched-syntax-mode t) + (global-semantic-decoration-mode t))) +#+END_SRC + +*** flycheck + +On-the-fly error checking in programming modes? Yes please. + +#+BEGIN_SRC emacs-lisp +(req-package flycheck + :diminish " ✓" + :init (global-flycheck-mode)) +#+END_SRC + +*** golang + +Go has a few packages to inter-operate with other emacs packages. + +#+BEGIN_SRC emacs-lisp +(when (file-exists-p "src/code.google.com/p/go.tools/cmd/oracle/oracle.el") + (req-package oracle + :load-path ,(expand-file-name "src/code.google.com/p/go.tools/cmd/oracle/oracle.el" (getenv "GOPATH")) + :init (progn + (add-hook 'go-mode-hook #'go-oracle-mode)))) + +(req-package company-go + :require go-mode + :config (progn + (setq company-go-show-annotation t) + (defun ap/company-go-setup () + (set (make-local-variable 'company-backends) + '(company-go))) + (add-hook 'go-mode-hook #'ap/company-go-setup))) + +(req-package go-eldoc + :require go-mode + :config (progn + (add-hook 'go-mode-hook #'go-eldoc-setup))) + +(req-package go-projectile + :require (go-mode go-eldoc projectile) + :config (progn + (setq go-projectile-switch-gopath 'maybe))) + + +#+END_SRC + +*** ggtags + +A nice completion backend for programming modes. + +#+BEGIN_SRC emacs-lisp +(req-package ggtags + :commands turn-on-ggtags-mode + :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 + +*** 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. Of course, no tabs in +lisps. Even I understand that. + +#+BEGIN_SRC emacs-lisp + (defcustom lisp-mode-common-hook nil + "Hook run when entering any Lisp mode." + :type 'hook + :group 'lisp) + + (defun ap/lisp-setup () + (run-hooks 'lisp-mode-common-hook) + (setq indent-tabs-mode nil)) +#+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 +(req-package redshank + :diminish " Λ" + :defer t + :init (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 +(rename-modeline emacs-lisp-mode "ξ") +(add-to-list 'auto-mode-alist '("/Cask\\'" . emacs-lisp-mode)) +(add-hook 'emacs-lisp-mode-hook #'ap/lisp-setup) +(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 + (req-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 +(req-package ielm + :defer t + :config (progn + (add-hook 'ielm-mode-hook (lambda () + (run-hooks 'lisp-mode-common-hook))))) +#+END_SRC + +I don’t only use this in elisp. It’s nice to do calculations in other +buffers too: it’s faster than quickrun and the parens mean that I +don’t have to worry about a selection. + +#+BEGIN_SRC emacs-lisp +(defun eval-and-replace () + "Replace the preceding sexp with its value." + (interactive) + (backward-kill-sexp) + (condition-case nil + (prin1 (eval (read (current-kill 0))) + (current-buffer)) + (error (message "Invalid expression") + (insert (current-kill 0))))) + +(bind-key "C-c e" #'eval-and-replace) +#+END_SRC + +**** Scheme & Lisp + +I don’t work with these as often as I would like + +#+BEGIN_SRC emacs-lisp + (add-hook 'scheme-mode-hook #'ap/lisp-setup) + (add-hook 'lisp-mode-hook #'ap/lisp-setup) + (defun set-common-lisp-indentation () + (set (make-local-variable 'lisp-indent-function) + #'common-lisp-indent-function)) + (add-hook 'lisp-mode-hook #'set-common-lisp-indentation) +#+END_SRC + +***** geiser + +A REPL thing for Scheme. Hopefully I’ll get to use it more in the +future. + +#+BEGIN_SRC emacs-lisp +(req-package geiser + :commands (geiser-mode + geiser + run-geiser + run-racket)) +#+END_SRC + +***** slime + +A REPL thing (and more) for Lisp. + +#+BEGIN_SRC emacs-lisp +(req-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)) + (setq inferior-lisp-program (executable-find "sbcl")))) +#+END_SRC + +**** Clojure + +#+BEGIN_SRC emacs-lisp +(req-package clojure-mode + :defer t + :init (progn + (add-hook 'cider-repl-mode-hook (lambda () (highlight-changes-mode -1))) + (add-hook 'clojure-mode-hook #'ap/lisp-setup))) + +(req-package clj-refactor + :defer t + :require clojure-mode + :config (progn + (cljr-add-keybindings-with-prefix "C-c C-m")) + :init (progn + (defun turn-on-clj-refactor-mode () + (clj-refactor-mode 1)) + (add-hook 'clojure-mode-hook #'turn-on-clj-refactor-mode))) +#+END_SRC + +***** cider + +A REPL thing for Clojure + +#+BEGIN_SRC emacs-lisp +(req-package cider + :require clojure-mode + :defer t + :config (progn + (setq nrepl-hide-special-buffers t) + (unbind-key "C-c C-f" cider-mode-map) + (add-hook 'cider-mode-hook #'cider-turn-on-eldoc-mode))) +#+END_SRC + +*** Auto-compile + +Auto-compile emacs lisp when saving. +#+BEGIN_SRC emacs-lisp +(req-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 +(req-package cc-mode + :defer t + :init (progn + (add-hook 'c-mode-common-hook #'electric-indent-mode)) + :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 +(req-package quickrun + :bind (("C-c C-e" . quickrun))) +#+END_SRC + +*** Web development + +**** skewer-mode + +I don’t use this as often as I probably should. I should figure out +why that is. +#+BEGIN_SRC emacs-lisp +(req-package skewer-mode + :defer t + :init (progn + (add-hook 'js2-mode-hook #'skewer-mode) + (add-hook 'html-mode-hook #'skewer-html-mode) + (add-hook 'css-mode-hook #'skewer-css-mode))) +#+END_SRC + +**** 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. I don’t +think there’s anything as good as paredit/redshank for refactoring in +it though + +#+BEGIN_SRC emacs-lisp + (req-package js2-mode + :mode ("\\.js\\'" . js2-mode) + :config (progn + (defun ap/javascript-setup () + (autopair-mode -1) + (auto-indent-mode -1)) + (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) + (add-hook 'js2-mode-hook #'ap/javascript-setup) + (setq js2-basic-offset 4 + js2-include-node-externs t))) + + (add-to-list 'auto-mode-alist '("composer\\.lock" . js-mode)) +#+END_SRC + +**** tern + +Tern understands javascript. It adds really clever documented +completions, besides other IDE-like things. + +#+BEGIN_SRC emacs-lisp + (req-package tern + :commands ap/enable-tern + :config (progn + (setq tern-command (list (executable-find "tern"))) + (defun ap/enable-tern () + (tern-mode 1)) + (add-hook 'js2-mode-hook #'ap/enable-tern))) + + (req-package tern-company + :require (tern company)) +#+END_SRC + +**** json-mode + +#+BEGIN_SRC emacs-lisp +(req-package json-mode + :mode ("\\.json\\'" . 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 +(req-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))) +#+END_SRC + +**** sgml-mode + +This is for HTML, since old versions of HTML were derived from SGML. +#+BEGIN_SRC emacs-lisp +(req-package sgml-mode + :defer t + :config (setq sgml-basic-offset 4)) +#+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 +(req-package emmet-mode + :commands (emmet-mode) + :diminish (emmet-mode . " >") + :init (progn + (if (functionp 'web-mode) + (add-hook 'web-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 +(req-package web-mode + :mode (("/views/.*\\.php\\'" . web-mode) + ("/layouts/.*\\.html\\'" . web-mode) + ("/templates/.*\\.php\\'" . web-mode) + ("\\.ejs\\'" . web-mode)) + :config (setq web-mode-code-indent-offset 4 + web-mode-css-indent-offset 4 + web-mode-markup-indent-offset 4 + web-mode-style-padding 0 + web-mode-script-padding 0 + web-mode-comment-style 2 + web-mode-enable-auto-pairing nil)) +#+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 + +**** mmm-mode + +With =web-mode= being so good, I don’t really use this much. It’s +good for embedded SQL though. + +#+BEGIN_SRC emacs-lisp +(req-package mmm-auto + :config (progn + (mmm-add-classes + '((php-sql + :submode sql-mode + :front "<<" . ispell-word)) + :config (progn + (setq ispell-program-name "aspell" + ispell-dictionary "british"))) +#+END_SRC + +**** TODO Set up some functions to switch between en-GB and de-DE + +** 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) + +(req-package sh-script + :mode (("\\.zsh\\'" . shell-script-mode)) + :config (setq sh-shell-file "/usr/bin/env zsh")) +#+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 +(req-package eshell + :bind ("C-c s" . eshell) + :config (progn + (setq eshell-directory-name "~/.emacs.d/eshell") + (add-hook 'eshell-load-hook (lambda () + (bind-key "C-c C-l" #'helm-eshell-history eshell-mode-map))) + (req-package em-smart + :config (progn + (setq eshell-where-to-jump 'begin + eshell-review-quick-commands nil + eshell-smart-space-goes-to-end t) + (eshell-smart-initialize))))) + +(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 +(req-package shell + :defer t + :config (define-key shell-mode-map + (kbd "C-d") 'comint-delchar-or-eof-or-kill-buffer)) + +(req-package comint + :defer t + :config (bind-key "C-c C-l" #'helm-comint-input-ring comint-mode-map)) + +(req-package multi-term + :if (not (eq system-type 'windows-nt)) + :bind ("C-`" . multi-term-dedicated-toggle)) + +(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 + +**** TODO Do I need multi-term? + +** 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) +#+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 +(req-package align + :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 x-select-enable-clipboard 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 + (delete-selection-mode t) +#+END_SRC + +Isearch has a keybind for searching for the currently-selected word. + I often want to use a symbol though, so this comes in handy. [[http://blog.jorgenschaefer.de/2012/11/emacs-search-for-symbol-at-point.html][Source]] + +#+BEGIN_SRC emacs-lisp +(defun fc/isearch-yank-symbol () + "Yank the symbol at point into the isearch minibuffer. + +C-w does something similar in isearch, but it only looks for +the rest of the word. I want to look for the whole string. And +symbol, not word, as I need this for programming the most." + (interactive) + (isearch-yank-string + (save-excursion + (when (and (not isearch-forward) + isearch-other-end) + (goto-char isearch-other-end)) + (thing-at-point 'symbol)))) +(bind-key "C-d" #'fc/isearch-yank-symbol isearch-mode-map) +#+END_SRC + +Sub-word movement is really nice for camel- and Pascal-case + +#+BEGIN_SRC emacs-lisp +(req-package subword + :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 +(req-package misc + :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 +(req-package expand-region + :bind ("C-M-SPC" . er/expand-region)) +#+END_SRC + +*** Typography + +I like using typographic symbols, but I don’t always remember (how) to +type them. + +#+BEGIN_SRC emacs-lisp +(req-package typopunct + :config (progn + (typopunct-change-language 'english t) + (defconst typopunct-minus (decode-char 'ucs #x2212)) + (defadvice typopunct-insert-typographical-dashes + (around minus-or-pm activate) + (cond + ((or (eq (char-before) typopunct-em-dash) + (looking-back "\\([[:blank:]]\\|^\\)\\^")) + (delete-char -1) + (insert typopunct-minus)) + ((looking-back "[^[:blank:]]\\^") + (insert typopunct-minus)) + (t ad-do-it))) + + (defconst typopunct-ellipsis (decode-char 'ucs #x2026)) + (defconst typopunct-middot (decode-char 'ucs #xB7)) ; or 2219 + (defun typopunct-insert-ellipsis-or-middot (arg) + "Change three consecutive dots to a typographical ellipsis mark." + (interactive "p") + (cond + ((and (= 1 arg) + (eq (char-before) ?^)) + (delete-char -1) + (insert typopunct-middot)) + ((and (= 1 arg) + (eq this-command last-command) + (looking-back "\\.\\.")) + (replace-match "") + (insert typopunct-ellipsis)) + (t + (self-insert-command arg)))) + (define-key typopunct-map "." 'typopunct-insert-ellipsis-or-middot) + + (defconst typopunct-times (decode-char 'ucs #xD7)) + (defun typopunct-insert-times (arg) + (interactive "p") + (if (and (= 1 arg) (looking-back "\\([[:blank:]]\\|^\\)\\^")) + (progn (delete-char -1) + (insert typopunct-times)) + (self-insert-command arg))) + (define-key typopunct-map "x" 'typopunct-insert-times) + + (defadvice typopunct-insert-quotation-mark (around wrap-region activate) + (let* ((lang (or (get-text-property (point) 'typopunct-language) + typopunct-buffer-language)) + (omark (if single + (typopunct-opening-single-quotation-mark lang) + (typopunct-opening-quotation-mark lang))) + (qmark (if single + (typopunct-closing-single-quotation-mark lang) + (typopunct-closing-quotation-mark lang)))) + (cond + (mark-active + (let ((skeleton-end-newline nil) + (singleo (typopunct-opening-single-quotation-mark lang)) + (singleq (typopunct-closing-single-quotation-mark lang))) + (if (> (point) (mark)) + (exchange-point-and-mark)) + (save-excursion + (while (re-search-forward (regexp-quote (string omark)) (mark) t) + (replace-match (regexp-quote (string singleo)) nil nil))) + (save-excursion + (while (re-search-forward (regexp-quote (string qmark)) (mark) t) + (replace-match (regexp-quote (string singleq)) nil nil))) + (skeleton-insert (list nil omark '_ qmark) -1))) + ((looking-at (regexp-opt (list (string omark) (string qmark)))) + (forward-char 1)) + (t ad-do-it))))) + :init (progn + (add-hook 'text-mode-hook #'typopunct-mode))) +#+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 +(req-package avy + :bind* (("M-g g" . avy-goto-line) + ("M-g M-g" . avy-goto-line) + ("C-|" . avy-goto-line) + ("C-c SPC" . avy-goto-char)) + :config (progn + (avy-setup-default) + (setq avy-all-windows nil))) +#+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 +(req-package goto-chg + :bind ("C-x SPC" . goto-last-change)) +#+END_SRC + +*** helm-swoop + +This fits somewhere between isearch and grep. For me, I didn’t +realise how useful it was until I actually tried it. + +#+BEGIN_SRC emacs-lisp +(req-package helm-swoop + :bind (("C-=" . helm-swoop) + ("C-c C-=" . helm-multi-swoop)) + :init (progn + (bind-key "C-=" #'helm-swoop isearch-mode-map) + (bind-key "C-=" #'helm-multi-swoop-all-from-helm-swoop))) +#+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 +(req-package multiple-cursors + :defer 1 + :config (progn + (bind-key "C-." #'mc/mark-next-like-this) + (bind-key "C-," #'mc/mark-previous-like-this) + (bind-key "M-" #'mc/mark-all-like-this-dwim) + (bind-key "C-" #'mc/mark-more-like-this-extended) + (bind-key "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 +(req-package paredit + :diminish "()" + :commands (paredit-mode) + :init (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 'minibuffer-setup-hook #'conditionally-enable-paredit-mode) + (defun conditionally-enable-paredit-mode () + "enable paredit-mode during eval-expression" + (if (eq this-command 'eval-expression) + (paredit-mode 1))))) +#+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 +(req-package smartparens-config + :config (progn + (sp-use-smartparens-bindings) + (fset 'wrap-with-paren "\C-](") ;; `sp-select-next-thing-exchange' + (bind-key "C-(" #'wrap-with-paren sp-keymap) + (bind-key "C-)" #'sp-forward-slurp-sexp sp-keymap) + (bind-key "M-" #'backward-kill-word sp-keymap) + (bind-key "M-?" #'sp-convolute-sexp sp-keymap) + (bind-key "C-M-t" #'sp-transpose-sexp sp-keymap) + (bind-key "M-r" #'sp-raise-sexp sp-keymap) + (bind-key "M-s" #'sp-splice-sexp sp-keymap) + (bind-key "M-S" #'sp-split-sexp sp-keymap) + (bind-key "M-J" #'sp-join-sexp sp-keymap) + (bind-key "M-" #'sp-splice-sexp-killing-backward sp-keymap) + (bind-key "M-" #'sp-splice-sexp-killing-forward sp-keymap) + (bind-key "C-M-S-k" #'sp-kill-hybrid-sexp sp-keymap) + (bind-key "C-S-" #'sp-slurp-hybrid-sexp sp-keymap) + (sp-with-modes '(web-mode 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))) +#+END_SRC + +*** move-text + +Transposing lines, made easier. + +#+BEGIN_SRC emacs-lisp +(req-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 +(req-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 + +*** 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 +(req-package visual-regexp + :bind (("C-c r" . vr/replace) + ("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. + +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 + (defun tangle-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)) + ;; Avoid running hooks when tangling. + (let ((prog-mode-hook nil)) + (org-babel-tangle) + (byte-compile-file (concat user-emacs-directory "init.el"))))) +#+END_SRC + +# Local Variables: +# eval: (when (fboundp #'tangle-init) (add-hook 'after-save-hook #'tangle-init)) +# End: +* End + +#+BEGIN_SRC emacs-lisp +(req-package-finish) +#+END_SRC + +Start a server if possible. A daemon is already a server. +#+BEGIN_SRC emacs-lisp +(unless (daemonp) + (require 'server) + (if (server-running-p server-name) + (message "Server already appears to be running") + (server-start))) +#+END_SRC -- cgit 1.4.1