marius.org
Getting by on the Mac
Command is meta, option is what it should be.
(setq mac-option-modifier "none")
(setq mac-command-modifier "meta")
Dot emacs, literate style
This file is loaded from init.el after any .org files in extras/ This is because we want to be able to use libraries from there from this file.
The basics
(setq inhibit-startup-screen t)
Packages
Emacs 24 ships with a package system, which is great. Let’s enable it:
(package-initialize)
and add some more repositories:
(add-to-list 'package-archives
'("marmalade" . "http://marmalade-repo.org/packages/"))
Yasnippet
I keep revisiting this one. Bin Chen suggests binding completion
to a different key combo than TAB
, which may make sense. Oh, and
he uses it for email, which is pretty awesome.
Giving it another shot, this time binding it to C-c k
;; (add-to-list 'load-path "~/.emacs.d/elpa/yasnippet-0.8.0")
(require 'yasnippet)
(yas/global-mode t)
(setq my-snippets (expand-file-name "~/.emacs.d/snippets"))
(add-to-list 'yas-snippet-dirs my-snippets)
Now to stop yasnippets from occupying TAB
(God, that’s annoying)
and rebind to C-c y e
(mnemonic Yas Expand).
(global-set-key (kbd "C-c y e") 'yas-expand)
(global-set-key (kbd "C-c y i") 'yas-insert-snippet)
(define-key yas-minor-mode-map [(tab)] nil)
Auto-fill in org-mode
I always want auto-fill-mode on in my org buffers.
(add-hook 'org-mode-hook
(lambda() (auto-fill-mode)))
Ido
Ido improves all kind of minibuffer activities:
- find-file
- switch-buffer
with case-insensitivity and all kinds of wonderful things. Let’s load it up:
(load-library "ido")
(ido-mode)
Jump to symbol support
Jump to a symbol (function, class etc.) with completion. No textmate required
(defun ido-goto-symbol (&optional symbol-list)
"Refresh imenu and jump to a place in the buffer using Ido."
(interactive)
(unless (featurep 'imenu)
(require 'imenu nil t))
(cond
((not symbol-list)
(let ((ido-mode ido-mode)
(ido-enable-flex-matching
(if (boundp 'ido-enable-flex-matching)
ido-enable-flex-matching t))
name-and-pos symbol-names position)
(unless ido-mode
(ido-mode 1)
(setq ido-enable-flex-matching t))
(while (progn
(imenu--cleanup)
(setq imenu--index-alist nil)
(ido-goto-symbol (imenu--make-index-alist))
(setq selected-symbol
(ido-completing-read "Symbol? " symbol-names))
(string= (car imenu--rescan-item) selected-symbol)))
(unless (and (boundp 'mark-active) mark-active)
(push-mark nil t nil))
(setq position (cdr (assoc selected-symbol name-and-pos)))
(cond
((overlayp position)
(goto-char (overlay-start position)))
(t
(goto-char position)))))
((listp symbol-list)
(dolist (symbol symbol-list)
(let (name position)
(cond
((and (listp symbol) (imenu--subalist-p symbol))
(ido-goto-symbol symbol))
((listp symbol)
(setq name (car symbol))
(setq position (cdr symbol)))
((stringp symbol)
(setq name symbol)
(setq position
(get-text-property 1 'org-imenu-marker symbol))))
(unless (or (null position) (null name)
(string= (car imenu--rescan-item) name))
(add-to-list 'symbol-names name)
(add-to-list 'name-and-pos (cons name position))))))))
Emacs server mode
Let’s support emacsclient. For that to work, we’ll need to start the server. Unless, of course, it’s already running
(require 'server)
(unless (server-running-p) (server-start))
Zen coding
Absolutely amazing. By entering CSS selectors like
html>head+body>div.content>ul#navigation>li.item*4
and caling
zencoding-expand-line
you end up with:
- an interactive preview of the markup that would be rendered
- Pressing
RET
will insert it into the buffer.
I made a short asciicast about it. Let’s activate it automatically for any SGML modes
(add-hook 'sgml-mode-hook 'zencoding-mode)
(add-hook 'web-mode-hook 'zencoding-mode)
Blogging from org
Apparently, we need to set up the project list
(setq org-publish-project-alist
'(("blogg"
:base-directory "/Users/marius/Projects/blog/orgfiles"
:publishing-directory "/Users/marius/Projects/blog/output"
:publishing-function org-html-publish-to-html
:headline-levels 3
:recursive t
:exclude "^\..$"
:table-of-contents nil
:html-preamble nil
:html-postamble nil
:body-only t
:section-numbers nil
:auto-sitemap t
:sitemap-filename "index.org"
:sitemap-sort-files anti-chronologically
:sitemap-sort-folders last
:sitemap-file-entry-format "%d: *%t*"
:sitemap-date-format "%B %e, %Y"
)
("images"
:base-directory "~/Projects/blog/images"
:base-extension "jpg\\|gif\\|png"
:publishing-directory "/ssh:friskbris.no:/var/www/zmalltalker.com/images/"
:publishing-function org-publish-attachment)
("bolig"
:base-directory "/Users/marius/Dropbox/dotfiles/orgfiles/bolig/"
:publishing-directory "/Users/marius/Dropbox/Public/Laarhalsen"
:headline-levels 3
:recursive t
:table-of-contents nil
:html-preamble nil
:html-postamble nil
:body-only t
:section-numbers nil
:auto-sitemap t
)
("gitorious-book"
:base-directory "/Users/marius/Projects/gitorious/gitorious-book/"
:publishing-directory "/tmp/gitorious-book"
:headline-levels 3
:recursive t
:table-of-contents t
:html-preamble nil
:html-postamble nil
:body-only nil
:section-numbers nil
:auto-sitemap t
)
))
Let’s bind C-x p
to org-publish-current-project
(global-set-key (kbd "C-x p") 'org-publish-current-project)
Org-mode produces some quite nasty HTML, and I use Twitter Bootstrap to mark up my code, so I want to use different tags from the defaults.
Because of this I export the body part only, and run a Rake task which uses ERB to generate a full HTML page afterwards. I’m adding a hook that’s run after publishing; this will generate any updated HTML files and publish it to my website.
(add-hook 'org-publish-after-export-hook (lambda ()
(shell-command "cd ~/Projects/blog && rake deploy")))
And then we definitely want to use htmlize, as this will do wonderful things to source code in org files. It’s distributed with orgmode, but we’ll need to load it.
(add-to-list 'load-path (concat dotfiles-dir "/src/org-mode/contrib/lisp"))
(require 'htmlize)
In order to fontify RPM specs, I’ll need this baby
(add-to-list 'load-path "/usr/share/emacs/site-lisp/")
(autoload 'rpm-spec-mode "rpm-spec-mode.el" "RPM spec mode." t)
;;(require 'rpm-spec-mode)
Does fontified Smalltalk sound good? Let’s do it!
(require 'smalltalk-mode)
YAML mode
YAML is … should we say picky? … to edit by hand. Indentation matters a lot, and syntax highlighting is a great help.
Let’s get some help:
(require 'yaml-mode)
(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
Update PATH
I need (among others?) node on my PATH within Emacs
(setenv "PATH"
(concat
"/opt/node/bin:"
(getenv "PATH")
)
)
Magnar’s awesome Magit setup
Magit. I was skeptical at first, but then I just … yum. Let’s load it
(require 'magit)
(add-to-list 'load-path "/Users/marius/.emacs.d/extras")
Magnar (or Christian?) shared some customizations for Magit that make it even better:
(require 'setup-magit)
I use C-x m for starting magit
(global-set-key (kbd "C-x m") 'magit-status)
Add a little formatting to done headlines in org-mode
Picked up this little nugget from this blog post.
(setq org-fontify-done-headline t)
(custom-set-faces
'(org-done ((t (:foreground "PaleGreen"
:weight normal
:strike-through t))))
'(org-headline-done
((((class color) (min-colors 16) (background dark))
(:foreground "LightSalmon" :strike-through t)))))
Recent files
Support open-recent-file. This needs some work.
(require 'recentf)
(recentf-mode 1)
I just copied something awesome off the Internet! It’s a function that does an ido-complete of the recently open files.
(defun recentf-interactive-complete ()
"find a file in the recently open file using ido for completion"
(interactive)
(let* ((all-files recentf-list)
(file-assoc-list (mapcar (lambda (x) (cons (file-name-nondirectory x) x)) all-files))
(filename-list (remove-duplicates (mapcar 'car file-assoc-list) :test 'string=))
(ido-make-buffer-list-hook
(lambda ()
(setq ido-temp-list filename-list)))
(filename (ido-read-buffer "Find Recent File: "))
(result-list (delq nil (mapcar (lambda (x) (if (string= (car x) filename) (cdr x))) file-assoc-list)))
(result-length (length result-list)))
(find-file
(cond
((= result-length 0) filename)
((= result-length 1) (car result-list))
( t
(let ( (ido-make-buffer-list-hook
(lambda ()
(setq ido-temp-list result-list))))
(ido-read-buffer (format "%d matches:" result-length))))
))))
Now let’s map this baby to C-x C-g:
(global-set-key (kbd "C-x C-g") 'recentf-interactive-complete)
Theme
Emacs 24 has built-in theming support.
Custom themes
Dropping any themes I want to try out into ~/.emacs.d/themes
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes")
Current theme
I’m using the solarized-dark theme right now. It’s really easy on my eyes and pretty as well. This theme is installed using Emacs’ package manager, so solarized would be in elpa/solarized-theme-0.5.0. To install a theme, use package-install.
(setq zmalltalker/default-theme 'zenburn)
(setq zmalltalker/lighter-theme 'solarized-light)
(defun zmalltalker/theme-lighter ()
(interactive)
(load-theme zmalltalker/lighter-theme t)
)
(defun zmalltalker/default-theme ()
(interactive)
(load-theme zmalltalker/default-theme t)
)
(zmalltalker/default-theme)
Sometimes I need to use a lighter theme, eg. when using htmlize. I’m adding a function for switching to this and back.
Run tests from Emacs
This is currently a wish list
- [X] find .rvmrc
- [X] set correct ruby
- [X] run $ruby -Ilib:test <project_root>/path
- [ ] compile
Mark text and delete/replace immediately
You know how other editors will let you select text and then start typing right away to replace it? You know how you need to remove this from your muscle memory when using Emacs? No more
(delete-selection-mode)
Ascii art to Unicode
Convert simple ASCII art drawings (and org-tables) to beautiful Unicode.
(add-to-list 'load-path (concat dotfiles-dir "/contrib"))
(require 'ascii-art-to-unicode)
TODO More org exporters (Org > 7.9)
This is WIP, as org 8.0 changes exports stuff a lot
Markdown is an inferior format, and can be generated. Halleluja, I can make man pages!
(setq org-export-backends '(ascii html icalendar latex man deck groff rss texinfo))
Use bullets for headings in org
(require 'org-bullets)
'(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
Speed commands in org
With speed commands enabled, I can enter single-letter commands
when the cursor is at the very beginning of a headline. ?
displays a menu
(setq org-use-speed-commands t)
Trailing whitespace
Removing trailing whitespace on save should be on by default. I’ve been looking like a clueless moron
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Cleaning up ugly JSON
From time to time we need to deal with really ugly “JSON”, eg from Outlook email. To clean this up, we have this baby.
(defun zmalltalker/json-cleanup ()
"Clean up dirty JSON from Outlook and whatnot"
(interactive)
(let ((new-contents (replace-regexp-in-string "[“”]" "\"" (buffer-string))))
(kill-region (point-min) (point-max))
(insert new-contents)
(json-pretty-print (point-min) (point-max))
))
Code cleanup
In order to have really neat source code, it sounds like a good idea to have a single keystroke for cleaning up a file.
(defun zmalltalker-clean-up-everything ()
"Perform housekeeping on the current buffer"
(interactive)
(save-excursion
(whitespace-cleanup)
(mark-whole-buffer)
(indent-region (point) (mark))
)
)
(global-set-key (kbd "C-c n") 'zmalltalker-clean-up-everything)
Rinari
No fucking way. I’m leaving this trail behind just to remind me not to do this again.
Email setup
I’m playing with Mutt as my MUA (with offlineimap for sync and msmtp for sending mail). It’s awesome.
I put “set editor=emacsclient -c” in my ~/.muttrc, which makes emacsclient open a new graphical frame when I compose/reply to/forward a message.
Set up mail mode when viewing a mutt buffer
(add-to-list 'auto-mode-alist '("/mutt" . mail-mode))
And of course I want auto-fill when writing email, and I want to bind C-c C-c to server-edit, which finishes the editing session
(defun zmalltalker-mail-mode-hook ()
(auto-fill-mode 1)
(local-set-key (kbd "C-c C-c") (lambda ()
(interactive)
(save-buffer)
(server-edit))))
(add-hook 'mail-mode-hook 'zmalltalker-mail-mode-hook)
Multiple cursors
This makes me look as cool as Magnar.
(add-to-list 'load-path (concat dotfiles-dir "/contrib/multiple-cursors"))
(require 'multiple-cursors)
;; Select next/previous/all places like the current
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
(global-set-key (kbd "C-S-c C-e") 'mc/edit-ends-of-lines)
(global-set-key (kbd "C-S-c C-a") 'mc/edit-beginnings-of-lines)
Goto line with feedback
M-g M-g is kind of boring; it could be helpful to turn on line numbers while the prompt is being displayed. Here we go.
;; turn line numbers off by default
(global-linum-mode -1)
(defun goto-line-with-feedback (&optional line)
"Show line numbers temporarily, while prompting for the line number input"
(interactive "P")
(if line
(goto-line line)
(unwind-protect
(progn
(linum-mode 1)
(goto-line (read-number "Goto line: ")))
(linum-mode -1))))
(global-set-key (vector 'remap 'goto-line) 'goto-line-with-feedback)
Mu4e
Trying out mu4e for my email. Mu is a search engine for Maildir email, and relies on my existing toolchain for email:
- Offlineimap for imap
- msmtp to send mail.
(add-to-list 'load-path (concat dotfiles-dir "contrib/mu4e"))
(require 'mu4e)
(setq mu4e-get-mail-command "offlineimap")
(setq mu4e-drafts-folder "/Gitorious/drafts")
(setq user-mail-address "marius@gitorious.com")
(setq mu4e-user-mail-address-list (list "marius@shortcut.no" "marius@gitorious.org" "zmalltalker@zmalltalker.com" "marius.mathiesen@gmail.com" "marius@gitorious.com"))
;; (setq user-mail-address-list "marius@gitorious.com")
(setq message-kill-buffer-on-exit t)
;; Use fancy chars
(setq mu4e-use-fancy-chars t)
;; Shortcuts
(setq mu4e-maildir-shortcuts
'(("/Gitorious/inbox" . ?g)
("/Gmail/inbox" . ?z)
("/Shortcut/inbox" . ?s)
("/Gmail/gitorious-ml" . ?m)
))
;; Smart refile locations
(setq mu4e-refile-folder
(lambda (msg)
(cond
;; messages sent directly to me go to /archive
;; also `mu4e-user-mail-address-regexp' can be used
((mu4e-message-contact-field-matches msg :to "marius@gitorious")
"/Gitorious/archive")
((mu4e-message-contact-field-matches msg :to "marius.mathiesen@gmail.com")
"/Gmail/archive")
((mu4e-message-contact-field-matches msg :to "zmalltalker@zmalltalker.com")
"/Gmail/archive")
((mu4e-message-contact-field-matches msg :to "marius@shortcut.no")
"/Shortcut/archive")
;; everything else goes to /archive
;; important to have a catch-all at the end!
(t "/Gmail/archive"))))
;; don't save message to Sent Messages, Gmail/IMAP takes care of this
(setq mu4e-sent-messages-behavior 'delete)
;; Try to display images in mu4e
(setq
mu4e-view-show-images t
mu4e-view-image-max-width 800)
;; use imagemagick, if available
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
;; sending mail
(setq message-send-mail-function 'message-send-mail-with-sendmail
sendmail-program "/usr/bin/msmtp"
user-full-name "Marius Mårnes Mathiesen")
(setq mu4e-confirm-quit nil
mu4e-headers-date-format "%d/%b/%Y %H:%M" ; date format
mu4e-html2text-command "html2text -utf8 -width 72"
)
;; Borrowed from http://ionrock.org/emacs-email-and-mu.html
;; Choose account label to feed msmtp -a option based on From header
;; in Message buffer; This function must be added to
;; message-send-mail-hook for on-the-fly change of From address before
;; sending message since message-send-mail-hook is processed right
;; before sending message.
(defun choose-msmtp-account ()
(if (message-mail-p)
(save-excursion
(let*
((from (save-restriction
(message-narrow-to-headers)
(message-fetch-field "from")))
(account
(cond
((string-match "marius.mathiesen@gmail.com" from) "gmail")
((string-match "zmalltalker@zmalltalker.com" from) "gmail")
((string-match "marius@shortcut.no" from) "shortcut")
((string-match "marius@gitorious.com" from) "gitorious")
((string-match "marius@gitorious.org" from) "gitorious"))))
(setq message-sendmail-extra-arguments (list '"-a" account))))))
(setq message-sendmail-envelope-from 'header)
(add-hook 'message-send-mail-hook 'choose-msmtp-account)
Dynamic sender addresses
When replying to an email I want to use the address I received this message to as the sender of the reply. This is fairly trivial:
(add-hook 'mu4e-compose-pre-hook
(defun my-set-from-address ()
"Set the From address based on the To address of the original."
(let ((msg mu4e-compose-parent-message)) ;; msg is shorter...
(if msg
(setq user-mail-address
(cond
((mu4e-message-contact-field-matches msg :to "gitorious@google")
"marius.mathiesen@gmail.com")
((mu4e-message-contact-field-matches msg :to "@gitorious")
"marius@gitorious.com")
((mu4e-message-contact-field-matches msg :to "marius@shortcut.no")
"marius@shortcut.no")
((mu4e-message-contact-field-matches msg :to "marius.mathiesen@gmail.com")
"zmalltalker@zmalltalker.com")
((mu4e-message-contact-field-matches msg :to "zmalltalker@zmalltalker.com")
"zmalltalker@zmalltalker.com")
(t "marius@gitorious.com")))))))
Bookmarks
(add-to-list 'mu4e-bookmarks
'("maildir:/Gitorious/inbox OR maildir:/Shortcut/inbox OR maildir:/Gmail/inbox flag:unread" "Today's news" ?z))
(add-to-list 'mu4e-bookmarks
'("maildir:/Gmail/gitorious-ml flag:unread" "Unread on the mailing list" ?m))
(add-to-list 'mu4e-bookmarks
'("flag:flagged" "Flagged messages" ?f))
Attaching files from dired
Wouldn’t it be awesome to be able to send files from dired using your mail client?
I’ll need a special version of the gnus-dired-mail-buffers function so it understands mu4e buffers as well:
(require 'gnus-dired)
;; make the `gnus-dired-mail-buffers' function also work on
;; message-mode derived modes, such as mu4e-compose-mode
(defun gnus-dired-mail-buffers ()
"Return a list of active message buffers."
(let (buffers)
(save-current-buffer
(dolist (buffer (buffer-list t))
(set-buffer buffer)
(when (and (derived-mode-p 'message-mode)
(null message-sent-message-via))
(push (buffer-name buffer) buffers))))
(nreverse buffers)))
(setq gnus-dired-mail-mode 'mu4e-user-agent)
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
With this, I can attach a file as an attachment to a new email
message by entering C-c RET C-a
, and I’m good to go.
Automatically get new mail
Although U
from the mu4e menu is simple, it’s even better
(maybe) to have mu4e fetch mail (and update the mu index)
automatically. Simply set mu4e-update-interval
to the number of
seconds between each check. Let’s go with every 10 minutes.
(setq mu4e-update-interval 600)
Attachments
Since any decent operating system mounts /tmp as tmpfs and sometimes it’s unpractical to lose downloaded attachments, I want to use ~/Downloads to store attachments from email.
(setq mu4e-attachment-dir "~/Downloads")
One click mail checking
My buddy Christian has an awesome setup where C-x M
a window
configuration is set up with mu4e (no other windows), which is
killed when pressing q
.
(defun mu4e-up-to-date-status ()
(interactive)
(window-configuration-to-register :mu4e-fullscreen)
(mu4e)
(delete-other-windows))
(defun mu4e-quit-session ()
"Restores the previous window configuration and kills the mu4e buffer"
(interactive)
(kill-buffer)
(jump-to-register :mu4e-fullscreen))
(define-key mu4e-main-mode-map (kbd "q") 'mu4e-quit-session)
(global-set-key (kbd "C-x M") 'mu4e-up-to-date-status)
Org integration
In order to use org “minor” mode when composing (awesome!) and store links to messages:
- to a message from message view
- to a query in headers view
(require 'org-mu4e)
To edit messages in org-mode, enter C-c o
to enable org-mode inside the message.
(define-key mu4e-compose-mode-map (kbd "C-c o") 'org-mu4e-compose-org-mode)
Encryption in email
Enable epa-mail-mode
when composing messages:
(add-hook 'mu4e-compose-mode-hook (defun my-setup-epa-hook () (epa-mail-mode)))
Now, when composing a message, use:
C-c C-e s
to sign a message.C-c C-e e
to encrypt a message
Let’s enable it in mu4e-view-mode
as well:
(add-hook 'mu4e-view-mode-hook
(defun my-view-mode-hook ()
(epa-mail-mode)))
Now, when viewing a message, enter:
C-c C-e v
to verify a signatureC-c C-e d
to decrypt a message
Org-agenda setup
Which org-files are included in the agenda?
(setq org-agenda-files '("~/Dropbox/dotfiles/orgfiles/today.org"))
Let’s bind C-c a
to org-agenda
(global-set-key (kbd "C-c a") 'org-agenda)
Key bindings when using org-schedule
(the little calendar thingie):
M-+
/M--
: next/previous day+[0-9]
: n days from todayM-n
/M-p
: next/previous week
Switch between org buffers
Org-mode has this really nice facility for switching between org
buffers; being all buffers in org-agenda-files
(and other open
org files, of course). I’m binding this baby to C-c b
(global-set-key (kbd "C-c b") 'org-switchb)
Unfill paragraphs for export to Wordpress etc
I use org-mode for authoring (naturally). However, tools like the WYSIWYG editor on wordpress creates paragraphs for newlines (YUCK!). Support creating really long lines.
(defun zmalltalker/wordpress-uglify (start end)
(interactive "r")
(let ((fc fill-column))
(setq fill-column 999999999)
(fill-region-as-paragraph start end)
(setq fill-column fc)
(copy-region-as-kill start end)
))
Since I use C-_
for undo, I’ll rebind this function to C-x u
.
(global-set-key (kbd "C-x u") 'zmalltalker/wordpress-uglify)
Publishing snippets
Blatantly stolen from https://github.com/magnars/.emacs.d/blob/master/users/fimasvee/my-defuns.el
(defun buffer-file-name-body ()
"Buffer file name stripped of directory and extension"
(if (buffer-file-name)
(file-name-nondirectory (file-name-sans-extension (buffer-file-name)))
(cadr (reverse (split-string (dired-current-directory) "/")))))
(defun wte--unique-filename (stub &optional index)
(setq index (or index 1))
(let ((filename (concat "~/Projects/snippets/"
stub
".el"
(if (< index 10) "-0" "-")
(number-to-string index)
".html")))
(if (file-exists-p filename)
(wte--unique-filename stub (1+ index))
filename)))
(defun zmalltalker-publish-snippet (beg end)
"Create a blog post containing the syntax highlighted code in selection"
(interactive "r")
(let* ((htmlized-reg (htmlize-region-for-paste beg end))
(filename (wte--unique-filename (buffer-file-name-body)))
(header (format "<!DOCTYPE html>
<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<link type=\"text/css\" media=\"screen\" href=\"stylesheets/app.css\" rel=\"stylesheet\" />
<title>Zmalltalker's snippets: %s</title>
</head>
<body>" (file-name-nondirectory (buffer-file-name))))
(footer "</body>
</html>")
)
(find-file filename)
(html-mode)
(save-excursion
(insert header)
(insert htmlized-reg)
(insert footer)
)
))
Clojure REPL
Looks like nrepl.el is the way to go. First of all, set up the melpa repo:
(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/") t)
nrepl.el lets you start a repl server from within Emacs, which is awesome. To try it out, simply use Leiningen to create a new project
lein new demo cd omg e src/omg/core.clj
Now with that running, start the repl from Emacs with M-x
nrepl-jack-in
and wait for the repl to appear. Once inside, try:
(require '[omg.core :as omg])
(omg/foo "Sure")
And once this is running, use the familiar C-x C-e
to evaluate
Clojure code so it’s visible within the REPL. And M-TAB
completes
symbols. It’s all really wonderful. Oh, and C-up
and C-down
walks the history.
To quit, run M-x repl-quit
.
scpaste
What a wonderful little thing.
(require 'scpaste)
(setq scpaste-http-destination "http://friskbris.no/snippets")
(setq scpaste-scp-destination "zmalltalker.com:/var/www/friskbris.no/snippets")
(setq scpaste-footer (concat "<p>Generated by Marius Mathiesen at %s."
(cadr (current-time-zone))
". <a href='%s'original>View/download original</a></p>"))
(defun themed-scpaste (original-name)
(interactive "MName (defaults to buffer name): ")
"Swap to a lighter team, run scpaste, and revert to the old theme"
(load-theme 'adwaita t)
(scpaste original-name)
(load-theme 'solarized-dark t)
)
Disable n00b-modes
Menu-bar be gone.
(menu-bar-mode 0)
Toolbars be gone.
(tool-bar-mode 0)
Can haz column numbers?
(column-number-mode t)
Indent buffer or region
Indent-region is really nice, but even better is a command that will indent the region (if inside a region) or the entire buffer.
Blatantly stolen from here. Binding this baby to “shift-left tab”.
(defun indent-buffer ()
"Indent the currently visited buffer."
(interactive)
(indent-region (point-min) (point-max)))
(defun indent-region-or-buffer ()
"Indent a region if selected, otherwise the whole buffer."
(interactive)
(save-excursion
(if (region-active-p)
(progn
(indent-region (region-beginning) (region-end))
(message "Indented selected region."))
(progn
(indent-buffer)
(message "Indented buffer.")))))
(global-set-key (kbd "<backtab>") 'indent-region-or-buffer)
Perspectives
Set up perspectives
(persp-mode)
Inspired by (=stolen from) this post I’m extending perspectives with support for names and a body.
(defmacro custom-persp (name &rest body)
`(let ((initialize (not (gethash ,name perspectives-hash)))
(current-perspective persp-curr))
(persp-switch ,name)
(when initialize ,@body)
(setq persp-last current-perspective)))
Set up a magic prefix key: the funny House key on my keyboard:
(defun custom-persp-kbd (key)
(kbd (concat "<M-p>" key))
)
Org files
Switch to the @org
perspective, open today.org
if first time.
(defun custom-persp/org ()
(interactive)
(custom-persp "@org"
(find-file "/Users/marius/Dropbox/dotfiles/orgfiles/today.org")))
(global-set-key (custom-persp-kbd "o") 'custom-persp/org)
Switch to mail, by default start mu4e.
Bound to C-c p m
(Perspective Mail)
(defun custom-persp/mail ()
(interactive)
(custom-persp "@email"
(mu4e)))
(global-set-key (kbd "C-c p m") 'custom-persp/mail)
Gitorious
Switch to Gitorious, by default open app/models/user.rb
.
(defun custom-persp/gitorious ()
(interactive)
(let ((gitorious-home "/Users/marius/Projects/gitorious/gitorious/"))
(custom-persp "@gitorious"
(find-file (concat gitorious-home "app/models/user.rb"))
(setq tags-file-name (concat gitorious-home "TAGS"))
)))
(global-set-key (custom-persp-kbd "g") 'custom-persp/gitorious)
Some extra sweetness
I run a tmux session with a zeus instance inside. Based on the following assumptions:
- there’s a tmux session named
gitorious
- this session has a window named
gts-tests
- zeus is running “somewhere”
I can execute the current test file from Emacs in the
gts-tests
window in the gitorious
tmux session using C-c
C-t
. Is that cool or what?
(defun gitorious/run-current-test-file ()
"Run tests via zeus in Tmux"
(interactive)
(shell-command (format "tmux send-keys -t gitorious:gts-tests.0 'zeus test %s' Enter" (buffer-file-name))))
;; (define-key ruby-mode-map (kbd "C-c C-t") 'gitorious/run-current-test-file)
Javascript
A javascript perspective, to my current javascript project.
It opens a javascript file, sets the current directory and starts a Guard subshell.
;; Don't open the file if it's already open
(defun guard-start ()
"Run guard in Emacs"
(interactive)
(async-shell-command "bundle exec guard" "*Guard*"))
(defun custom-persp/javascript ()
(interactive)
(custom-persp "@javascript"
(let ((current-js-project "/Users/marius/Projects/nordea-finans-sverige/webkalkyl"))
(setenv "JSTESTDRIVER_HOME" "/opt/lib")
(find-file (concat current-js-project "/src/bind.js"))
(cd current-js-project)
;; (guard-start)
)))
(global-set-key (custom-persp-kbd "j") 'custom-persp/javascript)
Lisp
All this scratching my private parts calls for a procrastination
perspective. House button l
to the resque.
(defun custom-persp/procrastination ()
"Speak with a lisp"
(interactive)
(custom-persp "@lisp"
(find-file (concat dotfiles-dir "/marius.org"))))
(global-set-key (custom-persp-kbd "l") 'custom-persp/procrastination)
Puppet recipes
(defun custom-persp/puppet ()
"Puppet perspective"
(interactive)
(let ((puppet-home "/Users/marius/Projects/puppet"))
(custom-persp "@puppet"
(find-file (concat puppet-home "/manifests/nodes.pp")))))
(global-set-key (custom-persp-kbd "p") 'custom-persp/puppet)
Unicode
Require my very own unicode-mode
(require 'unicode-mode)
Touch me now
Christian showed me a really neat trick implementing the
equivalent of touch
in Emacs. Handy.
Binding this to C-x t
.
(defun zmalltalker/touch ()
"touch(1) in Emacs"
(interactive)
(save-excursion
(insert " ")
(backward-delete-char 1)
(save-buffer)))
(global-set-key (kbd "C-x t") 'zmalltalker/touch)
Editing awesomeness
C-return
opens a new line below point.
S-S-return
opens a new line above point.
M-return
opens a new line with cursor at point on a new line
(defun open-line-below ()
(interactive)
(end-of-line)
(newline)
(indent-for-tab-command))
(defun open-line-above ()
(interactive)
(beginning-of-line)
(newline)
(forward-line -1)
(indent-for-tab-command))
(defun new-line-in-between ()
(interactive)
(newline)
(indent-for-tab-command))
(global-set-key (kbd "<C-return>") 'open-line-below)
(global-set-key (kbd "<C-S-return>") 'open-line-above)
(global-set-key (kbd "<M-return>") 'new-line-in-between)
Restclient.el
Yummy! Restclient is a major mode for interacting with REST interfaces. Enter something like:
GET https://gitorious.org/gitorious/mainline.xml
then hit C-c C-c
and view the (pretty-printed) results in
a separate buffer. C-c C-r
does the same without
pretty-printing.
(add-to-list 'load-path (concat dotfiles-dir "/contrib/restclient"))
(require 'restclient)
Yes or no?
Also known as y or n. I prefer the latter
(defalias 'yes-or-no-p 'y-or-n-p)
Projectile
I’m totally sold on this one
(projectile-global-mode)
When using projectile-switch-project
I’ll use dired rather than
find-file.
(setq projectile-switch-project-action 'projectile-dired)
My Emacs installation
My OS (Fedora 17) ships with Emacs 24 (doesn’t yours?). Sadly this version doesn’t work 100% with all of the orgmode features, either because it’s a prerelease version or because it’s poorly built.
Whenever I try to run org-export, I get an error along the lines of “cannot find library org”; trying to resolve this by altering org-mode just seems to make matters worse.
Because of this I have built and installed emacs 24.1 from source, and then used the alternatives system to swap the default Emacs installation with my own.
I used this recipe to install the required packages for building emacs, installed my custom emacs into a non-standard location (/usr/local/emacs24) and used alternatives to swap emacs implementation.
Keeping files in sync is tricky
By default, Emacs will not update the contents of open buffers when a file changes on disk. This is inconvenient when switching branches in Git - as you’d risk editing stale buffers.
This problem can be solved
(global-auto-revert-mode)
Misc stuff
Ruby mappings
I’m lazy, didn’t find a place to put this yet.
- Use ruby-mode for Rakefiles
- Use ruby-mode for Gemfiles
- Bind C-x / to comment-or-uncomment-region
(add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode))
(add-to-list 'auto-mode-alist '("Guardfile$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.gemspec$" . ruby-mode))
My buddy Christian just showed me how to transform this:
my_method(foo,
bar,
baz,
gee(1,
00,
zee(1,
1231)
))
into this:
my_method(foo,
bar,
baz,
gee(1,
00,
zee(1,
1231)
))
- How can I achieve this awesomeness? you ask. Let me show you:
(setq ruby-deep-indent-paren nil)
Web-mode
Countless times, I’ve been bitten my hacks like MMM (Multiple
Major Modes). But from what I hear, web-mode
actually
works. Let’s give it a shot
(add-to-list 'auto-mode-alist '("\\.erb$" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html$" . web-mode))
Encryption in org-mode
Stolen from http://orgmode.org/worg/org-tutorials/encrypting-files.html First of all, let’s require it
(require 'org-crypt)
Next, set up which GPG key to use for encryption.
(setq org-crypt-key "marius@gitorious.com")
To encrypt an entry, simply use org-encrypt-entry
, like has been
done in the next paragraph.
This is invisible
**** You can’t touch this.
Chruby
Swith my Rubies in Emacs with chruby.el.
(require 'chruby)
(chruby "1.9.3")
Smart-parens
Take care of those parens etc with style. When entering anything that acts like a paren, add a closing one. Manually typing a closing paren skips that character:
(|) (foo)|
And it handles quoted pairs as well, deleting the matching ones:
"\"({foo})\""
(add-hook 'ruby-mode-hook 'smartparens-mode)
XMPfilter
Now that I have a working Ruby inside Emacs (through chruby-el
)
I can finally use xmpfilter.
Use a hashrocket comment and hit C-c C-c
to evaluate:
foo = {name: "John"}
foo # => {:name=>"John"}
+BEGIN_SRC emacs-lisp (require ‘rcodetools) ;;(define-key ruby-mode-map (kbd “C-c C-c”) ‘xmp)
Other (contributed) libraries
Expand region
Lets you do wonderful things with regions.
(add-to-list 'load-path (concat dotfiles-dir "contrib/expand-region"))
(require 'expand-region)
(global-set-key (kbd "C-=") 'er/expand-region)
rvm
Use a usable ruby
(add-to-list 'load-path (concat dotfiles-dir "contrib/rvm.el"))
(require 'rvm)
Puppet-mode
We need puppet-mode for puppet manifests
(require 'puppet-mode)
(add-to-list 'auto-mode-alist '("\\.pp$" . puppet-mode))
Browser
I can’t believe I have to run through these hoops just to launch a browser. Oh well
(setq browse-url-generic-program
(substring (shell-command-to-string "gconftool-2 -g /desktop/gnome/applications/browser/exec") 0 -1)
browse-url-browser-function 'browse-url-generic)
So I can visit http://zmalltalker.com/
Gitorious stuff
I’m working on an Emacs thing for merge requests.
(require 'merge-requests)
Beer
Of course I want my beer stuff in Emacs.
Calculate alcolhol by volume
ABV = (og – fg) * 131.25
(defun beer/calculate-abv
(original-gravity finishing-gravity)
"Calculate alcohol by volume given OG and FG"
(* (- original-gravity finishing-gravity) 131.25)
)
(defun beer/calculate-alcohol
(og fg)
(interactive "nOriginal gravity: \nnFinishing gravity: ")
(message (concat "Alcohol: " (number-to-string (beer/calculate-abv og fg))
)))
(beer/calculate-alcohol 1.02 1.0)
Conversions
(defun beer/gallon-to-litre (gallons)
(interactive "nHow many gallons? ")
(message (format "%f gallons is %.2f litres" gallons (* gallons 3.78))))
(defun beer/litre-to-gallons (litres)
(interactive "nHow many litres? ")
(message (format "%f litres is %.2f gallons" litres (/ litres 3.78))))
Gradle
Let’s use groovy-mode for Gradle build files.
(add-to-list 'auto-mode-alist '("\\.gradle$" . groovy-mode))