|
|
@@ -0,0 +1,881 @@ |
|
|
#+TITLE: Sean Cribbs' Emacs 24 Configuration |
|
|
#+AUTHOR: Sean Cribbs |
|
|
#+EMAIL: [email protected] |
|
|
#+OPTIONS: toc:3 num:nil |
|
|
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://thomasf.github.io/solarized-css/solarized-light.min.css" /> |
|
|
* Introduction |
|
|
Inspired by [[http://www.aaronbedra.com/emacs.d/][Aaron Bedra's emacs configuration]], I have converted mine |
|
|
to an org-mode file as well. This should improve load speed over my |
|
|
bespoke number-oriented-multi-file config, as well as improve |
|
|
documentation of my settings. You might notice a few things lifted |
|
|
directly from Aaron's config. |
|
|
* Startup |
|
|
I want to do a few things early in the startup process, like |
|
|
cleanup some of Emacs' less savory defaults, so these come first. |
|
|
I'm also trying to wean myself off of emacs-starter-kit, so things |
|
|
that it does early in the startup process that I want to co-opt |
|
|
will go in this section. |
|
|
** Environment |
|
|
There are plenty of things installed outside of the default =PATH=. |
|
|
This allows me to establish additional PATH information. At the |
|
|
moment, the only things that added are /usr/local/bin for homebrew |
|
|
on OS X. |
|
|
|
|
|
Sadly, there's no built-in variable pointing to the user's home |
|
|
directory, so I pull that out based on the environment variable |
|
|
=HOME=, or failing that, the parent directory of the Emacs |
|
|
configuration. |
|
|
|
|
|
I also keep some non-ELPA things in my emacs directory. |
|
|
#+begin_src emacs-lisp |
|
|
(setenv "PATH" (concat "/usr/local/bin:/opt/local/bin:/usr/bin:/bin" (getenv "PATH"))) |
|
|
|
|
|
(defconst user-home-directory |
|
|
(or (getenv "HOME") |
|
|
(expand-file-name ".." user-emacs-directory)) |
|
|
"The user's home directory.") |
|
|
|
|
|
(add-to-list 'load-path (expand-file-name "site-lisp" user-emacs-directory)) |
|
|
#+end_src |
|
|
** Common Lisp for Emacs |
|
|
Emacs lisp is really only a subset of common lisp, and I need to |
|
|
have some of the additional functionality to make the |
|
|
configuration and its dependencies work properly, which we get by |
|
|
requiring Common Lisp for Emacs. |
|
|
#+begin_src emacs-lisp |
|
|
(require 'cl) |
|
|
#+end_src |
|
|
|
|
|
** Key Bindings |
|
|
Miscellaneous keybindings that don't belong anywhere else. I use |
|
|
Option as =super= and Command as =meta= on OS/X. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(setq mac-option-modifier 'super) |
|
|
(setq mac-command-modifier 'meta) |
|
|
|
|
|
(global-set-key (kbd "C-S-k") 'delete-region) |
|
|
(global-set-key (kbd "C-s") 'isearch-forward-regexp) |
|
|
(global-set-key (kbd "") 'isearch-backward-regexp) |
|
|
(global-set-key (kbd "M-%") 'query-replace-regexp) |
|
|
(global-set-key (kbd "C-M-s") 'isearch-forward) |
|
|
(global-set-key (kbd "C-M-r") 'isearch-backward) |
|
|
(global-set-key (kbd "C-M-%") 'query-replace) |
|
|
|
|
|
(setq imenu-auto-rescan t) |
|
|
(global-set-key (kbd "C-x TAB") 'imenu) |
|
|
|
|
|
(put 'upcase-region 'disabled nil) |
|
|
#+end_src |
|
|
** Yes and No |
|
|
Nobody likes to have to type out the full yes or no when Emacs |
|
|
asks. Which it does often. Make it one character. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defalias 'yes-or-no-p 'y-or-n-p) |
|
|
#+end_src |
|
|
|
|
|
** Backup Files |
|
|
I hate backup files just as much as the next person. This is why |
|
|
we have version control systems, people. |
|
|
#+begin_src emacs-lisp |
|
|
(setq make-backup-files nil) |
|
|
(setq backup-directory-alist `((".*" . ,temporary-file-directory))) |
|
|
(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t))) |
|
|
#+end_src |
|
|
** Marking text |
|
|
There are some behaviors in Emacs that aren't intuitive related to |
|
|
marking text. Specifically, typing or yanking into the selected |
|
|
region should replace it (=delete-selection-mode=), and when the |
|
|
buffer is changed, the region is de-selected |
|
|
(=transient-mark-mode=). |
|
|
#+begin_src emacs-lisp |
|
|
(delete-selection-mode t) |
|
|
(transient-mark-mode t) |
|
|
#+end_src |
|
|
* Server |
|
|
I use =emacsclient= obsessively, especially via my shell alias =e=, |
|
|
which is mapped to =emacsclient -n=. In order for this to work, you |
|
|
have to start the "server". |
|
|
#+BEGIN_SRC emacs-lisp |
|
|
(require 'server) |
|
|
(server-start) |
|
|
#+END_SRC |
|
|
* Packages |
|
|
Since Emacs 24, Emacs includes the Emacs Lisp Package Archive |
|
|
(ELPA) by default. This provides a nice way to install additional |
|
|
packages. Since the default package archive doesn't include |
|
|
everything necessary, the marmalade, and melpa repositories are |
|
|
also added. This also prefetches the package list if we don't have |
|
|
a cached copy yet. |
|
|
|
|
|
#+BEGIN_SRC emacs-lisp |
|
|
(require 'package) |
|
|
(package-initialize) |
|
|
|
|
|
(add-to-list 'package-archives |
|
|
'("marmalade" . "http://marmalade-repo.org/packages/")) |
|
|
(add-to-list 'package-archives |
|
|
'("melpa" . "http://melpa.milkbox.net/packages/") t) |
|
|
|
|
|
(setq package-archive-enable-alist '(("melpa" magit graphviz-dot-mode lua-mode elixir-mode elixir-yasnippets flymake-elixir))) |
|
|
|
|
|
(when (not package-archive-contents) |
|
|
(package-refresh-contents)) |
|
|
#+END_SRC |
|
|
** Define packages |
|
|
This is the list of packages used in this configuration. I start |
|
|
with major modes and enhancements first, add flymake, and then |
|
|
utilities and themes. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defvar seancribbs/packages |
|
|
'( |
|
|
clojure-mode |
|
|
elixir-mode |
|
|
elixir-yasnippets |
|
|
graphviz-dot-mode |
|
|
haskell-mode |
|
|
inf-ruby |
|
|
js2-mode |
|
|
lua-mode |
|
|
markdown-mode |
|
|
mmm-mode |
|
|
php-mode |
|
|
protobuf-mode |
|
|
python-mode |
|
|
rspec-mode |
|
|
ruby-end |
|
|
scala-mode |
|
|
wc-mode |
|
|
web-mode |
|
|
yaml-mode |
|
|
|
|
|
flymake |
|
|
flymake-easy |
|
|
flymake-elixir |
|
|
flymake-lua |
|
|
flymake-ruby |
|
|
flymake-haskell-multi |
|
|
|
|
|
org-present |
|
|
|
|
|
ag |
|
|
auto-complete |
|
|
dash-at-point |
|
|
expand-region |
|
|
highlight |
|
|
hlinum |
|
|
ido-ubiquitous |
|
|
magit |
|
|
minimap |
|
|
neotree |
|
|
paredit |
|
|
smex |
|
|
htmlize |
|
|
|
|
|
ir-black-theme |
|
|
solarized-theme |
|
|
twilight-theme |
|
|
underwater-theme |
|
|
) |
|
|
) |
|
|
#+end_src |
|
|
** Install default packages |
|
|
When Emacs boots, check to make sure all of the packages defined |
|
|
in =seancribbs/packages= are installed. If not, have ELPA take |
|
|
care of it. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(dolist (p seancribbs/packages) |
|
|
(when (not (package-installed-p p)) |
|
|
(package-install p))) |
|
|
#+end_src |
|
|
|
|
|
* Visual tweaks |
|
|
** Window chrome |
|
|
Most people don't use =menu-bar-mode=, but some things provided by |
|
|
my add-ons don't have key combos bound to the menu items they |
|
|
create, so I enable it. Unfortunately it doesn't help things in |
|
|
console mode, so I only enable it in graphical modes. |
|
|
|
|
|
The default frame title leaves a bit to be desired, so both |
|
|
Aaron's and ESK's config include the next tweak. |
|
|
|
|
|
I don't want to hear audible bells or see the splash screen, so |
|
|
those are disabled. |
|
|
#+begin_src emacs-lisp |
|
|
(when window-system |
|
|
(menu-bar-mode 1) |
|
|
(setq frame-title-format '(buffer-file-name "%f" ("%b")))) |
|
|
|
|
|
(tool-bar-mode -1) |
|
|
(scroll-bar-mode -1) |
|
|
|
|
|
(setq visible-bell t |
|
|
inhibit-splash-screen t |
|
|
inhibit-startup-message t |
|
|
initial-scratch-message nil) |
|
|
#+end_src |
|
|
** Font |
|
|
I've used DejaVu Sans Mono for years. Thanks, Aaron, for making this |
|
|
easier for me to set! It's also nice to be able to quickly tweak |
|
|
the text size. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(when window-system |
|
|
(when (functionp 'set-fontset-font) |
|
|
(set-fontset-font "fontset-default" |
|
|
'unicode |
|
|
(font-spec :family "DejaVu Sans Mono" |
|
|
:width 'normal |
|
|
:size 12.4 |
|
|
:weight 'normal)))) |
|
|
|
|
|
(global-set-key (kbd "C-+") 'text-scale-increase) |
|
|
(global-set-key (kbd "C--") 'text-scale-decrease) |
|
|
#+end_src |
|
|
** Theme |
|
|
I use the =solarized-light= theme most of the time, so I figure it |
|
|
should startup in that theme. |
|
|
#+begin_src emacs-lisp |
|
|
(load-theme 'solarized-light t) |
|
|
#+end_src |
|
|
** Window Resizing |
|
|
Following this are some experimental keys that I've been |
|
|
trying so I can easily grow or shrink a window split. I'm not |
|
|
particularly happy with them yet. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(global-set-key (kbd "s-<right>") 'enlarge-window-horizontally) |
|
|
(global-set-key (kbd "s-<left>") 'shrink-window-horizontally) |
|
|
(global-set-key (kbd "s-<up>") 'enlarge-window) |
|
|
(global-set-key (kbd "s-<down>") 'shrink-window) |
|
|
#+end_src |
|
|
** Buffer management |
|
|
Switching buffers should be easy and fast, and killing them too. |
|
|
And sometimes, you just have to declare buffer-bankruptcy. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(global-set-key (kbd "M-]") 'next-buffer) |
|
|
(global-set-key (kbd "M-[") 'previous-buffer) |
|
|
|
|
|
(defun kill-current-buffer () |
|
|
"Kills the current buffer" |
|
|
(interactive) |
|
|
(kill-buffer (buffer-name))) |
|
|
(global-set-key (kbd "C-x C-k") 'kill-current-buffer) |
|
|
|
|
|
(defun nuke-all-buffers () |
|
|
"Kill all buffers, leaving *scratch* only" |
|
|
(interactive) |
|
|
(mapcar (lambda (x) (kill-buffer x)) |
|
|
(buffer-list)) |
|
|
(delete-other-windows)) |
|
|
(global-set-key (kbd "C-x C-S-k") 'nuke-all-buffers) |
|
|
|
|
|
(global-set-key (kbd "C-c r") 'revert-buffer) |
|
|
#+end_src |
|
|
** Whitespace |
|
|
I like to see where the unnecessary whitespace is in all |
|
|
programming modes, and have a quick key to clean it up. There |
|
|
shall be no tabs in my files, only spaces. I'd also like to |
|
|
quickly reindent an entire buffer according to the modes' electric |
|
|
indentation. The last three functions were copied from ESK. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'whitespace) |
|
|
|
|
|
(unless (member 'whitespace-mode prog-mode-hook) |
|
|
(add-hook 'prog-mode-hook 'whitespace-mode)) |
|
|
(global-set-key (kbd "C-c w") 'whitespace-cleanup) |
|
|
(set-default 'indicate-empty-lines t) |
|
|
(set-default 'indent-tabs-mode nil) |
|
|
(setq whitespace-style '(face trailing lines-tail tabs) |
|
|
whitespace-line-column 80) |
|
|
|
|
|
(defun seancribbs/untabify-buffer () |
|
|
(interactive) |
|
|
(untabify (point-min) (point-max))) |
|
|
|
|
|
(defun seancribbs/indent-buffer () |
|
|
(interactive) |
|
|
(indent-region (point-min) (point-max))) |
|
|
|
|
|
(defun seancribbs/cleanup-buffer () |
|
|
"Perform a bunch of operations on the whitespace content of a buffer." |
|
|
(interactive) |
|
|
(seancribbs/indent-buffer) |
|
|
(seancribbs/untabify-buffer) |
|
|
(delete-trailing-whitespace)) |
|
|
|
|
|
(global-set-key (kbd "C-c n") 'seancribbs/cleanup-buffer) |
|
|
#+end_src |
|
|
|
|
|
** Modeline |
|
|
The Emacs modeline contains helpful status information. I turn on |
|
|
column and line numbers globally. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(line-number-mode 1) |
|
|
(column-number-mode 1) |
|
|
#+end_src |
|
|
** Highlights |
|
|
I took these customizations from ESK. First, it's always nice to |
|
|
quickly see what line you're on, and then when you put in |
|
|
watchwords, those should show up highlighted. I'd also like to see |
|
|
matching parens so I can be sure my code is structured correctly. |
|
|
#+begin_src emacs-lisp |
|
|
(defun seancribbs/turn-on-hl-line-mode () |
|
|
(when (> (display-color-cells) 8) |
|
|
(hl-line-mode t))) |
|
|
|
|
|
(defun seancribbs/add-watchwords () |
|
|
(font-lock-add-keywords |
|
|
nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\|HACK\\|REFACTOR\\|NOCOMMIT\\)" |
|
|
1 font-lock-warning-face t)))) |
|
|
|
|
|
(add-hook 'prog-mode-hook 'seancribbs/turn-on-hl-line-mode) |
|
|
(add-hook 'prog-mode-hook 'seancribbs/add-watchwords) |
|
|
|
|
|
(show-paren-mode t) |
|
|
#+end_src |
|
|
|
|
|
* Major modes |
|
|
** Programming Modes |
|
|
These customizations I like to use in all "programming modes", |
|
|
i.e. modes derived from =prog-mode=. The main change here is that |
|
|
I find =comment-dwim= to not "do what I mean" in most cases, so I use |
|
|
this function that used to be part of ESK or some dependency of |
|
|
it. Instead of inserting a comment at the end-of-line, it will |
|
|
toggle commenting out the current line. Unfortunately the key I'm |
|
|
used to is usually occupied by =dabbrev-expand=, so I assign that |
|
|
to something else. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defun comment-or-uncomment-region-or-line () |
|
|
"Comments or uncomments the region or the current line if there's no active region." |
|
|
(interactive) |
|
|
(let (beg end) |
|
|
(if (region-active-p) |
|
|
(setq beg (region-beginning) end (region-end)) |
|
|
(setq beg (line-beginning-position) end (line-end-position))) |
|
|
(comment-or-uncomment-region beg end))) |
|
|
|
|
|
(global-set-key (kbd "M-/") 'comment-or-uncomment-region-or-line) |
|
|
(global-set-key (kbd "M-\\") 'dabbrev-expand) |
|
|
#+end_src |
|
|
** Flymake |
|
|
Flymake is super-useful for finding dumb errors in my source files |
|
|
by running compilation in the background. This adds a key to |
|
|
easily jump to the next error in the current buffer. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defun seancribbs/flymake-keys () |
|
|
"Adds keys for navigating between errors found by Flymake." |
|
|
(local-set-key (kbd "C-c C-n") 'flymake-goto-next-error) |
|
|
(local-set-key (kbd "C-c C-p") 'flymake-goto-prev-error)) |
|
|
|
|
|
(add-hook 'flymake-mode-hook 'seancribbs/flymake-keys) |
|
|
#+end_src |
|
|
|
|
|
** Erlang |
|
|
I write a lot of Erlang. Unlike most people, I don't like the all |
|
|
the quirks that come with =edts= and other "Emacs IDE for Erlang" |
|
|
packages, so I load the mode from the latest OTP I have installed. |
|
|
I also add Quviq QuickCheck and Wrangler. |
|
|
*** Find Erlang Mode |
|
|
There's a few curiosities here. I use multiple Erlang versions |
|
|
and found =kerl= too hacky to maintain, so I wrote a few short |
|
|
shell functions to build, install, and switch between versions of |
|
|
OTP I have in =$HOME/erlang=. This means I need to pull |
|
|
=erlang-mode= from the latest "tools" application in OTP. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defconst seancribbs/erlang/root |
|
|
"/usr/local/Cellar/erlang" |
|
|
"The root directory where various versions of Erlang are installed") |
|
|
|
|
|
(defvar seancribbs/erlang/latest |
|
|
"18.2.1" |
|
|
"The latest version of Erlang installed.") |
|
|
|
|
|
(defvar seancribbs/erlang/latest/tools-version |
|
|
"2.8.2" |
|
|
"The version of the 'tools' application in the latest Erlang.") |
|
|
|
|
|
(defun seancribbs/erlang/latest/root () |
|
|
"Computes the root directory of the latest Erlang installed." |
|
|
(expand-file-name seancribbs/erlang/latest seancribbs/erlang/root)) |
|
|
|
|
|
(defun seancribbs/erlang/latest/bin () |
|
|
"Computes the latest Erlang's executable directory" |
|
|
(expand-file-name "bin" (seancribbs/erlang/latest/root))) |
|
|
|
|
|
(defun seancribbs/erlang/latest/lib () |
|
|
"Computes the latest Erlang's library directory" |
|
|
(expand-file-name "erlang" (expand-file-name "lib" (seancribbs/erlang/latest/root)))) |
|
|
|
|
|
(defun seancribbs/erlang/latest/emacs () |
|
|
"Computes the location of the OTP emacs mode." |
|
|
(cl-reduce 'expand-file-name |
|
|
(list "emacs" |
|
|
(format "tools-%s" seancribbs/erlang/latest/tools-version) |
|
|
"lib" |
|
|
(seancribbs/erlang/latest/lib)) |
|
|
:from-end t)) |
|
|
#+end_src |
|
|
|
|
|
*** Load Erlang Mode |
|
|
Now that we have that boilerplate out of the way, we can add the |
|
|
mode. First we add the tools/emacs directory to the load path, |
|
|
set the Erlang root, add its binaries to the executable path and |
|
|
require the mode. |
|
|
|
|
|
Somehow Erlang mode is not derived from =prog-mode=, so my usual |
|
|
additions don't apply, so I need to add them to make it |
|
|
consistent. |
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'load-path (seancribbs/erlang/latest/emacs)) |
|
|
(add-to-list 'exec-path (seancribbs/erlang/latest/bin)) |
|
|
(setq erlang-root-dir (seancribbs/erlang/latest/lib)) |
|
|
(require 'erlang-start) |
|
|
|
|
|
(add-hook 'erlang-mode-hook 'seancribbs/add-watchwords) |
|
|
(add-hook 'erlang-mode-hook 'seancribbs/turn-on-hl-line-mode) |
|
|
(add-hook 'erlang-mode-hook 'whitespace-mode) |
|
|
#+end_src |
|
|
|
|
|
*** Additional Files |
|
|
The OTP emacs mode doesn't come with some of my commonly used |
|
|
files that are Erlang code or terms. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'auto-mode-alist '("rebar.config" . erlang-mode)) ;; rebar |
|
|
(add-to-list 'auto-mode-alist '("rebar.config.script" . erlang-mode)) ;; rebar |
|
|
(add-to-list 'auto-mode-alist '("app.config" . erlang-mode)) ;; embedded node/riak |
|
|
;;(add-to-list 'auto-mode-alist '(".riak_test.config" . erlang-mode)) |
|
|
(add-to-list 'auto-mode-alist '("\\.erlang$" . erlang-mode)) ;; User customizations file |
|
|
#+end_src |
|
|
|
|
|
*** Flymake |
|
|
Flymake is my savior for =erlang-mode= and requires only a little |
|
|
bit of configuration. For rebar3-based projects, we need to look |
|
|
in the =_build/*= directories for dependencies, not just in |
|
|
=deps/= (not working yet). |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'erlang-flymake) |
|
|
(setq erlang-flymake-command (expand-file-name "erlc" (seancribbs/erlang/latest/bin))) |
|
|
|
|
|
(defun rebar3/erlang-flymake-get-include-dirs () |
|
|
(append |
|
|
(erlang-flymake-get-include-dirs) |
|
|
(file-expand-wildcards (concat (erlang-flymake-get-app-dir) "_build/*/lib"))) |
|
|
) |
|
|
|
|
|
(setq erlang-flymake-get-include-dirs-function 'rebar3/erlang-flymake-get-include-dirs) |
|
|
|
|
|
(defun rebar3/erlang-flymake-get-code-path-dirs () |
|
|
(append |
|
|
(erlang-flymake-get-code-path-dirs) |
|
|
(file-expand-wildcards (concat (erlang-flymake-get-app-dir) "_build/*/lib/*/ebin")))) |
|
|
|
|
|
(setq erlang-flymake-get-code-path-dirs-function 'rebar3/erlang-flymake-get-code-path-dirs) |
|
|
#+end_src |
|
|
|
|
|
*** Erlang QuickCheck (Quviq) |
|
|
QuickCheck is the best testing tool, and comes with a bunch of |
|
|
helpful templates and shortcut keys for building out |
|
|
property-based tests. |
|
|
|
|
|
NB: I have disabled this since I no longer have a license. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
;;(defvar seancribbs/erlang/eqc-version |
|
|
;; "1.34.2" |
|
|
;; "The latest version of EQC I have installed.") |
|
|
|
|
|
;;(defun seancribbs/erlang/eqc/root () |
|
|
;; "Computes the location of the latest EQC app." |
|
|
;; (cl-reduce 'expand-file-name |
|
|
;; (list (format "eqc-%s" seancribbs/erlang/eqc-version) |
|
|
;; seancribbs/erlang/eqc-version |
|
|
;; "eqc" |
|
|
;; seancribbs/erlang/root) |
|
|
;; :from-end t)) |
|
|
|
|
|
;;(add-to-list 'load-path (expand-file-name "emacs" (seancribbs/erlang/eqc/root))) |
|
|
;;(autoload 'eqc-erlang-mode-hook "eqc-ext" "EQC Mode" t) |
|
|
;;(add-hook 'erlang-mode-hook 'eqc-erlang-mode-hook) |
|
|
;;(setq eqc-max-menu-length 30) |
|
|
;;(setq eqc-root-dir (seancribbs/erlang/eqc/root)) |
|
|
#+end_src |
|
|
*** Wrangler |
|
|
Wrangler is an Erlang refactoring tool that I use less often than |
|
|
other things, but can be super helpful in renaming functions, |
|
|
modules, and extracting common functionality. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'load-path (expand-file-name "dev/wrangler/elisp" user-home-directory)) |
|
|
(require 'vc) |
|
|
(require 'wrangler) |
|
|
|
|
|
(setq wrangler-search-paths '()) |
|
|
|
|
|
(defconst seancribbs/erlang/project-subdirs |
|
|
'("src" "test" "deps" "apps")) |
|
|
|
|
|
(defun seancribbs/erlang/expand-project-path (project-root subdir) |
|
|
"Expands a subdirectory" |
|
|
(let ((full-path (expand-file-name subdir project-root))) |
|
|
(when (file-exists-p full-path) |
|
|
(list full-path)))) |
|
|
|
|
|
(defconst seancribbs/erlang/project-root-files-regexp |
|
|
(regexp-opt '(".git" "rebar.config"))) |
|
|
|
|
|
(defun seancribbs/erlang/project-root-filter (name) |
|
|
(when (not (file-regular-p name)) |
|
|
(and (not (string-match-p "/\\(deps\\|apps\\)" name)) |
|
|
(directory-files name nil seancribbs/erlang/project-root-files-regexp) |
|
|
))) |
|
|
|
|
|
(defun seancribbs/erlang/project-root () |
|
|
"Finds the root of a project, based on presence of Git or rebar |
|
|
artifacts." |
|
|
(locate-dominating-file buffer-file-name 'seancribbs/erlang/project-root-filter)) |
|
|
|
|
|
(defun seancribbs/erlang/wrangler-set-paths () |
|
|
"Sets the wrangler search paths based on the location of the |
|
|
current file." |
|
|
(interactive) |
|
|
(let* ((project-root (expand-file-name (seancribbs/erlang/project-root))) |
|
|
(subdir-finder (lambda (subdir) (seancribbs/erlang/expand-project-path project-root subdir)))) |
|
|
(setq wrangler-search-paths |
|
|
(apply 'append (mapcar subdir-finder seancribbs/erlang/project-subdirs))) |
|
|
(minibuffer-message "Set wrangler paths to %S" wrangler-search-paths))) |
|
|
|
|
|
(eval-after-load "erlang" |
|
|
'(define-key erlang-mode-map (kbd "C-c C-w !") 'seancribbs/erlang/wrangler-set-paths)) |
|
|
#+end_src |
|
|
|
|
|
*** Customizations |
|
|
Erlang binaries are a pain to type, so I add a function and |
|
|
keybinding that inserts one for me. I'm still getting this one in |
|
|
my fingers. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(defun erlang-insert-binary () |
|
|
"Inserts a binary string into an Erlang buffer and places the |
|
|
point between the quotes." |
|
|
(interactive) |
|
|
(insert "<<\"\">>") |
|
|
(backward-char 3) |
|
|
) |
|
|
(eval-after-load "erlang" '(define-key erlang-mode-map (kbd "C-c b") 'erlang-insert-binary)) |
|
|
#+end_src |
|
|
|
|
|
** Lua |
|
|
Lua is a pretty interesting embeddable scripting language. I'm |
|
|
currently using it inside =nginx= and =luajit= from the shell. |
|
|
|
|
|
For some reason =lua-mode= defaults to 3-space indent, but all my |
|
|
coworkers use 4. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'lua-mode) |
|
|
(setq lua-default-application "luajit") |
|
|
(setq lua-indent-level 4) |
|
|
#+end_src |
|
|
|
|
|
** Scala |
|
|
Scala is used by one of the major projects I am working on. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'auto-mode-alist '(".scala$" . scala-mode)) |
|
|
(add-to-list 'auto-mode-alist '(".sbt$" . scala-mode)) |
|
|
#+end_src |
|
|
|
|
|
** Python |
|
|
Python's PEP8 tool is really picky about line-length, so this |
|
|
changes =fill-paragraph= to flow to narrower widths. I also hate |
|
|
the default of 8-space indentation. 4 is more humane. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-hook 'python-mode-hook |
|
|
(lambda () (set (make-local-variable 'fill-column) 75) |
|
|
(set (make-local-variable 'tab-width) 4))) |
|
|
#+end_src |
|
|
|
|
|
** Ruby |
|
|
The default auto-mode list for Ruby is insufficient. I also want |
|
|
to edit ERB files using MMM's ERB mode. One also shouldn't edit |
|
|
Rubinius compiler output. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'ruby-mode) |
|
|
(require 'mmm-erb) |
|
|
|
|
|
(add-to-list 'auto-mode-alist '("Guardfile$" . ruby-mode)) |
|
|
(add-to-list 'auto-mode-alist '("Assetfile$" . ruby-mode)) |
|
|
(add-to-list 'auto-mode-alist '(".html.erb" . html-erb-mode)) |
|
|
|
|
|
(add-to-list 'completion-ignored-extensions ".rbc") |
|
|
(add-to-list 'completion-ignored-extensions ".rbo") |
|
|
#+end_src |
|
|
** Haskell |
|
|
I'm learning Haskell. =haskell-mode= makes you choose an |
|
|
indentation strategy, so I'm using =haskell-indentation-mode= right |
|
|
now. |
|
|
#+begin_src emacs-lisp |
|
|
(add-hook 'haskell-mode-hook 'haskell-indentation-mode) |
|
|
#+end_src |
|
|
** JavaScript |
|
|
We should edit JSON files in JavaScript mode. |
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'auto-mode-alist '("\\.json$" . js-mode)) |
|
|
#+end_src |
|
|
** Emacs Lisp |
|
|
ElDoc and paredit make editing Emacs Lisp a lot easier. |
|
|
#+begin_src emacs-lisp |
|
|
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode) |
|
|
(add-hook 'emacs-lisp-mode-hook 'paredit-mode) |
|
|
(define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol) |
|
|
(define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent) |
|
|
(define-key emacs-lisp-mode-map (kbd "C-c v") 'eval-buffer) |
|
|
#+end_src |
|
|
** Clojure |
|
|
I'm starting to use a little Clojure with riemann, but paredit is |
|
|
off by default. |
|
|
#+begin_src emacs-list |
|
|
(add-hook 'clojure-mode-hook (lambda () (paredit-mode t))) |
|
|
#+end_src |
|
|
** Org |
|
|
I co-opted a lot of these =org-mode= customizations from Aaron. |
|
|
|
|
|
=org-present= is for doing presentations direct from =org-mode=. I |
|
|
added =hide-mode-line= so that you don't get the modeline noise |
|
|
while presenting. It is not available as a package but you can |
|
|
download it: [[http://webonastick.com/emacs-lisp/hide-mode-line.el]] |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'ob) |
|
|
|
|
|
(org-babel-do-load-languages |
|
|
'org-babel-load-languages |
|
|
'((sh . t) |
|
|
(dot . t) |
|
|
(ruby . t) |
|
|
(js . t) |
|
|
(C . t))) |
|
|
|
|
|
(add-to-list 'org-src-lang-modes (quote ("dot". graphviz-dot))) |
|
|
|
|
|
(setq org-src-fontify-natively t) |
|
|
|
|
|
(require 'org-present) |
|
|
(require 'hide-mode-line) |
|
|
|
|
|
(define-key org-present-mode-keymap (kbd "q") 'org-present-quit) |
|
|
|
|
|
(defun seancribbs/org-present-hook () |
|
|
"Entry hook for org-present mode" |
|
|
(window-configuration-to-register :org-present-register) |
|
|
(delete-other-windows) |
|
|
(org-present-big) |
|
|
(org-display-inline-images) |
|
|
(hide-mode-line-in (current-buffer))) |
|
|
|
|
|
(add-hook 'org-present-mode-hook 'seancribbs/org-present-hook) |
|
|
|
|
|
(defun seancribbs/org-present-quit-hook () |
|
|
"Entry hook for org-present mode" |
|
|
(org-present-small) |
|
|
(org-remove-inline-images) |
|
|
(show-mode-line-in (current-buffer)) |
|
|
(redraw-display) |
|
|
(when (get-register :org-present-register) |
|
|
(jump-to-register :org-present-register))) |
|
|
|
|
|
(add-hook 'org-present-mode-quit-hook 'seancribbs/org-present-quit-hook) |
|
|
|
|
|
#+end_src |
|
|
** Markdown |
|
|
Most of my Markdown editing uses Github-flavored, so I use |
|
|
=gfm-mode= instead of the regular =markdown-mode=. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-to-list 'auto-mode-alist '(".md$" . gfm-mode)) |
|
|
#+end_src |
|
|
** Text |
|
|
I like my text modes to auto-wrap paragraphs. |
|
|
|
|
|
I did a project for a little while where I tried to write 750 |
|
|
words a day, to improve my writing skills. I didn't get very far, |
|
|
but I added =wc-mode= and a quick keychord to launch it. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(add-hook 'text-mode-hook 'turn-on-auto-fill) |
|
|
|
|
|
(require 'wc-mode) |
|
|
|
|
|
(defun open-daily-writing () |
|
|
"Open today's writing file" |
|
|
(interactive) |
|
|
(let ((filename (format-time-string "%Y-%m-%d.txt"))) |
|
|
(find-file (concat user-home-directory "/notes/writing/" |
|
|
filename)) |
|
|
(with-current-buffer filename |
|
|
(wc-mode t) |
|
|
(wc-set-word-goal 750)) |
|
|
) |
|
|
(delete-other-windows)) |
|
|
|
|
|
(global-set-key (kbd "C-x C-S-W") 'open-daily-writing) |
|
|
#+end_src |
|
|
|
|
|
** Graphviz |
|
|
Graphviz dot is great for quickly specifying graphs. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
;; NB: (require 'graphviz-dot-mode) doesn't work because the file |
|
|
;; doesn't have a (provide), but it does have an autoload. |
|
|
(setq graphviz-dot-dot-program "/usr/local/bin/dot" |
|
|
graphviz-dot-indent-width 4) |
|
|
#+end_src |
|
|
** LaTeX |
|
|
I use LaTeX for papers and sometimes presentations in Beamer. |
|
|
|
|
|
Fontifying sub/superscripts can be incredibly annoying, especially |
|
|
when your file contains source code that might have underscores, so |
|
|
I turn off =tex-fontify-script=. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'tex-mode) |
|
|
|
|
|
(defvar texlive-bin |
|
|
"/usr/local/texlive/2014/bin/x86_64-darwin" |
|
|
"The location of the TeXlive distribution binaries.") |
|
|
|
|
|
(setq latex-run-command (concat (expand-file-name "pdflatex" texlive-bin) " -shell-escape") |
|
|
tex-bibtex-command (expand-file-name "bibtex" texlive-bin) |
|
|
tex-fontify-script nil) |
|
|
#+end_src |
|
|
|
|
|
* Utilities |
|
|
** Uniquify |
|
|
=uniquify= is a built-in library that renames buffers according to |
|
|
relative paths instead of adding numbers to the names like |
|
|
=foo.txt<2>=. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'uniquify) |
|
|
(setq uniquify-buffer-name-style 'forward) |
|
|
#+end_src |
|
|
** Ido |
|
|
Ido mode provides a nice way to navigate the filesystem. These |
|
|
tweaks come from ESK. |
|
|
#+begin_src emacs-lisp |
|
|
(ido-mode t) |
|
|
(ido-ubiquitous-mode) |
|
|
(setq ido-enable-prefix nil |
|
|
ido-enable-flex-matching t |
|
|
ido-auto-merge-work-directories-length nil |
|
|
ido-create-new-buffer 'always |
|
|
ido-use-filename-at-point 'guess |
|
|
ido-use-virtual-buffers t |
|
|
ido-handle-duplicate-virtual-buffers 2 |
|
|
ido-max-prospects 10) |
|
|
|
|
|
(global-set-key (kbd "C-x M-f") 'ido-find-file-other-window) |
|
|
#+end_src |
|
|
** ffap |
|
|
Find file at point is useful for jumping between files based on |
|
|
the word pointed at, e.g. Erlang modules in the current directory. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'ffap) |
|
|
#+end_src |
|
|
|
|
|
** Smex |
|
|
smex is a necessity. It provides history and searching on top of |
|
|
M-x. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(setq smex-save-file (expand-file-name ".smex-items" user-emacs-directory)) |
|
|
(smex-initialize) |
|
|
(global-set-key (kbd "M-x") 'smex) |
|
|
(global-set-key (kbd "M-X") 'smex-major-mode-commands) |
|
|
#+end_src |
|
|
|
|
|
** Magit |
|
|
Magit is the best VCS tool I've ever used. It makes all sorts of |
|
|
things in git easier. |
|
|
|
|
|
I add an advice around launching Magit that saves and restores the |
|
|
previous window configuration when exiting. This lets you |
|
|
"fullscreen" changes and other VCS windows, then quickly return to |
|
|
your previously opened buffers and windows. |
|
|
|
|
|
I also set the diff switches to use unified diffs, which ESK also |
|
|
does. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(setq magit-last-seen-setup-instructions "1.4.0") |
|
|
|
|
|
(require 'magit) |
|
|
;; TODO is this needed if we have the PATH set correctly? |
|
|
(setq magit-git-executable "/usr/local/bin/git") |
|
|
(global-set-key (kbd "C-c g") 'magit-status) |
|
|
|
|
|
(defadvice magit-status (around magit-fullscreen activate) |
|
|
(window-configuration-to-register :magit-fullscreen) |
|
|
ad-do-it |
|
|
(delete-other-windows)) |
|
|
|
|
|
(defun magit-quit-session () |
|
|
"Restores the previous window configuration and kills the magit buffer" |
|
|
(interactive) |
|
|
(kill-buffer) |
|
|
(when (get-register :magit-fullscreen) |
|
|
(jump-to-register :magit-fullscreen))) |
|
|
|
|
|
(define-key magit-status-mode-map (kbd "q") 'magit-quit-session) |
|
|
|
|
|
(setq diff-switches "-u") |
|
|
#+end_src |
|
|
|
|
|
** Ag |
|
|
=ag= (aka =the_silver_searcher=) is a great command-line tool for |
|
|
finding things in programming source files. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'ag) |
|
|
(global-set-key (kbd "C-x C-g") 'ag-project) ;; Bind C-x C-g to ag-project |
|
|
#+end_src |
|
|
|
|
|
** Dash |
|
|
Dash is a Mac OS/X documentation browser and has a nice way to |
|
|
launch it from Emacs. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(require 'dash-at-point) |
|
|
(global-set-key (kbd "C-c d") 'dash-at-point) |
|
|
#+end_src |
|
|
** Neotree |
|
|
Neotree is the only "project browser sidebar" thing I've ever been |
|
|
able to tolerate. It does a pretty good job if you turn off the |
|
|
icons and base its colors on the theme. |
|
|
|
|
|
#+begin_src emacs-lisp |
|
|
(setq neo-theme 'ascii) |
|
|
(custom-set-faces |
|
|
'(neo-banner-face ((t . (:inherit shadow))) t) |
|
|
'(neo-header-face ((t . (:inherit shadow))) t) |
|
|
'(neo-root-dir-face ((t . (:inherit link-visited :underline nil))) t) |
|
|
'(neo-dir-link-face ((t . (:inherit dired-directory))) t) |
|
|
'(neo-file-link-face ((t . (:inherit default))) t) |
|
|
'(neo-button-face ((t . (:inherit dired-directory))) t) |
|
|
'(neo-expand-btn-face ((t . (:inherit button))) t)) |
|
|
#+end_src |