Skip to content

Instantly share code, notes, and snippets.

@jahfer
Created September 15, 2014 16:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jahfer/ca38b504803d70669e96 to your computer and use it in GitHub Desktop.
Save jahfer/ca38b504803d70669e96 to your computer and use it in GitHub Desktop.
;; 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment