Skip to content

Instantly share code, notes, and snippets.

@jahfer
Created September 15, 2014 16:49

Revisions

  1. jahfer created this gist Sep 15, 2014.
    334 changes: 334 additions & 0 deletions init.el
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,334 @@
    ;; Package

    ;; Managing extensions for Emacs is simplified using =package= which
    ;; is built in to Emacs 24 and newer. To load downloaded packages we
    ;; need to initialize =package=.

    (require 'package)
    (setq package-enable-at-startup nil)
    (package-initialize)

    ;; Packages can be fetched from different mirrors, [[http://melpa.milkbox.net/#/][melpa]] is the largest
    ;; archive and is well maintained.

    (setq package-archives
    '(("gnu" . "http://elpa.gnu.org/packages/")
    ("org" . "http://orgmode.org/elpa/")
    ("MELPA" . "http://melpa.milkbox.net/packages/")))

    ;; We can define a predicate that tells us whether or not the newest version
    ;; of a package is installed.

    (defun newest-package-installed-p (package)
    "Return true if the newest available PACKAGE is installed."
    (when (package-installed-p package)
    (let* ((local-pkg-desc (or (assq package package-alist)
    (assq package package--builtins)))
    (newest-pkg-desc (assq package package-archive-contents)))
    (and local-pkg-desc newest-pkg-desc
    (version-list-= (package-desc-vers (cdr local-pkg-desc))
    (package-desc-vers (cdr newest-pkg-desc)))))))

    ;; Let's write a function to install a package if it is not installed or
    ;; upgrades it if a new version has been released. Here our predicate comes
    ;; in handy.

    (defun upgrade-or-install-package (package)
    "Unless the newest available version of PACKAGE is installed
    PACKAGE is installed and the current version is deleted."
    (unless (newest-package-installed-p package)
    (let ((pkg-desc (assq package package-alist)))
    (when pkg-desc
    (package-delete (symbol-name package)
    (package-version-join
    (package-desc-vers (cdr pkg-desc)))))
    (and (assq package package-archive-contents)
    (package-install package)))))

    ;; Also, we will need a function to find all dependencies from a given package.

    (defun dependencies (package)
    "Returns a list of dependencies from a given PACKAGE."
    (let* ((pkg-desc (assq package package-alist))
    (reqs (and pkg-desc (package-desc-reqs (cdr pkg-desc)))))
    (mapcar 'car reqs)))

    ;; The =package-refresh-contents= function downloads archive descriptions,
    ;; this is a major bottleneck in this configuration. To avoid this we can
    ;; try to only check for updates once every day or so. Here are three
    ;; variables. The first specifies how often we should check for updates. The
    ;; second specifies whether one should update during the initialization. The
    ;; third is a path to a file where a time-stamp is stored in order to check
    ;; when packages were updated last.

    (defvar days-between-updates 7)
    (defvar do-package-update-on-init t)
    (defvar package-last-update-file
    (expand-file-name (concat user-emacs-directory ".package-last-update")))

    ;; The tricky part is figuring out when packages were last updated. Here is
    ;; a hacky way of doing it, using [[http://www.gnu.org/software/emacs/manual/html_node/emacs/Time-Stamps.html][time-stamps]]. By adding a time-stamp to the
    ;; a file, we can determine whether or not to do an update. After that we
    ;; must run the =time-stamp=-function to update the time-stamp.

    (require 'time-stamp)
    ;; Open the package-last-update-file
    (with-temp-file package-last-update-file
    (if (file-exists-p package-last-update-file)
    (progn
    ;; Insert it's original content's.
    (insert-file-contents package-last-update-file)
    (let ((start (re-search-forward time-stamp-start nil t))
    (end (re-search-forward time-stamp-end nil t)))
    (when (and start end)
    ;; Assuming we have found a time-stamp, we check determine if it's
    ;; time to update.
    (setq do-package-update-on-init
    (<= days-between-updates
    (days-between
    (current-time-string)
    (buffer-substring-no-properties start end))))
    ;; Remember to update the time-stamp.
    (when do-package-update-on-init
    (time-stamp)))))
    ;; If no such file exists it is created with a time-stamp.
    (insert "Time-stamp: <>")
    (time-stamp)))


    ;; Now we can use the function above to make sure packages are installed and
    ;; up to date. Here are some packages I find useful (some of these
    ;; configurations are also dependent on them).

    (when (and do-package-update-on-init
    (y-or-n-p "Update all packages?"))
    (package-refresh-contents)

    (let* ((packages
    '(;ac-geiser ; Auto-complete backend for geiser
    ;ac-slime ; An auto-complete source using slime completions
    ;ace-jump-mode ; quick cursor location minor mode
    ;auto-compile ; automatically compile Emacs Lisp libraries
    auto-complete ; auto completion
    cider ; clojure integrated development environment and REPL
    clojure-mode ; major mode for clojure code
    ;elscreen ; window session manager
    ;expand-region ; Increase selected region by semantic units
    flx-ido ; flx integration for ido
    ;idle-require ; load elisp libraries while Emacs is idle
    ido-vertical-mode ; Makes ido-mode display vertically.
    ;geiser ; GNU Emacs and Scheme talk to each other
    ;haskell-mode ; A Haskell editing mode
    ;jedi ; Python auto-completion for Emacs
    ;js2-mode ; Improved JavaScript editing mode
    magit ; control Git from Emacs
    markdown-mode ; Emacs Major mode for Markdown-formatted files.
    ;matlab-mode ; MATLAB integration with Emacs.
    ;inkpot-theme ; port of vim's inkpot theme
    monokai-theme ; A fruity color theme for Emacs.
    move-text ; Move current line or region with M-up or M-down
    multiple-cursors ; Multiple cursors for Emacs.
    org ; Outline-based notes management and organizer
    paredit ; minor mode for editing parentheses
    powerline ; Rewrite of Powerline
    pretty-lambdada ; the word `lambda' as the Greek letter.
    smex ; M-x interface with Ido-style fuzzy matching.
    projectile-rails ; projectile support for rails projectsx
    undo-tree)) ; Treat undo history as a tree
    ;; Fetch dependencies from all packages.
    (reqs (mapcar 'dependencies packages))
    ;; Append these to the original list, and remove any duplicates.
    (packages (delete-dups (apply 'append packages reqs))))

    (dolist (package packages)
    (upgrade-or-install-package package)))

    ;; This package is only relevant for Mac OS X.
    (when (memq window-system '(mac ns))
    (upgrade-or-install-package 'exec-path-from-shell))
    (package-initialize))

    ;; Mac OS X

    ;; I run this configuration mostly on Mac OS X, so we need a couple of
    ;; settings to make things work smoothly. In the package section
    ;; =exec-path-from-shell= is included (only if you're running OS X), this is
    ;; to include environment-variables from the shell. It makes useing Emacs
    ;; along with external processes a lot simpler. I also prefer using the
    ;; =Command=-key as the =Meta=-key.

    (when (memq window-system '(mac ns))
    (setq mac-option-modifier 'meta
    x-select-enable-clipboard t)
    (run-with-idle-timer 5 nil 'exec-path-from-shell-initialize))

    ;; Some mac-bindings interfere with Emacs bindings.
    (when (boundp 'mac-pass-command-to-system)
    (setq mac-pass-command-to-system nil))

    (defvar emacs-autosave-directory
    (concat user-emacs-directory "autosaves/")
    "This variable dictates where to put auto saves. It is set to a
    directory called autosaves located wherever your .emacs.d/ is
    located.")

    ;; Sets all files to be backed up and auto saved in a single directory.
    (setq backup-directory-alist
    `((".*" . ,emacs-autosave-directory))
    auto-save-file-name-transforms
    `((".*" ,emacs-autosave-directory t)))

    ;; Set =utf-8= as preferred coding system.
    (set-language-environment "UTF-8")

    ;; Call =auto-complete= default configuration, which enables =auto-complete=
    ;; globally.
    (eval-after-load 'auto-complete-config `(ac-config-default))

    ;; Modes

    ;; There are some modes that are enabled by default that I don't find
    ;; particularly useful. We create a list of these modes, and disable all of
    ;; these.

    (dolist (mode
    '(tool-bar-mode ; No toolbars, more room for text.
    scroll-bar-mode ; No scroll bars either.
    blink-cursor-mode)) ; The blinking cursor gets old.
    (funcall mode 0))


    ;; Let's apply the same technique for enabling modes that are disabled by
    ;; default.

    (dolist (mode
    '(;abbrev-mode ; E.g. sopl -> System.out.println.
    column-number-mode ; Show column number in mode line.
    delete-selection-mode ; Replace selected text.
    recentf-mode ; Recently opened files.
    show-paren-mode ; Highlight matching parentheses.
    global-undo-tree-mode)) ; Undo as a tree.
    (funcall mode 1))


    ;; This makes =.md=-files open in =markdown-mode=.
    (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))

    ;; Visual
    ;; Change the color-theme to =monokai= (downloaded using =package=).
    (load-theme 'monokai t)

    ;; [[https://github.com/milkypostman/powerline][Powerline]] is an extension to customize the mode line. This is modified
    ;; version =powerline-nano-theme=.
    (setq-default
    mode-line-format
    '("%e"
    (:eval
    (let* ((active (powerline-selected-window-active))
    ;; left hand side displays Read only or Modified.
    (lhs (list (powerline-raw
    (cond (buffer-read-only "Read only")
    ((buffer-modified-p) "Modified")
    (t "")) nil 'l)))
    ;; right side hand displays (line,column).
    (rhs (list
    (powerline-raw
    (concat
    "(" (number-to-string (line-number-at-pos))
    "," (number-to-string (current-column)) ")") nil 'r)))
    ;; center displays buffer name.
    (center (list (powerline-raw "%b" nil))))
    (concat (powerline-render lhs)
    (powerline-fill-center nil (/ (powerline-width center) 2.0))
    (powerline-render center)
    (powerline-fill nil (powerline-width rhs))
    (powerline-render rhs))))))


    ;; Ido

    ;; Interactive do (or =ido-mode=) changes the way you switch buffers and
    ;; open files/directories. Instead of writing complete file paths and buffer
    ;; names you can write a part of it and select one from a list of
    ;; possibilities. Using =ido-vertical-mode= changes the way possibilities
    ;; are displayed, and =flx-ido-mode= enables fuzzy matching.

    (dolist (mode
    '(ido-mode ; Interactivly do.
    ido-everywhere ; Use Ido for all buffer/file reading.
    ;ido-vertical-mode ; Makes ido-mode display vertically.
    flx-ido-mode)) ; Toggle flx ido mode.
    (funcall mode 1))


    ;; We can set the order of file selections in =ido=. I prioritize source
    ;; files along with =org=- and =tex=-files.

    (setq ido-file-extensions-order
    '(".el" ".scm" ".lisp" ".java" ".c" ".h" ".org" ".tex"))

    ;; Sometimes when using =ido-switch-buffer= the =*Messages*= buffer get in
    ;; the way, so we set it to be ignored (it can be accessed using =C-h e=, so
    ;; there is really no need for it in the buffer list).

    (add-to-list 'ido-ignore-buffers "*Messages*")

    ;; To make =M-x= behave more like =ido-mode= we can use the =smex=
    ;; package. It needs to be initialized, and we can replace the binding to
    ;; the standard =execute-extended-command= with =smex=.

    (smex-initialize)
    (global-set-key (kbd "M-x") 'smex)


    ;; Interactive functions
    ;; <<sec:defuns>>

    ;; To search recent files useing =ido-mode= we add this snippet from
    ;; [[http://www.emacswiki.org/emacs/CalendarWeekNumbers][EmacsWiki]].

    (defun recentf-ido-find-file ()
    "Find a recent file using Ido."
    (interactive)
    (let ((f (ido-completing-read "Choose recent file: " recentf-list nil t)))
    (when f
    (find-file f))))


    ;; Projectile configuration

    (projectile-global-mode)

    ;; Lisp

    ;; =Pretty-lambda= provides a customizable variable
    ;; =pretty-lambda-auto-modes= that is a list of common lisp modes. Here we
    ;; can add some extra lisp-modes. We run the =pretty-lambda-for-modes=
    ;; function to activate =pretty-lambda-mode= in lisp modes.

    (dolist (mode '(clojure-mode slime-repl-mode geiser-repl-mode))
    (add-to-list 'pretty-lambda-auto-modes mode))

    (pretty-lambda-for-modes)

    ;; I use =Paredit= when editing lisp code, we enable this for all lisp-modes
    ;; in the =pretty-lambda-auto-modes= list.

    (dolist (mode pretty-lambda-auto-modes)
    ;; add paredit-mode to all mode-hooks
    (add-hook (intern (concat (symbol-name mode) "-hook")) 'paredit-mode))

    (setq shell-file-name "/bin/sh")

    ;; Key bindings

    ;; Bind some native Emacs functions.
    (global-set-key (kbd "C-x k") 'kill-this-buffer)
    (global-set-key (kbd "C-x C-r") 'recentf-ido-find-file)

    ;; Bindings for [[http://magit.github.io][Magit]].
    (global-set-key (kbd "C-c m") 'magit-status)

    ;; Bindings for =move-text=.
    (global-set-key (kbd "<M-up>") 'move-text-up)
    (global-set-key (kbd "<M-down>") 'move-text-down)