Skip to content

Latest commit

 

History

History
1424 lines (1175 loc) · 48.3 KB

dotemacs.org

File metadata and controls

1424 lines (1175 loc) · 48.3 KB

DotEmacs

A. Bootstrap | B. Theme | C. Features

A. Bootstrap

  1. Use better defaults
  2. Validate Emacs’ version
  3. Benchmark startup time
  4. Load .custom.el
  5. Load .secret.el
  6. Initialize MELPA

1. Use better defaults

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

2. Validate Emacs’ version

(when (version<= emacs-version "24")
  (unless (yes-or-no-p "Your Emacs is getting old. Kitten may be killed, continue? ")
    (kill-emacs)))

3. Benchmark startup time

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

4. Load .custom.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))

5. Load .secret.el

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

6. Initialize MELPA

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!

John Wiegley

(eval-when-compile
  (require 'use-package)
  (setq-default
   use-package-always-defer t
   use-package-always-ensure t))

B. Theme

  1. Set a color palette
  2. Configure Zenburn

1. Set a color palette

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

2. Configure Zenburn

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

C. Features

  1. Auto-Completion
  2. CSS
  3. Comments
  4. Customization
  5. Diff
  6. Dired
  7. Docker
  8. Expand
  9. Git
  10. Helm
  11. Helm Plugins
  12. HTML
  13. JavaScript
  14. Linters
  15. Lisp
  16. Markdown
  17. Mode-line
  18. Org
  19. OS X
  20. Navigation
  21. Parentheses
  22. Point
  23. Projectile
  24. Python
  25. Quality of Life
  26. Slack
  27. Whitespaces
  28. Web Browsing
  29. Windows
  30. 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.

1. Auto-Completion

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

2. CSS

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

3. Comments

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

4. Customization

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

5. Diff

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

6. Dired

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

7. Docker

(use-package dockerfile-mode
  :delight dockerfile-mode "Dockerfile"
  :mode "Dockerfile\\'")

8. Expand

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

9. Git

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)

Jonas Bernoulli

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

10. Helm

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.

Bozhidar Batsov

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

11. Helm Plugins

Fourth-party packages for Helm.

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

12. HTML

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

13. JavaScript

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.

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

14. Linters

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

15. Lisp

(use-package lisp-mode
  :ensure nil
  :delight lisp-mode "Lisp"
  :config
  (delight
   '((emacs-lisp-mode "Emacs Lisp")
     (lisp-interaction-mode "Lisp Interaction"))))

16. Markdown

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

17. Mode-line

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.

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

18. Navigation

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)

19. Org

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.

Carsten Dominik

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

20. OS X

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

21. Parentheses

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 "[[" "]]"))

22. Point

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

23. Projectile

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

Bozhidar Batsov

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

24. Python

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

25. Quality of Life

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

26. Slack

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

27. Whitespaces

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

28. Web Browsing

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 customize eww-header-line-format?
(use-package eww
  :ensure nil
  :delight eww-mode "Emacs Web Wowser"
  :config (setq eww-header-line-format " %t: %u"))

29. Windows

Adjust the size of every windows and focus the active one. It uses the mathematical golden ratio somewhere in its formulas.

(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 (calling winner-redo).

Ivar Rummelhoff

(use-package winner
  :ensure nil
  :if (fboundp 'winner-mode)
  :init (winner-mode 1))

30. YAML

(use-package yaml-mode
  :delight yaml-mode "YAML"
  :mode "\\.yml\\'")

Back to top