;; Added by Package.el. This must come before configurations of ;; installed packages. Don't delete this line. If you don't want it, ;; just comment it out by adding a semicolon to the start of the line. ;; You may delete these explanatory comments. (require 'package) (add-to-list 'package-archives (cons "melpa-stable" "https://stable.melpa.org/packages/") t) (package-initialize) ;; Remove UI clutter. (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) (tooltip-mode -1) (set-fringe-mode 10) (setq inhibit-startup-message t) ; no splash screen (setq visible-bell t) ;; Maximize frames (add-to-list 'default-frame-alist '(fullscreen . maximized)) ;; Stop customize from writing to my init file. Who thought this was ;; a good idea? (setq custom-file "~/.emacs.d/custom.el") (defun home-file (file-name) "Prefix FILE-NAME with the current home directory." (concat (getenv "HOME") file-name)) ;;; ;;; Packages ;;; (require 'use-package) (add-to-list 'load-path (home-file "/.guix-profile/share/emacs/site-lisp")) ;;; ;;; Look and Feel ;;; (defun font-exists-p (font) "Return 't' if FONT exists." (not (null (x-list-fonts font)))) ;; Use Inconsolata font. (add-to-list 'default-frame-alist '(font . "Inconsolata-12")) (use-package doom-themes :config (load-theme 'doom-vibrant t) ;; Enable flashing mode-line on errors (doom-themes-visual-bell-config) ;; Enable custom neotree theme (all-the-icons must be installed!) (doom-themes-neotree-config) ;; Corrects (and improves) org-mode's native fontification. (doom-themes-org-config)) (use-package doom-modeline :init (doom-modeline-mode 1) :custom ((doom-modeline-irc t) (doom-modeline-irc-buffers t))) (column-number-mode t) (which-function-mode t) (add-hook 'prog-mode-hook (lambda () (display-line-numbers-mode t))) (use-package which-key :init (which-key-mode) :diminish which-key-mode :custom (which-key-idle-delay 0.3)) ;;; ;;; Dired ;;; (use-package dired-x) ;;; ;;; TRAMP ;;; (use-package tramp-sh ;; Include the current path for the system to TRAMP's remote path. ;; This is necessary for GuixSD, where the usual /usr/bin, ;; /usr/local/bin, etc. do not exist. :config (push 'tramp-own-remote-path tramp-remote-path)) ;;; ;;; Battery ;;; (use-package battery :init ;; Display battery level in modeline only if a battery is present, ;; otherwise display-battery-mode will throw an error. (when (and (boundp 'battery-status-function) (not (null battery-status-function)) (not (string-match-p "N/A" (battery-format "%B" (funcall battery-status-function))))) (display-battery-mode t))) ;;; ;;; Minibuffer and completion ;;; (use-package swiper :bind (("C-s" . swiper) ("C-r" . swiper-backward))) (use-package ivy :config (ivy-mode t) :custom ((ivy-initial-inputs-alist nil))) (use-package ivy-rich :init (ivy-rich-mode 1)) (use-package counsel :bind (("M-x" . counsel-M-x) ("C-x b" . counsel-switch-buffer) ("C-x C-f" . counsel-find-file) ("C-h f" . counsel-describe-function) ("C-h v" . counsel-describe-variable) :map minibuffer-local-map ("C-r" . counsel-minibuffer-history))) (use-package helpful :bind (("C-h k" . helpful-key)) :custom ((counsel-describe-function-function 'helpful-callable) (counsel-describe-variable-function 'helpful-variable))) ;;; ;;; Buffers ;;; ;; Kill buffers that haven't been modified in awhile. (use-package midnight) ;; Save point position between sessions (use-package saveplace :custom ((save-place t) (save-place-file (expand-file-name ".places" user-emacs-directory)))) (defun cleanup-buffer-safe () "Perform a bunch of safe operations on the whitespace content of a buffer. Does not indent buffer, because it is used for a before-save-hook, and that might be bad." (interactive) (delete-trailing-whitespace) (set-buffer-file-coding-system 'utf-8)) ;; Various superfluous white-space. Just say no. (add-hook 'before-save-hook 'cleanup-buffer-safe) (use-package ibuffer :init (add-hook 'ibuffer-mode-hook (lambda () (ibuffer-switch-to-saved-filter-groups "default"))) :custom ((ibuffer-saved-filter-groups '(("default" ("dired" (mode . dired-mode)) ("org" (mode . org-mode)) ("erc" (mode . erc-mode))))))) (setq view-read-only t) ;;; ;;; Tabs and Newlines ;;; (setq-default indent-tabs-mode nil) (setq indent-tabs-mode nil) (setq tab-width 2) (setq require-final-newline t) (setq electric-indent-mode t) ;;; ;;; Version Control ;;; (use-package magit :bind (("C-c g" . magit-status)) :config (use-package magit-blame) :custom ;; I don't like magit's default local tracking branch naming ;; strategy. ((magit-default-tracking-name-function 'magit-default-tracking-name-branch-only) (magit-last-seen-setup-instructions "1.4.0") (magit-completing-read-function #'magit-ido-completing-read))) ;; Follow symlinks automatically instead of asking each time. (setq vc-follow-symlinks t) ;;; ;;; Project Management ;;; (use-package projectile :init (projectile-mode 1) :bind-keymap (("C-c p" . projectile-command-map)) :custom ((projectile-completion-system 'ivy))) (use-package neotree :bind (("C-c n" . neotree))) ;;; ;;; Ediff ;;; ;; Don't break out a separate frame for ediff. (setq ediff-window-setup-function 'ediff-setup-windows-plain) (setq ediff-split-window-function 'split-window-horizontally) ;;; ;;; C ;;; (setq c-default-style "k&r") (setq-default c-basic-offset 2) (setq-default c-basic-indent 2) ;;; ;;; Javascript ;;; (setq js-indent-level 2) (use-package js2-mode :init (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)) :custom ((js2-basic-offset 2))) ;;; ;;; Web ;;; (use-package web-mode :init (add-to-list 'auto-mode-alist '("\\.html$" . web-mode)) (add-to-list 'auto-mode-alist '("\\.tpl$" . web-mode)) (add-to-list 'auto-mode-alist '("\\.erb$" . web-mode)) (add-hook 'web-mode-hook (lambda () (setq web-mode-markup-indent-offset 2)))) ;;; ;;; Lisp ;;; (show-paren-mode t) (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) (use-package scheme) (use-package paredit :config (add-hook 'emacs-lisp-mode-hook (lambda () (paredit-mode t))) (add-hook 'lisp-mode-hook (lambda () (paredit-mode t))) (add-hook 'lisp-interaction-mode-hook (lambda () (paredit-mode t))) (add-hook 'scheme-mode-hook (lambda () (paredit-mode t)))) (use-package geiser :config (use-package geiser-guile) :custom ((geiser-active-implementations '(guile)))) ;; Use scheme-mode for Skribe documents. (add-to-list 'auto-mode-alist '("\\.skr$" . scheme-mode)) ;; Hacked to properly indent keywords. Thanks to mark_weaver. (defun scheme-indent-function (indent-point state) "Scheme mode function for the value of the variable `lisp-indent-function'. This behaves like the function `lisp-indent-function', except that: i) it checks for a non-nil value of the property `scheme-indent-function' \(or the deprecated `scheme-indent-hook'), rather than `lisp-indent-function'. ii) if that property specifies a function, it is called with three arguments (not two), the third argument being the default (i.e., current) indentation." (let ((normal-indent (current-column))) (goto-char (1+ (elt state 1))) (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) (if (and (elt state 2) (not (looking-at "\\sw\\|\\s_"))) ;; car of form doesn't seem to be a symbol (progn (if (not (> (save-excursion (forward-line 1) (point)) calculate-lisp-indent-last-sexp)) (progn (goto-char calculate-lisp-indent-last-sexp) (beginning-of-line) (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t))) ;; Indent under the list or under the first sexp on the same ;; line as calculate-lisp-indent-last-sexp. Note that first ;; thing on that line has to be complete sexp since we are ;; inside the innermost containing sexp. (backward-prefix-chars) (current-column)) (let ((function (buffer-substring (point) (progn (forward-sexp 1) (point)))) method) (setq method (or (get (intern-soft function) 'scheme-indent-function) (get (intern-soft function) 'scheme-indent-hook))) (cond ((or (eq method 'defun) (and (null method) (> (length function) 3) (string-match "\\`def" function))) (lisp-indent-defform state indent-point)) ;; This next cond clause is the only change -mhw ((and (null method) (> (length function) 1) ; The '#' in '#:' seems to get lost, not sure why (string-match "\\`:" function)) (let ((lisp-body-indent 1)) (lisp-indent-defform state indent-point))) ((integerp method) (lisp-indent-specform method state indent-point normal-indent)) (method (funcall method state indent-point normal-indent))))))) ;;; ;;; Ruby ;;; ;; Rake files are ruby, too, as are gemspecs, rackup files, etc. (add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode)) (add-to-list 'auto-mode-alist '("\\.gemspec$" . ruby-mode)) (add-to-list 'auto-mode-alist '("\\.ru$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode)) (use-package ruby-test-mode :hook ruby-mode) ;;; ;;; SQL ;;; ;; Don't wrap lines so that table listings with a lot of columns ;; remain readable. (add-hook 'sql-interactive-mode-hook (lambda () (setq truncate-lines t))) ;;; ;;; Org ;;; (use-package ox-beamer) (defun org-sort-by-priority-and-todo () "Sort org entries first by priority, and then by TODO status." (interactive) (push-mark) (push-mark (point-max) nil t) (lexical-let ((p (point))) (goto-char (point-min)) (org-sort-entries nil ?p) (org-sort-entries nil ?o) (goto-char p)) (pop-mark)) (add-hook 'org-mode-hook (lambda () (local-set-key (kbd "C-c o") 'org-sort-by-priority-and-todo))) ;;; ;;; GPG ;;; (setq epg-gpg-program "gpg") (setq epa-pinentry-mode 'loopback) ;;; ;;; IRC ;;; (use-package erc :init (erc-autojoin-mode t) (erc-track-mode t) :custom ((erc-interpret-mirc-color t) (erc-kill-buffer-on-part t) (erc-kill-queries-on-quit t) (erc-kill-server-buffer-on-quit t) (erc-server-coding-system '(utf-8 . utf-8)) (erc-autojoin-channels-alist '(("freenode.net" "#guile" "#guix" "#lispgames"))) ;; Don't open channel buffers in place of the current ;; buffer because that drives me fucking crazy. (erc-join-buffer 'bury) (erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE" "324" "329" "332" "333" "353" "477")) (erc-save-buffer-on-part t))) (use-package erc-log :custom ((erc-log-channels-directory "~/.erc/logs/"))) (if (not (file-exists-p erc-log-channels-directory)) (mkdir erc-log-channels-directory t)) (use-package erc-notify) (use-package erc-autoaway) (use-package erc-services) (use-package tls) ;; Start and stop erc (defun start-irc () "Connect to IRC." (interactive) (erc-tls :server "irc.freenode.net" :port 6697 :nick "davexunit" :password (read-passwd "Password: "))) (defun stop-irc () "Disconnects from all irc servers" (interactive) (dolist (buffer (delq nil (mapcar (lambda (x) (and (erc-server-buffer-p x) x)) (buffer-list)))) (message "Server buffer: %s" (buffer-name buffer)) (with-current-buffer buffer (erc-quit-server "Later")))) (global-set-key (kbd "C-c i") 'start-irc) ;;; ;;; Keybindings ;;; (global-set-key (kbd "RET") 'newline-and-indent) (global-set-key (kbd "C-c p") 'package-list-packages) (global-set-key (kbd "C-c C-f") 'ff-find-other-file) (global-set-key (kbd "M-%") 'query-replace-regexp) ;; No more minimizing Emacs by accident. (global-unset-key (kbd "C-z")) ;; Enable some disabled-by-default functions. (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil)