Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1416 lines (1192 sloc) 43.8 KB

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 signature
  • C-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 today
  • M-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)

Mail

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))