Skip to content

My life is dope and I have dope emacs configs

Notifications You must be signed in to change notification settings

arecker/emacs.d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Emacs Configuration

Introduction

This is my Emacs configuration. Org Babel, a native feature of Emacs that can run code snippets embedded in rich text documents, spurred a fad in the Emacs community where users define their personal configs in README documents like this one.

In that spirit, I tried to contain my actual lisp code in this document, save for one function that you need in init.el to kick off the process.

(defun recker/load-config ()
  "Tangle configuration and load it."
  (let ((config (concat (file-name-as-directory user-emacs-directory) "README.org")))
    (if (file-exists-p config)
        (org-babel-load-file config)
      (warn (concat config " not found - not loading")))))

(recker/load-config)

From here on, all lisp code snippets with syntax highlighting are run on startup in the order they appear.

One more note before we get going. You are free to use this as a starting place for your own configuration. All of my custom functions begin with the recker/ prefix. To change it, just perform a string replace on (defun recker/ within this document. Beyond that, just update these global variables with your own info.

(setq user-full-name "Alex Recker")
(setq user-mail-address "alex@reckerfamily.com")

Packages

First, we setup the Emacs package manager. This occurs at the top of the file so we can install packages as we need them.

The Emacs package manager does a nice job. With the help of John Wiegley’s use-package, we can simultaneously declare a package we need and configure the package after it installs and loads.

As far as package maintenance, I sometimes run M-x package-list-packages to bring up the packages screen. You can press U then x at this screen to pull down any updates that are ready, and it’s also a good idea to restart Emacs to make sure everything is still working.

(require 'package)

(defun recker/configure-packages ()
  "Set up the package manager."

  ;; set and load custom file first (this is gitignored)
  (setq custom-file (concat user-emacs-directory "custom.el"))
  (if (file-exists-p custom-file) (load custom-file)
    (warn "couldn't find custom file %s" custom-file))

  ;; set the repo URLs
  (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
                           ("melpa" . "https://melpa.org/packages/")))

  ;; initialize the package manager
  (package-initialize)

  ;; install use-package
  (unless (package-installed-p 'use-package)
    (package-refresh-contents)
    (package-install 'use-package)))

(recker/configure-packages)

Application

If you’re using Emacs through a CLI, I’d recommend you close it out and download the real thing instead (if you’re running a mac, Emacs for Mac OS X is great no-frills package). Flipping between emacs and the terminal is still fine, though. Especially since with this config, running the command emacsclient will connect to the running Emacs process seamlessly. You can even export EDITOR=emacsclient in your environment so other tools can get on the same page.

(defun recker/configure-application ()

  ;; prompt when quitting (protects from fat fingers)
  (setq-default confirm-kill-emacs #'yes-or-no-p)

  ;; start the server
  (server-start))

(recker/configure-application)

Appearance

Default Emacs gets a lot of crap for its “ugly” UI. I find it cozy and nostalgic. In an effort to maintain that unmistakable aesthetic, I make just a few modest tweaks to the appearance.

(defun recker/configure-appearance ()
  "Configure the Emacs UI."

  ;; Suppress widgets
  (menu-bar-mode 0)
  (tool-bar-mode 0)
  (scroll-bar-mode 0)

  ;; Set font
  (when (string= system-type "darwin")
    (set-frame-font "Monaco 18" nil t))
  (when (string= system-type "gnu/linux")
    (set-frame-font "Monospace 13" nil t))

  ;; Full screen by default
  (unless (eq (frame-parameter (selected-frame) 'fullscreen) 'maximized)
    (toggle-frame-maximized))

  ;; Use this package to hide minor modes.  I like to know which major
  ;; mode I'm editing, but the minor mode list gets a little too
  ;; cluttered trying to list all the plugins I have running.
  (unless (bound-and-true-p rich-minority-mode) ;it breaks if it runs twice?
    (use-package rich-minority
      :ensure t
      :init (rich-minority-mode 't)
      :config (setq rm-blacklist ""))))

(recker/configure-appearance)

Movement

The buffer would have to be the most common form of transportation in the Emacs world. Suppressing the more boisterous default splash screen, I’ve made the *scratch* buffer my home. With these configs, I’ve made it so that this buffer can never be deleted. I wrote a good amount of custom code to print a different ascii image and output from the infamous fortune command on every launch. It’s also a great place to quickly test lisp expressions or paste random text.

;; don't show the splash screen
(setq inhibit-splash-screen 't)

;; never kill the scratch buffer
(defun recker/not-scratch-p ()
  "Return NIL if the current buffer is the *scratch* buffer."
  (not (equal (buffer-name (current-buffer)) "*scratch*")))

(add-hook 'kill-buffer-query-functions 'recker/not-scratch-p)

;; display the output of "fortune" as the scratch message
(setq recker/scratch-message-command "fortune --wrap 72 --comment ';; '")

(defun recker/scratch-message ()
  "Return a scratch message from fortune-blog."
  (concat "\n"
          (recker/scratch-lisp-comment (format-time-string "%A, %B %-d %Y"))
          "\n\n"
          (recker/random-scratch-ascii)
          "\n\n"
          (shell-command-to-string recker/scratch-message-command)))

(defun recker/random-scratch-ascii ()
  "Return a lisp random ascii image from emacs.d/ascii."
  (let* ((ascii-files (file-expand-wildcards (concat user-emacs-directory "ascii/*.txt")))
         (choice (expand-file-name (nth (random (length ascii-files)) ascii-files))))
    (recker/scratch-lisp-comment (with-temp-buffer
                                   (insert-file-contents-literally choice)
                                   (buffer-string)))))

(defun recker/scratch-lisp-comment (text)
  "Turn text into a lisp comment."
  (with-temp-buffer
    (insert text)
    (let ((comment-start ";; "))
      (comment-region (point-min) (point-max)))
    (concat "\n" (buffer-string) "\n")
    (buffer-string)))

(defun recker/refresh-scratch-buffer ()
  "Redraw the *scratch* buffer."
  (interactive)
  (save-excursion
    (switch-to-buffer "*scratch*")
    (erase-buffer)
    (insert (recker/scratch-message))))

(setq initial-scratch-message (recker/scratch-message))

Where C-x p deletes the current buffer, I added my own function that deletes all buffers which you can call by C-x P. Just like my browser tabs, sometimes I get a little overwhelmed and I need a clean slate to focus.

(global-set-key (kbd "C-x k") 'kill-this-buffer)

(defun recker/purge-buffers ()
  "Delete all buffers, except for *scratch*."
  (interactive)
  (mapc #'(lambda (b) (unless (string= (buffer-name b) "*scratch*") (kill-buffer b))) (buffer-list)))

(global-set-key (kbd "C-x P") 'recker/purge-buffers)

In Emacs, you spend much of your time selecting things in the minibuffer. “Interactive Do” (IDO for short) can enhance this experience. IDO comes with Emacs, but I install some packages to display options vertically instead of horizontally, and also to plug the interface in to Imenu.

(defun recker/configure-ido ()
  (setq ido-enable-flex-matching t)
  (setq ido-everywhere t)
  (ido-mode t)
  (use-package ido-vertical-mode
    :ensure t
    :config (setq ido-vertical-define-keys 'C-n-and-C-p-only)
    :init (ido-vertical-mode))
  (use-package idomenu
    :ensure t
    :bind ("C-c i" . idomenu)))

(recker/configure-ido)

The M-x menu also carries a lot of weight in the Emacs workflow. Transparently swapping out this command with the smex package adds value to this interface without changing the intuitive experience.

(use-package smex
  :ensure t
  :init (smex-initialize)
  :bind (("M-x" . 'smex)
         ("M-X" . 'smex-major-mode-commands)))

For quickly jumping around a buffer, standard isearch can’t be beat. But as a small luxury, sometimes I use the swiper package to quickly fuzzy search a buffer. I bind this to a similar keystroke as isearch so it’s easy to remember.

(use-package swiper
  :ensure t
  :bind ("C-c s" . swiper))

Use company mode for autocomplete. Without a direct way to call company mode, this plugin feels more magical to me. But other language modes seem to know where to find it without any needed interference, so that’s good.

(use-package company
  :ensure t
  :init (add-hook 'after-init-hook 'global-company-mode))

Use projectile for moving around git repos. From the outside, this plugin feels huge and robust. Compared to everything it can do, I barely use it. I’m content to leverage the project wide file search with C-c p f and the compile interface with C-c p P (all the projectile commands fall under the same C-c p prefix).

(use-package projectile
  :ensure t
  :config
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (setq projectile-completion-system 'ido)
  :init (projectile-mode t))

Files

Unfortunately, Emacs litters the filesystem with “backup” files. I can appreciate that it’s trying to be helpful, but it drives me nuts so I turn it off. Another edge case - if a file changes while I’m looking at it, I make Emacs re-render the buffer live.

(setq make-backup-files nil)
(setq auto-save-default nil)
(global-auto-revert-mode t)

Speaking of backing up files, tell emacs version control to follow symlinks if the file is under version control.

(setq vc-follow-symlinks 't)

And while we’re at it, install magit for working with git. This is not an understatement - magit is truly a beautiful piece of software. The way I have it configured, you can open the interface with C-x g (it will open git for the current file or prompt you for a git project).

(use-package magit
  :ensure t
  :bind ("C-x g" . magit-status))

Emacs has a great file manager called dired. To activate it, visit a directory just as you would open a file. Not wanting to interfere with greatness, I make just a few changes to the default behavior. I like to hide hidden files by default (you can see these by pressing C-x M-o), hide the . and .. pointers that you see by default, and blow through extra confirmations when you delete a file with a visiting buffer.

(require 'dired-x)
(setq dired-use-ls-dired nil)
(setq dired-clean-confirm-killing-deleted-buffers nil)
(setq-default dired-omit-files-p t)
(setq dired-omit-files (concat dired-omit-files "\\|^\\..+$"))
(add-hook 'dired-mode-hook 'dired-omit-mode)

About

My life is dope and I have dope emacs configs

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published