___ __ .-----.--------.---.-.----.-----.______.----.-----.-----.' _|__|.-----. | -__| | _ | __|__ --|______| __| _ | | _| || _ | |_____|__|__|__|___._|____|_____| |____|_____|__|__|__| |__||___ | |_____|
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 :
- Joodie emacs-literal-config
- Dakrone emacs configuration
- Sacha Chua’s Emacs configuration
- “Steckemacs” steckerhalter literal emacs config
- Lartsvei dot-emacs
- Grettke emacs configuration
- Johns customizations to maximize emacs (jmax)
- jwiegley dot-emacs
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) :
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 .
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))
(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))
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)
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)
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)
;; )
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))
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))
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))
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"))
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)
Move the mouse away to not bother.
(mouse-avoidance-mode 'jump)
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)
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)
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)
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)))))
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 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))
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 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")
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)
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))
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)
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)
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)
Taking from here, ensure that M-v
always undoes C-v
, so you can go back exactly.
(setq scroll-preserve-screen-position 'always)
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 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)))
(use-package ace-jump-mode
:ensure t
:commands ace-jump-mode
:bind ("<f7>" . ace-jump-mode))
(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")))
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)
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)
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.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)
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))))
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))
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 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)
(use-package helm-make
:ensure t)
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)))
Emacs Helm Interface for quick Google searches
(use-package helm-google
:ensure t)
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 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 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))
(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)
(use-package magit
:ensure t
:bind ("C-c g" . magit-status))
(setq magit-last-seen-setup-instructions "1.4.0")
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
.
(use-package git-gutter-fringe
:ensure t
:config (global-git-gutter-mode +1))
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)
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)
(use-package git-blame
:ensure t)
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)))
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))
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)))
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 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 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 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-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.
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 minimumBLOCKED
: task that I start working on but cannot anymore (for some reason), thus they are blockedREVIEW
: 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)))
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)))))
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
))
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)
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)))
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 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.
Important | Kaizen | Panic |
tag important | improvements | emergency |
---|---|---|
Less Important | Organics | Social investment |
no tag important | inspiration | Social activities |
Less Urgent | Urgent | |
no tag urgent | tag urgent |
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)))))
(use-package org-pomodoro
:ensure t)
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"))
))
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 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 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)))
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)
))
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)
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)
(use-package lua-mode
:ensure t)
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)
)
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))
)
(use-package clojure-mode
:ensure t
:config
(progn
(add-hook 'clojure-mode-hook 'my/lisps-mode-hook)))
(use-package cider
:ensure t)
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)))
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)
(use-package markdown-mode
:ensure t)
(use-package markdown-mode+
:ensure t)
(use-package yaml-mode
:ensure t)
(use-package toml-mode
:ensure t)
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 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))
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))
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
;;; ς ε ρ τ υ θ ι ο π α σ δ φ γ η ξ κ λ ζ χ ψ ω β ν μ
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)
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)
Interact with Github gist(s) from Emacs :)
(use-package gist
:ensure t
:config
(setq gist-view-gist t))
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)))
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))
)