GithubHelp home page GithubHelp logo

mrwacky42 / emacs-config Goto Github PK

View Code? Open in Web Editor NEW

This project forked from vdemeester/emacs-config

0.0 2.0 0.0 882 KB

Personal emacs configuration, managed using vcsh and mr

Emacs Lisp 99.68% Shell 0.32%

emacs-config's Introduction

Vincent Demeester’s emacs configuration

                                                          ___ __
.-----.--------.---.-.----.-----.______.----.-----.-----.'  _|__|.-----.
|  -__|        |  _  |  __|__ --|______|  __|  _  |     |   _|  ||  _  |
|_____|__|__|__|___._|____|_____|      |____|_____|__|__|__| |__||___  |
                                                                 |_____|

This is my first attempt to create a readable, maintainable and self documented emacs configuration. I’m hopeful that using Org-Babel and a literate programming style will help.

There is a lot of inspiration for this file, I’m just gonna list the one I took the most of it :

This file is an always work-in-progress, and is currently under heavy modifications. The latest version of this file is always available at my emacs-config github repository, the emacs.org file.

It looks kinda like that (click to open the real one) :

./.emacs.d/images/emacs-config-small.png

How to use my configuration 🚀

You can obtain the source by cloning this repository somewhere, but the repository is made to work with vcsh.

vcsh clone git://github.com/vdemeester/emacs-config emacs-config

If you don’t want to use vcsh but still want to have my .emacs.d folder in your $HOME, you could link it like that :

$ cd $HOME
$ mkdir -p src
$ git clone git://github.com/vdemeester/emacs-config src/vde-emacs-config
$ ln -s src/vde-emacs-config/.emacs.d .

The init.el

If you just want to get the emacs.org file, you will have to define and setup some stuff for this file to work with org-babel. You could take a look to my init.el file but let’s show the main stuff.

First you will need to setup packages repository and define a require-package function, let’s see what’s in there (defined in lisp/setup-package.el).

(require 'package)

;; add org to package repos
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))

;; add melpa and melpa-stable to package repos
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(add-to-list 'package-archives '("mela-stable" . "http://stable.melpa.org/packages/"))

;; If gpg cannot be found, signature checking will fail, so we
;; conditionnally enable it according wether gpg is availabel.
;; We re-run this check once $PATH has been configured
(defun sanityinc/package-maybe-enable-signatures ()
  (setq package-check-signature (when (executable-find "gpg") 'allow-unsigned)))

(sanityinc/package-maybe-enable-signatures)

;; Fire up package.el
(package-initialize)

;; Load package contents if not present
(when (not package-archive-contents)
  (package-refresh-contents))

;; Load use-package
(require 'use-package)

(provide 'setup-package)

Let’s now see how I load the emacs.org file. In the following lines of code, I’m also ensuring that a recent version of org-mode is present on the system ; if not, I’m unload the current one, installing a recent one and load it.

;; Support for Emacs 24 and higher only
(let ((minver 24))
  (unless (>= emacs-major-version minver)
    (error "Your Emacs is too old -- this config requires v%s or higher" minver)))

;; Keep track of loading time
(defconst emacs-start-time (current-time))

;; Add custom lisp files to the load-path
(add-to-list 'load-path "~/.emacs.d/lisp")
;; Add a specific version of use-package
(add-to-list 'load-path "~/.emacs.d/lisp/use-package")

(require 'vde-functions)
;; initialize all ELPA packages
(require 'setup-package)

;; (setq package-enable-at-startup nil)
(let ((elapsed (float-time (time-subtract (current-time)
                                           emacs-start-time))))
  (message "Loaded packages in %.3fs" elapsed))

;; Make sure we have a decent and recent org-mode version
(require 'org)
(when (string-match "^[1234567]" (org-version))
  (progn
    (warn "Org-mode is out of date. We expect org 8 or higher, but instead we have %s" (org-version))
    (warn "Force the installation from org elpa.")
    (package-install 'org)
    (unload-org-mode)
    (require 'org)
    ))

;; keep customize settings in their own file
(setq custom-file
      (expand-file-name "custom.el"
                        user-emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file))

;; load the literate configuration
(require 'ob-tangle)

(org-babel-load-file "~/.emacs.d/emacs.org")

(let ((elapsed (float-time (time-subtract (current-time)
                                           emacs-start-time))))
  (message "Loaded settings...done in %.3fs" elapsed))

Personal information 👨

(setq user-full-name "Vincent Demeester"
      user-mail-address "[email protected]")

Let’s define default value that could be owerwritten by the host and user file 🐣.

(setq
 ;; General
 ;; TODO use xdg to get these
 desktop-folder (substitute-env-in-file-name "$HOME/desktop")
 videos-folder (expand-file-name "videos" desktop-folder)
 downloads-folder (expand-file-name "downloads" desktop-folder)
 music-folder (expand-file-name "music" desktop-folder)
 pictures-folder (expand-file-name "pictures" desktop-folder)
 ;; Orgmode related
 org-root-directory (substitute-env-in-file-name "$HOME/desktop/org")
 org-todos-directory-name "todos"
 org-notes-directory-name "notes"
 org-sites-directory-name "sites"
 org-archive-directory-name "archive"
 org-archive-file-pattern "%s_archive::"
 org-inbox-file "inbox.org"
 org-main-file "personal.org"
 org-journal-file "journal.org"
 org-stackoverflow-file "stack.org"
 org-web-article-file "ent.org"
 org-publish-folder (substitute-env-in-file-name "$HOME/var/public_html")
 sites-folder (substitute-env-in-file-name "$HOME/src/sites/")
 ;; Github related
 github-general-folder (substitute-env-in-file-name "$HOME/src/github")
 github-username "vdemeester")

Loads user settings if the file is available. I put all my personal modifications or sensitive information into this file.

(when (file-readable-p "~/.emacs.d/user.el")
  (load "~/.emacs.d/user.el"))

Same will goes with host-specific files and os-specific files.

(setq FULLHOSTNAME (format "%s" system-name))
(setq HOSTNAME (substring (system-name) 0 (string-match "\\." (system-name))))

(setq HOSTNAME-FILE
      (expand-file-name
       (format "hosts/%s.el" HOSTNAME)
       "~/.emacs.d"))

(when (file-readable-p HOSTNAME-FILE)
  (load HOSTNAME-FILE))

And build the final variables with the possibly overwritten ones.

(setq
 ;; Orgmode related
 org-todos-directory (expand-file-name org-todos-directory-name org-root-directory)
 org-notes-directory (expand-file-name org-notes-directory-name org-root-directory)
 org-sites-directory (expand-file-name org-sites-directory-name org-root-directory)
 org-archive-directory (expand-file-name org-archive-directory-name org-root-directory)
 ;; Github related
 github-personal-folder (expand-file-name github-username github-general-folder))

General configuration 🐸

Appearance

Unclutter the screen by removing menubar, toolbar and stuff, and by disabling the splash-screen.

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(blink-cursor-mode -1)
(setq inhibit-splash-screen t)

We want to see somewhere the column and line number, and also highlight the current line to see it easily.

(line-number-mode 1)
(column-number-mode 1)
(global-hl-line-mode 1)

Depending on the files opened and the syntax highlighting enabled, font-lock-mode can be slow, we try to limit that, to keep Emacs reactive.

(setq font-lock-maximum-decoration 2)

Fringe decorations

The fringe is the vertical region at the right and left of the buffer. Emacs lets you customize it of course.

Here I set up git diffs and buffer position in the fringe.

(setq-default indicate-buffer-boundaries 'left)
(setq-default indicate-empty-lines +1)

Fonts

I tend to install Ubuntu font family on all my computers, I like it :). But I don’t want emacs to fail loading because they aren’t there yet, so let’s define Ubuntu Mono as fonts, only if they are available.

;;(when (member "Ubuntu Mono" (font-family-list))
  (set-default-font "Ubuntu Mono-12")
  (set-frame-font "Ubuntu Mono-12")
  (set-face-attribute 'default nil :family "Ubuntu Mono" :height 110)
;;  )

This will set Symbola as fallback-font for Emojis when it is available for the created frame. Because emojis and unicode are cool : 🙆 😆 😁 ♨ ⛅ 🚲.

;;(when (member "Symbola" (font-family-list))
(set-fontset-font t 'unicode "Symbola" nil 'prepend)
;;  )

Themes

First let’s install the theme(s) and load the new theme

(use-package sublime-themes
             :ensure t
             :defer t)
(use-package dakrone-theme
             :ensure t
             :defer t)
(use-package leuven-theme
             :ensure t
             :init
             (load-theme 'leuven))

Powerline

We are going to use powerline because it is way more sexy than the default modeline design.

(use-package powerline
             :ensure t
             :init
             (powerline-default-theme))

Behaviour

First thing first, let’s define a shortcuts for editing this configuration.

(defun my/edit-emacs-configuration ()
  (interactive)
  (find-file "~/.emacs.d/emacs.org"))

(global-set-key "\C-ce" 'my/edit-emacs-configuration)

Although I don’t really care, let’s add a new line at the end of files. Some people at work will thank me for that ;-D.

(setq require-final-newline t)

Answering yes and no to each question from Emacs can be tedious, a single y or n will suffice.

(fset 'yes-or-no-p 'y-or-n-p)

Add some macros to be able to conditionnally load stuff (taken from emacs-fu.

(defmacro require-maybe (feature &optional file)
  "*Try to require FEATURE, but don't signal an error if `require' fails."
  `(require ,feature ,file 'noerror))

(defmacro when-available (func foo)
  "*Do something if FUNCTION is available."
  `(when (fboundp ,func) ,foo))

Setting the PATH

I’m playing a lot with the $PATH variable in my shell, and I sometimes pested that Emacs didn’t have the same one. But thanks to exec-path-from-shell it’s all ok now :P.

(use-package exec-path-from-shell
  :ensure t
  :config
  (exec-path-from-shell-initialize)
  (exec-path-from-shell-copy-env "HISTFILE"))

Encoding

Make sur that we use utf-8 by default.

(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8)

Mouse

Move the mouse away to not bother.

(mouse-avoidance-mode 'jump)

Backup files

Files suffixed with ~ in the current directory are ugly. We are still going to use backup files, as it can saves some time in case of trouble, but we’ll move them somewhere else : /tmp/emacs-1001 (for a user with the uid = 1001).

Note the we store them in /tmp so in case of a reboot, we loose them.

(defconst emacs-tmp-dir (format "%s/%s%s/" temporary-file-directory "emacs" (user-uid)))
(setq backup-directory-alist
      `((".*" . ,emacs-tmp-dir))
      auto-save-file-name-transforms
      `((".*" ,emacs-tmp-dir t))
      auto-save-list-file-prefix emacs-tmp-dir)

Now that all the temporary files are out of the way, we can keep more of them.

(setq delete-old-versions t
      kept-new-versions 6
      kept-old-versions 2
      version-control t)

Buffers

Setup uniquify so that non-unique buffer names get the parent path included to make them unique.

(use-package uniquify)
(setq uniquify-buffer-name-style 'forward)

Most of the time, when I want to kill the current buffer so let’s remap the C-x k the a function that do that (and no ask) ; it will save few keystroke per days \o/.

(defun kill-default-buffer ()
  "Kill the currently active buffer"
  (interactive)
  (let (kill-buffer-query-functions) (kill-buffer)))

(global-set-key (kbd "C-x k") 'kill-default-buffer)

Comment/Uncomment region

There is a cool function in emacs wich is commend-dwim (bounded to M-;. This adds a comment at the right place (at the end of the line, up the method, etc..

Something I’m really use to, with IntelliJ or Eclipse, is being able to quickly comment a line or a region with simple keystroke. If nothing is selected, it comments the current line, if there is a selection, it comments the line selected (even if the selection doesn’t start at the beginning of line. Let’s bind it to C-M-/ (Ctrl+Alt+/).

(defun my/toggle-comments ()
    "A modified way to toggle comments, 'à-la' ide (intelliJ, Eclipse).
If no region is selected, comment/uncomment the line. If a region is selected, comment/uncomment this region *but* starting from the begining of the first line of the region to the end of the last line of the region"
  (interactive)
  (save-excursion
    (if (region-active-p)
        (progn
          (setq start (save-excursion
                        (goto-char (region-beginning))
                        (beginning-of-line)
                        (point))
                end (save-excursion
                      (goto-char (region-end))
                      (end-of-line)
                      (point)))
          (comment-or-uncomment-region start end))
      (progn
        (comment-or-uncomment-region (line-beginning-position) (line-end-position)))
      )))
(global-set-key (kbd "C-M-/") 'my/toggle-comments)

Kill advice

Let’s define few advice with kill-ring-save and kill-region.

(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
           (line-beginning-position 2)))))

(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, copy a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

Formatting

Use space instead on tabs for indentation by default (again some people at work will thank me for that).

(setq-default indent-tabs-mode nil)
(defcustom indent-sensitive-modes
  '(coffee-mode python-mode haml-mode yaml-mode)
  "Modes for which auto-indenting is suppressed."
  :type 'list)

Let’s define a few cleaning functions :

  • untabify the buffer
(defun my/untabify-buffer ()
  "Untabify the currently visited buffer."
  (interactive)
  (untabify (point-min) (point-max)))

(defun my/untabify-region-or-buffer ()
  "Untabify a region if selected, otherwise the whole buffer."
  (interactive)
  (unless (member major-mode indent-sensitive-modes)
    (save-excursion
      (if (region-active-p)
          (progn
            (untabify (region-beginning) (region-end))
            (message "Untabify selected region."))
        (progn
          (my/untabify-buffer)
          (message "Untabify buffer.")))
      )))
  • ident the buffer, using the mode indentation stuff
(defun my/indent-buffer ()
  "Indent the currently visited buffer."
  (interactive)
  (indent-region (point-min) (point-max)))

(defun my/indent-region-or-buffer ()
  "Indent a region if selected, otherwise the whole buffer."
  (interactive)
  (unless (member major-mode indent-sensitive-modes)
    (save-excursion
      (if (region-active-p)
          (progn
            (indent-region (region-beginning) (region-end))
            (message "Indented selected region."))
        (progn
          (my/indent-buffer)
          (message "Indented buffer.")))
      (whitespace-cleanup))))
  • cleanup the buffer
(defun my/cleanup-buffer ()
  "Perform a bunch of operations on the whitespace content of a buffer."
  (interactive)
  (my/indent-buffer)
  (my/untabify-buffer)
  (delete-trailing-whitespace))
  • cleanup the region
(defun my/cleanup-region (beg end)
  "Remove tmux artifacts from region."
  (interactive "r")
  (dolist (re '("\\\\*\n" "\W*│*"))
    (replace-regexp re "" nil beg end)))

And bind cleanup-buffer and cleanup-region.

(global-set-key (kbd "C-x M-t") 'my/cleanup-region)
(global-set-key (kbd "C-c n") 'my/cleanup-buffer)
(global-set-key (kbd "C-C i") 'my/indent-region-or-buffer)

For writing text, I prefer Emacs to do line wrapping for me. Also, superfluous white-space should be shown. There is two choices here : auto-fill-mode and visual-line-mode ; the difference is the one is actually inserting linke breaks, when the other is just a visual thing. Most of the time I want auto-fill-mode in my text files (or org-mode files), so let’s add this as default and handle special cases.

(add-hook 'text-mode-hook
          (lambda()
            (turn-on-auto-fill)
            (setq show-trailing-whitespace 't))
          )

Let’s also rewrite some built-in to better default. Let’s start with smarter navigation to the beginning of a line.

(defun smarter-move-beginning-of-line (arg)
  "Move point back to indentation of beginning of line.

Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.

If ARG is not nil or 1, move forward ARG - 1 lines first.  If
point reaches the beginning or end of the buffer, stop there."
  (interactive "^p")
  (setq arg (or arg 1))

  ;; Move lines first
  (when (/= arg 1)
    (let ((line-move-visual nil))
      (forward-line (1- arg))))

  (let ((orig-point (point)))
    (back-to-indentation)
    (when (= orig-point (point))
      (move-beginning-of-line 1))))

;; remap C-a to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
                'smarter-move-beginning-of-line)

pretty-mode

Pretty mode turn some stuff prettier, for example in Haskell /= becomes , or -> becomes .

(use-package pretty-mode
             :ensure t
             :init
             (add-hook 'prog-mode-hook
                       'turn-on-pretty-mode))

raindow-identifiers

I read an intersting article about how to make syntax highlighting more useful and I really like the concept. And guess what, there’s a mode for that.

(use-package rainbow-identifiers
             :ensure t
             :init
             (add-hook 'prog-mode-hook
                       (lambda () (rainbow-identifiers-mode))))

Dired

Dired is really a cool mode, let’s enhance it.

First load dired-x and set a list of default guess when issuing ! (dired-do-shell-command) or & (dired-do-async-shell-command).

(use-package dired-x)
(setq dired-guess-shell-alist-user
         '(("\\.pdf\\'" "evince" "okular")
           ("\\.\\(?:djvu\\|eps\\)\\'" "evince")
           ("\\.\\(?:jpg\\|jpeg\\|png\\|gif\\|xpm\\)\\'" "geeqie")
           ("\\.\\(?:xcf\\)\\'" "gimp")
           ("\\.csv\\'" "libreoffice")
           ("\\.tex\\'" "pdflatex" "latex")
           ("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\|ogv\\)\\(?:\\.part\\)?\\'"
            "mpv")
           ("\\.\\(?:mp3\\|flac\\)\\'" "mpv")
           ("\\.html?\\'" "firefox")
           ("\\.cue?\\'" "audacious")))
(put 'dired-find-alternate-file 'disabled nil)

Install dired+.

(setq diredp-hide-details-initially-flag nil)
(use-package dired+
             :ensure t
             :init)

Then, use nohup to not attach a process to emacs.

(use-package dired-aux)

(defvar dired-filelist-cmd
  '(("vlc" "-L")))

(defun dired-start-process (cmd &optional file-list)
  (interactive
   (let ((files (dired-get-marked-files
                 t current-prefix-arg)))
     (list
      (dired-read-shell-command "& on %s: "
                                current-prefix-arg files)
      files)))
  (let (list-switch)
    (start-process
     cmd nil shell-file-name
     shell-command-switch
     (format
      "nohup 1>/dev/null 2>/dev/null %s \"%s\""
      (if (and (> (length file-list) 1)
             (setq list-switch
                   (cadr (assoc cmd dired-filelist-cmd))))
          (format "%s %s" cmd list-switch)
        cmd)
      (mapconcat #'expand-file-name file-list "\" \"")))))

(define-key dired-mode-map "c" 'dired-start-process)

Let’s also add a command to display the size of marked files.

(defun dired-get-size ()
  (interactive)
  (let ((files (dired-get-marked-files)))
    (with-temp-buffer
      (apply 'call-process "/usr/bin/du" nil t nil "-schL" files) ;; -L to dereference (git-annex folder)
      (message
       "Size of all marked files: %s"
       (progn
         (re-search-backward "\\(^[ 0-9.,]+[A-Za-z]+\\).*total$")
         (match-string 1))))))
(define-key dired-mode-map (kbd "z") 'dired-get-size)

Add a binding for find-name-dired. It will transform a find search into a dired buffer, which is.. well.. pretty cool :D.

(define-key dired-mode-map "F" 'find-name-dired)

Also add a binding to switch to wdired which is the awsomeness of awesome, because it let’s you edit the dired buffer as a text file (changing name, etc.) and will apply it when leaving (C-c C-c)

(define-key dired-mode-map "e" 'wdired-change-to-wdired-mode)

Open or re-use the ansi-term from the current directory in dired.

(define-key dired-mode-map (kbd "`") 'dired-open-term)
;; FIXME it seems not to work propertly..
(defun dired-open-term ()
  "Open an `ansi-term' that corresponds to current directory."
  (interactive)
  (let ((current-dir (dired-current-directory)))
    (term-send-string
     (terminal)
     (if (file-remote-p current-dir)
         (let ((v (tramp-dissect-file-name current-dir t)))
           (format "ssh %s@%s\n"
                   (aref v 1) (aref v 2)))
       (format "cd '%s'\n" current-dir)))))

Customize a bit the dired buffer

(setq dired-listing-switches "-laGh1v --group-directories-first")

Search

Make isearch-forward put the cursor at the start of the search, not the end, so that isearch can be used for navigation. See also http://www.emacswiki.org/emacs/IsearchOtherEnd.

(defun my-isearch-goto-match-beginning ()
  (when (and isearch-forward (not isearch-mode-end-hook-quit)) (goto-char isearch-other-end)))
(add-hook 'isearch-mode-end-hook 'my-isearch-goto-match-beginning)

selection

One feature of IntelliJ that really rocks is the C-w shortcuts that select “intelligently”. exand-region is doing this for emacs, see Emacs Rocks Episode 09.

(use-package expand-region
  :ensure t
  :bind ("C-=" . er/expand-region))

Notifications

Emacs now has notifications (freedesktop.org specifications) built-in. Let’s load it for potential needs.

(use-package notifications)

You can use it like this \o/.

(notifications-notify
    :title "You've got mail!"
    :body "There's 34 mails unread"
    :app-icon "~/.emacs.d/icons/mail.png"
    :urgency 'low)

Zoom(ing)

Being able to zoom in and out can be cool, especially when presenting something with emacs ; so that everybody can see what’s written.

(global-set-key (kbd "C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)

Key maps & binding

Endless Parentheses is a great sourse of tips & trick on GNU/Emacs. Following this and this articles, Let’s define some keymaps for some quick toggling and launching.

First, let’s define a toogle-map, that will allow to toggle some stuff like line numbers, minor modes and stuffs.

(define-prefix-command 'vde/toggle-map)
;; The manual recommends C-c for user keys, but C-x t is
;; always free, whereas C-c t is used by some modes.
(define-key ctl-x-map "t" 'vde/toggle-map)
(define-key vde/toggle-map "d" #'toggle-debug-on-error)
(define-key vde/toggle-map "f" #'auto-fill-mode)
(define-key vde/toggle-map "v" #'visual-line-mode)
(define-key vde/toggle-map "l" #'toggle-truncate-lines)
(define-key vde/toggle-map "q" #'toggle-debug-on-quit)
(define-key vde/toggle-map "r" #'dired-toggle-read-only)
(define-key vde/toggle-map' "w" #'whitespace-mode)

And now let’s define a launcher-map to launch major modes and useful commands.

(define-prefix-command 'vde/launcher-map)
(define-key ctl-x-map "l" 'vde/launcher-map)
(global-set-key (kbd "s-l") 'vde/launcher-map)
(define-key vde/launcher-map "c" #'calc)
(define-key vde/launcher-map "d" #'ediff-buffers)
(define-key vde/launcher-map "f" #'find-dired)
(define-key vde/launcher-map "g" #'lgrep)
(define-key vde/launcher-map "G" #'rgrep)
(define-key vde/launcher-map "h" #'man)    ; Help
(define-key vde/launcher-map "s" #'shell)
(define-key vde/launcher-map "r" #'multi-term)
(define-key vde/launcher-map "t" #'proced) ; top
(define-key vde/launcher-map "m" #'mu4e)   ; mails
(define-key vde/launcher-map "u" #'mu4e-update-mail-and-index)

Scrolling

Taking from here, ensure that M-v always undoes C-v, so you can go back exactly.

(setq scroll-preserve-screen-position 'always)

Window moving & resizing

Use ace-window to switch easily windows.

(defun joe-scroll-other-window()
  (interactive)
  (scroll-other-window 1))
(defun joe-scroll-other-window-down ()
  (interactive)
  (scroll-other-window-down 1))
;; From https://github.com/abo-abo/ace-window/wiki but adapted to bepo
(use-package ace-window
  :ensure t
  :bind (("C-x C-o" . ace-window)
         ("C-x M-s" . avi-goto-word-1))
  :config
  (set-face-attribute 'aw-leading-char-face nil :foreground "deep sky blue" :weight 'bold :height 3.0)
  (set-face-attribute 'aw-mode-line-face nil :inherit 'mode-line-buffer-id :foreground "lawn green")
  (setq aw-keys   '(?a ?u ?i ?e ?t ?s ?r)
        aw-dispatch-always t
        aw-dispatch-alist
        '((?y aw-delete-window     "Ace - Delete Window")
          (?x aw-swap-window       "Ace - Swap Window")
          (?\' aw-flip-window)
          (?\. aw-split-window-vert "Ace - Split Vert Window")
          (?c aw-split-window-horz "Ace - Split Horz Window")
          (?n delete-other-windows "Ace - Maximize Window")
          (?\, delete-other-windows)
          (?k balance-windows)
          (?v winner-undo)
          (?o winner-redo)))

  (when (package-installed-p 'hydra)
    (defhydra hydra-window-size (:color red)
      "Windows size"
      ("c" shrink-window-horizontally "shrink horizontal")
      ("t" shrink-window "shrink vertical")
      ("s" enlarge-window "enlarge vertical")
      ("r" enlarge-window-horizontally "enlarge horizontal"))
    (defhydra hydra-window-frame (:color red)
      "Frame"
      ("e" make-frame "new frame")
      ("y" delete-frame "delete frame"))
    (defhydra hydra-window-scroll (:color red)
      "Scroll other window"
      ("'" joe-scroll-other-window "scroll")
      ("j" joe-scroll-other-window-down "scroll down"))
    (add-to-list 'aw-dispatch-alist '(?w hydra-window-size/body) t)
    (add-to-list 'aw-dispatch-alist '(?l hydra-window-scroll/body) t)
    (add-to-list 'aw-dispatch-alist '(?g hydra-window-frame/body) t))
  (ace-window-display-mode t)
  (winner-mode 1))

Use shift + control + arrows to change the size of windows.

(global-set-key (kbd "S-C-<right>") 'shrink-window-horizontally)
(global-set-key (kbd "S-C-<left>") 'enlarge-window-horizontally)
(global-set-key (kbd "S-C-<down>") 'enlarge-window)
(global-set-key (kbd "S-C-<up>") 'shrink-window)
;; install fullframe for list-packages
(use-package fullframe
  :init
  (progn
    (fullframe list-packages quit-window))
  :ensure t)

Popwin

popwin is a popup window manager for Emacs which makes you free from the hell of annoying buffers such like Help, Completions, compilation, and etc.

That says it all, it’s kind of a must.

(use-package popwin
  :ensure t
  :config
  (progn
    (add-to-list 'popwin:special-display-config `("*Swoop*" :height 0.5 :position bottom))
    (add-to-list 'popwin:special-display-config `("*Warnings*" :height 0.5 :noselect t))
    (add-to-list 'popwin:special-display-config `("*Procces List*" :height 0.5))
    (add-to-list 'popwin:special-display-config `("*Messages*" :height 0.5 :noselect t))
    (add-to-list 'popwin:special-display-config `("*Backtrace*" :height 0.5))
    (add-to-list 'popwin:special-display-config `("*Compile-Log*" :height 0.5 :noselect t))
    (add-to-list 'popwin:special-display-config `("*Remember*" :height 0.5))
    (add-to-list 'popwin:special-display-config `("*All*" :height 0.5))
    (add-to-list 'popwin:special-display-config `(flycheck-error-list-mode :height 0.5 :regexp t :position bottom))
    (popwin-mode 1)
    (global-set-key (kbd "C-z") popwin:keymap)))

Ace jump

(use-package ace-jump-mode
  :ensure t
  :commands ace-jump-mode
  :bind ("<f7>" . ace-jump-mode))

Highligh indentation

(use-package highlight-indentation
  :ensure t
  :commands (highlight-indentation-mode highlight-indentation-current-column-mode)
  :init
  (progn
    ;; Add a key to toggle-map
    (define-key vde/toggle-map "C" #'highlight-indentation-mode)
    (define-key vde/toggle-map "c" #'highlight-indentation-current-column-mode))
  :config
  (progn
    (set-face-background 'highlight-indentation-face "#e3e3d3")
    (set-face-background 'highlight-indentation-current-column-face "#c3b3b3")))

Evil

I come from a vim background and the modal editor comes with some really good stuff. Evil is an extensible vi layer for Emacs, exacty what we need. It also few extensions.

;;; Load undo-tree before evil for the :bind
(use-package undo-tree
  :ensure t
  :bind (("C-*" . undo-tree-undo)))
(use-package evil
  :ensure t
  :init
  (progn
    (define-key vde/toggle-map "e" #'evil-mode)))

Let’s change the default cursor colours to easily identify wich mode we are in.

(setq evil-emacs-state-cursor '("red" box))
(setq evil-normal-state-cursor '("green" box))
(setq evil-visual-state-cursor '("orange" box))
(setq evil-insert-state-cursor '("red" bar))
(setq evil-replace-state-cursor '("red" bar))
(setq evil-operator-state-cursor '("red" hollow))

And define some internals.

(setq evil-search-module 'evil-search)

evil-leader

The evil-leader extension provides the <leader> feature from Vim that provides an easy way to bind keys under a variable prefix key.

(use-package evil-leader
  :ensure t
  :requires evil
  :init
  (global-evil-leader-mode t))

(evil-leader/set-leader ",")
(evil-leader/set-key
  "e" 'find-file
  "b" 'switch-to-buffer
  "k" 'kill-buffer)

evil-args

The evil-args extension provides motions and text objects for delimited arguments in Evil.

(use-package evil-args
  :ensure t
  :requires evil
  :config
  (progn
    ;; bind evil-args text objects
    (define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
    (define-key evil-outer-text-objects-map "a" 'evil-outer-arg)
    ;; bind evil-forward/backward-args
    (define-key evil-normal-state-map "L" 'evil-forward-arg)
    (define-key evil-normal-state-map "H" 'evil-backward-arg)
    (define-key evil-motion-state-map "L" 'evil-forward-arg)
    (define-key evil-motion-state-map "H" 'evil-backward-arg)
    ;; bind evil-jump-out-args
    (define-key evil-normal-state-map "K" 'evil-jump-out-args)
    ))

Async

async.el is a module for doing asynchronous processing in Emacs. Let’s load it as it’s gonna be useful.

(use-package async
  :ensure t)

Server mode

Start a server in not already running. I usually start emacs as a daemon when at the start of the computer, but you never know ;-).

I have an error about unsafe directory for /tmp/emacs100, that’s why the advice is there, to ignore the error (from stackoverflow).

(defadvice server-ensure-safe-dir (around
                                   my-around-server-ensure-safe-dir
                                   activate)
  "Ignores any errors raised from server-ensure-safe-dir"
  (ignore-errors ad-do-it))
(unless (string= (user-login-name) "root")
  (require 'server)
  (when (or (not server-process)
           (not (eq (process-status server-process)
                  'listen)))
    (unless (server-running-p server-name)
      (server-start))))

Other Modes 🐥

Discover my major

Discover key bindings and their meaning for the current Emacs major mode.

The command is inspired by discover.el and also uses the makey library. I thought, “Hey! Why not parse the information about the major mode bindings somehow and display that like discover.el does…”

(use-package discover-my-major
  :ensure t
  :bind ("C-h C-m" . discover-my-major))

Manage my minor

Let’s also use manage-my-minor to be able to enable/disable minor-modes.

(use-package manage-minor-mode
  :ensure t
  :bind ("C-c x n" . manage-minor-mode))

Helm

Helm is incremental completion and selection narrowing framework for Emacs. It will help steer you in the right direction when you’re looking for stuff in Emacs (like buffers, files, etc).

Helm is a fork of anything.el originaly written by Tamas Patrovic and can be considered to be its successor. Helm sets out to clean up the legacy code in anything.el and provide a cleaner, leaner and more modular tool, that’s not tied in the trap of backward compatibility.

By default the completion on the selected line is done by C-z (the function is helm-execute-persistent-action) and Tab is used for showing action you can do on it. Let’s invert them as Tab is used for completion in other tools (shells for example).

Let’s define that all helm commands will be prefixed by C-h, C-h x will be Helm M-x.

(use-package helm
  :ensure t
  :config
  (progn
    (require 'helm-config)
    (setq helm-idle-delay 0.1
          helm-input-idle-delay 0.1
          helm-buffer-max-length 40
          helm-M-x-always-save-history t
          helm-move-to-line-cycle-in-source t
          helm-ff-file-name-history-use-recentf t
          ;; Enable fuzzy matching
          helm-M-x-fuzzy-match t
          helm-buffers-fuzzy-matching t
          helm-recentf-fuzzy-match t)
    (add-to-list 'helm-sources-using-default-as-input 'helm-source-man-pages)
    ;; Rebind actions
    (define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action)
    (define-key helm-map (kbd "C-i") 'helm-execute-persistent-action)
    (define-key helm-map (kbd "C-z") 'helm-select-action)
    (helm-autoresize-mode t)
    (helm-mode 1))
  :bind (("C-c h" . helm-command-prefix)
         ("C-x C-f" . helm-find-files)
         ("M-x" . helm-M-x)
         ("C-c b" . helm-mini)
         ("C-x C-b" . helm-buffers-list)
         ("M-y" . helm-show-kill-ring)
         ("C-x c o" . helm-occur)))
;; (add-to-list 'helm-completing-read-handlers-alist '(org-refile)) ; helm-mode does not do org-refile well
;; (add-to-list 'helm-completing-read-handlers-alist '(org-agenda-refile)) ; same goes for org-agenda-refile

Because it can be hard to remember all keybindings, let’s use helm-descbinds.

(use-package helm-descbinds
  :ensure t
  :defer t
  :bind ("C-h b" . helm-descbinds))
(use-package helm-gtags
  :ensure t)
;; (helm-gtags-mode 1)

helmp-make

(use-package helm-make
  :ensure t)

helm-swoop

helm-swoop is a great Helm powered buffer search/occur interface:

(use-package helm-swoop
  :ensure t
  :defer t
  :bind (("C-S-s" . helm-swoop)
         ("M-I" . helm-swoop-back-to-last-point))
  :config
  (progn
    (define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch)
    (define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop)))

helm-google

Emacs Helm Interface for quick Google searches

(use-package helm-google
  :ensure t)

Hydra

Once you summon the Hydra through the prefixed binding (the body + any one head), all heads can be called in succession with only a short extension.

The Hydra is vanquished once Hercules, any binding that isn’t the Hydra’s head, arrives. Note that Hercules, besides vanquishing the Hydra, will still serve his original purpose, calling his proper command. This makes the Hydra very seamless, it’s like a minor mode that disables itself auto-magically.

Hydra is quite impressive, a video is gonna be more than a long explanation.

(use-package hydra
  :ensure t
  :config
  (hydra-add-font-lock)
  ;; Zooming
  (defhydra hydra-zoom (global-map "<f2>")
    "zoom"
    ("g" text-scale-increase "in")
    ("l" text-scale-decrease "out"))
  ;; Toggling modes
  (global-set-key
   (kbd "C-c C-v")
   (defhydra hydra-toggle-simple (:color blue)
     "toggle"
     ("a" abbrev-mode "abbrev")
     ("d" toggle-debug-on-error "debug")
     ("f" auto-fill-mode "fill")
     ("t" toggle-truncate-lines "truncate")
     ("w" whitespace-mode "whitespace")
     ("q" nil "cancel")))
  ;; Buffer menu
  (defhydra hydra-buffer-menu (:color pink
                                      :hint nil)
    "
^Mark^ ^Unmark^ ^Actions^ ^Search
^^^^^^^^----------------------------------------------------------------- (__)
_m_: mark _u_: unmark _x_: execute _R_: re-isearch (oo)
_s_: save _U_: unmark up _b_: bury _I_: isearch /------\\/
_d_: delete ^ ^ _g_: refresh _O_: multi-occur / | ||
_D_: delete up ^ ^ _T_: files only: % -28`Buffer-menu-files-only^^ * /\\---/\\
_~_: modified ^ ^ ^ ^ ^^ ~~ ~~
"
    ("m" Buffer-menu-mark)
    ("u" Buffer-menu-unmark)
    ("U" Buffer-menu-backup-unmark)
    ("d" Buffer-menu-delete)
    ("D" Buffer-menu-delete-backwards)
    ("s" Buffer-menu-save)
    ("~" Buffer-menu-not-modified)
    ("x" Buffer-menu-execute)
    ("b" Buffer-menu-bury)
    ("g" revert-buffer)
    ("T" Buffer-menu-toggle-files-only)
    ("O" Buffer-menu-multi-occur :color blue)
    ("I" Buffer-menu-isearch-buffers :color blue)
    ("R" Buffer-menu-isearch-buffers-regexp :color blue)
    ("c" nil "cancel")
    ("v" Buffer-menu-select "select" :color blue)
    ("o" Buffer-menu-other-window "other-window" :color blue)
    ("q" quit-window "quit" :color blue))
  (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
  ;; apropos
  (defhydra hydra-apropos (:color blue
                                  :hint nil)
    "
_a_propos _c_ommand
_d_ocumentation _l_ibrary
_v_ariable _u_ser-option
^ ^ valu_e_"
    ("a" apropos)
    ("d" apropos-documentation)
    ("v" apropos-variable)
    ("c" apropos-command)
    ("l" apropos-library)
    ("u" apropos-user-option)
    ("e" apropos-value))
  (global-set-key (kbd "C-c h") 'hydra-apropos/body)
  ;; Window managing
  (global-set-key
   (kbd "C-M-o")
   (defhydra hydra-window (:color amaranth)
     "
Move Point^^^^   Move Splitter   ^Ace^                       ^Split^
--------------------------------------------------------------------------------
_w_, _<up>_      Shift + Move    _C-a_: ace-window           _2_: split-window-below
_a_, _<left>_                    _C-s_: ace-window-swap      _3_: split-window-right
_s_, _<down>_                    _C-d_: ace-window-delete    ^ ^
_d_, _<right>_                   ^   ^                       ^ ^
You can use arrow-keys or WASD.
"
     ("2" split-window-below nil)
     ("3" split-window-right nil)
     ("a" windmove-left nil)
     ("s" windmove-down nil)
     ("w" windmove-up nil)
     ("d" windmove-right nil)
     ("A" hydra-move-splitter-left nil)
     ("S" hydra-move-splitter-down nil)
     ("W" hydra-move-splitter-up nil)
     ("D" hydra-move-splitter-right nil)
     ("<left>" windmove-left nil)
     ("<down>" windmove-down nil)
     ("<up>" windmove-up nil)
     ("<right>" windmove-right nil)
     ("<S-left>" hydra-move-splitter-left nil)
     ("<S-down>" hydra-move-splitter-down nil)
     ("<S-up>" hydra-move-splitter-up nil)
     ("<S-right>" hydra-move-splitter-right nil)
     ("C-a" ace-window nil)
     ("u" hydra--universal-argument nil)
     ("C-s" (lambda () (interactive) (ace-window 4)) nil)
     ("C-d" (lambda () (interactive) (ace-window 16)) nil)
     ("q" nil "quit")))
  )

Auto-complete

Auto-Complete is an intelligent auto-completion extension for Emacs. It extends the standard Emacs completion interface and provides an environment that allows users to concentrate more on their own work.

Install and use a basic configuration for auto-complete and setup defaults.

(use-package auto-complete
  :ensure t
  :config
  (progn
    (require 'auto-complete-config)
    (setq ac-use-fuzzy t
          ac-auto-start t
          ac-use-quick-help nil
          ac-ignore-case t)
    (set-default 'ac-sources
                 '(ac-source-imenu
                   ac-source-dictionary
                   ac-source-words-in-buffer
                   ac-source-words-in-same-mode-buffers
                   ac-source-words-in-all-buffer))
    (dolist (mode '(magit-log-edit-mode
                    log-edit-mode org-mode text-mode haml-mode
                    git-commit-mode
                    sass-mode yaml-mode csv-mode espresso-mode haskell-mode
                    html-mode nxml-mode sh-mode smarty-mode clojure-mode
                    lisp-mode textile-mode markdown-mode tuareg-mode
                    js3-mode css-mode less-css-mode sql-mode
                    sql-interactive-mode
                    inferior-emacs-lisp-mode))
      (add-to-list 'ac-modes mode))
    (global-auto-complete-mode t))
  )

deft

Deft is an Emacs mode for quickly browsing, filtering, and editing directories of plain text notes, inspired by Notational Velocity.

Deft is cool to use with org-mode, let’s use it for notes.

(use-package deft
  :ensure t
  :config
  (progn
    (setq deft-extension "org"
          deft-text-mode 'org-mode
          deft-directory org-notes-directory
          deft-use-filename-as-title t))
  :bind ("<f9>" . deft))

Version control integration

Git

(use-package git-commit-mode
  :ensure t)
(use-package git-rebase-mode
  :ensure t)
(use-package gitignore-mode
  :ensure t)
(use-package gitconfig-mode
  :ensure t)
(use-package gitattributes-mode
  :ensure t)

magit

(use-package magit
  :ensure t
  :bind ("C-c g" . magit-status))
(setq magit-last-seen-setup-instructions "1.4.0")
Magit git-svn integration

At work, I use git-svn to be able to use git locally but integrating in the subversion they use. Integrating magit and git-svn is a bonus but, as it exists, let’s do it :).

(use-package magit-svn
  :ensure t)

The quick key to get the magit-svn menu is N.

git fringe decoration

(use-package git-gutter-fringe
    :ensure t
    :config (global-git-gutter-mode +1))

git-annex

Git-annex is a wonderful piece of software that I use a lot in my repositories.

git-annex allows managing files with git, without checking the file contents into git. While that may seem paradoxical, it is useful when dealing with files larger than git can currently easily handle, whether due to limitations in memory, time, or disk space.

In Emacs, it integrates with magit and dired mode. The annex subcommand for magit is @.

(use-package git-annex
  :ensure t)
(use-package magit-annex
  :ensure t)

git-timemachine

I recently discovered an extremely cool package called git-timemachine that allows you to step though the git history of the file you’re currently editing in Emacs.

(use-package git-timemachine
  :ensure t)

git-blame

(use-package git-blame
  :ensure t)

highlight-symbol

Automatic and manual symbol highlighting for Emacs

Highlights the word/symbol at point and any other occurrences in view. Also allows to jump to the next or previous occurrence.

(use-package highlight-symbol
  :ensure t
  :config
  (progn
    (setq highlight-symbol-on-navigation-p t)
    (add-hook 'prog-mode-hook 'highlight-symbol-mode))
  :bind (("C-<f3>" . highlight-symbol-at-point)
         ("<f3>" . highlight-symbol-next)
         ("S-<f3>" . highlight-symbol-prev)
         ("M-<f3>" . highlight-symbol-query-replace)))

move-text

Allows to move the current line or region up/down. The source code is on the Wiki: http://www.emacswiki.org/emacs/move-text.el

(use-package move-text
  :ensure t
  :config (move-text-default-bindings))

Diff

The diff-mode of Emacs is pretty cool, but let’s show important whitespace when in this mode.

(add-hook 'diff-mode-hook (lambda ()
                            (setq-local whitespace-style
                                        '(face
                                          tabs
                                          tab-mark
                                          spaces
                                          space-mark
                                          trailing
                                          indentation::space
                                          indentation::tab
                                          newline
                                          newline-mark))
                            (whitespace-mode 1)))

Terminal

Let’s install and use multi-term, which is a cool addition to term.el.

(use-package multi-term
  :ensure t
  :bind (("M-[" . multi-term-prev)
         ("M-]" . multi-term-next)))

multiple-cursors

Multiple cursors for Emacs, this is a pretty badass functionnality.

(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . mc/edit-lines)
         ("C->" . mc/mark-next-like-this)
         ("C-<" . mc/mark-previous-like-this)
         ("C-c C-<" . mc/mark-all-like-this)))

Flyspell

Flyspell enables on-the-fly spell checking in Emacs by the means of a minor mode. It is called Flyspell. This facility is hardly intrusive. It requires no help. Flyspell highlights incorrect words as soon as they are completed or as soon as the TextCursor hits a new word.

(use-package flyspell
  :ensure t
  :init
  (progn
    (use-package flyspell-lazy
      :ensure t))
  :config
  (progn
    (define-key vde/toggle-map "i" #'ispell-change-dictionary)
    (define-key vde/launcher-map "i" #'flyspell-buffer)
    (setq ispell-program-name "aspell")
    (setq ispell-local-dictionary "en_US")
    (setq ispell-local-dictionary-alist
          '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil nil nil utf-8)
            ("fr_FR" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil nil nil utf-8)))
    (add-hook 'text-mode-hook 'flyspell-mode)
    (add-hook 'prog-mode-hook 'flyspell-prog-mode)))

Flycheck

Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs 24, intended as replacement for the older Flymake extension which is part of GNU Emacs.

It uses various syntax checking and linting tools to check the contents of buffers, and reports warnings and errors directly in the buffer, or in an optional error list.

Let’s install it and configure it for the common part. The language specifics will be defined in the corresponding language section.

(use-package flycheck
  :ensure t
  :config
  (progn
    (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc))
    (setq flycheck-indication-mode 'right-fringe)
    (add-hook 'after-init-hook #'global-flycheck-mode)))

Org

Org-mode is a powerful system for organizing your complex life with simple plain-text files. It seamlessly integrates all your notes, mindmaps, TODO lists, calendar, day planner, and project schedules into a single system that can be easily searched (e.g. by grep), encrypted (e.g. by GnuPG), backed up and synced (e.g. by Dropbox), imported/exported, and accessed on the go (e.g. on an iPhone or Android smartphone). It can even be used for authoring web pages and documents.

Depending on how this section grows, org-mode might need its own litterate org configuration file.

Standard configuration

First let’s define the default directory for the org files, the one to be added to the agenda and the archives.

(require 'find-lisp)
(setq org-directory org-root-directory)
(setq org-agenda-files (find-lisp-find-files org-todos-directory "\.org$"))

We’ll also set which files should be opened using org-mode : *.org, *.org_archive, *.txt.

(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode))

Let’s also define the default todo-keywords and the workflow between them.

  • TODO : task not started yet, part of the backlog :)
  • PROGRESS : task that are currently in progress, should be a minimum
  • BLOCKED : task that I start working on but cannot anymore (for some reason), thus they are blocked
  • REVIEW : task that should be done, but I need or wait for a review (by someone else or by me)
  • DONE : task that are completed.
  • ARCHIVED : same as done but keep it here (and not moving into archive)
    (defface org-progress ; font-lock-warning-face
      (org-compatible-face nil
        '((((class color) (min-colors 16) (background light)) (:foreground "#A197BF" :bold t :background "#E8E6EF" :box (:line-width 1 :color "#A197BF")))
          (((class color) (min-colors 8)  (background light)) (:foreground "blue"  :bold t))
          (t (:inverse-video t :bold t))))
      "Face for PROGRESS keywords."
      :group 'org-faces)
    (defface org-cancelled ; font-lock-warning-face
      (org-compatible-face nil
        '((((class color) (min-colors 16) (background light)) (:foreground "#3D3D3D" :bold t :background "#7A7A7A" :box (:line-width 1 :color "#3D3D3D")))
          (((class color) (min-colors 8)  (background light)) (:foreground "black"  :bold t))
          (t (:inverse-video t :bold t))))
      "Face for PROGRESS keywords."
      :group 'org-faces)
    (defface org-review ; font-lock-warning-face
      (org-compatible-face nil
        '((((class color) (min-colors 16) (background light)) (:foreground "#FC9B17" :bold t :background "#FEF2C2" :box (:line-width 1 :color "#FC9B17")))
          (((class color) (min-colors 8)  (background light)) (:foreground "yellow"  :bold t))
          (t (:inverse-video t :bold t))))
      "Face for PROGRESS keywords."
      :group 'org-faces)
    (defface org-blocked ; font-lock-warning-face
      (org-compatible-face nil
        '((((class color) (min-colors 16) (background light)) (:foreground "#FF8A80" :bold t :background "#ffdad6" :box (:line-width 1 :color "#FF8A80")))
          (((class color) (min-colors 8)  (background light)) (:foreground "red"  :bold t))
          (t (:inverse-video t :bold t))))
      "Face for PROGRESS keywords."
      :group 'org-faces)
    
    (setq org-todo-keywords
          (quote ((sequence "TODO(t!)" "PROGRESS(p!)" "BLOCKED" "REVIEW" "|" "DONE(d!)" "ARCHIVED")
                  (sequence "REPORT(r!)" "BUG" "KNOWNCAUSE" "|" "FIXED(f!)")
                  (sequence "|" "CANCELLED(c@)"))))
    
    
    (setq org-todo-keyword-faces
          (quote (("TODO" . org-todo)
                  ("PROGRESS" . org-progress)
                  ("BLOCKED" . org-blocked)
                  ("REVIEW" . org-review)
                  ("DONE" . org-done)
                  ("ARCHIVED" . org-done)
                  ("CANCELLED" . org-cancelled)
                  ("REPORT" . org-todo)
                  ("BUG" . org-blocked)
                  ("KNOWNCAUSE" . org-review)
                  ("FIXED" . org-done))))
    
    (setq org-todo-state-tags-triggers
          (quote (("CANCELLED" ("CANCELLED" . t)))))
        

I have a folder with notes, where I don’t want auto-fill-mode enabled, but visual-line-mode, let’s do that.

(defun turn-on-auto-visual-line (expression)
  (cond ((string-match expression buffer-file-name)
         (progn
           (auto-fill-mode -1)
           (visual-line-mode 1))
         )))

Undefine some binding (C-c [, C-c ] since this breaks org-agenda files that have been defined in this file (a directory).

(add-hook 'org-mode-hook
          '(lambda ()
             (org-defkey org-mode-map "\C-c[" 'undefined)
             (org-defkey org-mode-map "\C-c]" 'undefined)
             (org-defkey org-mode-map "\C-c;" 'undefined)
             (turn-on-auto-visual-line (concat org-notes-directory "/*")))
          'append)

All org-mode buffers will be automatically saved each hours.

(run-at-time "00:59" 3600 'org-save-all-org-buffers)

And add some miscellaneous stuff.

(setq
 org-completion-use-ido t         ;; use IDO for completion
 org-cycle-separator-lines 0      ;; Don't show blank lines
 org-catch-invisible-edits 'error ;; don't edit invisible text
 org-refile-targets '((org-agenda-files . (:maxlevel . 6)))
 )

Let’s also define a org related keymap map.

(define-prefix-command 'vde/org-map)
(global-set-key (kbd "C-c o") 'vde/org-map)
(define-key vde/org-map "p" (lambda () (interactive) (find-file (expand-file-name org-main-file org-todos-directory))))
(define-key vde/org-map "n" (lambda () (interactive) (find-file org-notes-directory)))

Speed commands

Org-mode speed keys (or spee commands) are really cool, here is a quotation from the manual

Single keys can be made to execute commands when the cursor is at the beginning of a headline, i.e., before the first star.

(setq org-use-speed-commands t)

However the default n (next) and p (previous) speed keys aren’t optimal for my use. When I go to the next one using speed commands I want the others closed. Let’s redefine it.

(defun my/org-show-next-heading-tidily ()
  "Show next entry, keeping other entries closed."
  (if (save-excursion (end-of-line) (outline-invisible-p))
      (progn (org-show-entry) (show-children))
    (outline-next-heading)
    (unless (and (bolp) (org-on-heading-p))
      (org-up-heading-safe)
      (hide-subtree)
      (error "Boundary reached"))
    (org-overview)
    (org-reveal t)
    (org-show-entry)
    (show-children)))

(defun my/org-show-previous-heading-tidily ()
  "Show previous entry, keeping other entries closed."
  (let ((pos (point)))
    (outline-previous-heading)
    (unless (and (< (point) pos) (bolp) (org-on-heading-p))
      (goto-char pos)
      (hide-subtree)
      (error "Boundary reached"))
    (org-overview)
    (org-reveal t)
    (org-show-entry)
    (show-children)))

And let’s bind it.

(setq org-speed-commands-user '(("n" . my/org-show-next-heading-tidily)
                                ("p" . my/org-show-previous-heading-tidily)
                                (":" . org-set-tags-command)
                                ("c" . org-toggle-checkbox)
                                ("d" . org-cut-special)
                                ("P" . org-set-property)
                                ("C" . org-clock-display)
                                ("z" . (lambda () (interactive)
                                         (org-tree-to-indirect-buffer)
                                         (other-window 1)
                                         (delete-other-windows)))))

Captures

First thing first, bind a key sequence to org-capture.

(define-key vde/org-map "r" 'org-capture)

Setup captures templates..

(setq org-capture-templates
      '(;; other entries
        ("t" "Inbox list item" entry
         (file+headline (expand-file-name org-main-file org-todos-directory) "Inbox")
         "* %?\n %i\n %a")
        ("j" "Journal entry" plain
         (file+datetree+prompt (exand-file-name org-journal-file org-root-directory))
         "%K - %a\n%i\n%?\n")
        ;; other entries
        ))

Code blocks

We are using a lot of code block in org-mode, in this file for example ; let’s fontify the code blocks first.

(setq org-src-fontify-natively t)

Add a function to easily add a code block and bind it.

(defun my/org-insert-src-block (src-code-type)
  "Insert a `SRC-CODE-TYPE' type source code block in org-mode."
  (interactive
   (let ((src-code-types
          '("emacs-lisp" "python" "C" "sh" "java" "js" "clojure" "C++" "css"
            "calc" "dot" "gnuplot" "ledger" "R" "sass" "screen" "sql" "awk" 
            "ditaa" "haskell" "latex" "lisp" "matlab" "org" "perl" "ruby"
            "sqlite" "rust" "scala" "golang")))
     (list (ido-completing-read "Source code type: " src-code-types))))
  (progn
    (newline-and-indent)
    (insert (format "#+BEGIN_SRC %s\n" src-code-type))
    (newline-and-indent)
    (insert "#+END_SRC\n")
    (previous-line 2)
    (org-edit-src-code)))

(add-hook 'org-mode-hook
          '(lambda ()
             (local-set-key (kbd "C-c s e") 'org-edit-src-code)
             (local-set-key (kbd "C-c s i") 'my/org-insert-src-block))
          'append)

Mobile

Define some stuff for the org-mobile synchronization. The org-mobile-directory is a on a remote ssh, defined in the ~/.emacs.d/user.el file (using (setq personal-org-mobile-directory "")).

(require 'org-mobile)
(setq org-mobile-directory personal-org-mobile-directory
      org-mobile-inbox-for-pull (expand-file-name org-inbox-file org-todos-directory)
      org-mobile-files '(org-todos-directory))

Let’s also configure auto push, asynchronously like in this gist. One thing that I should add though is to auto-commit too (because my todos are on git).

(defun notify-push (result)
  (notifications-notify
   :title "Push complete"
   :body (format "Org-mobile-push: %s" result)
   ))

;; Fork the work of pushing to mobile
(defun fork-org-push-mobile ()
  (interactive)
  (async-start
   ;; What to do in the child process
   `(lambda ()
      (require 'org)
      ,(async-inject-variables "org-\\(mobile-\\|directory\\)")
      (org-mobile-push))
                                        ; What to do when it finishes
   (lambda (result)
     (notify-push result))))

;; Define a timer variable
(defvar org-mobile-push-timer nil
  "Timer that `org-mobile-push-timer' used to reschedule itself, or nil.")

;; Push to mobile when the idle timer runs out
(defun org-mobile-push-with-delay (secs)
  (when org-mobile-push-timer
    (cancel-timer org-mobile-push-timer))
  (setq org-mobile-push-timer
        (run-with-idle-timer
         (* 1 secs) nil 'fork-org-push-mobile)))

;; After saving files, start a 30 seconds idle timer after which we
;; are going to push
(add-hook 'after-save-hook
          (lambda ()
            (when (eq major-mode 'org-mode)
              (dolist (file (org-mobile-files-alist))
                (if (string= (expand-file-name (car file)) (buffer-file-name))
                    (org-mobile-push-with-delay 30)))
              )))

;; At least run it once a day, but no need for a delay this time
(run-at-time "12:05" 86400 '(lambda () (org-mobile-push-with-delay 1)))

Archives

We want to be able to archive some done projects. Let’s load org-archive and configure it.

(require 'org-archive)
(setq org-archive-location (concat org-archive-directory "%s_archive::"))

Tags

Tags should be displayed from the 90 column.

(setq org-tags-column -90)

Define a list of default tags that should apply for all org-mode buffers.

(setq org-tag-alist '(
                     ("important" . ?i)
                     ("urgent" . ?u)
                     ("ongoing" . ?o)   ;; ongoing "project", use to filter big project that are on the go
                     ("next" . ?n)      ;; next "project"/"task", use to filter next things to do
                     ("@home" . ?h)     ;; needs to be done at home
                     ("@work" . ?w)     ;; needs to be done at work
                     ("@client" . ?c)   ;; needs to be done at a client place (consulting..)
                     ("dev" . ?e)       ;; this is a development task
                     ("infra" . ?a)     ;; this is a sysadmin/infra task
                     ("document" . ?d)  ;; needs to produce a document (article, post, ..)
                     ("download" . ?D)  ;; needs to download something
                     ("media" . ?m)     ;; this is a media (something to watch, listen, record, ..)
                     ("mail" . ?M)      ;; mail-related (to write & send or to read)
                     ("triage" . ?t)    ;; need "triage", tag it to easily find them
                     ("task" . ?a)      ;; a simple task (no project), the name is kinda misleading
                     ))

Note that important and urgent helps me prioritize my todos, in a quadrant fashion way.

ImportantKaizenPanic
tag importantimprovementsemergency
Less ImportantOrganicsSocial investment
no tag importantinspirationSocial activities
Less UrgentUrgent
no tag urgenttag urgent

Agenda(s)

First thing first, bind a key sequence to org-agenda.

(global-set-key (kbd "C-c a") 'org-agenda)

Then set custom agendas.. For the syntax, look in worg : Advanced searching and Custom Agenda Commands.

(setq org-agenda-custom-commands
      '(("t" todo "TODO"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("p" todo "PROGRESS"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("r" todo "REVIEW"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("b" todo "BLOCKED"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("o" "Ongoing projects" tags-todo "ongoing"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-tags-exclude-from-inheritance '("ongoing"))
          (org-agenda-prefix-format "  Mixed: ")))
        ("n" "Next tasks" tags-todo "next"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-tags-exclude-from-inheritance '("next"))
          (org-agenda-prefix-format "  Mixed: ")))
        ;; Timelines
        ("d" "Timeline for today" ((agenda "" ))
         ((org-agenda-ndays 1)
          (org-agenda-show-log t)
          (org-agenda-log-mode-items '(clock closed))
          (org-agenda-clockreport-mode t)
          (org-agenda-entry-types '())))
        ("w" "Weekly review" agenda ""
         ((org-agenda-span 7)
          (org-agenda-log-mode 1)))
        ("W" "Weekly review sans DAILY" agenda ""
         ((org-agenda-span 7)
          (org-agenda-log-mode 1)
          (org-agenda-tag-filter-preset '("-DAILY"))))
        ("2" "Bi-weekly review" agenda "" ((org-agenda-span 14) (org-agenda-log-mode 1)))
        ;; Panic tasks : urgent & important
        ;; Probably the most important to do, but try not have to much of them..
        ("P" . "Panic -emergency-")
        ("Pt" "TODOs" tags-todo "important&urgent/!TODO"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Pb" "BLOCKEDs" tags-todo "important&urgent/!BLOCKED"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Pr" "REVIEWs" tags-todo "important&urgent/!REVIEW"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ;; Kaizen tasks : important but not urgent
        ("K" . "Kaizen -improvement-")
        ("Kt" "TODOs" tags-todo "important&-urgent/!TODO"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Kb" "BLOCKEDs" tags-todo "important&-urgent/!BLOCKED"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Kr" "REVIEWs" tags-todo "important&-urgent/!REVIEW"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ;; Social investment : urgent
        ("S" . "Social -investment-")
        ("St" "TODOs" tags-todo "-important&urgent/!TODO"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Sb" "BLOCKEDs" tags-todo "-important&urgent/!BLOCKED"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Sr" "REVIEWs" tags-todo "-important&urgent/!REVIEW"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ;; Organics
        ("O" . "Organics -inspiration-")
        ("Ot" "TODOs" tags-todo "-important&-urgent/!TODO"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Ob" "BLOCKEDs" tags-todo "-important&-urgent/!BLOCKED"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("Or" "REVIEWs" tags-todo "-important&-urgent/!REVIEW"
         ((org-agenda-sorting-strategy '(priority-down))
          (org-agenda-prefix-format "  Mixed: ")))
        ("N" search ""
         ((org-agenda-files '("~org/notes.org"))
          (org-agenda-text-search-extra-files nil)))))

Pomodoro

(use-package org-pomodoro
  :ensure t)

Publishing

Let’s configure the publishing part of org-mode. The first org-mode files we want to publish are in ~/desktop/org/{project}, and we want to publish them in ~/var/public_html/{project} for now.

Few org-export and org-html configuration.

(use-package htmlize
  :ensure t
  :defer t)
;;      (setq org-html-head "<link rel=\"stylesheet\" type=\"text/css\" hrefl=\"css/stylesheet.css\" />")
(setq org-html-include-timestamps nil)
;; (setq org-html-htmlize-output-type 'css)
(setq org-html-head-include-default-style nil)

And the projects.

(use-package ox-publish)
;; (use-package ox-rss)

;; Define some variables to write less :D
(setq sbr-base-directory (expand-file-name "sbr" org-sites-directory)
      sbr-publishing-directory (expand-file-name "sbr" org-publish-folder)
      znk-base-directory (expand-file-name "zenika" org-sites-directory)
      znk-publishing-directory (expand-file-name "zenika" org-publish-folder)
      vdf-base-directory (expand-file-name "vdf" org-sites-directory)
      vdf-site-directory (expand-file-name "blog" sites-folder)
      vdf-publishing-directory (expand-file-name "posts" (expand-file-name "content" vdf-site-directory))
      vdf-static-directory (expand-file-name "static" vdf-site-directory)
      vdf-css-publishing-directory (expand-file-name "css" vdf-static-directory)
      vdf-assets-publishing-directory vdf-static-directory)

;; Project
(setq org-publish-project-alist
      `(("sbr-notes"
         :base-directory ,sbr-base-directory
         :base-extension "org"
         :publishing-directory ,sbr-publishing-directory
         :makeindex t
         :exclude "FIXME"
         :recursive t
         :htmlized-source t
         :publishing-function org-html-publish-to-html
         :headline-levels 4
         :auto-preamble t
         :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />"
         :html-preamble "<div id=\"nav\">
<ul>
<li><a href=\"/\" class=\"home\">Home</a></li>
</ul>
</div>"
         :html-postamble "<div id=\"footer\">
%a %C %c
</div>")
        ("sbr-static"
         :base-directory ,sbr-base-directory
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg"
         :publishing-directory ,sbr-publishing-directory
         :recursive t
         :publishing-function org-publish-attachment
         )
        ("sbr" :components ("sbr-notes" "sbr-static"))
        ("vdf-notes"
         :base-directory ,vdf-base-directory
         :base-extension "org"
         :publishing-directory ,vdf-publishing-directory
         :exclude "FIXME"
         :section-numbers nil
         :with-toc nil
         :with-drawers t
         :htmlized-source t
         :publishing-function org-html-publish-to-html
         :headline-levels 4
         :body-only t)
        ("vdf-static-css"
         :base-directory ,vdf-base-directory
         :base-extension "css"
         :publishing-directory ,vdf-css-publishing-directory
         :recursive t
         :publishing-function org-publish-attachment
         )
        ("vdf-static-assets"
         :base-directory ,vdf-base-directory
         :base-extension "png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg"
         :publishing-directory ,vdf-assets-publishing-directory
         :recursive t
         :publishing-function org-publish-attachment
         )
        ("vdf" :components ("vdf-notes" "vdf-static-css" "vdf-static-assets"))
        ("znk-notes"
         :base-directory ,znk-base-directory
         :base-extension "org"
         :publishing-directory ,znk-publishing-directory
         :makeindex t
         :exclude "FIXME"
         :recursive t
         :htmlized-source t
         :publishing-function org-html-publish-to-html
         :headline-levels 4
         :auto-preamble t
         :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />"
         :html-preamble "<div id=\"nav\">
<ul>
<li><a href=\"/\" class=\"home\">Home</a></li>
</ul>
</div>"
         :html-postamble "<div id=\"footer\">
%a %C %c
</div>")
        ("znk-static"
         :base-directory ,znk-base-directory
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg"
         :publishing-directory ,znk-publishing-directory
         :recursive t
         :publishing-function org-publish-attachment
         )
        ("znk" :components ("znk-notes" "znk-static"))
        ))

Protocol

Trying out org-protocol based on http://oremacs.com/2015/01/07/org-protocol-1/ and http://oremacs.com/2015/01/08/org-protocol-2/.

(use-package org-capture)
(use-package org-protocol)
(use-package async
  :ensure t)
(setq org-protocol-default-template-key "l")
(push '("l" "Link" entry (function org-handle-link)
        "* TODO %(org-wash-link)\nAdded: %U\n%(org-link-hooks)\n%?")
      org-capture-templates)

(defun org-wash-link ()
  (let ((link (caar org-stored-links))
        (title (cadar org-stored-links)))
    (setq title (replace-regexp-in-string
                 " - Stack Overflow" "" title))
    (org-make-link-string link title)))

(defvar org-link-hook nil)

(defun org-link-hooks ()
  (prog1
      (mapconcat #'funcall
                 org-link-hook
                 "\n")
    (setq org-link-hook)))

(defun org-handle-link ()
  (let ((link (caar org-stored-links))
        file)
    (cond ((string-match "^https://www.youtube.com/" link)
           (org-handle-link-youtube link))
          ((string-match (regexp-quote
                          "http://stackoverflow.com/") link)
           (find-file ((expand-file-name org-stackoverflow-file org-notes-directory)))
           (goto-char (point-min))
           (re-search-forward "^\\*+ +Questions" nil t))
          (t
           (find-file ((expand-file-name org-web-article-file org-notes-directory)))
           (goto-char (point-min))
           (re-search-forward "^\\*+ +Articles" nil t)))))

(defun org-handle-link-youtube (link)
  (lexical-let*
      ((file-name (org-trim
                   (shell-command-to-string
                    (concat
                     "youtube-dl \""
                     link
                     "\""
                     " -o \"%(title)s.%(ext)s\" --get-filename"))))
       (dir videos-folder)
       (full-name
        (expand-file-name file-name dir)))
    (add-hook 'org-link-hook
              (lambda ()
                (concat
                 (org-make-link-string dir dir)
                 "\n"
                 (org-make-link-string full-name file-name))))
    (async-shell-command
     (format "youtube-dl \"%s\" -o \"%s\"" link full-name))
    (find-file (org-expand "ent.org"))
    (goto-char (point-min))
    (re-search-forward "^\\*+ +videos" nil t)))

Projectile

Projectile is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies(when feasible). For instance - finding project files has a portable implementation written in pure Emacs Lisp without the use of GNU find (but for performance sake an indexing mechanism backed by external commands exists as well).

(use-package projectile
  :ensure t
  :config
  (progn
    (setq projectile-completion-system 'default)
    (setq projectile-enable-caching t)
    (projectile-global-mode)))

And let’s use the helm integration too.

(use-package helm-projectile
  :ensure t
  :config (helm-projectile-on))

Perspective

Perspective is a minor mode that provides the ability to manage different workspaces. It integrates well with projectile.

(use-package perspective
  :ensure t)
(use-package persp-projectile
  :ensure t
  :requires perspective
  :config
  (progn
    (define-key projectile-mode-map (kbd "s-s") 'projectile-persp-switch-project)
    (persp-mode)))

Compilation mode

Set options and key binding for compile.

(use-package compile
  :commands compile
  :bind ("<f5>" . compile)
  :config
  (progn
    (setq compilation-ask-about-save nil
          compilation-always-kill t
          compilation-scroll-output 'first-error)
    ))

Compilation mode improvements

See http://stackoverflow.com/questions/3072648/cucumbers-ansi-colors-messing-up-emacs-compilation-buffer

(require 'ansi-color)
(defun my/colorize-compilation-buffer ()
  (toggle-read-only)
  (ansi-color-apply-on-region (point-min) (point-max))
  (toggle-read-only))
(add-hook 'compilation-filter-hook 'my/colorize-compilation-buffer)

And let’s configure the compilation-mode to follow the compilation, not waiting at the top..

(setq compilation-scroll-output t)

Provided configuration

I’m managing my configurations using vcsh and myrepos, like that. I have a lot of different configuration repository (here) and the way I use it is I get only the one I need on the computer I need. This means I don’t always want the ruby-config or the go-config on my computers. And this means that I don’t need these part in my emacs configuration as well ; it even might need some dependencies that I wouldn’t have without the *-config repository.

So, each repository will come (or not :-P) with a part of emacs configuration, that will be load by the following code. They will put their code into $HOME/.emacs.d/provided/.

;; The folder is by default $HOME/.emacs.d/provided
(setq user-emacs-provided-directory (concat user-emacs-directory "provided/"))
;; Regexp to find org files in the folder
(setq provided-configuration-file-regexp "\\`[^.].*\\.org\\'")
;; Define the function
(defun load-provided-configuration (dir)
  "Load org file from =use-emacs-provided-directory= as configuration with org-babel"
  (unless (file-directory-p dir) (error "Not a directory '%s'" dir))
  (dolist (file (directory-files dir nil provided-configuration-file-regexp nil) nil)
    (unless (member file '("." ".."))
      (let ((file (concat dir file)))
        (unless (file-directory-p file)
          (message "loading file %s" file)
          (org-babel-load-file file)
          )
        ))
    )
  )
;; Load it
(load-provided-configuration user-emacs-provided-directory)

Lua

(use-package lua-mode
  :ensure t)

Lisp(s)

General

Let’s install some LISP common useful modes.

(use-package paredit
  :ensure t)
(use-package rainbow-mode
  :ensure t)
(use-package rainbow-delimiters
  :ensure t)
(use-package highlight-parentheses
  :ensure t)

And define a comme lisp hook for all LISP-related prog-modes, mostly about parentheses.

(defun my/lisps-mode-hook ()
  (paredit-mode t)
  (rainbow-delimiters-mode t)
  (highlight-parentheses-mode t)
  )

Emacs lisp

Define some useful alias (just because I’m lazy).

(defalias 'eb 'eval-buffer)
(defalias 'er 'eval-region)
(defalias 'ed 'eval-defun)
(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            (my/lisps-mode-hook)
            (eldoc-mode 1))
          )

Clojure

(use-package clojure-mode
  :ensure t
  :config
  (progn
    (add-hook 'clojure-mode-hook 'my/lisps-mode-hook)))

cider

(use-package cider
  :ensure t)

SQL

Emacs is really more than an editor. The SQL mode is quick cool to used (and do not eat my memory like mysql-workbench for example).

By default, Emacs does not automatically truncate long lines in SQL(i) mode, let’s change that.

(add-hook 'sql-interactive-mode-hook
          (lambda ()
            (toggle-truncate-lines t)))

Linux related modes

Archlinux

I’m using Archlinux on my personnal computers and I maintain a few packages on aur, hopefully there is a mode for that.

(use-package pkgbuild-mode
  :ensure t)

Markdown, Yaml & Toml

(use-package markdown-mode
  :ensure t)
(use-package markdown-mode+
  :ensure t)
(use-package yaml-mode
  :ensure t)
(use-package toml-mode
  :ensure t)

Docker 🐳

I’m playing a lot with docker and most of the time editing Dockerfile and stuff inside Emacs.

(use-package dockerfile-mode
  :ensure t)

Ansible

Ansible is a great automation tool I use to manage my servers and desktops.

(use-package ansible
  :ensure t
  :config
  (progn
    (add-hook 'yaml-mode-hook '(lambda () (ansible 1)))))

The following snippet is taken from lunaryorn article about getting ansible doc in emacs.

(defconst lunaryorn-ansible-doc-buffer " *Ansible Doc*"
  "The Ansible Doc buffer.")

(defvar lunaryorn-ansible-modules nil
  "List of all known Ansible modules.")

(defun lunaryorn-ansible-modules ()
  "Get a list of all known Ansible modules."
  (unless lunaryorn-ansible-modules
    (let ((lines (ignore-errors (process-lines "ansible-doc" "--list")))
          modules)
      (dolist (line lines)
        (push (car (split-string line (rx (one-or-more space)))) modules))
      (setq lunaryorn-ansible-modules (sort modules #'string<))))
  lunaryorn-ansible-modules)

(defun lunaryorn-ansible-doc (module)
  "Show ansible doc for MODULE."
  (interactive
   (list (ido-completing-read "Ansible Module: "
                              (lunaryorn-ansible-modules)
                              nil nil nil nil nil
                              (thing-at-point 'symbol 'no-properties))))
  (let ((buffer (get-buffer-create lunaryorn-ansible-doc-buffer)))
    (with-current-buffer buffer
      (setq buffer-read-only t)
      (view-mode)
      (let ((inhibit-read-only t))
        (erase-buffer)
        (call-process "ansible-doc" nil t t module))
      (goto-char (point-min)))
    (display-buffer buffer)))

Let’s bind it.

(eval-after-load 'yaml-mode
  '(define-key yaml-mode-map (kbd "C-c h a") 'lunaryorn-ansible-doc))

Yasnippet

Use YASnippet for snippets.

(use-package yasnippet
  :ensure t
  :config
  (progn
    (setq yas-verbosity 1
          yas-snippet-dir (expand-file-name "snippets" user-emacs-directory))
    (define-key yas-minor-mode-map (kbd "<tab>") nil)
    (define-key yas-minor-mode-map (kbd "TAB") nil)
    (define-key yas-minor-mode-map (kbd "<C-tab>") 'yas-expand)
    (yas-global-mode 1)))
(use-package helm-c-yasnippet
  :ensure t
  :bind ("C-c y" . helm-yas-complete))

Clean the modeline

With all the modes (major & minor), the modeline becomes really big and unusable ; let’s clean it.

;; FIXME handle this with provided configuration
(defvar mode-line-cleaner-alist
  `((auto-complete-mode         . " α")
    (yas-minor-mode             . " γ")
    (paredit-mode               . " Φ")
    (eldoc-mode                 . "")
    (abbrev-mode                . "")
    (undo-tree-mode             . " τ")
    (volatile-highlights-mode   . " υ")
    (elisp-slime-nav-mode       . " δ")
    (nrepl-mode                 . " ηζ")
    (nrepl-interaction-mode     . " ηζ")
    (cider-mode                 . " ηζ")
    (cider-interaction          . " ηζ")
    (highlight-parentheses-mode . "")
    (highlight-symbol-mode      . "")
    (projectile-mode            . "")
    (helm-mode                  . "")
    (ace-window-mode            . "")
    (magit-auto-revert-mode     . "")
    (sh-mode                    . "sh")
    (org-mode                   . "")
    (go-mode                    . "🐹")
    ;; Major modes
    (term-mode                  . "")
    (clojure-mode               . " Ɩ")
    (hi-lock-mode               . "")
    (visual-line-mode           . " ω")
    (auto-fill-function         . " ψ")
    (python-mode                . " Py")
    (emacs-lisp-mode            . " EL")
    (markdown-mode              . " md")
    (magit                      . " ma")
    (haskell-mode               . " λ")
    (flyspell-mode              . " fs")
    (flymake-mode               . " fm")
    (flycheck-mode              . " fc"))
  "Alist for `clean-mode-line'.

When you add a new element to the alist, keep in mind that you
must pass the correct minor/major mode symbol and a string you
want to use in the modeline *in lieu of* the original.")

(defun clean-mode-line ()
  (interactive)
  (loop for cleaner in mode-line-cleaner-alist
        do (let* ((mode (car cleaner))
                  (mode-str (cdr cleaner))
                  (old-mode-str (cdr (assq mode minor-mode-alist))))
             (when old-mode-str
               (setcar old-mode-str mode-str))
             ;; major mode
             (when (eq mode major-mode)
               (setq mode-name mode-str)))))


(add-hook 'after-change-major-mode-hook 'clean-mode-line)


;;; Greek letters - C-u C-\ greek ;; C-\ to revert to default
;;; ς ε ρ τ υ θ ι ο π α σ δ φ γ η ξ κ λ ζ χ ψ ω β ν μ

Floobits

I’m trying out Floobits @work for remote pairing, mostly with intellij idea but let’s try it out in Emacs \o/.

(use-package floobits
  :ensure t)

Vagrant

Let’s add support for vagrant.

(use-package vagrant
  :ensure t
  :defer t
  :init
  (progn
    (evil-leader/set-key
      "VD" 'vagrant-destroy
      "Ve" 'vagrant-edit
      "VH" 'vagrant-halt
      "Vp" 'vagrant-provision
      "Vr" 'vagrant-resume
      "Vs" 'vagrant-status
      "VS" 'vagrant-suspend
      "VV" 'vagrant-up)))

And let’s also add a TRAMP add-on for Vagrant. The idea is to be able to do something like /vagrant:mybox/etc/hostname

(use-package vagrant-tramp
  :ensure t
  :defer t)

Gist

Interact with Github gist(s) from Emacs :)

(use-package gist
  :ensure t
  :config
  (setq gist-view-gist t))

Irc

Why not putting all the thing in Emacs =:). IRC is one of them and let’s try something different than the good old ERC : let’s try circe.

(use-package circe
  :ensure t
  :config
  (progn
    (use-package helm-circe
      :ensure t)))

Mails ✉

Don’t load if not on a computer where there is mails.

(defvar load-mail-setup (file-exists-p "~/desktop/mails/main"))
(when load-mail-setup

Add mu4e to the load-path and load it.

(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
(require-maybe 'mu4e)
(require-maybe 'helm-mu)

Let’s detect if mu is installed as mu-git or mu. It’s a workaround I need to use because of the name conflict between mu and the mails-utils mu command.

;; (setq mu4e-mu-binary "/usr/local/bin/mu")

Set the maildir, folders and stuff.

(setq mu4e-maildir (expand-file-name "~/desktop/mails"))
(setq mu4e-drafts-folder "/main/Drafts")
(setq mu4e-sent-folder   "/main/Sent")
(setq mu4e-trash-folder  "/main/Trash")

(setq mu4e-get-mail-command "offlineimap")
(setq mu4e-html2text-command "html2text")
(setq message-send-mail-function 'message-send-mail-with-sendmail
      sendmail-program "/usr/bin/msmtp"
      user-full-name "Vincent Demeester")
(add-to-list 'mu4e-view-actions '("retag" . mu4e-action-retag-message))
(add-to-list 'mu4e-headers-actions '("retag" . mu4e-action-retag-message))
)

emacs-config's People

Contributors

vdemeester avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.