DotEmacs
Table of Content
Bootstrap
Use better defaults
Some UI elements are rather invasive. No-mouse master race.
(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 tooltipsHere are what I consider better defaults as per my own experience.
(setq-default
ad-redefinition-action 'accept ; Silence warnings for redefinition
auto-window-vscroll nil ; Lighten vertical scroll
confirm-kill-emacs 'yes-or-no-p ; Confirm before exiting Emacs
cursor-in-non-selected-windows t ; 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 80 ; Set width for automatic line breaks
help-window-select t ; Focus new help windows when opened
indent-tabs-mode nil ; Stop using tabs to indent
inhibit-startup-screen t ; Disable start-up screen
initial-scratch-message "" ; Empty the initial *scratch* buffer
left-margin-width 1 right-margin-width 1 ; Add left and right margins
mouse-yank-at-point t ; Yank at point rather than pointer
ns-use-srgb-colorspace nil ; Don't use sRGB colors
recenter-positions '(5 top bottom) ; Set re-centering positions
scroll-conservatively most-positive-fixnum ; Always scroll by one line
scroll-margin 10 ; Add a margin when scrolling vertically
select-enable-clipboard t ; Merge system's and Emacs' clipboard
sentence-end-double-space nil ; End a sentence after a dot and a space
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-stretch-cursor t) ; Stretch cursor to the glyph width
(delete-selection-mode 1) ; Replace region when inserting text
(display-time-mode 1) ; Enable time in the mode-line
(fringe-mode 0) ; Disable fringes
(fset 'yes-or-no-p 'y-or-n-p) ; Replace yes/no prompts with y/n
(global-hl-line-mode 1) ; Hightlight current line
(global-subword-mode 1) ; Iterate through CamelCase words
(menu-bar-mode 0) ; Disable the menu bar
(mouse-avoidance-mode 'banish) ; Avoid collision of mouse with point
(put 'downcase-region 'disabled nil) ; Enable downcase-region
(put 'upcase-region 'disabled nil) ; Enable upcase-region
(cd "~/") ; Move to the user directoryEnable fullscreen.
(if (eq window-system 'ns)
(toggle-frame-maximized)
(toggle-frame-fullscreen))Garbage-collect on focus-out, Emacs should feel snappier.
(add-hook 'focus-out-hook #'garbage-collect)Load .custom.el
One is able to use the customization interface that is bundled within Emacs. It
is meant to help people who are not 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 a 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))Load .secret.el
I load ~/.emacs.d/.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. This is also where you want your API tokens to live.
(defvar me/erc-nick nil "The ERC nick to use.")
(defvar me/erc-password nil "The ERC password to use.")
(defvar me/erc-port nil "The ERC port to use.")
(defvar me/erc-server nil "The ERC server to use.")
(defvar me/font-family "Courier" "The font to use.")
(defvar me/font-size-default 110 "The font size to use for default text.")
(defvar me/font-size-header-line 120 "The font size to use for the header-line.")
(defvar me/font-size-mode-line 110 "The font size to use for the mode-line.")
(defvar me/font-size-title 140 "The font size to use for titles.")
(let ((secret.el (expand-file-name ".secret.el" user-emacs-directory)))
(when (file-exists-p secret.el)
(load secret.el)))Theme
The face for italic text is underlined when the font does not support slant by default. I don’t like it.
(set-face-attribute 'italic nil :underline nil)I don’t like bold text, mostly because it looks like crap on Windows. Since faces can be defined in every packages, I need to unboldify after that specfic package has been loaded. That function should be called after the provided faces have been defined.
(defun me/unboldify (&optional faces)
"Set the weight property of FACES to `normal'.
If FACES is not provided or nil, use `face-list' instead."
(interactive)
(mapc (lambda (face)
(when (eq (face-attribute face :weight) 'bold)
(set-face-attribute face nil :weight 'normal)))
(or faces (face-list))))Load zenburn-theme and fix some high-level faces to match my personal
preferences.
(use-package zenburn-theme
:demand t
:config
(load-theme 'zenburn t)
(set-face-attribute 'default nil :font me/font-family :height me/font-size-default)
(set-face-attribute 'fixed-pitch nil :font me/font-family)
(set-face-attribute 'font-lock-comment-face nil :italic t)
(set-face-attribute 'font-lock-doc-face nil :italic t)
(zenburn-with-color-variables
(set-face-attribute 'button nil :foreground zenburn-yellow-2)
(set-face-attribute 'help-argument-name nil :foreground zenburn-orange :italic nil)
(set-face-attribute 'highlight nil :background zenburn-yellow :foreground zenburn-fg-1)
(set-face-attribute 'hl-line nil :background zenburn-bg+1)
(set-face-attribute 'header-line nil
:box `(:line-width 1 :color ,zenburn-bg-1)
:height me/font-size-header-line)
(set-face-attribute 'mode-line nil
:box `(:line-width 1 :color ,zenburn-bg-1)
:foreground zenburn-bg+3
:height me/font-size-mode-line)
(set-face-attribute 'mode-line-inactive nil
:box `(:line-width 1 :color ,zenburn-bg-05)
:foreground zenburn-bg+3
:height me/font-size-mode-line)
(set-face-attribute 'region nil
:background zenburn-fg-1
:distant-foreground 'unspecified)
(set-face-attribute 'vertical-border nil :foreground zenburn-bg))
(me/unboldify '(bold
error
font-lock-builtin-face
font-lock-keyword-face
font-lock-negation-char-face
font-lock-regexp-grouping-backslash
font-lock-regexp-grouping-construct
font-lock-warning-face
link
mode-line-buffer-id
success
warning)))(use-package mdi
:demand t
:load-path "lisp/mdi/")Languages
As pedantic as I like to be, some packages have a use-package clause for
nothing but the customization of their lighter.
CSS
(use-package css-mode
:ensure nil
:config (setq-default css-indent-offset 2))
(use-package scss-mode
:ensure nil
:preface
(defun me/scss-set-comment-style ()
(setq-local comment-end "")
(setq-local comment-start "//"))
:delight scss-mode "SCSS"
:mode ("\\.sass\\'" "\\.scss\\'")
:hook (scss-mode . me/scss-set-comment-style))CSV
(use-package csv-mode
:config (setq-default csv-align-padding 2))Docker
(use-package dockerfile-mode
:delight dockerfile-mode "Dockerfile"
:mode "Dockerfile\\'")HTML
HTML mode is defined in sgml-mode.el.
(use-package sgml-mode
:ensure nil
:delight html-mode "HTML"
:preface
(defun me/html-set-pretty-print-function ()
(setq me/pretty-print-function #'sgml-pretty-print))
:hook
((html-mode . me/html-set-pretty-print-function)
(html-mode . sgml-electric-tag-pair-mode)
(html-mode . sgml-name-8bit-mode)
(html-mode . toggle-truncate-lines))
:config (setq-default sgml-basic-offset 2))JavaScript
- FIXME: Indent level is broken (https://github.com/joshwnj/json-mode/issues/32).
(use-package js
:ensure nil
:delight js-mode "JavaScript"
:preface
(defun me/turn-on-prettify-symbols-mode ()
(add-to-list 'prettify-symbols-alist '("function" . ?ƒ))
(prettify-symbols-mode 1))
:hook (js-mode . me/turn-on-prettify-symbols-mode)
:config
(setq-default js-indent-level 2))
(use-package js2-mode
:ensure nil
:delight js2-mode "JavaScript 2"
:config
(setq-default js2-idle-timer-delay 0)
(me/unboldify '(js2-error)))
(use-package json-mode
:delight json-mode "JSON"
:mode "\\.json\\'"
:preface
(defun me/json-set-indent-level ()
(setq-local js-indent-level 2))
:hook (json-mode . me/json-set-indent-level))
(use-package rjsx-mode
:delight rjsx-mode "RJSX"
:preface
(defun me/rjsx-set-ongoing-hydra-body ()
(setq me/ongoing-hydra-body #'hydra-rjsx/body))
(defun me/rjsx-set-pretty-print-function ()
(setq me/pretty-print-function #'sgml-pretty-print))
:hook
((rjsx-mode . me/rjsx-set-ongoing-hydra-body)
(rjsx-mode . me/rjsx-set-pretty-print-function)
(rjsx-mode . sgml-electric-tag-pair-mode)
(rjsx-mode . turn-off-auto-fill)))Lisp
(use-package emacs-lisp-mode
:ensure nil
:delight emacs-lisp-mode "Emacs Lisp"
:config (delight 'lisp-interaction-mode "Lisp Interaction"))
(use-package ielm
:ensure nil
:hook (ielm-mode . (lambda () (setq-local scroll-margin 0))))
(use-package lisp-mode
:ensure nil
:delight lisp-mode "Lisp")Markdown
(use-package markdown-mode
:delight markdown-mode "Markdown"
:preface
(defun me/markdown-set-ongoing-hydra-body ()
(setq me/ongoing-hydra-body #'hydra-markdown/body))
:mode
("INSTALL\\'"
"CONTRIBUTORS\\'"
"LICENSE\\'"
"README\\'"
"\\.markdown\\'"
"\\.md\\'")
:hook (markdown-mode . me/markdown-set-ongoing-hydra-body)
:config
(unbind-key "M-<down>" markdown-mode-map)
(unbind-key "M-<up>" markdown-mode-map)
(setq-default
markdown-asymmetric-header t
markdown-split-window-direction 'right)
(me/unboldify '(markdown-header-face)))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.
(use-package org
:ensure nil
:delight org-mode "Org"
:preface
(defun me/org-src-buffer-name (org-buffer-name language)
"Construct the buffer name for a source editing buffer. See
`org-src--construct-edit-buffer-name'."
(format "*%s*" org-buffer-name))
(defun me/org-backward-paragraph-shifted ()
"See `org-backward-paragraph'. Support shift."
(interactive "^")
(org-backward-paragraph))
(defun me/org-forward-paragraph-shifted ()
"See `org-forward-paragraph'. Support shift."
(interactive "^")
(org-forward-paragraph))
(defun me/org-set-ongoing-hydra-body ()
(setq me/ongoing-hydra-body #'hydra-org/body))
:bind
(:map org-mode-map
([remap backward-paragraph] . me/org-backward-paragraph-shifted)
([remap forward-paragraph] . me/org-forward-paragraph-shifted)
("<C-return>" . nil)
("<C-S-down>" . nil)
("<C-S-up>" . nil)
("<M-S-down>" . nil)
("<M-S-up>" . nil))
:hook
((org-mode . me/org-set-ongoing-hydra-body)
(org-mode . org-sticky-header-mode)
(org-mode . toc-org-enable))
:config
(setq-default
org-descriptive-links nil
org-support-shift-select 'always
org-startup-folded nil
org-startup-truncated nil)
(advice-add 'org-src--construct-edit-buffer-name :override #'me/org-src-buffer-name))
(use-package org-faces
:ensure nil
:after org
:config
(zenburn-with-color-variables
(set-face-attribute 'org-block nil :background zenburn-bg+05))
(me/unboldify '(org-tag org-todo)))
(use-package org-src
:ensure nil
:after org
:config
(setq-default
org-edit-src-content-indentation 0
org-edit-src-persistent-message nil
org-src-window-setup 'current-window))Display the current Org header in the header-line.
(use-package org-sticky-header
:config
(setq-default
org-sticky-header-full-path 'full
org-sticky-header-outline-path-separator " / "))Tired of having to manually update your tables of contents? This package will
maintain a TOC at the first heading that has a :TOC: tag.
(use-package toc-org :after org)Python
- TODO: Fix for
ipython5.1.0.
(use-package python
:ensure nil
:delight python-mode "Python"
:hook (python-mode . turn-on-prettify-symbols-mode)
:config
(when (executable-find "ipython")
(setq-default
python-shell-interpreter "ipython"
python-shell-interpreter-args "--colors=Linux --profile=default --simple-prompt"
python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: "
python-shell-prompt-regexp "In \\[[0-9]+\\]: "
python-shell-completion-setup-code
"from IPython.core.completerlib import module_completion"
python-shell-completion-module-string-code
"';'.join(module_completion('''%s'''))\n"
python-shell-completion-string-code
"';'.join(get_ipython().Completer.all_completions('''%s'''))\n")))(use-package pip-requirements
:delight pip-requirements-mode "PyPA Requirements"
:preface
(defun me/pip-requirements-ignore-case ()
(setq-local completion-ignore-case t))
:hook (pip-requirements-mode . me/pip-requirements-ignore-case))YAML
(use-package yaml-mode
:delight yaml-mode "YAML"
:mode "\\.yml\\'")Features
Alert
Alert is a Growl-workalike for Emacs which uses a common notification interface and multiple, selectable “styles”, whose use is fully customizable by the user.
(use-package alert
:config
(when (eq system-type 'darwin)
(setq-default alert-default-style 'osx-notifier)))Auto-Completion
Auto-completion at point. Display a small pop-in containing the candidates.
Company is a text completion framework for Emacs. The name stands for “complete anything”. It uses pluggable back-ends and front-ends to retrieve and display completion candidates.
(use-package company
:defer 1
:config
(global-company-mode 1)
(setq-default
company-idle-delay .2
company-minimum-prefix-length 1
company-require-match nil
company-tooltip-align-annotations t))
(use-package company-dabbrev
:ensure nil
:after company
:config (setq-default company-dabbrev-downcase nil))Buffers and Windows
Don’t ask before killing a buffer. I’m a consenting adult.
(global-set-key [remap kill-buffer] #'kill-this-buffer)Allow repeated use of ← and → when using previous-buffer and
next-buffer.
- TODO: Make a hydra.
(defun me/switch-to-buffer-continue ()
"Activate a sparse keymap:
<left> `previous-buffer'
<right> `next-buffer'"
(set-transient-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "<left>") #'previous-buffer)
(define-key map (kbd "<right>") #'next-buffer)
map)))
(advice-add 'previous-buffer :after #'me/switch-to-buffer-continue)
(advice-add 'next-buffer :after #'me/switch-to-buffer-continue)Save and restore Emacs status, including buffers, point and window configurations.
(use-package desktop
:ensure nil
:demand t
:config
(desktop-save-mode 1)
(add-to-list 'desktop-globals-to-save 'golden-ratio-adjust-factor))Workspaces within Emacs.
eyebrowseis a global minor mode for Emacs that allows you to manage your window configurations in a simple manner, just like tiling window managers like i3wm with their workspaces do. It displays their current state in the modeline by default. The behaviour is modeled after ranger, a file manager written in Python.
(use-package eyebrowse
:defer 1
:bind
("<f5>" . eyebrowse-switch-to-window-config-1)
("<f6>" . eyebrowse-switch-to-window-config-2)
("<f7>" . eyebrowse-switch-to-window-config-3)
("<f8>" . eyebrowse-switch-to-window-config-4)
:config
(eyebrowse-mode 1)
(setq-default eyebrowse-new-workspace t))Window management.
- TODO: Shackle Magit.
shacklegives you the means to put an end to popped up buffers not behaving they way you’d like them to. By setting up simple rules you can for instance make Emacs always select help buffers for you or make everything reuse your currently selected window.
(use-package shackle
:defer 1
:config
(setq-default
shackle-rules '((help-mode :inhibit-window-quit t :same t))
shackle-select-reused-windows t)
(shackle-mode 1))Bind commands to move around windows.
(use-package windmove
:ensure nil
:bind
(("C-M-<left>". windmove-left)
("C-M-<right>". windmove-right)
("C-M-<up>". windmove-up)
("C-M-<down>". windmove-down)))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
:defer 1
:config (winner-mode 1))Comments
(use-package newcomment
:ensure nil
:bind ("<M-return>" . comment-indent-new-line)
:config
(setq-default
comment-auto-fill-only-comments t
comment-multi-line t))Customization Menus
This merely changes face attributes. It also Zenburn customization buffers a little more.
(use-package cus-edit
:ensure nil
:config
(set-face-attribute 'custom-group-tag nil
:font me/font-family
:height me/font-size-title)
(zenburn-with-color-variables
(set-face-attribute 'custom-state nil :foreground zenburn-green+4))
(me/unboldify '(custom-variable-tag)))Daemon
This package let us start a server to edit editable elements in a Chrome browser from Emacs.
(use-package edit-server
:defer 1
:config (edit-server-start))Emacs can be run as a daemon onto which Emacs clients can latch on. This allows for much shorter starting times when you already got Emacs running ie. when you want to edit a single file for a quick edit.
(use-package server
:ensure nil
:defer 1
:config (server-start))Dictionary
Define words using Wordnik.
(use-package define-word)Translage using Google.
(use-package google-translate
:config (me/unboldify '(google-translate-translation-face)))Diff
Ediff is a visual interface to Unix diff.
(use-package diff-mode
:ensure nil
:config
(set-face-attribute 'diff-added nil :background nil)
(set-face-attribute 'diff-removed nil :background nil))(use-package ediff-init
:ensure nil
:config
(me/unboldify '(ediff-fine-diff-A
ediff-fine-diff-B
ediff-fine-diff-C)))
(use-package ediff-wind
:ensure nil
:config
(setq-default
ediff-split-window-function #'split-window-horizontally
ediff-window-setup-function #'ediff-setup-windows-plain))- TODO: Make a pull request over https://github.com/bbatsov/zenburn-emacs.
(use-package smerge-mode
:ensure nil
:config
(zenburn-with-color-variables
(set-face-attribute 'smerge-mine nil :background zenburn-red-2)
(set-face-attribute 'smerge-other nil :background zenburn-green)
(set-face-attribute 'smerge-refined-added nil :background zenburn-green-1)
(set-face-attribute 'smerge-refined-removed nil :background zenburn-red-4)))Dired
Configure Dired buffers. Amongst many other things, Emacs is also a file explorer.
(use-package dired
:ensure nil
:delight dired-mode "Dired"
:preface
(defun me/dired-directories-first ()
"Sort dired listings with directories first before adding marks."
(save-excursion
(let (buffer-read-only)
(forward-line 2)
(sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
(set-buffer-modified-p nil)))
:hook (dired-mode . dired-hide-details-mode)
:config
(advice-add 'dired-readin :after #'me/dired-directories-first)
(setq-default
dired-auto-revert-buffer t
dired-dwim-target t
dired-hide-details-hide-symlink-targets nil
dired-listing-switches "-alh"
dired-ls-F-marks-symlinks nil
dired-recursive-copies 'always))
(use-package dired-x
:ensure nil
:preface
(defun me/dired-revert-after-command (command &optional output error)
(revert-buffer))
:config
(advice-add 'dired-smart-shell-command :after #'me/dired-revert-after-command))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-return>. Basically it’s an expand DWIM.
(use-package emmet-mode
:bind
(:map emmet-mode-keymap
("<C-return>" . nil)
("C-M-<left>" . nil)
("C-M-<right>" . nil)
("C-c w" . nil))
:hook (css-mode html-mode rjsx-mode)
:config (setq-default emmet-move-cursor-between-quote t))
(use-package hippie-exp
:ensure nil
:preface
(defun me/emmet-try-expand-line (args)
"Try `emmet-expand-line' if `emmet-mode' is active. Else, does nothing."
(interactive "P")
(when emmet-mode (emmet-expand-line args)))
:bind ("<C-return>" . hippie-expand)
:config
(setq-default
hippie-expand-try-functions-list '(yas-hippie-try-expand me/emmet-try-expand-line)
hippie-expand-verbose nil))
(use-package yasnippet
:bind
(:map yas-minor-mode-map
("TAB" . nil)
("<tab>" . nil))
:hook
((emacs-lisp-mode . yas-minor-mode)
(html-mode . yas-minor-mode)
(js-mode . yas-minor-mode)
(org-mode . yas-minor-mode)
(python-mode . yas-minor-mode))
:config
(setq-default yas-snippet-dirs `(,(expand-file-name "snippets/" user-emacs-directory)))
(yas-reload-all))Folding
This is a package to perform text folding like in Vim. It has the following features:
- folding of active regions;
- good visual feedback: it’s obvious which part of text is folded;
- persistence by default: when you close file your folds don’t disappear;
- persistence scales well, you can work on hundreds of files with lots of folds without adverse effects;
- it doesn’t break indentation or something;
- folds can be toggled from folded state to unfolded and back very easily;
- quick navigation between existing folds;
- you can use mouse to unfold folds (good for beginners and not only for them);
- for fans of avy package: you can use avy to fold text with minimal number of key strokes!
(use-package vimish-fold
:defer 1
:bind
(:map vimish-fold-folded-keymap ("<tab>" . vimish-fold-unfold)
:map vimish-fold-unfolded-keymap ("<tab>" . vimish-fold-refold))
:init
(setq-default vimish-fold-dir (expand-file-name ".vimish-fold/" user-emacs-directory))
(vimish-fold-global-mode 1)
:config
(setq-default vimish-fold-header-width 79))Helm
Helm is a beast. Although heavily, it replaces ido-mode in many ways.
Helmis 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.Helmcleans the legacy code that is leaner, modular, and unchained from constraints of backward compatibility.
- TODO: Test
me/helm-pulse-followon MacOS. Is it Windows that makes it ugly? - FIXME: The recentering is too aggressive.
(use-package helm
:defer 1
:preface
(defun me/helm-focus-follow ()
;; (let ((point (point)))
;; (when (and (pulse-available-p) (> point 1))
;; (pulse-momentary-highlight-one-line point)))
(recenter-top-bottom (car recenter-positions)))
(defun me/helm-grab-candidates (beg end)
(interactive "r")
(if (region-active-p)
(kill-ring-save beg end)
(with-helm-buffer (kill-ring-save (point-min) (point-max)))))
:bind (:map helm-map ("M-w" . me/helm-grab-candidates))
:hook (helm-after-action . me/helm-focus-follow)
:config
(helm-mode 1)
(setq-default
helm-always-two-windows t
helm-display-header-line nil
helm-split-window-default-side 'left)
(set-face-attribute 'helm-action nil :underline nil)
(set-face-attribute 'helm-match nil :background nil)
(set-face-attribute 'helm-source-header nil
:box nil
:background nil
:height me/font-size-title)
(zenburn-with-color-variables
(set-face-attribute 'helm-prefarg nil :foreground zenburn-magenta))
(me/unboldify '(helm-match helm-source-header)))Helm sub-modules can be customized separately. Many basic Emacs commands have their Helm equivalents.
- TODO: Do I actually want to split all of these?
- TODO: Help buffer resizes the frame when killed.
(use-package helm-bookmarks
:ensure nil
:after helm
:config
;; NOTE: See https://github.com/bbatsov/zenburn-emacs/pull/279.
(set-face-attribute 'helm-bookmark-directory nil
:foreground 'unspecified
:inherit 'dired-directory))
(use-package helm-buffers
:ensure nil
:after helm
:config
(setq-default
helm-buffers-fuzzy-matching t
helm-buffer-max-length nil)
(set-face-attribute 'helm-buffer-directory nil :inherit 'dired-directory)
(set-face-attribute 'helm-non-file-buffer nil :inherit 'shadow)
(zenburn-with-color-variables
(set-face-attribute 'helm-buffer-size nil :foreground zenburn-fg-1))
;; NOTE: See https://github.com/bbatsov/zenburn-emacs/pull/279.
(set-face-attribute 'helm-buffer-directory nil
:background 'unspecified
:foreground 'unspecified
:inherit 'dired-directory))
(use-package helm-color
:ensure nil
:after helm
:bind
(:map helm-color-map
("<left>" . backward-char)
("<right>" . forward-char)))
(use-package helm-command
:ensure nil
:after helm
:bind ([remap execute-extended-command] . helm-M-x)
:config
(setq-default helm-M-x-fuzzy-match t)
(zenburn-with-color-variables
(set-face-attribute 'helm-M-x-key nil :foreground zenburn-orange :underline nil)))
(use-package helm-files
:ensure nil
:after helm
:bind ([remap find-file] . helm-find-files)
:config
(setq-default
helm-ff-no-preselect t
helm-ff-skip-boring-files t
helm-find-file-ignore-thing-at-point t)
(me/unboldify '(helm-ff-directory helm-ff-symlink))
;; NOTE: See https://github.com/bbatsov/zenburn-emacs/pull/279.
(zenburn-with-color-variables
(set-face-attribute 'helm-ff-dotted-directory nil
:background nil
:foreground zenburn-fg-1)
(set-face-attribute 'helm-ff-directory nil
:foreground 'unspecified
:inherit 'dired-directory)
(set-face-attribute 'helm-ff-dirs nil
:foreground 'unspecified
:inherit 'dired-directory)))
(use-package helm-grep
:ensure nil
:after helm
:config
(zenburn-with-color-variables
(set-face-attribute 'helm-grep-lineno nil :foreground zenburn-yellow-2)))
(use-package helm-imenu
:ensure nil
:after helm
:bind
(:map helm-imenu-map
("<left>" . backward-char)
("<right>" . forward-char)))
(use-package helm-misc
:ensure nil
:after helm
:bind ([remap switch-to-buffer] . helm-buffers-list))
(use-package helm-lib
:ensure nil
:after helm
:config
(setq-default
helm-help-full-frame nil
helm-scroll-amount 5))
(use-package helm-mode
:ensure nil
:after helm
:config
(setq-default
helm-completion-in-region-fuzzy-match t
helm-mode-fuzzy-match t))
(use-package helm-net
:ensure nil
:after helm
:config (setq-default helm-net-prefer-curl (if (executable-find "curl") t nil)))
(use-package helm-org
:ensure nil
:after helm
:config (setq-default helm-org-headings-fontify t))
(use-package helm-regexp
:ensure nil
:after helm
:bind
(([remap isearch-forward] . helm-occur)
:map helm-moccur-map
("<left>" . backward-char)
("<right>" . forward-char))
:config
(zenburn-with-color-variables
(set-face-attribute 'helm-moccur-buffer nil :foreground zenburn-blue)))Helm Plugins
Fourth-party packages for Helm.
(use-package helm-ag
:defer nil
:after helm
:bind
(:map helm-ag-map
("<left>" . backward-char)
("<right>" . forward-char))
:config (setq-default helm-ag-show-status-function nil))
(use-package helm-descbinds
:defer nil
:after helm
:config
(helm-descbinds-mode 1)
(setq-default helm-descbinds-window-style 'split-window))
(use-package helm-describe-modes
:after helm
:bind ([remap describe-mode] . helm-describe-modes))
(use-package helm-flycheck :after helm)
(use-package helm-projectile
:defer nil
:after helm
:bind
(nil
:map helm-projectile-find-file-map
("<left>" . backward-char)
("<right>" . forward-char)
:map helm-projectile-projects-map
("<left>" . backward-char)
("<right>" . forward-char))
:config (helm-projectile-toggle 1))Help
(use-package help-mode
:ensure nil
:bind
(:map help-mode-map
("<" . help-go-back)
(">" . help-go-forward)))Hydra
Hydra allows me to group binds together. It also shows a list of all implemented commands in the eho area.
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.
(use-package hydra
:preface
(defvar-local me/ongoing-hydra-body nil)
(defun me/ongoing-hydra ()
(interactive)
(if me/ongoing-hydra-body
(funcall me/ongoing-hydra-body)
(user-error "me/ongoing-hydra: me/ongoing-hydra-body is not set")))
:bind
("C-c <tab>" . hydra-fold/body)
("C-c d" . hydra-dates/body)
("C-c e" . hydra-eyebrowse/body)
("C-c f" . hydra-flycheck/body)
("C-c g" . hydra-magit/body)
("C-c h" . hydra-helm/body)
("C-c o" . me/ongoing-hydra)
("C-c p" . hydra-projectile/body)
("C-c s" . hydra-system/body)
("C-c w" . hydra-windows/body)
:config (setq-default hydra-default-hint nil))Hydra / Dates
Group date-related commands.
(defhydra hydra-dates (:color blue)
"
^
^Dates^ ^Insert^ ^Insert with Time^
^─────^─────────────^──────^────────────^────────────────^──
_q_ quit _d_ short _D_ short
^^ _i_ iso _I_ iso
^^ _l_ long _L_ long
^^ ^^ ^^
"
("q" nil)
("d" me/date-short)
("D" me/date-short-with-time)
("i" me/date-iso)
("I" me/date-iso-with-time)
("l" me/date-long)
("L" me/date-long-with-time))Hydra / Eyebrowse
Group Eyebrowse commands.
(defhydra hydra-eyebrowse (:color blue)
"
^
^Eyebrowse^ ^Do^ ^Switch^
^─────────^─────────^──^────────────────^──────^────────────
_q_ quit _c_ create _<_ previous
^^ _k_ kill _>_ next
^^ _r_ rename _e_ last
^^ ^^ _s_ switch
^^ ^^ ^^
"
("q" nil)
("<" eyebrowse-prev-window-config :color red)
(">" eyebrowse-next-window-config :color red)
("c" eyebrowse-create-window-config)
("e" eyebrowse-last-window-config)
("k" eyebrowse-close-window-config :color red)
("r" eyebrowse-rename-window-config)
("s" eyebrowse-switch-to-window-config))Hydra / Flycheck
Group Flycheck commands.
(defhydra hydra-flycheck (:color pink)
"
^
^Flycheck^ ^Errors^ ^Checker^
^────────^──────────^──────^────────────^───────^───────────
_q_ quit _<_ previous _?_ describe
_m_ manual _>_ next _d_ disable
_v_ verify setup _f_ check _s_ select
^^ _l_ list ^^
^^ ^^ ^^
"
("q" nil)
("<" flycheck-previous-error)
(">" flycheck-next-error)
("?" flycheck-describe-checker :color blue)
("d" flycheck-disable-checker :color blue)
("f" flycheck-buffer)
("l" flycheck-list-errors :color blue)
("m" flycheck-manual :color blue)
("s" flycheck-select-checker :color blue)
("v" flycheck-verify-setup :color blue))Hydra / Fold
Group folding commands.
- TODO: Use
:bind.
(defhydra hydra-fold (:color pink)
"
^
^Fold^ ^Do^ ^Jump^ ^Toggle^
^────^──────────────^──^────────────────^────^──────────────^──────^────────────
_q_ quit _f_ fold _<_ previous _<tab>_ current
^^ _k_ kill _>_ next _S-<tab>_ all
^^ _K_ kill all ^^ ^^
^^ ^^ ^^ ^^
"
("q" nil)
("<tab>" vimish-fold-toggle)
("S-<tab>" vimish-fold-toggle-all)
("<" vimish-fold-previous-fold)
(">" vimish-fold-next-fold)
("f" vimish-fold)
("k" vimish-fold-delete)
("K" vimish-fold-delete-all))Hydra / Helm
Group Helm commands.
- TODO: Make
helm-mdi.
(defhydra hydra-helm (:color blue)
"
^
^Helm^ ^Browse^ ^Do^
^────^──────────────^──────^────────────^──^────────────────
_q_ quit _c_ colors _f_ flycheck
_r_ resume _g_ google ^^
^^ _i_ imenu ^^
^^ _k_ kill-ring ^^
^^ ^^ ^^
"
("q" nil)
("c" helm-colors)
("f" helm-flycheck)
("g" helm-google-suggest)
("i" helm-imenu)
("k" helm-show-kill-ring)
("r" helm-resume))Hydra / Magit
Group Magit commands.
(defhydra hydra-magit (:color blue)
"
^
^Magit^ ^Do^
^─────^─────────────^──^────────────────
_q_ quit _b_ blame
^^ _c_ clone
^^ _i_ init
^^ _s_ status
^^ ^^
"
("q" nil)
("b" magit-blame)
("c" magit-clone)
("i" magit-init)
("s" magit-status))Hydra / Markdown
Group Markdown commands.
(defhydra hydra-markdown (:color pink)
"
^
^Markdown^ ^Table Columns^ ^Table Rows^
^────────^──────────^─────────────^─────^──────────^────────
_q_ quit _c_ insert _r_ insert
^^ _C_ delete _R_ delete
^^ _M-<left>_ left _M-<down>_ down
^^ _M-<right>_ right _M-<up>_ up
^^ ^^ ^^
"
("q" nil)
("c" markdown-table-insert-column)
("C" markdown-table-delete-column)
("r" markdown-table-insert-row)
("R" markdown-table-delete-row)
("M-<left>" markdown-table-move-column-left)
("M-<right>" markdown-table-move-column-right)
("M-<down>" markdown-table-move-row-down)
("M-<up>" markdown-table-move-row-up))Hydra / Org
Group Org commands.
(defhydra hydra-org (:color pink)
"
^
^Org^ ^Links^ ^Outline^
^───^───────────────^─────^─────────────^───────^───────────
_q_ quit _i_ insert _<_ previous
^^ _n_ next _>_ next
^^ _p_ previous _a_ all
^^ _s_ store _o_ goto
^^ ^^ _v_ overview
^^ ^^ ^^
"
("q" nil)
("<" org-backward-element)
(">" org-forward-element)
("a" outline-show-all)
("i" org-insert-link :color blue)
("n" org-next-link)
("o" helm-org-in-buffer-headings :color blue)
("p" org-previous-link)
("s" org-store-link)
("v" org-overview))Hydra / Projectile
Group Projectile commands.
(defhydra hydra-projectile (:color blue)
"
^
^Projectile^ ^Buffers^ ^Find^ ^Search^
^──────────^────────^───────^───────────^────^──────────────^──────^────────────
_q_ quit _b_ list _d_ directory _r_ replace
_i_ reset cache _K_ kill all _D_ root _R_ regexp replace
^^ _S_ save all _f_ file _s_ ag
^^ ^^ _p_ project ^^
^^ ^^ ^^ ^^
"
("q" nil)
("b" helm-projectile-switch-to-buffer)
("d" helm-projectile-find-dir)
("D" projectile-dired)
("f" helm-projectile-find-file)
("i" projectile-invalidate-cache :color red)
("K" projectile-kill-buffers)
("p" helm-projectile-switch-project)
("r" projectile-replace)
("R" projectile-replace-regexp)
("s" helm-projectile-ag)
("S" projectile-save-project-buffers))Hydra / RJSX
Group React JavaScript commands.
(defhydra hydra-rjsx (:color pink)
"
^
^RJSX^
^────^──────────────
_q_ quit
^^
"
("q" nil))Hydra / System
Group system-related commands.
(defhydra hydra-system (:color blue)
"
^
^System^ ^Packages^ ^Processes^
^──────^────────────^────────^──────────^─────────^─────────
_q_ quit _p_ list _s_ list
^^ _P_ upgrade ^^
^^ ^^ ^^
"
("q" nil)
("p" paradox-list-packages)
("P" paradox-upgrade-packages)
("s" list-processes))Hydra / Windows
Group window-related commands.
(defhydra hydra-windows (:color pink)
"
^
^Windows^ ^Window^ ^Zoom^
^───────^───────────^──────^────────────^────^──────────────
_q_ quit _b_ balance _-_ out
^^ _i_ heighten _+_ in
^^ _j_ narrow _=_ reset
^^ _k_ lower ^^
^^ _l_ widen ^^
^^ ^^ ^^
"
("q" nil)
("b" balance-windows)
("i" enlarge-window)
("j" shrink-window-horizontally)
("k" shrink-window)
("l" enlarge-window-horizontally)
("-" text-scale-decrease)
("+" text-scale-increase)
("=" (text-scale-increase 0)))IRC
- TODO: Display the current count of users.
(hash-table-count erc-channel-users)
(use-package erc
:ensure nil
:preface
(defun me/erc ()
"Connect to `me/erc-server' on `me/erc-port' as `me/erc-nick' with
`me/erc-password'."
(interactive)
(erc :server me/erc-server
:port me/erc-port
:nick me/erc-nick
:password me/erc-password))
(defun me/erc-bol-shifted ()
"See `erc-bol'. Support shift."
(interactive "^")
(erc-bol))
:bind
(:map erc-mode-map
([remap erc-bol] . me/erc-bol-shifted)
("M-<down>" . erc-next-command)
("M-<up>" . erc-previous-command))
:hook (erc-mode . (lambda () (setq-local scroll-margin 0)))
:config
(make-variable-buffer-local 'erc-fill-column)
(erc-scrolltobottom-enable)
(setq-default
erc-autojoin-channels-alist '(("freenode.net" "#emacs"))
erc-fill-function 'erc-fill-static
erc-fill-static-center 19
erc-header-line-format " %n on %t %m"
erc-insert-timestamp-function 'erc-insert-timestamp-left
erc-lurker-hide-list '("JOIN" "PART" "QUIT")
erc-prompt (format "%18s" ">")
erc-timestamp-format nil)
(set-face-attribute 'erc-prompt-face nil :background nil)
(zenburn-with-color-variables
(set-face-attribute 'erc-timestamp-face nil :foreground zenburn-fg-1))
(me/unboldify '(erc-bold-face
erc-button
erc-nick-default-face
erc-my-nick-face
erc-my-nick-prefix-face
erc-nick-prefix-face
erc-prompt-face)))
(use-package erc-button
:ensure nil
:config (set-face-attribute 'erc-button nil :inherit 'button))
(use-package erc-match
:ensure nil
:config (me/unboldify '(erc-current-nick-face)))Colorize nicks with unique colors.
- TODO: Pastel’ize the colors.
(use-package erc-hl-nicks :after erc)Keep track of ERC buffers in which new messages have been posted.
- TODO: Filter and track only the actual messages.
(use-package erc-track
:ensure nil
:after erc
:preface
(defun me/erc-set-fill-column ()
"Set `erc-fill-column' to the width of the current window."
(save-excursion
(walk-windows
(lambda (window)
(let ((buffer (window-buffer window)))
(set-buffer buffer)
(when (and (eq major-mode 'erc-mode) (erc-buffer-visible buffer))
(setq erc-fill-column (- (window-width window) 2))))))))
:hook (window-configuration-change . me/erc-set-fill-column))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.org).
(use-package flycheck
:hook
((css-mode . flycheck-mode)
(emacs-lisp-mode . flycheck-mode)
(js-mode . flycheck-mode)
(python-mode . flycheck-mode))
:config
(setq-default
flycheck-check-syntax-automatically '(save mode-enabled)
flycheck-disabled-checkers '(emacs-lisp-checkdoc)
flycheck-display-errors-delay .3)
(zenburn-with-color-variables
(set-face-attribute 'flycheck-error nil :underline zenburn-red)
(set-face-attribute 'flycheck-info nil :underline zenburn-blue+1)
(set-face-attribute 'flycheck-warning nil :underline zenburn-orange)))Mode-Line
Mode-Line / Screenshots
Here is how it looks:
In an active window
In an inactive window
In a dirty buffer
With unread ERC messages
With Flycheck errors
When inside of a Helm session
When using isearch
With an active region
With an active rectangle
- Green means buffer is clean ie. file is saved
- Red means buffer is dirty ie. file is modified
- Blue means buffer is read-only
- The segment next to the clock indicate the current
eyebrowseworkspace
Mode-Line / Delight
Delight allows you to change modes — both major and minor — lighters. They
are the descriptive strings than you see appear within the mode-line.
To make it work with spaceline (which uses powerline internally), I need to
allow it to use the newly changed strings.
- TODO: Remove
delightdependency frominit.el.
(use-package delight
:ensure nil
:preface
(defun me/delight-powerline-major-mode (original-function &rest arguments)
(let ((inhibit-mode-name-delight nil)) (apply original-function arguments)))
(defun me/delight-powerline-minor-mode (original-function &rest arguments)
(let ((inhibit-mode-name-delight nil)) (apply original-function arguments)))
:config
(advice-add 'powerline-major-mode :around #'me/delight-powerline-major-mode)
(advice-add 'powerline-minor-mode :around #'me/delight-powerline-minor-mode))Mode-Line / Spaceline
Spaceline, is a mode-line configuration framework. Like what powerline does
but at a shallower level. It’s still very customizable nonetheless.
This is the package that provides Spacemacs with its famous mode-line theme. It has been extracted as an independent package for general fun and profit.
(use-package spaceline
:demand t
:config
(spaceline-define-segment me/erc-track
"Show the ERC buffers with new messages."
(when (bound-and-true-p erc-track-mode)
(mapcar (lambda (buffer)
(format "%s%s%s"
(buffer-name (pop buffer))
erc-track-showcount-string
(pop buffer)))
erc-modified-channels-alist)))
(spaceline-define-segment me/helm-follow
"Show `helm-follow-mode' status."
(if (and (bound-and-true-p helm-alive-p)
spaceline--helm-current-source
(eq 1 (cdr (assq 'follow spaceline--helm-current-source))))
(propertize (mdi "eye") 'face 'success)
(propertize (mdi "eye-off") 'face 'warning)))
(spaceline-define-segment me/selection-info
"Show the size of current region."
(when mark-active
(let ((characters (- (region-end) (region-beginning)))
(rows (count-lines (region-beginning) (min (1+ (region-end)) (point-max))))
(columns (1+ (abs (- (spaceline--column-number-at-pos (region-end))
(spaceline--column-number-at-pos (region-beginning)))))))
(cond
((bound-and-true-p rectangle-mark-mode)
(format "%d %s %d" (1- columns) (mdi "arrow-expand-all") rows))
((> rows 1)
(format "%d" (if (eq (current-column) 0) (1- rows) rows)))
(t (format "%d" characters))))))
(spaceline-define-segment me/version-control
"Show the current version control branch."
(when vc-mode
(substring vc-mode (+ 2 (length (symbol-name (vc-backend buffer-file-name))))))))- FIXME: Projectile segment doesn’t use submodules.
- FIXME: Can’t load
spaceline-configthrough:after.
(use-package spaceline-config
:demand t
:ensure nil
:config
;; Configure the mode-line
(setq-default
mode-line-format '("%e" (:eval (spaceline-ml-main)))
powerline-default-separator 'wave
powerline-height 20
spaceline-highlight-face-func 'spaceline-highlight-face-modified
spaceline-flycheck-bullet (format "%s %s" (mdi "record") "%s")
spaceline-separator-dir-left '(left . left)
spaceline-separator-dir-right '(right . right))
(spaceline-helm-mode 1)
;; Build the mode-lines
(spaceline-install
`((major-mode :face highlight-face)
((remote-host buffer-id line) :separator ":")
((flycheck-error flycheck-warning flycheck-info))
(me/selection-info))
`((me/erc-track :face spaceline-highlight-face :when active)
(anzu)
((projectile-root me/version-control) :separator ":")
(workspace-number)
(global :face highlight-face)))
(spaceline-install
'helm
'((helm-buffer-id :face spaceline-read-only)
(helm-number)
(me/helm-follow)
(helm-prefix-argument))
'((me/erc-track :face spaceline-highlight-face :when active)
(workspace-number)
(global :face spaceline-read-only)))
;; Customize the mode-line
(zenburn-with-color-variables
(set-face-attribute 'powerline-active2 nil :background zenburn-bg+05)
(set-face-attribute 'powerline-inactive2 nil :background zenburn-bg)
(set-face-attribute 'spaceline-flycheck-error nil :foreground zenburn-red)
(set-face-attribute 'spaceline-flycheck-info nil :foreground zenburn-blue+1)
(set-face-attribute 'spaceline-flycheck-warning nil :foreground zenburn-orange)
(set-face-attribute 'spaceline-highlight-face nil
:background zenburn-yellow
:foreground zenburn-fg-1)
(set-face-attribute 'spaceline-modified nil
:background zenburn-red
:foreground zenburn-red-4)
(set-face-attribute 'spaceline-read-only nil
:background zenburn-blue+1
:foreground zenburn-blue-5)
(set-face-attribute 'spaceline-unmodified nil
:background zenburn-green-1
:foreground zenburn-green+4)))Navigation
Navigation / Inline
Smarter C-a.
(global-set-key [remap move-beginning-of-line] #'me/beginning-of-line-dwim)
(defun me/beginning-of-line-dwim ()
"Move point to first non-whitespace character, or beginning of line."
(interactive "^")
(let ((origin (point)))
(beginning-of-line)
(and (= origin (point))
(back-to-indentation))))Navigation / Paragraphs
I disagree with Emacs’ definition of paragraphs so I redefined the way it should jump from one paragraph to another.
- FIXME: Ignore invisible text.
(global-set-key [remap backward-paragraph] #'me/backward-paragraph-dwim)
(global-set-key [remap forward-paragraph] #'me/forward-paragraph-dwim)
(defun me/backward-paragraph-dwim ()
"Move backward to start of paragraph."
(interactive "^")
(skip-chars-backward "\n")
(unless (search-backward-regexp "\n[[:blank:]]*\n" nil t)
(goto-char (point-min)))
(skip-chars-forward "\n"))
(defun me/forward-paragraph-dwim ()
"Move forward to start of next paragraph."
(interactive "^")
(skip-chars-forward "\n")
(unless (search-forward-regexp "\n[[:blank:]]*\n" nil t)
(goto-char (point-max)))
(skip-chars-forward "\n"))Navigation / Pulse
Pulse temporarily highlights the background color of a line or region.
(use-package pulse
:ensure nil
:config
(zenburn-with-color-variables
(set-face-attribute 'pulse-highlight-start-face nil :background zenburn-red+1)))Navigation / Replace
Better search and replace features. Even though I prefer to use
multiple-cursors to replace text in different places at once, anzu has a
nice feedback on regexp matches.
anzu.elis an Emacs port of anzu.vim.anzu.elprovides a minor mode which displays current match and total matches information in the mode-line in various search modes.
Regular replace
Regexp replace
(use-package anzu
:defer 1
:bind ([remap query-replace] . anzu-query-replace-regexp)
:config
(global-anzu-mode 1)
(setq-default
anzu-cons-mode-line-p nil
anzu-replace-to-string-separator (mdi "arrow-right" t))
(zenburn-with-color-variables
(set-face-attribute 'anzu-replace-highlight nil
:background zenburn-red-4
:foreground zenburn-red+1)
(set-face-attribute 'anzu-replace-to nil
:background zenburn-green-1
:foreground zenburn-green+4))
(me/unboldify '(anzu-mode-line anzu-mode-line-no-match)))Navigation / Scroll
Enable horizontal scroll.
- TODO: Scroll the window under cursor instead of where point is.
(put 'scroll-left 'disabled nil)
(defun me/scroll-left ()
(interactive)
(when truncate-lines (scroll-left 2)))
(defun me/scroll-right ()
(interactive)
(when truncate-lines (scroll-right 2)))
(global-set-key (kbd "<wheel-left>") #'me/scroll-right)
(global-set-key (kbd "<wheel-right>") #'me/scroll-left)
(global-set-key (kbd "S-<wheel-down>") #'me/scroll-left)
(global-set-key (kbd "S-<wheel-up>") #'me/scroll-right)Configure the mouse scroll.
(use-package mwheel
:ensure nil
:config
(setq-default
mouse-wheel-progressive-speed nil
mouse-wheel-scroll-amount '(1 ((control) . 5))))Navigation / Search
Isearch stands for incremental search. This means that search results are highlighted while you are typing your query, incrementally. Since he who can do more can do less, I’ve replaced default bindings with the regexp-equivalent commands.
(use-package isearch
:ensure nil
:bind
(("C-S-r" . isearch-backward-regexp)
("C-S-s" . isearch-forward-regexp)
:map isearch-mode-map
("<M-down>" . isearch-ring-advance)
("<M-up>" . isearch-ring-retreat)
:map minibuffer-local-isearch-map
("<M-down>" . next-history-element)
("<M-up>" . previous-history-element))
:init
(setq-default
isearch-allow-scroll t
lazy-highlight-cleanup nil
lazy-highlight-initial-delay 0)
(zenburn-with-color-variables
(set-face-attribute 'isearch nil
:background zenburn-blue
:foreground zenburn-blue-5)
(set-face-attribute 'isearch-lazy-highlight-face nil
:background zenburn-blue-5
:foreground zenburn-blue))
(me/unboldify '(isearch lazy-highlight)))OS-Specific
Augment Emacs experience for MacOS users.
(when (eq system-type 'darwin)
(setq-default
exec-path (append exec-path '("/usr/local/bin")) ; Add Homebrew path
ns-command-modifier 'meta ; Map Meta to the Cmd key
ns-option-modifier 'super ; Map Super to the Alt key
ns-right-option-modifier nil)) ; Disable the right Alt keyInitialize environment variables.
Ever find that a command works in your shell, but not in Emacs?
This happens a lot on OS X, where an Emacs instance started from the GUI inherits a default set of environment variables.
This library works solves this problem by copying important environment variables from the user’s shell: it works by asking your shell to print out the variables of interest, then copying them into the Emacs environment.
(use-package exec-path-from-shell
:if (memq window-system '(mac ns))
:defer 1
:config (exec-path-from-shell-initialize))Parentheses
Highlight parenthese-like delimiters in a rainbow fashion. It ease the reading when dealing with mismatched parentheses.
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode)
:config
(zenburn-with-color-variables
(set-face-attribute 'rainbow-delimiters-mismatched-face nil
:foreground zenburn-red-4)
(set-face-attribute 'rainbow-delimiters-unmatched-face nil
:foreground zenburn-red-4)))I am still looking for the perfect parenthesis management setup as of today… No package seem to please my person.
- TODO: Find a better parenthese management package.
(use-package smartparens
:defer 1
: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))
:config
(require 'smartparens-config)
(smartparens-global-mode 1)
(sp-pair "{{" "}}")
(sp-pair "[[" "]]"))Paste
This mode allows to paste whole buffers or parts of buffers to pastebin-like services. It supports more than one service and will failover if one service fails.
(use-package webpaste)Point and Region
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/contract-region)
("C-=" . er/expand-region))Persistent highlighting.
(use-package highlight)Enable multiple cursors at once. Some witchcraft at work here.
(use-package multiple-cursors
:defer 1
: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/list-file (expand-file-name ".multiple-cursors.el" user-emacs-directory))
:config
(setq-default
mc/edit-lines-empty-lines 'ignore
mc/insert-numbers-default 1))Enable new custom binds when region is active. I’ve also added a few helpers to
use with selected.
(use-package selected
:defer 1
:preface
(defvar-local me/pretty-print-function nil)
(defun me/pretty-print (beg end)
(interactive "r")
(if me/pretty-print-function
(progn (funcall me/pretty-print-function beg end)
(setq deactivate-mark t))
(user-error "me/pretty-print: me/pretty-print-function is not set")))
:bind
(:map selected-keymap
("<" . mc/mark-previous-like-this)
(">" . mc/mark-next-like-this)
("C-<tab>" . me/pretty-print)
("C-<" . mc/unmark-previous-like-this)
("C->" . mc/unmark-next-like-this)
("C-M-<" . mc/skip-to-previous-like-this)
("C-M->" . mc/skip-to-next-like-this)
("C-?" . hydra-selected/body)
("C-c C-c" . me/eval-region-and-kill-mark)
("C-b" . me/browse-url-and-kill-mark)
("C-c c" . capitalize-region)
("C-c k" . me/kebab-region)
("C-c l" . downcase-region)
("C-c u" . upcase-region)
("C-d" . define-word-at-point)
("C-f" . fill-region)
("C-g" . selected-off)
("C-h h" . hlt-highlight-region)
("C-h H" . hlt-unhighlight-region)
("C-p" . webpaste-paste-region)
("C-s r" . reverse-region)
("C-s s" . sort-lines)
("C-s w" . me/sort-words)
("C-t" . google-translate-at-point)
("<M-left>" . me/indent-rigidly-left-and-keep-mark)
("<M-right>" . me/indent-rigidly-right-and-keep-mark)
("<M-S-left>" . me/indent-rigidly-left-tab-and-keep-mark)
("<M-S-right>" . me/indent-rigidly-right-tab-and-keep-mark))
:config
(require 'browse-url)
(selected-global-mode 1))(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-left-tab-and-keep-mark (beg end)
"Indent all lines between BEG and END leftward to a tab stop.
Call `indent-rigidly-left-to-tab-stop' and keep mark."
(interactive "r")
(indent-rigidly-left-to-tab-stop 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/indent-rigidly-right-tab-and-keep-mark (beg end)
"Indent all lines between BEG and END rightward to a tab stop.
Call `indent-rigidly-right-to-tab-stop' and keep mark."
(interactive "r")
(indent-rigidly-right-to-tab-stop beg end)
(setq deactivate-mark nil))
(defun me/kebab-region (begin end)
"Convert region to kebab-case."
(interactive "r")
(downcase-region begin end)
(save-excursion
(perform-replace " +" "-" nil t nil nil nil begin end)))
(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-up>") 'me/duplicate-backward)
(global-set-key (kbd "<M-S-down>") 'me/duplicate-forward)
(global-set-key (kbd "<M-down>") 'me/swap-line-down)
(global-set-key (kbd "<M-up>") 'me/swap-line-up)
(defun me/duplicate-line (&optional stay)
"Duplicate current line.
With optional argument STAY true, leave point where it was."
(save-excursion
(move-end-of-line nil)
(save-excursion
(insert (buffer-substring (point-at-bol) (point-at-eol))))
(newline))
(unless stay
(let ((column (current-column)))
(forward-line)
(forward-char column))))
(defun me/duplicate-backward ()
"Duplicate current line upward or region backward.
If region was active, keep it so that the command can be repeated."
(interactive)
(if (region-active-p)
(let (deactivate-mark)
(save-excursion
(insert (buffer-substring (region-beginning) (region-end)))))
(me/duplicate-line t)))
(defun me/duplicate-forward ()
"Duplicate current line downward or region forward.
If region was active, keep it so that the command can be repeated."
(interactive)
(if (region-active-p)
(let (deactivate-mark (point (point)))
(insert (buffer-substring (region-beginning) (region-end)))
(push-mark point))
(me/duplicate-line)))
(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))
(defun me/swap-line-up ()
"Move up the line under point."
(interactive)
(transpose-lines 1)
(forward-line -2)
(indent-according-to-mode))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).
(use-package projectile
:defer 1
:init
(setq-default
projectile-cache-file (expand-file-name ".projectile-cache" user-emacs-directory)
projectile-keymap-prefix (kbd "C-c C-p")
projectile-known-projects-file (expand-file-name
".projectile-bookmarks" user-emacs-directory))
:config
(projectile-global-mode 1)
(setq-default
projectile-completion-system 'helm
projectile-enable-caching t
projectile-mode-line '(:eval (projectile-project-name))))Quality of Life
Auto-indent code as you write.
electric-indent-modeis enough to keep your code nicely aligned when all you do is type. However, once you start shifting blocks around, transposing lines, or slurping and barfing sexps, indentation is bound to go wrong.
aggressive-indent-modeis a minor mode that keeps your code always indented. It reindents after every change, making it more reliable than electric-indent-mode.
(use-package aggressive-indent
:hook
((css-mode . aggressive-indent-mode)
(emacs-lisp-mode . aggressive-indent-mode)
(js-mode . aggressive-indent-mode)
(lisp-mode . aggressive-indent-mode)
(sgml-mode . aggressive-indent-mode))
:config
(setq-default aggressive-indent-comments-too t)
(add-to-list 'aggressive-indent-protected-commands 'comment-dwim))Insert the current date.
(defun me/date-iso ()
"Insert the current date, ISO format, eg. 2016-12-09."
(interactive)
(insert (format-time-string "%F")))
(defun me/date-iso-with-time ()
"Insert the current date, ISO format with time, eg. 2016-12-09T14:34:54+0100."
(interactive)
(insert (format-time-string "%FT%T%z")))
(defun me/date-long ()
"Insert the current date, long format, eg. December 09, 2016."
(interactive)
(insert (format-time-string "%B %d, %Y")))
(defun me/date-long-with-time ()
"Insert the current date, long format, eg. December 09, 2016 - 14:34."
(interactive)
(insert (capitalize (format-time-string "%B %d, %Y - %H:%M"))))
(defun me/date-short ()
"Insert the current date, short format, eg. 2016.12.09."
(interactive)
(insert (format-time-string "%Y.%m.%d")))
(defun me/date-short-with-time ()
"Insert the current date, short format with time, eg. 2016.12.09 14:34"
(interactive)
(insert (format-time-string "%Y.%m.%d %H:%M")))Disable documentation for object at point in the echo area. It conflicts with Flycheck.
(use-package eldoc
:ensure nil
:config (global-eldoc-mode -1))Customize the noisy default towards backup files.
(use-package files
:ensure nil
:config
(setq-default
backup-by-copying t
backup-directory-alist `(("." . ,(expand-file-name "backups/" user-emacs-directory)))
delete-old-versions t
version-control t))Add visual guides towards indenting levels.
(use-package highlight-indent-guides
:hook (python-mode . highlight-indent-guides-mode)
:config (setq-default highlight-indent-guides-method 'character))Originally, midnight is used to run something at midnight. I use its feature that
kills old buffers.
(use-package midnight
:ensure nil
:config
(setq-default clean-buffer-list-delay-general 1)
(add-to-list 'clean-buffer-list-kill-never-buffer-names "dotemacs.org"))Augment Emacs’ package menu.
Project for modernizing Emacs’ Package Menu. With improved appearance, mode-line information. Github integration, customizability, asynchronous upgrading, and more.
(use-package paradox
:config
(setq-default
paradox-column-width-package 27
paradox-column-width-version 13
paradox-execute-asynchronously t
paradox-github-token t
paradox-hide-wiki-packages t)
(remove-hook 'paradox-after-execute-functions #'paradox--report-buffer-print))Colorize colors as text with their value.
(use-package rainbow-mode
:hook prog-mode
:config (setq-default rainbow-x-colors-major-mode-list '()))Turn on auto-fill-mode almost everywhere.
(use-package simple
:ensure nil
:hook
((prog-mode . turn-on-auto-fill)
(text-mode . turn-on-auto-fill)))Terminal
Yes, Emacs emulates terminals too.
- **TODO**: Source
.bash_profileonM-x term. - **TODO**: Disable
hl-line.
(use-package term
:ensure nil
:hook (term-mode . (lambda () (setq-local scroll-margin 0))))Provide a way to invoke bash on Windows. This requires “Developer Mode” to
be enabled in the first place.
(when (eq system-type 'windows-nt)
(defun me/bash ()
(interactive)
(let ((explicit-shell-file-name "C:/Windows/System32/bash.exe"))
(shell))))Version Control
Magit provides 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 git-commit
:preface
(defun me/git-commit-auto-fill-everywhere ()
(setq fill-column 72)
(setq-local comment-auto-fill-only-comments nil))
:hook (git-commit-mode . me/git-commit-auto-fill-everywhere)
:config
(setq-default git-commit-summary-max-length 50)
(me/unboldify '(git-commit-comment-action
git-commit-comment-branch-local
git-commit-comment-branch-remote
git-commit-comment-heading)))(use-package magit
:preface
(defun me/magit-display-buffer-same (buffer)
"Display most magit popups in the current 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)))))
:config
;; Use better defaults
(setq-default
magit-display-buffer-function 'me/magit-display-buffer-same
magit-diff-highlight-hunk-body nil
magit-diff-highlight-hunk-region-functions
'(magit-diff-highlight-hunk-region-dim-outside
magit-diff-highlight-hunk-region-using-face)
magit-popup-display-buffer-action '((display-buffer-same-window))
magit-refs-show-commit-count 'all
magit-section-show-child-count t)
;; 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-file-heading-highlight nil :background nil)
(set-face-attribute 'magit-diff-hunk-region nil :inherit 'region)
(set-face-attribute 'magit-popup-heading nil :height me/font-size-title)
(set-face-attribute 'magit-section-heading nil :height me/font-size-title)
(set-face-attribute 'magit-section-highlight nil :background nil)
(me/unboldify '(magit-branch-current
magit-branch-local
magit-branch-remote
magit-head
magit-refname
magit-refname-stash
magit-refname-wip
magit-tag)))
(use-package magit-blame
:ensure nil
:config (me/unboldify '(magit-blame-summary)))
(use-package magit-diff
:ensure nil
:config
(me/unboldify '(magit-diff-file-heading
magit-diff-file-heading-highlight
magit-diff-file-heading-selection)))
(use-package magit-popup
:ensure nil
:config
(me/unboldify '(magit-popup-argument
magit-popup-heading
magit-popup-key
magit-popup-option-value)))
(use-package magit-section
:ensure nil
:config
(me/unboldify '(magit-section-heading
magit-section-heading-selection
magit-section-secondary-heading)))
(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")Whitespaces
Highlight space-like characters, eg. trailing spaces, tabs, empty lines.
(use-package whitespace
:demand t
:ensure nil
:hook
((prog-mode . whitespace-turn-on)
(text-mode . whitespace-turn-on))
:config (setq-default whitespace-style '(face empty tab trailing)))





















