A. Bootstrap | B. Theme | C. Features
- Use better defaults
- Validate Emacs’ version
- Benchmark startup time
- Load .custom.el
- Load .secret.el
- Initialize MELPA
Here is what I consider better defaults for my own experience.
(setq-default
ad-redefinition-action 'accept ; Silence warnings for redefinition
confirm-kill-emacs 'yes-or-no-p ; Confirm before exiting Emacs
cursor-in-non-selected-windows nil ; Hide the cursor in inactive windows
delete-by-moving-to-trash t ; Delete files to trash
display-time-default-load-average nil ; Don't display load average
display-time-format "%H:%M" ; Format the time string
fill-column 85 ; Set width for automatic line breaking
gc-cons-threshold most-positive-fixnum ; Increase garbage collector treshold
help-window-select t ; Focus new help windows when opened
indent-tabs-mode nil ; Stop using tabs to indent
indicate-empty-lines t ; Indicate unused lines in the fringe
inhibit-startup-screen t ; Disable start-up screen
initial-scratch-message "" ; Empty the initial *scratch* buffer
mouse-yank-at-point t ; Yank at point rather than cursor
require-final-newline 'visit ; Add a newline at EOF on visit
scroll-conservatively 9999 ; Disable re-center when scrolling
scroll-margin 1 ; Add a window margin when scrolling
show-trailing-whitespace nil ; Display trailing whitespaces
split-height-threshold nil ; Disable vertical window splitting
split-width-threshold nil ; Disable horizontal window splitting
tab-width 4 ; Set width for tabs
uniquify-buffer-name-style 'forward ; Uniquify buffer names
window-combination-resize t ; Resize windows proportionally
x-select-enable-clipboard t) ; Merge system's and Emacs' clipboard
Some UI elements are rather invasive and oppose to the no-mouse philosophy.
(when window-system
(blink-cursor-mode 0) ; Disable the cursor blinking
(scroll-bar-mode 0) ; Disable the scroll bar
(tool-bar-mode 0) ; Disable the tool bar
(tooltip-mode 0)) ; Disable the tooltips
(column-number-mode 0) ; Hide the column number
(display-battery-mode 0) ; Hide the battery level
(display-time-mode 1) ; Hide the time representation
(fringe-mode '(10 . 10)) ; Show vertical fringes
(global-hl-line-mode 1) ; Hightlight current line
(global-subword-mode 1) ; Iterate through CamelCase words
(line-number-mode 1) ; Show the line number
(menu-bar-mode 0) ; Disable the menu bar
(mouse-avoidance-mode 'animate) ; Move pointer to avoid collision with point
(set-frame-parameter nil 'fullscreen 'fullboth) ; Enable pseudo fullscreen
Enable some more goodies.
(fset 'yes-or-no-p 'y-or-n-p) ; Replace yes/no prompts with the shorter y/n
(put 'downcase-region 'disabled nil) ; Enable downcase-region
(put 'upcase-region 'disabled nil) ; Enable upcase-region
Reset garbage collector treshold after initialization is finished and `garbage-collect` on focus-out.
(add-hook 'after-init-hook (lambda () (setq gc-cons-threshold 800000)))
(add-hook 'focus-out-hook 'garbage-collect)
I want an easy way to change the appearance of things and be consistent about it. Those variables are used throughout the whole configuration.
(defvar me/font-family "Monaco" "The font to use.")
(defvar me/font-size-default 120 "The font size to use for default text.")
(defvar me/font-size-header 140 "The font size to use for headers.")
(defvar me/font-size-mode-line 120 "The font size to use for the mode line.")
(when (version<= emacs-version "24")
(unless (yes-or-no-p "Your Emacs is getting old. Kitten may be killed, continue? ")
(kill-emacs)))
Currently 1.4 seconds start-up time. But this is cheating: this snippet of code
should live as early as in init.el
.
- FIXME: Find a way to dynamically look for
benchmark-init.el
.
(let ((benchmark-init.el
(expand-file-name
"elpa/benchmark-init-20150905.238/benchmark-init.el" user-emacs-directory)))
(when (file-exists-p benchmark-init.el)
(load benchmark-init.el)))
One is able to use the customization interface that is bundled within Emacs. It is
meant to help people non familiar with Emacs Lisp in the configuration of Emacs
itself. By default, changes in the customization will be automatically detected and
appended at the end of the configuration file, init.el
.
Since that in my case, the actual configuration file is new one, crafted by
org-mode
, adding code at the end of init.el
might mess things up. The following
tells Emacs to add extra code in another file that would be then loaded if existing.
(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))
I load .secret.el
to keep sensible things out of version control.
For instance, you could set your identity by customizing both user-full-name
and
user-mail-address
in this file.
(let ((secret.el (expand-file-name ".secret.el" user-emacs-directory)))
(when (file-exists-p secret.el)
(load secret.el)))
Dependency checks and MELPA initialization, sugar-wrapped.
- FIXME: What if emacs-major-version < 24?
- FIXME: It sometimes does an extra
package-refresh-contents
.
(when (>= emacs-major-version 24)
(setq-default
load-prefer-newer t
package-enable-at-startup nil)
(package-initialize)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(unless (package-installed-p 'delight)
(package-refresh-contents)
(package-install 'delight))
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package)))
In order to have unified package declaration in my Emacs files, I use use-package. It allows for isolation and clarity.
The
use-package
macro allows you to isolate package configuration in your.emacs
file in a way that is both performance-oriented and, well, tidy. I created it because I have over 80 packages that I use in Emacs, and things were getting difficult to manage. Yet with this utility my total load time is around 2 seconds, with no loss of functionality!
(eval-when-compile
(require 'use-package)
(setq-default
use-package-always-defer t
use-package-always-ensure t))
I like to have an accessible copy of my active theme’s color codes. That way, I can fix other packages’ colors while still using the same color codes and keep consistency everywhere.
This method is considered safe because I am using the all-famous Zenburn Emacs port palette. It is very unlikely that any of its tones will ever change.
(defconst zenburn/bg+3 "#6F6F6F" "Zenburn palette: #6F6F6F.")
(defconst zenburn/bg+2 "#5F5F5F" "Zenburn palette: #5F5F5F.")
(defconst zenburn/bg+1 "#4F4F4F" "Zenburn palette: #4F4F4F.")
(defconst zenburn/bg+0 "#494949" "Zenburn palette: #494949.")
(defconst zenburn/bg "#3F3F3F" "Zenburn palette: #3F3F3F.")
(defconst zenburn/bg-0 "#383838" "Zenburn palette: #383838.")
(defconst zenburn/bg-1 "#2B2B2B" "Zenburn palette: #2B2B2B.")
(defconst zenburn/bg-2 "#000000" "Zenburn palette: #000000.")
(defconst zenburn/blue+1 "#94BFF3" "Zenburn palette: #94BFF3.")
(defconst zenburn/blue "#8CD0D3" "Zenburn palette: #8CD0D3.")
(defconst zenburn/blue-1 "#7CB8BB" "Zenburn palette: #7CB8BB.")
(defconst zenburn/blue-2 "#6CA0A3" "Zenburn palette: #6CA0A3.")
(defconst zenburn/blue-3 "#5C888B" "Zenburn palette: #5C888B.")
(defconst zenburn/blue-4 "#4C7073" "Zenburn palette: #4C7073.")
(defconst zenburn/blue-5 "#366060" "Zenburn palette: #366060.")
(defconst zenburn/cyan "#93E0E3" "Zenburn palette: #93E0E3.")
(defconst zenburn/fg+1 "#FFFFEF" "Zenburn palette: #FFFFEF.")
(defconst zenburn/fg "#DCDCCC" "Zenburn palette: #DCDCCC.")
(defconst zenburn/fg-1 "#656555" "Zenburn palette: #656555.")
(defconst zenburn/green+4 "#BFEBBF" "Zenburn palette: #BFEBBF.")
(defconst zenburn/green+3 "#AFD8AF" "Zenburn palette: #AFD8AF.")
(defconst zenburn/green+2 "#9FC59F" "Zenburn palette: #9FC59F.")
(defconst zenburn/green+1 "#8FB28F" "Zenburn palette: #8FB28F.")
(defconst zenburn/green "#7F9F7F" "Zenburn palette: #7F9F7F.")
(defconst zenburn/green-1 "#5F7F5F" "Zenburn palette: #5F7F5F.")
(defconst zenburn/magenta "#DC8CC3" "Zenburn palette: #DC8CC3.")
(defconst zenburn/orange "#DFAF8F" "Zenburn palette: #DFAF8F.")
(defconst zenburn/red+1 "#DCA3A3" "Zenburn palette: #DCA3A3.")
(defconst zenburn/red "#CC9393" "Zenburn palette: #CC9393.")
(defconst zenburn/red-1 "#BC8383" "Zenburn palette: #BC8383.")
(defconst zenburn/red-2 "#AC7373" "Zenburn palette: #AC7373.")
(defconst zenburn/red-3 "#9C6363" "Zenburn palette: #9C6363.")
(defconst zenburn/red-4 "#8C5353" "Zenburn palette: #8C5353.")
(defconst zenburn/yellow "#F0DFAF" "Zenburn palette: #F0DFAF.")
(defconst zenburn/yellow-1 "#E0CF9F" "Zenburn palette: #E0CF9F.")
(defconst zenburn/yellow-2 "#D0BF8F" "Zenburn palette: #D0BF8F.")
Load zenburn-theme
and fix some high-level faces to match my personal preferences.
(use-package zenburn-theme
:init (load-theme 'zenburn t)
:config
(set-face-attribute 'default nil :height me/font-size-default)
(set-face-attribute 'font-lock-doc-face nil :italic t)
(set-face-attribute 'font-lock-comment-face nil :italic t)
(set-face-attribute 'font-lock-comment-delimiter-face nil
:foreground zenburn/bg+3 :italic t)
(set-face-attribute 'font-lock-function-name-face nil :foreground zenburn/blue)
(set-face-attribute 'fringe nil :background zenburn/bg :foreground zenburn/bg+3)
(set-face-attribute 'header-line nil
:box `(:line-width 1 :color ,zenburn/bg-1)
:height me/font-size-header)
(set-face-attribute 'help-argument-name nil :foreground zenburn/orange)
(set-face-attribute 'hl-line nil :background zenburn/bg+1)
(set-face-attribute 'region nil :foreground zenburn/green)
(set-face-attribute 'vertical-border nil :foreground zenburn/bg-1)
(when (member me/font-family (font-family-list))
(set-face-attribute 'default nil :font me/font-family)))
- Auto-Completion
- CSS
- Comments
- Customization
- Diff
- Dired
- Docker
- Expand
- Git
- Helm
- Helm Plugins
- HTML
- JavaScript
- Linters
- Lisp
- Markdown
- Mode-line
- Org
- OS X
- Navigation
- Parentheses
- Point
- Projectile
- Python
- Quality of Life
- Slack
- Whitespaces
- Web Browsing
- Windows
- YAML
Features are alphabetically sorted because, well, I’m fussy. And they’re easier to find that way… so there’s that.
- TODO: Add a list of all custom shortcuts.
Auto-completion at point. Display a small popin containing the candidates.
(use-package company
:init (global-company-mode)
:config
(setq-default
company-idle-delay .2
company-minimum-prefix-length 1
company-tooltip-align-annotations t))
(use-package company-tern
:init (add-to-list 'company-backends 'company-tern)
:config
(setq-default
company-tern-meta-as-single-line t
company-tern-property-marker " *"))
(use-package css-mode
:delight css-mode "CSS"
:config (setq-default css-indent-offset 2))
(use-package scss-mode
:delight scss-mode "SCSS"
:mode ("\\.css\\'" "\\.sass\\'" "\\.scss\\'")
:init
(add-hook 'scss-mode-hook
(lambda ()
(setq-local comment-end "")
(setq-local comment-start "//")))
:config (setq-default scss-compile-at-save nil))
(use-package newcomment
:ensure nil
:bind ("M-RET" . comment-indent-new-line)
:config
(setq-default
comment-auto-fill-only-comments t
comment-multi-line t))
This merely changes face attributes and Zenburn customization buffers a little more. Should I just try a pull request over zenburn-emacs?
(use-package cus-edit
:ensure nil
:config
(set-face-attribute 'custom-group-tag nil :foreground zenburn/yellow :height me/font-size-header)
(set-face-attribute 'custom-state nil :foreground zenburn/green+4)
(set-face-attribute 'custom-variable-tag nil :foreground zenburn/blue)
(when (member me/font-family (font-family-list))
(set-face-attribute 'custom-group-tag nil :font me/font-family)))
Ediff is a visual interface to Unix diff
.
(use-package ediff-util
:ensure nil
:init (add-hook 'ediff-mode-hook #'me/setup-ediff-map)
:config
(defun me/setup-ediff-map ()
(ediff-setup-keymap)
(define-key ediff-mode-map (kbd "<down>") #'ediff-next-difference)
(define-key ediff-mode-map (kbd "<up>") #'ediff-previous-difference)))
(use-package ediff-wind
:ensure nil
:config
(setq-default
ediff-split-window-function #'split-window-horizontally
ediff-window-setup-function #'ediff-setup-windows-plain))
Configure Dired buffers. Amongst many other things, Emacs is also a file explorer.
(use-package dired
:ensure nil
:delight dired-mode "Dired"
:config
(defadvice dired-readin (after dired-after-updating-hook first () activate)
"Sort dired listings with directories first before adding marks."
(save-excursion
(let (buffer-read-only)
(forward-line 2) ;; beyond dir. header
(sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
(set-buffer-modified-p nil)))
(setq-default
dired-auto-revert-buffer t
dired-listing-switches "-alh"
dired-ls-F-marks-symlinks nil
dired-recursive-copies 'always))
(use-package dockerfile-mode
:delight dockerfile-mode "Dockerfile"
:mode "Dockerfile\\'")
HippieExpand manages expansions a la Emmet. So I’ve gathered all features that look
anywhere close to this behavior for it to handle under the same bind, that is
C-RET
. Basically I made a DWIM for expand-like completion out of it.
(use-package emmet-mode
:init
(add-hook 'css-mode-hook 'emmet-mode)
(add-hook 'sgml-mode-hook 'emmet-mode)
:config
(setq-default emmet-move-cursor-between-quote t)
(unbind-key "<C-return>" emmet-mode-keymap)
(unbind-key "C-M-<left>" emmet-mode-keymap)
(unbind-key "C-M-<right>" emmet-mode-keymap))
(use-package hippie-exp
:ensure nil
:bind ("<C-return>" . hippie-expand)
:config
(setq-default
hippie-expand-try-functions-list '(yas-hippie-try-expand emmet-expand-line)))
(use-package yasnippet
:init
(add-hook 'js-mode-hook 'yas-minor-mode)
(add-hook 'org-mode-hook 'yas-minor-mode)
(add-hook 'sgml-mode-hook 'yas-minor-mode)
:config
(setq-default yas-snippet-dirs '("~/.emacs.d/snippets"))
(yas-reload-all)
(unbind-key "TAB" yas-minor-mode-map)
(unbind-key "<tab>" yas-minor-mode-map))
Magit provide Git facilities directly from within Emacs.
Magit is an interface to the version control system Git, implemented as an Emacs package. Magit aspires to be a complete Git porcelain. While we cannot (yet) claim that Magit wraps and improves upon each and every Git command, it is complete enough to allow even experienced Git users to perform almost all of their daily version control tasks directly from within Emacs. While many fine Git clients exist, only Magit and Git itself deserve to be called porcelains. (more)
(use-package magit
:bind
(("C-c g b" . magit-blame)
("C-c g l" . magit-log)
("C-c g p" . magit-pull)
("C-c g s" . magit-status))
:config
(defun me/magit-display-buffer-function (buffer)
"Render some magit modes in the currently selected buffer."
(display-buffer
buffer
(cond ((and (derived-mode-p 'magit-mode)
(eq (with-current-buffer buffer major-mode)
'magit-status-mode))
nil)
((memq (with-current-buffer buffer major-mode)
'(magit-process-mode
magit-revision-mode
magit-diff-mode
magit-stash-mode))
nil)
(t
'(display-buffer-same-window)))))
;; Use better defaults
(setq-default
magit-display-buffer-function 'me/magit-display-buffer-function
magit-diff-highlight-hunk-body nil
magit-popup-display-buffer-action '((display-buffer-same-window))
magit-refs-show-commit-count (quote all)
magit-section-show-child-count t
magit-set-upstream-on-push 'askifnotset)
;; Customize lighters
(delight
'((magit-diff-mode "Magit Diff")
(magit-log-mode "Magit Log")
(magit-popup-mode "Magit Popup")
(magit-status-mode "Magit Status")))
;; Customize faces
(set-face-attribute 'magit-diff-added nil
:background zenburn/bg+0 :foreground zenburn/green+3)
(set-face-attribute 'magit-diff-context nil :background zenburn/bg+0)
(set-face-attribute 'magit-diff-file-heading-highlight nil :background 'unspecified)
(set-face-attribute 'magit-diff-hunk-heading nil :background zenburn/bg+2)
(set-face-attribute 'magit-diff-hunk-heading-highlight nil :background zenburn/bg+2)
(set-face-attribute 'magit-diff-removed nil
:background zenburn/bg+0 :foreground zenburn/red)
(set-face-attribute 'magit-popup-heading nil :height me/font-size-header)
(set-face-attribute 'magit-section-heading nil :height me/font-size-header)
(set-face-attribute 'magit-section-highlight nil :background 'unspecified))
(use-package gitattributes-mode :delight gitattributes-mode "Git Attributes")
(use-package gitconfig-mode :delight gitconfig-mode "Git Config")
(use-package gitignore-mode :delight gitignore-mode "Git Ignore")
Helm is a beast. Although heavily, it replaces ido-mode
in many ways.
Helm
is an Emacs framework for incremental completions and narrowing selections. It helps to rapidly complete file names, buffer names, or any other Emacs interactions requiring selecting an item from a list of possible choices.Helm is a fork of
anything.el
, which was originally written by Tamas Patrovic and can be considered to be its successor.Helm
cleans the legacy code that is leaner, modular, and unchained from constraints of backward compatibility.
- TODO: Make helm-list-faces-display.
- TODO: Fix the mode-line for Helm buffers.
(use-package helm
:defer 1
:bind
(("C-c h k" . helm-show-kill-ring)
("C-c h g" . helm-google-suggest)
("C-c h i" . helm-imenu)
("C-c h r" . helm-resume))
:config
(helm-mode 1)
(setq-default
helm-always-two-windows t
helm-display-header-line nil
helm-mode-line-string nil
helm-split-window-default-side 'left)
(set-face-attribute 'helm-ff-dotted-directory nil
:background 'unspecified :foreground zenburn/bg+3)
(set-face-attribute 'helm-match nil :foreground zenburn/green+2 :weight 'normal)
(set-face-attribute 'helm-source-header nil
:box nil :background 'unspecified :height me/font-size-header))
Helm sub-modules can be customized separately. Many basic Emacs commands have their Helm equivalents.
(use-package helm-buffers
:ensure helm
:config (setq-default helm-buffers-fuzzy-matching t))
(use-package helm-color
:ensure helm
:bind ("C-c h c" . helm-colors))
(use-package helm-command
:ensure helm
:bind ([remap execute-extended-command] . helm-M-x)
:config
(setq-default helm-M-x-fuzzy-match t)
(set-face-attribute 'helm-M-x-key nil :foreground zenburn/orange :underline nil))
(use-package helm-files
:ensure helm
:bind (:map helm-find-files-map ("C-s" . helm-ff-run-grep-ag)))
(use-package helm-grep
:ensure helm
:config (set-face-attribute 'helm-grep-lineno nil :foreground zenburn/yellow-2))
(use-package helm-misc
:ensure helm
:bind ([remap switch-to-buffer] . helm-buffers-list))
(use-package helm-mode
:ensure helm
:config
(setq-default
helm-completion-in-region-fuzzy-match t
helm-mode-fuzzy-match t))
(use-package helm-net
:ensure helm
:config (setq-default helm-net-prefer-curl t))
(use-package helm-regexp
:ensure helm
:config (set-face-attribute 'helm-moccur-buffer nil :foreground zenburn/blue))
Fourth-party packages for Helm.
- NOTE: Does not respect
helm-split-window-default-side
(emacsorphanage/helm-css-scss#7). - TODO: Fix Zenburn palette (bbatsov/zenburn-emacs#220).
(use-package helm-ag)
(use-package helm-css-scss
:bind ("C-c h s" . helm-css-scss)
:config (setq-default helm-css-scss-split-direction 'split-window-horizontally))
(use-package helm-descbinds
:bind ([remap describe-key] . helm-descbinds)
:config (setq-default helm-descbinds-window-style 'split-window))
(use-package helm-describe-modes
:bind ([remap describe-mode] . helm-describe-modes))
(use-package helm-flycheck
:bind ("C-c h f" . helm-flycheck))
(use-package helm-projectile
:after helm
:config (helm-projectile-on))
HTML mode is defined in sgml-mode.el
.
(use-package sgml-mode
:ensure nil
:delight html-mode "HTML"
:config (setq-default sgml-basic-offset 2))
Tern is a code-analysis engine for JavaScript. I use it to check syntax and grammar in my JavaScript code. With an auto-complete frontend, it can also provide candidates for variables and properties.
- FIXME: Indent level is broken (json-emacs/json-mode#32).
(use-package js
:delight js-mode "JavaScript"
:config (setq-default js-indent-level 2))
(use-package json-mode
:delight json-mode "JSON"
:mode "\\.json\\'"
:config
(add-hook 'json-mode-hook (lambda () (setq-local js-indent-level 2))))
(use-package tern
:config (add-hook 'js-mode-hook 'tern-mode))
Flycheck lints warnings and errors directly within buffers. It can check a lot of different syntaxes, as long as you make sure that Emacs has access to the binaries (see README.md).
(use-package flycheck
:bind
(("C-c e l" . list-flycheck-errors)
("C-c e p" . flycheck-previous-error)
("C-c e n" . flycheck-next-error))
:init
(add-hook 'emacs-lisp-mode-hook 'flycheck-mode)
(add-hook 'js-mode-hook 'flycheck-mode)
(add-hook 'python-mode-hook 'flycheck-mode)
(add-hook 'scss-mode-hook 'flycheck-mode)
:config
(setq-default
flycheck-check-syntax-automatically '(save mode-enabled)
flycheck-disabled-checkers '(emacs-lisp-checkdoc)
flycheck-display-errors-delay .3
flycheck-flake8rc "~/.flake8rc"
flycheck-jshintrc "~/.jshintrc"
flycheck-pylintrc "~/.pylintrc")
(set-face-attribute 'flycheck-error nil :underline zenburn/red-1)
(set-face-attribute 'flycheck-info nil :underline zenburn/blue+1)
(set-face-attribute 'flycheck-warning nil :underline zenburn/orange)
(set-face-attribute 'flycheck-fringe-error nil :foreground zenburn/red-1)
(set-face-attribute 'flycheck-fringe-info nil :foreground zenburn/blue+1)
(set-face-attribute 'flycheck-fringe-warning nil :foreground zenburn/orange))
(use-package lisp-mode
:ensure nil
:delight lisp-mode "Lisp"
:config
(delight
'((emacs-lisp-mode "Emacs Lisp")
(lisp-interaction-mode "Lisp Interaction"))))
(use-package markdown-mode
:delight markdown-mode "Markdown"
:mode
("INSTALL\\'"
"CONTRIBUTORS\\'"
"LICENSE\\'"
"README\\'"
"\\.markdown\\'"
"\\.md\\'")
:init (add-hook 'markdown-mode-hook 'turn-on-auto-fill)
:config
(unbind-key "M-<down>" markdown-mode-map)
(unbind-key "M-<up>" markdown-mode-map)
(setq-default markdown-asymmetric-header t))
Delight allows you to change modes — both major and minor modes — lighters. They
are the descriptive strings than you often see appear within the mode-line
.
(use-package delight
:config
(defadvice powerline-major-mode (around delight-powerline-major-mode activate)
(let ((inhibit-mode-name-delight nil))
ad-do-it))
(defadvice powerline-minor-modes (around delight-powerline-minor-modes activate)
(let ((inhibit-mode-name-delight nil))
ad-do-it)))
Brace yourself, this is quite big and possibly sub-optimal. I use powerline
to
customize the mode-line
a la Vim.
- TODO: Check out https://www.emacswiki.org/emacs/delight-powerline.el.
(use-package powerline
:demand t
:preface
;; Setup the mode-line components
(defvar me/powerline-hud nil)
;; Define new faces for elements
(defface me/buffer-clean-face '((t (:inherit powerline-active1)))
"Face used for the buffer string: clean."
:group 'me/powerline)
(defface me/buffer-read-only-face '((t (:inherit powerline-active1)))
"Face used for the buffer string: read only."
:group 'me/powerline)
(defface me/buffer-modified-face '((t (:inherit powerline-active1)))
"Face used for the buffer string: modified."
:group 'me/powerline)
(defface me/fc-error-face '((t (:inherit powerline-active1)))
"Face used for the error count."
:group 'me/powerline)
(defface me/fc-info-face '((t (:inherit powerline-active1)))
"Face used for the info count."
:group 'me/powerline)
(defface me/fc-warning-face '((t (:inherit powerline-active1)))
"Face used for the warning count."
:group 'me/powerline)
(defface me/hud-face '((t (:inherit powerline-active1)))
"Face used for the XPM of relative buffer location."
:group 'me/powerline)
(defface me/line-number-face '((t (:inherit powerline-active1)))
"Face used for the line number string."
:group 'me/powerline)
(defface me/projectile-face '((t (:inherit powerline-active1)))
"Face used for the projectile string."
:group 'me/powerline)
(defface me/vc-face '((t (:inherit powerline-active1)))
"Face used for the version control string."
:group 'me/powerline)
:config
(defadvice vc-mode-line (after me/vc-mode-line () activate)
"Strip backend from the VC information."
(when (stringp vc-mode)
(let ((vc-text (replace-regexp-in-string "^ Git." ":" vc-mode)))
(setq vc-mode vc-text))))
(defmacro me/flycheck-lighter (error)
"Return a formatted string describing the ERROR (error, warning, info) count."
`(let* ((error-counts (flycheck-count-errors flycheck-current-errors))
(errorp (flycheck-has-current-errors-p ',error))
(count (or (cdr (assq ',error error-counts)) "?"))
(running (eq 'running flycheck-last-status-change)))
(if (or errorp running) (format "• %s" count))))
;; Customize appearance
(setq-default
powerline-default-separator 'wave
powerline-height 20
me/powerline-hud nil)
;; Define the mode-line format
(setq-default
mode-line-format
'("%e"
(:eval
(let* ((active (powerline-selected-window-active))
;; Define faces for mode-line elements
(buffer-face
(if active
(cond
(buffer-read-only 'me/buffer-read-only-face)
((buffer-modified-p) 'me/buffer-modified-face)
(t 'me/buffer-clean-face))
(cond
((buffer-modified-p) 'me/buffer-modified-face)
(t ''powerline-inactive1))))
(fc-error-face (if active 'me/fc-error-face 'powerline-inactive1))
(fc-info-face (if active 'me/fc-info-face 'powerline-inactive1))
(fc-warning-face (if active 'me/fc-warning-face 'powerline-inactive1))
(hud-face 'me/hud-face)
(line-number-face (if active 'me/line-number-face 'powerline-inactive1))
(mode-line-1-face (if active 'mode-line 'mode-line-inactive))
(mode-line-2-face (if active 'powerline-active1 'powerline-inactive1))
(mode-line-3-face (if active 'powerline-active2 'powerline-inactive2))
(projectile-face (if active 'me/projectile-face 'powerline-inactive1))
(vc-face (if active 'me/vc-face 'powerline-inactive1))
;; Define faces for separators
(separator-left
(intern
(format
"powerline-%s-%s"
(powerline-current-separator) (car powerline-default-separator-dir))))
(separator-right
(intern
(format
"powerline-%s-%s"
(powerline-current-separator) (cdr powerline-default-separator-dir))))
;; List left elements
(lhs
(append
(list
(powerline-major-mode mode-line-1-face 'l)
(powerline-raw " " mode-line-1-face)
(funcall separator-left mode-line-1-face mode-line-2-face))
(list
(powerline-raw "%b" buffer-face 'l)
(powerline-raw ":%l" line-number-face)
(powerline-raw " " mode-line-2-face)
(funcall separator-left mode-line-2-face mode-line-3-face))))
;; List right elements
(rhs
(append
(when (and
(bound-and-true-p flycheck-mode)
(or flycheck-current-errors (eq 'running flycheck-last-status-change)))
(list
(funcall separator-right mode-line-3-face mode-line-2-face)
(powerline-raw " " mode-line-2-face)
(powerline-raw (me/flycheck-lighter error) fc-error-face 'r)
(powerline-raw (me/flycheck-lighter warning) fc-warning-face 'r)
(powerline-raw (me/flycheck-lighter info) fc-info-face 'r)
(funcall separator-left mode-line-2-face mode-line-3-face)
(powerline-raw " " mode-line-3-face)))
(list
(funcall separator-right mode-line-3-face mode-line-2-face)
(powerline-raw " " mode-line-2-face)
(powerline-raw (projectile-project-name) projectile-face)
(powerline-vc vc-face)
(powerline-raw " " mode-line-2-face))
(list
(funcall separator-right mode-line-2-face mode-line-1-face)
(powerline-raw " " mode-line-1-face)
(powerline-raw display-time-string mode-line-1-face 'r)
(if me/powerline-hud (powerline-hud hud-face mode-line-2-face 2))))))
;; Build the result
(concat
(powerline-render lhs)
(powerline-fill mode-line-3-face (powerline-width rhs))
(powerline-render rhs))))))
;; Customize faces
(set-face-attribute 'mode-line nil
:box `(:line-width 1 :color ,zenburn/bg-1)
:background zenburn/green-1 :foreground zenburn/green+2
:height me/font-size-mode-line)
(set-face-attribute 'mode-line-inactive nil
:box `(:line-width 1 :color ,zenburn/bg-1)
:background zenburn/bg-1 :foreground zenburn/bg+3
:height me/font-size-mode-line)
(set-face-attribute 'powerline-active1 nil :background zenburn/bg-0 :foreground zenburn/fg)
(set-face-attribute 'powerline-active2 nil :background zenburn/bg+1)
(set-face-attribute 'powerline-inactive1 nil :background zenburn/bg-0)
(set-face-attribute 'powerline-inactive2 nil :background zenburn/bg+1)
(set-face-attribute 'me/buffer-clean-face nil :foreground zenburn/green)
(set-face-attribute 'me/buffer-modified-face nil :foreground zenburn/red)
(set-face-attribute 'me/buffer-read-only-face nil :foreground zenburn/magenta)
(set-face-attribute 'me/fc-error-face nil :foreground zenburn/red-1)
(set-face-attribute 'me/fc-info-face nil :foreground zenburn/blue+1)
(set-face-attribute 'me/fc-warning-face nil :foreground zenburn/orange)
(set-face-attribute 'me/hud-face nil :background zenburn/fg-1)
(set-face-attribute 'me/line-number-face nil :foreground zenburn/bg+3)
(set-face-attribute 'me/projectile-face nil :foreground zenburn/blue)
(set-face-attribute 'me/vc-face nil :foreground zenburn/bg+3))
Jump to a specific position in the buffer using a char-based decision tree.
(use-package avy
:bind ("C-s" . avy-goto-char)
:config
(setq-default
avy-all-windows nil
avy-background t))
I disagree with Emacs’ definition of paragraphs so I redefined the way it should jump from one block to another.
(global-set-key (kbd "<C-down>") 'me/goto-next-block)
(global-set-key (kbd "<C-up>") 'me/goto-previous-block)
(defun me/goto-next-block ()
"Jump to next paragraph."
(interactive "^")
(skip-chars-forward "\n")
(unless (search-forward-regexp "\n[[:blank:]]*\n" nil t)
(goto-char (point-max)))
(skip-chars-forward "\n"))
(defun me/goto-previous-block ()
"Jump to previous paragraph."
(interactive "^")
(skip-chars-backward "\n")
(unless (search-backward-regexp "\n[[:blank:]]*\n" nil t)
(goto-char (point-min)))
(skip-chars-forward "\n"))
Bind commands to move around windows.
(global-set-key (kbd "C-M-<left>") 'windmove-left)
(global-set-key (kbd "C-M-<right>") 'windmove-right)
(global-set-key (kbd "C-M-<up>") 'windmove-up)
(global-set-key (kbd "C-M-<down>") 'windmove-down)
This very file is organized with org-mode
. I am definitely not a power user of Org,
but I’m getting there. :)
Org mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system.
- FIXME: Fix
hl-line
in source blocks.
(use-package org
:delight org-mode "Org"
:init (add-hook 'org-mode-hook 'turn-on-auto-fill)
:config
(setq-default
org-edit-src-content-indentation 0
org-src-fontify-natively t
org-src-window-setup 'current-window
org-support-shift-select 'always
org-startup-folded nil
org-startup-truncated nil)
(set-face-attribute 'org-block-background nil :background zenburn/bg+0)
(set-face-attribute 'org-block-begin-line nil :background 'unspecified)
(set-face-attribute 'org-block-end-line nil :background 'unspecified)
(unbind-key "C-a" org-mode-map)
(unbind-key "C-e" org-mode-map)
(unbind-key "<C-return>" org-mode-map)
(unbind-key "<C-S-down>" org-mode-map)
(unbind-key "<C-S-up>" org-mode-map)
(define-key org-mode-map (kbd "<M-return>") 'org-insert-heading-after-current))
Augment Emacs experience for OS X users.
(defvar ns-command-modifier)
(defvar ns-option-modifier)
(when (eq system-type 'darwin)
(setq-default
exec-path (append exec-path '("/usr/local/bin")) ; Add path to binaries installed with Homebrew
ns-command-modifier 'meta ; Map the Meta key to the `cmd' key
ns-option-modifier nil)) ; Disable the `alt' key
Highlight parenthese-like delimiters in a rainbow fashion. It ease the reading when dealing with mismatched parentheses.
(use-package rainbow-delimiters
:init
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
(add-hook 'scss-mode-hook #'rainbow-delimiters-mode))
I am still looking for the perfect parenthesis management setup as of today… No package seem to please my person.
(use-package smartparens
:functions sp-pair
:bind
(("M-<backspace>" . sp-unwrap-sexp)
("M-<left>" . sp-forward-barf-sexp)
("M-<right>" . sp-forward-slurp-sexp)
("M-S-<left>" . sp-backward-slurp-sexp)
("M-S-<right>" . sp-backward-barf-sexp))
:init (require 'smartparens-config)
:config
(smartparens-global-mode 1)
(setq-default sp-autoinsert-quote-if-followed-by-closing-pair t)
(sp-pair "{{" "}}")
(sp-pair "[[" "]]"))
Increase region by semantic units. It tries to be smart about it and adapt to the structure of the current major mode.
(use-package expand-region
:bind ("C-=" . er/expand-region)
:init (pending-delete-mode t))
Enable multiple cursors at once. Some witchcraft at work here.
(use-package multiple-cursors
:bind
(("C-S-<mouse-1>" . mc/add-cursor-on-click)
("C-S-c C-S-a" . mc/vertical-align-with-space)
("C-S-c C-S-c" . mc/edit-lines)
("C-S-c C-S-l" . mc/insert-letters)
("C-S-c C-S-n" . mc/insert-numbers)
("C-'" . mc-hide-unmatched-lines-mode))
:init
(setq-default
mc/edit-lines-empty-lines 'ignore
mc/insert-numbers-default 1
mc/list-file (expand-file-name ".multiple-cursors.el" user-emacs-directory)))
Enable new custom binds when region is active. I’ve also added a few helpers to use
with selected
.
- TODO: Make a help buffer à la Magit.
(use-package selected
:defines selected-keymap
:bind
(:map selected-keymap
("C-c C-c" . me/eval-region-and-kill-mark)
("<M-left>" . me/indent-rigidly-left-and-keep-mark)
("<M-right>" . me/indent-rigidly-right-and-keep-mark)
("<" . mc/mark-previous-like-this)
(">" . mc/mark-next-like-this)
("C-b b" . me/browse-url-and-kill-mark)
("C-c c" . capitalize-region)
("C-c l" . downcase-region)
("C-c u" . upcase-region)
("C-f f" . fill-region)
("C-g" . selected-off)
("C-s r" . reverse-region)
("C-s s" . sort-lines)
("C-s w" . me/sort-words))
:init (selected-global-mode))
(defun me/eval-region-and-kill-mark (beg end)
"Execute the region as Lisp code.
Call `eval-region' and kill mark. Move back to the beginning of the region."
(interactive "r")
(eval-region beg end)
(setq deactivate-mark t)
(goto-char beg))
(defun me/browse-url-and-kill-mark (url &rest args)
"Ask a WWW browser to load URL.
Call `browse-url' and kill mark."
(interactive (browse-url-interactive-arg "URL: "))
(apply #'browse-url url args)
(setq deactivate-mark t))
(defun me/indent-rigidly-left-and-keep-mark (beg end)
"Indent all lines between BEG and END leftward by one space.
Call `indent-rigidly-left' and keep mark."
(interactive "r")
(indent-rigidly-left beg end)
(setq deactivate-mark nil))
(defun me/indent-rigidly-right-and-keep-mark (beg end)
"Indent all lines between BEG and END rightward by one space.
Call `indent-rigidly-right' and keep mark."
(interactive "r")
(indent-rigidly-right beg end)
(setq deactivate-mark nil))
(defun me/sort-words (reverse beg end)
"Sort words in region alphabetically, in REVERSE if negative.
Prefixed with negative \\[universal-argument], sorts in reverse.
The variable `sort-fold-case' determines whether alphabetic case
affects the sort order.
See `sort-regexp-fields'."
(interactive "*P\nr")
(sort-regexp-fields reverse "\\w+" "\\&" beg end))
Work on lines.
- TODO: Handle regions.
(global-set-key (kbd "<M-S-down>") 'me/duplicate-line-down)
(global-set-key (kbd "<M-S-up>") 'me/duplicate-line-up)
(global-set-key (kbd "<M-down>") 'me/swap-line-down)
(global-set-key (kbd "<M-up>") 'me/swap-line-up)
(defun me/duplicate-line-down ()
"Duplicate downward the line under point."
(interactive)
(kill-whole-line 0)
(yank)
(newline)
(yank)
(move-beginning-of-line 1))
(defun me/duplicate-line-up ()
"Duplicate upward the line under point."
(interactive)
(kill-whole-line 0)
(yank)
(move-beginning-of-line 1)
(yank)
(newline)
(move-beginning-of-line 0))
(defun me/swap-line-down ()
"Move down the line under point."
(interactive)
(forward-line 1)
(transpose-lines 1)
(forward-line -1)
(indent-according-to-mode)
(delete-trailing-whitespace))
(defun me/swap-line-up ()
"Move up the line under point."
(interactive)
(transpose-lines 1)
(forward-line -2)
(indent-according-to-mode)
(delete-trailing-whitespace))
Projectile brings project-level facilities to Emacs such as grep, find and replace.
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
:init (projectile-global-mode)
:config
(defun me/projectile-project-name (orig-fun &rest args)
"Prefer `me/project-name' over default Projectile project string."
(or me/project-name (apply orig-fun args)))
(setq-default
projectile-completion-system 'helm
projectile-enable-caching t
projectile-mode-line '(:eval (projectile-project-name)))
(advice-add 'projectile-project-name :around #'me/projectile-project-name))
(use-package python
:delight python-mode "Python")
(use-package pip-requirements
:delight pip-requirements-mode "PyPA Requirements"
:config (add-hook 'pip-requirements-mode-hook (lambda () (setq-local completion-ignore-case t))))
Colorize colors as text with their value.
(use-package rainbow-mode
:init (add-hook 'prog-mode-hook 'rainbow-mode)
:config (setq-default rainbow-x-colors-major-mode-list '()))
Slack integration.
- TODO: Register teams in
.secret.el
.
(use-package slack
:commands (slack-start)
:config
(setq-default
slack-buffer-function 'switch-to-buffer
slack-prefer-current-team t)
(slack-register-team
:name "FiftyFor"
:default t
:client-id me/fiftyfor-client-id
:client-secret me/fiftyfor-client-secret
:token me/fiftyfor-token
:subscribed-channels '(dev general))
(set-face-attribute
'slack-message-output-header nil :foreground zenburn/orange :underline nil)
(set-face-attribute
'slack-message-output-reaction nil :background zenburn/bg+2 :overline nil)
(set-face-attribute 'slack-message-output-text nil :height 1))
Highlight space-like characters, eg. trailing spaces, tabs, empty lines.
(use-package whitespace
:init (global-whitespace-mode 1)
:config
(setq-default whitespace-style '(face empty tab trailing))
(set-face-attribute 'whitespace-empty nil :background zenburn/red-1)
(set-face-attribute 'whitespace-tab nil :background zenburn/red-1)
(set-face-attribute 'whitespace-trailing nil :background zenburn/red-1))
EWW stands for Emacs Web Wowser. Yeah that’s right… Emacs is also a Web browser, text-based that is.
- NOTE: Why can’t I use
setq-default
to customizeeww-header-line-format
?
(use-package eww
:ensure nil
:delight eww-mode "Emacs Web Wowser"
:config (setq eww-header-line-format " %t: %u"))
Adjust the size of every windows and focus the active one. It uses the mathematical golden ratio somewhere in its formulas.
- TODO: Find a way to automatically adjust
golden-ratio-adjust-factor
depending on the current display. - TODO: Check out https://github.com/mina86/auto-dim-other-buffers.el.
(use-package golden-ratio
:preface
(defconst me/golden-ratio-adjust-factor-1 .8 "A factor for 16/10: bi-split.")
(defconst me/golden-ratio-adjust-factor-2 .525 "A factor for 16/10: tri-split.")
(defconst me/golden-ratio-adjust-factor-3 .805 "A factor for 16/9: bi-split.")
(defconst me/golden-ratio-adjust-factor-4 .53 "A factor for 16/9: tri-split.")
(defun me/golden-ratio-adjust-1 ()
(interactive)
(golden-ratio-adjust me/golden-ratio-adjust-factor-1))
(defun me/golden-ratio-adjust-2 ()
(interactive)
(golden-ratio-adjust me/golden-ratio-adjust-factor-2))
(defun me/golden-ratio-adjust-3 ()
(interactive)
(golden-ratio-adjust me/golden-ratio-adjust-factor-3))
(defun me/golden-ratio-adjust-4 ()
(interactive)
(golden-ratio-adjust me/golden-ratio-adjust-factor-4))
(defun me/ediff-comparison-buffer-p ()
(if (boundp 'ediff-this-buffer-ediff-sessions)
(progn
(balance-windows)
ediff-this-buffer-ediff-sessions)))
:bind
(("<f5>" . me/golden-ratio-adjust-1)
("<f6>" . me/golden-ratio-adjust-2)
("<f7>" . me/golden-ratio-adjust-3)
("<f8>" . me/golden-ratio-adjust-4))
:init (golden-ratio-mode 1)
:config
(setq-default golden-ratio-adjust-factor me/golden-ratio-adjust-factor-3)
(add-to-list 'golden-ratio-exclude-modes "ediff-mode")
(add-to-list 'golden-ratio-inhibit-functions 'me/ediff-comparison-buffer-p))
Allow undo’s and redo’s with window configurations.
Winner mode is a global minor mode that records the changes in the window configuration (i.e. how the frames are partitioned into windows) so that the changes can be “undone” using the command
winner-undo
. By default this one is bound to the key sequence ctrl-c left. If you change your mind (while undoing), you can press ctrl-c right (callingwinner-redo
).
(use-package winner
:ensure nil
:if (fboundp 'winner-mode)
:init (winner-mode 1))
(use-package yaml-mode
:delight yaml-mode "YAML"
:mode "\\.yml\\'")