Xiaojie's Emacs Init File Written in Org-Mode
Table of Contents
- 1. About
- 2. Personal Information
- 3. Bootstraping
- 4. Basic settings used everywhere
- 4.1. General user interface and appearance
- 4.1.1. Startup screen and errors reporting
- 4.1.2. Set frames title with buffer name
- 4.1.3. Distinguish buffers with the same file name
- 4.1.4. Menu bar, tool bar, scroll bar. No!
- 4.1.5. Modeline settings
- 4.1.6. Put empty line markers into the left hand side
- 4.1.7. Display Line Numbers
- 4.1.8. Cursor and mouse
- 4.1.9. Sweet highlight
- 4.1.10. Nice scrolling
- 4.1.11. No
#autosave#
andbackup~
files - 4.1.12. Change "yes or no" to "y or n"
- 4.1.13. Confirm before quit
- 4.2. Commands - useful interactive functions
- 4.3. Navigation
- 4.3.1.
Projectile
- project interaction - 4.3.2.
Dired
- directory editor - 4.3.3.
Neotree
- tree layout directory explorer - 4.3.4.
Winner
- undo and redo window configuration - 4.3.5.
Windmove
- switch between windows - 4.3.6.
Buffer-move
- move or swap buffer to other window - 4.3.7.
C-x o
: Moving to another window - 4.3.8.
C-x k
: Quick kill buffer - 4.3.9.
Avy
- fast cursor movement - 4.3.10.
C-a
: Smart beginning of line - 4.3.11.
C-w
andM-w
: Smart cut and copy - 4.3.12.
M-\
: Smart delete whitespaces around cursor - 4.3.13.
C-k
: Smart kill entire lines - 4.3.14.
Expand-region
- Smart region selection - 4.3.15.
Fancy-narrow
- Smart narrowing - 4.3.16.
M-;
: Smart Comment - 4.3.17.
M-p
andM-n
: Smart Scan - 4.3.18. Better Searching and Visual Regular Expressions
- 4.3.1.
- 4.4. Editing
- 4.4.1. Coding - always UTF-8
- 4.4.2. Tabs, spaces, enters
- 4.4.3. Delete the selection with a keypress
- 4.4.4.
Whitespace
- show and clean devil - 4.4.5.
Smartparents
- Insert closing parens automagically - 4.4.6.
Undo-tree
- visualize your undos and branches - 4.4.7.
Auto-fill
- warp long lines - 4.4.8.
Hippie-expand
- Text Expansion - 4.4.9.
Company
- Completion for Anything - 4.4.10.
Yasnippet
- Code Templates - 4.4.11.
Flyspell
- Spelling Checking - 4.4.12.
Multiple Cursors
- edit with multiple cursors
- 4.5. Helm - interactive completion and selection
- 4.6. Backup and autosave
- 4.7. Persistence and history
- 4.8. Global Key Bindings
- 4.1. General user interface and appearance
- 5. Aesthetics
- 6. Programming Environment
- 7. Programming Languages
- 8. Typesetting Languages
- 9. Git and Magit
- 10. Org-Mode
- 11. Acknowledges
1 About
1.1 My Emacs Init File
This is my Emacs configuration file. Inspired by Sacha and Bernt, l written it using Org-babel in literate style, to make it easy to explain.
Author: Xiaojie Feng Keywords: emacs, dotfile, config ___ _ __ ___ __ _ ___ ___ / _ \ '_ ` _ \ / _` |/ __/ __| | __/ | | | | | (_| | (__\__ \ (_)___|_| |_| |_|\__,_|\___|___/
1.2 License
Copyright (C) 2016-2019 Xiaojie Feng
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
Code in this document is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1.3 Commentary
Emacs outshines all other editing software in approximately the same way that the noonday sun does the stars. It is not just bigger and brighter; it simply makes everything else vanish. [Neal Stephenson]
People talk about getting used to a new editor, but over time, it is precisely the opposite that should happen — the editor should get used to us. [Vivek Haldar]
"Show me your ~/.emacs and I will tell you who you are." [Bogdan Maryniuk]
"Emacs is like a laser guided missile. It only has to be slightly mis-configured to ruin your whole day." [Sean McGrath]
"While any text editor can save your files, only Emacs can save your soul." [Per Abrahamsen]
1.4 What I Want to Say
If you are not familiar with the Emacs basic usage, I highly recommend you to read some sophisticated Emacs users' Emacs guide, such as Tuhdo's Emacs Mini Manual (PART 1) - THE BASICS and Xah Lee's Practical Emacs Tutorial, instead of the official Emacs Manual. The official manual is too long to read for Emacs newbies.
You can always use my init file as long as you master the basic usage of Emacs,
even though my configuration contains something a little advanced to Emacs (and
Emacs Lisp) beginners. As I think, the init file was well organized in
structural and code blocks (setq
, defun
, package configuration etc.) were
written together with plenty explanation about why and how to use, thanks to
the Literate programming paradigm introduced by Donald Knuth.
1.5 How to Use This Document
This document is available as an org file which you can load in Emacs and
tangle with M-x org-babel-tangle (C-c C-v C-t)
which will create
org-mode.el
in the same directory as the org-mode.org
file. This will
extract all of the elisp examples in this document into a file you can include
in your $HOME/.emacs.d/init.el
file.
If you're new to Emacs Lisp, you probably don't want to copy and paste large
chunks of this code. Instead, copy small parts of it (always making sure to
copy a complete set of parentheses) into your *scratch*
buffer or some other
buffer in emacs-lisp-mode
. Use M-x eval-buffer
to evaluate the code and see
if you like the way that Emacs behaves.
If you're viewing the Org file, you can open source code blocks (those are the
ones in begin_src) in a separate buffer by moving your point inside them and
typing C-c ' (M-x org-edit-special
). This opens another buffer in
emacs-lisp-mode
, so you can use M-x eval-buffer
to load the changes.
2 Personal Information
Emacs will normally pick this up automatically, but this way I can be sure the right information is always present.
Note: You should modify this with your personal info.
(setq user-full-name "Xiaojie Feng" user-mail-address "fengxiaojie1997@gmail.com")
3 Bootstraping
3.1 Load Multiple Emacs Files
3.1.1 My Directory Location
Conventionally, additional per-user Emacs-specific files are placed in
.emacs.d
directory in the HOME
directory. The variable
user-emacs-directory
holds that.
Structure the .emacs.d
directory by putting some sub-directories in it.
Following functions make it easy to get the location (whole path) of these
sub-directories (and files):
(defun user-emacs-subdirectory (d) (expand-file-name d user-emacs-directory)) (defun user-emacs-file (f) (expand-file-name f user-emacs-directory))
But, in practice, I didn't use them.
3.1.2 Directory Structure
In case this is the first time running this on a computer, we need to make sure the following directories have been created.
(defconst user-emacs-savefile-dir (expand-file-name "savefile" user-emacs-directory) "This folder stores all the history and cache files") (defconst user-emacs-backup-dir (expand-file-name "backup" user-emacs-directory) "This folder stores all the backup~ files") (defconst user-emacs-autosave-dir (expand-file-name "autosave" user-emacs-directory) "This folder stores all the #autosave# files") (unless (file-exists-p user-emacs-savefile-dir) (make-directory user-emacs-savefile-dir)) (unless (file-exists-p user-emacs-backup-dir) (make-directory user-emacs-backup-dir)) (unless (file-exists-p user-emacs-autosave-dir) (make-directory user-emacs-autosave-dir))
3.1.3 Customization
While I would rather program my configurations, sometimes the Emacs menu system is "good enough", but I want it in its own file:
(setq custom-file (expand-file-name "custom.el" user-emacs-directory)) (when (file-exists-p custom-file) (load custom-file))
3.1.4 Setting up the Load Path
Extra packages not available via the package manager go in my personal stash at
$HOME/.emacs.d/elisp
. As long as they're in a directory in my load-path
,
Emacs can find them.
(add-to-list 'load-path (expand-file-name "elisp" user-emacs-directory))
3.2 Package Management
3.2.1 ELPA
- Packages Installer and Manager
Emacs has become like every other operating system, and now has a package manager called Emacs Lisp Package Archive (ELPA) with its own collection repository. This provides a nice way to install additional packages. But since it is so conservative, we need to add more package source.
(require 'package) (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") ("org" . "http://orgmode.org/elpa/") ("melpa" . "https://melpa.org/packages/"))) (package-initialize) (setq package-enable-at-startup nil)
Note: As a Chinese user, I use the following mirrors instead. If you want to
use my emacs init file directly, you should change the value yes
and no
after variable :tangle
in the org file, then tangle the org file with
org-babel
to use the official package source.
(require 'package) (setq package-archives '(("gnu" . "http://elpa.emacs-china.org/gnu/") ("melpa" . "http://elpa.emacs-china.org/melpa/") ("org" . "http://elpa.emacs-china.org/org/"))) (package-initialize) (setq package-enable-at-startup nil)
3.2.2 Use-Package
- Package Configuration Macro
This use-package macro provides more concise ways to setup package autoloads, keybindings, and various mode configuration. The focus is on decreasing startup time by autoloading packages instead loading them on startup.
(unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (setq use-package-verbose t use-package-always-ensure t) (eval-when-compile (require 'use-package)) ;; Please don't load outdated byte code (setq load-prefer-newer t)
3.3 Library Dependency
Load up a collection of enhancements to Emacs Lisp, to make the configuration and its dependencies work properly.
(require 'cl) ; provides useful things like `loop' and `setf' (use-package dash :ensure t) ; a modern list library (use-package diminish :ensure t) ; diminish keeps the modeline tidy
Benefiting from org-mode's contrib:
(use-package org :ensure org-plus-contrib)
3.4 Environment fixup
On macOS, Emacs doesn't use the shell PATH if it's not started from the shell (started from the GUI). Exec-path-from-shell can fix this problem. It ensure environment variables inside Emacs look the same as in the user's shell.
(use-package exec-path-from-shell :defer t :init (progn (when (memq window-system '(mac ns)) (exec-path-from-shell-initialize))))
3.5 Keyboard settings for macOS users
Set keys for Apple keyboard, for Emacs in macOS.
(when (eq system-type 'darwin) (setq mac-command-modifier 'meta) ; make command key do Meta (setq mac-option-modifier 'super) ; make option key do Super (setq mac-control-modifier 'control) ; make control key do Control (setq ns-function-modifier 'hyper) ; make fn key do Hyper )
4 Basic settings used everywhere
4.1 General user interface and appearance
4.1.1 Startup screen and errors reporting
Turn off the startup messages when entering Emacs.
(setq inhibit-startup-screen t) ; disable startup screen
No beep when reporting errors.
(setq ring-bell-function (lambda ())) ; disable the annoying bell ring
4.1.2 Set frames title with buffer name
Use project and buffer name as frame title.
(setq frame-title-format (list "[" '(:eval (projectile-project-name)) "]" " ψωETωψ ◎ %b"))
4.1.3 Distinguish buffers with the same file name
Make two buffers with the same file name distinguishable.
(require 'uniquify) (setq uniquify-buffer-name-style 'forward) (setq uniquify-separator "/") (setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified (setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers
4.1.4 Menu bar, tool bar, scroll bar. No!
Get rid of the menu bar, tool bar, and scroll bar. Useless!
(menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1)
4.1.5 Modeline settings
Show current line and cursor column position.
(line-number-mode 1) (column-number-mode 1)
Indicate current file size.
(size-indication-mode t)
Display the time.
(display-time-mode 1)
4.1.6 Put empty line markers into the left hand side
Put empty line markers into the left hand side to see when a file actually ends.
(setq-default indicate-empty-lines t) (when (not indicate-empty-lines) (toggle-indicate-empty-lines))
4.1.7 Display Line Numbers
According to this article, Emacs now has two line numbers mode: linum-mode
and display-line-numbers-mode
(Emacs 26). Use the new one :)
(global-display-line-numbers-mode)
With the display-line-numbers-mode
turned on, we can use M-g g
(goto-line
) to go to the desired line quickly.
4.1.8 Cursor and mouse
The blinking cursor is nothing, but an annoyance.
(blink-cursor-mode -1) ; No blinking cursor
Hide the mouse while typing.
(setq make-pointer-invisible t) ; Hide the mouse while typing
4.1.9 Sweet highlight
Hightlight something sweet.
(global-font-lock-mode 1) ; Syntax highlight (global-hl-line-mode 1) ; Highlight cursor line
Show-paren-mode
highlights the matching parenthesis on point.
(show-paren-mode 1) ; Highlight parenthesis pairs (setq show-paren-delay 0) ; No delay (setq blink-matching-paren-distance nil) ; Blinking parenthesis (setq show-paren-style 'expression) ; Highlight text between parenthesis
Volatile-highlights
highlight things like undo, copy, paste, etc.
(use-package volatile-highlights :diminish "" :init (volatile-highlights-mode))
Hl-todo
highlight annotations like TODO in source code.
(use-package hl-todo :diminish "" :init (global-hl-todo-mode))
4.1.10 Nice scrolling
Scroll the screen in a better way.
(setq scroll-margin 0 scroll-conservatively 100000 scroll-preserve-screen-position 1)
4.1.11 No #autosave#
and backup~
files
Stop creating backup~
files and #autosave#
files.
(setq auto-save-default nil) ; No #autosave# files (setq make-backup-files nil) ; No backup~ files
Emacs backup is so annoying. This will completely stop Emacs from creating
temoporary symbolic link files (lock file) named #.something
:
(setq create-lockfiles nil) ; No #.something symbolic link files
Warning: Disable lock file may be a problem if you have situations where a file is being edited by different people or instances of Emacs. (So I didn't disable it.)
4.1.12 Change "yes or no" to "y or n"
(defalias 'yes-or-no-p 'y-or-n-p) ; y/n instead of yes/no
4.1.13 Confirm before quit
Confirmation is required before exiting Emacs.
(setq confirm-kill-emacs 'yes-or-no-p)
4.2 Commands - useful interactive functions
4.2.1 Reload emacs initialization file
Here are the commands I used frequently when I writing this Emacs configuration
in org-mode
:
(defun my/reload-emacs-init-el-file () (interactive) (load-file (expand-file-name "init.el" user-emacs-directory)))
(defun my/reload-emacs-init-org-file () (interactive) (org-babel-load-file (expand-file-name "init.org" user-emacs-directory)))
4.2.2 macOS swap Meta and Super
Swap the mapping of Meta
and Super
if necessary (taken form Prelude
project):
(defun prelude-swap-meta-and-super () "Swap the mapping of Meta and Super. Very useful for people using their Mac with a Windows external keyboard from time to time." (interactive) (if (eq mac-command-modifier 'super) (progn (setq mac-command-modifier 'meta) (setq mac-option-modifier 'super) (message "Command is now bound to META and Option is bound to SUPER.")) (setq mac-command-modifier 'super) (setq mac-option-modifier 'meta) (message "Command is now bound to SUPER and Option is bound to META.")))
4.2.3 Copy filename to clipboard
Sometimes I need to copy the name of the currently visited file to the clipboard. Emacs does not have a built-in command for that, but cooking one is pretty straightforward:
(defun copy-file-name-to-clipboard () "Copy the current buffer file name to the clipboard." (interactive) (let ((filename (if (equal major-mode 'dired-mode) default-directory (buffer-file-name)))) (when filename (kill-new filename) (message "Copied buffer file name '%s' to the clipboard." filename))))
4.2.4 Open File in external app
Here's a command to open the current file or marked dired files in external app. (as if you double-clicked the file on desktop) It's useful for image files, PDF file, video, audio files.
(defun xah-open-in-external-app (&optional @fname) "Open the current file or dired marked files in external app. The app is chosen from your OS's preference. When called in emacs lisp, if @fname is given, open that. URL `http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html' Version 2019-01-18" (interactive) (let* ( ($file-list (if @fname (progn (list @fname)) (if (string-equal major-mode "dired-mode") (dired-get-marked-files) (list (buffer-file-name))))) ($do-it-p (if (<= (length $file-list) 5) t (y-or-n-p "Open more than 5 files? ")))) (when $do-it-p (cond ((string-equal system-type "windows-nt") (mapc (lambda ($fpath) (w32-shell-execute "open" (replace-regexp-in-string "/" "\\" $fpath t t))) $file-list)) ((string-equal system-type "darwin") (mapc (lambda ($fpath) (shell-command (concat "open " (shell-quote-argument $fpath)))) $file-list)) ((string-equal system-type "gnu/linux") (mapc (lambda ($fpath) (let ((process-connection-type nil)) (start-process "" nil "xdg-open" $fpath))) $file-list))))))
4.3 Navigation
4.3.1 Projectile
- project interaction
The Projectile project is a nifty way to run commands and search for files in a
particular "project". All projectile keybindings is placed under C-x p
. And,
the most used commands by myself are C-x p p
to switch-project, and C-x p f
to find a file and C-x p d
to find a directory.
(use-package projectile :ensure t :diminish projectile-mode :init (projectile-global-mode) ;; caching can speedup file and directory listings ;;(setq projectile-enable-caching t) ;; projectile cache file location (setq projectile-cache-file (expand-file-name "projectile.cache" user-emacs-savefile-dir)) :commands projectile-ag :config (define-key projectile-mode-map (kbd "s-p") 'projectile-command-map) (define-key projectile-mode-map (kbd "C-x p") 'projectile-command-map) (setq projectile-completion-system 'helm ; `ido' or `helm' interface? projectile-switch-project-action 'projectile-commander projectile-create-missing-test-files t) (add-to-list 'projectile-globally-ignored-files ".DS_Store") (def-projectile-commander-method ?d "Open project root in dired." (projectile-dired)) (def-projectile-commander-method ?s "Open a *shell* buffer for the project." (projectile-run-shell)) (def-projectile-commander-method ?c "Run `compile' in the project." (projectile-compile-project nil)) (def-projectile-commander-method ?F "Git fetch." (magit-status) (call-interactively #'magit-fetch-current)))
Much of the section came from this essay. Read it for config details and usage.
4.3.2 Dired
- directory editor
Install GNU Coreutils (and add it to your $PATH correctly) to make sure "ls" program support "–dired" option:
brew install coreutils
(setq ls-lisp-use-insert-directory-program nil)
Alternatively, you might want to use Emacs’s own emulation of "ls", by using:
(setq ls-lisp-use-insert-directory-program t)
After dired-x
mode turned on. C-x C-j
(dired-jump
) can jump to the
directory of any current buffer:
(use-package direx :ensure t :bind (("C-x j" . direx:jump-to-directory) ("C-x C-j" . direx:jump-to-directory)))
Tell dired
to stop asking me whether I want to recursively delete or copy,
since I never respond to that question with no
.
(setq dired-recursive-copies 'always) ; recursive copies without asking (setq dired-recursive-deletes 'top) ; recursive deletes with asked only once
Enables Do What I Mean mode for dired: If I'm in a split frame with two dired buffers, the default target to copy (and rename) will be the other window.
(setq dired-dwim-target t)
This dired-hide-details-mode
enhancement to dired hides the ugly details
(owner permission info) until you hit (
and shows the details with )
hit
again. I want it always on:
(add-hook 'dired-mode-hook (lambda () (dired-hide-details-mode 1))) (setq dired-listing-switches "-alh") ; human readable format
I also want dired to automatically revert, but to be quiet about it. The first line actually enables auto-revert for any buffers.
(global-auto-revert-mode 1) (setq global-auto-revert-non-file-buffers t) (setq auto-revert-verbose nil)
The ability to create a dired buffer based on searching for files in a
directory tree with find-name-dired
is fantastic. The following magic
optimizes this approach:
(use-package find-dired :ensure t :init (setq find-ls-option '("-print0 | xargs -0 ls -od" . "-od")))
The peep project allows you to preview files before loading them into a dedicated buffer:
(use-package peep-dired :defer t ; don't access `dired-mode-map' until `peep-dired' is loaded :bind (:map dired-mode-map ("P" . peep-dired)))
4.3.3 Neotree
- tree layout directory explorer
The NeoTree project provides a nice tree layout file explorer, and it gives an ide-like look and feel.
(use-package neotree :ensure t :defer t :bind ("C-x t n" . neotree-toggle) :config (setq projectile-switch-project-action 'neotree-projectile-action) (setq neo-show-hidden-files t) (setq neo-smart-open t)) (global-set-key [f2] 'neotree-toggle) (global-set-key [f8] 'neotree-toggle)
4.3.4 Winner
- undo and redo window configuration
Change window configuration and then return to the old configuration with
winner-mode. Use Control-C Arrow
keys to cycle through window/frame
configurations. This is handy when something has popped up a buffer that you
want to look at briefly before returning to whatever you were working on. When
you're done, press C-c <left>
.
(winner-mode 1)
4.3.5 Windmove
- switch between windows
Windmove
lets you move between windows with something more natural than
cycling through C-x o
(other-window
).
(use-package windmove :bind (("s-<right>" . windmove-right) ("s-<left>" . windmove-left) ("s-<up>" . windmove-up) ("s-<down>" . windmove-down)))
4.3.6 Buffer-move
- move or swap buffer to other window
Buffer-move
is similar to windmove
, but more powerful. It can swap the
buffers.
(use-package buffer-move :config (global-set-key (kbd "<C-s-up>") 'buf-move-up) (global-set-key (kbd "<C-s-down>") 'buf-move-down) (global-set-key (kbd "<C-s-left>") 'buf-move-left) (global-set-key (kbd "<C-s-right>") 'buf-move-right))
4.3.7 C-x o
: Moving to another window
A visual replacement for C-x o
.
(use-package switch-window :bind (("C-x o" . switch-window)))
4.3.8 C-x k
: Quick kill buffer
I rarely want to kill any buffer but the one I'm looking at. And, I usually want to kill buffers even if modified unconditionally. Code from this discussion.
(defun kill-this-buffer-volatile () "Kill current buffer unconditionally, even if it has been modified." (interactive) (set-buffer-modified-p nil) (kill-this-buffer)) ;; Kill the current visible buffer without confirmation unless the buffer has ;; been modified. In this last case, you have to answer y/n. (global-set-key (kbd "C-x k") 'kill-this-buffer) ;; Unconditionally kill unmodified buffers. (global-set-key (kbd "C-x K") 'kill-this-buffer-volatile)
4.3.9 Avy
- fast cursor movement
Avy enable fast cursor movement to visible text using a char-based decision tree. Avy is fast!
(use-package avy :ensure t :init (setq avy-background t) :config (global-set-key (kbd "s-;") 'avy-goto-line) (global-set-key (kbd "s-l") 'avy-goto-line) (global-set-key (kbd "s-.") 'avy-goto-char-timer) (global-set-key (kbd "s-j") 'avy-goto-char-timer) (global-set-key (kbd "s-,") 'avy-pop-mark) (global-set-key (kbd "s-J") 'avy-pop-mark))
4.3.10 C-a
: Smart beginning of line
This Emacs Redux article has a great suggestion for having C-a
go to the
beginning of the line's content instead of the actual beginning of the line.
Hit C-a
a second to get to the actual beginning.
(defun my/smarter-move-beginning-of-line (arg) "Move point back to indentation of beginning of line. Move point to the first non-whitespace character on this line. If point is already there, move to the beginning of the line. Effectively toggle between the first non-whitespace character and the beginning of the line. If ARG is not nil or 1, move forward ARG - 1 lines first. If point reaches the beginning or end of the buffer, stop there." (interactive "^p") (setq arg (or arg 1)) ;; Move lines first (when (/= arg 1) (let ((line-move-visual nil)) (forward-line (1- arg)))) (let ((orig-point (point))) (back-to-indentation) (when (= orig-point (point)) (move-beginning-of-line 1)))) ;; remap C-a to `smarter-move-beginning-of-line' (global-set-key [remap move-beginning-of-line] 'my/smarter-move-beginning-of-line)
4.3.11 C-w
and M-w
: Smart cut and copy
Here's a function to cut current line if there's no text selection:
(defun xah-cut-line-or-region () "Cut current line, or text selection. When `universal-argument' is called first, cut whole buffer (respects `narrow-to-region'). URL `http://ergoemacs.org/emacs/emacs_copy_cut_current_line.html' Version 2015-06-10" (interactive) (if current-prefix-arg (progn ; not using kill-region because we don't want to include previous kill (kill-new (buffer-string)) (delete-region (point-min) (point-max))) (progn (if (use-region-p) (kill-region (region-beginning) (region-end) t) (kill-region (line-beginning-position) (line-beginning-position 2)))))) (global-set-key (kbd "C-w") 'xah-cut-line-or-region)
Here is a function copy current line if there is no text selection. If called again, it'll append-copy next line. So you can press a key repeatedly to keep copying lines.
(defun xah-copy-line-or-region () "Copy current line, or text selection. When called repeatedly, append copy subsequent lines. When `universal-argument' is called first, copy whole buffer (respects `narrow-to-region'). URL `http://ergoemacs.org/emacs/emacs_copy_cut_current_line.html' Version 2018-09-10" (interactive) (if current-prefix-arg (progn (copy-region-as-kill (point-min) (point-max))) (if (use-region-p) (progn (copy-region-as-kill (region-beginning) (region-end))) (if (eq last-command this-command) (if (eobp) (progn ) (progn (kill-append "\n" nil) (kill-append (buffer-substring-no-properties (line-beginning-position) (line-end-position)) nil) (progn (end-of-line) (forward-char)))) (if (eobp) (if (eq (char-before) 10 ) (progn ) (progn (copy-region-as-kill (line-beginning-position) (line-end-position)) (end-of-line))) (progn (copy-region-as-kill (line-beginning-position) (line-end-position)) (end-of-line) (forward-char))))))) (global-set-key (kbd "M-w") 'xah-copy-line-or-region) (global-set-key (kbd "M-[") 'xah-copy-line-or-region)
4.3.12 M-\
: Smart delete whitespaces around cursor
Here's a function combine most of the deleting whitespaces around cursor command into single one:
(defun xah-delete-blank-lines () "Delete all newline around cursor. URL `http://ergoemacs.org/emacs/emacs_shrink_whitespace.html' Version 2018-04-02" (interactive) (let ($p3 $p4) (skip-chars-backward "\n") (setq $p3 (point)) (skip-chars-forward "\n") (setq $p4 (point)) (delete-region $p3 $p4))) (defun xah-shrink-whitespaces () "Remove whitespaces around cursor to just one, or none. Shrink any neighboring space tab newline characters to 1 or none. If cursor neighbor has space/tab, toggle between 1 or 0 space. If cursor neighbor are newline, shrink them to just 1. If already has just 1 whitespace, delete it. URL `http://ergoemacs.org/emacs/emacs_shrink_whitespace.html' Version 2018-04-02T14:38:04-07:00" (interactive) (let* ( ($eol-count 0) ($p0 (point)) $p1 ; whitespace begin $p2 ; whitespace end ($charBefore (char-before)) ($charAfter (char-after )) ($space-neighbor-p (or (eq $charBefore 32) (eq $charBefore 9) (eq $charAfter 32) (eq $charAfter 9))) $just-1-space-p ) (skip-chars-backward " \n\t") (setq $p1 (point)) (goto-char $p0) (skip-chars-forward " \n\t") (setq $p2 (point)) (goto-char $p1) (while (search-forward "\n" $p2 t ) (setq $eol-count (1+ $eol-count))) (setq $just-1-space-p (eq (- $p2 $p1) 1)) (goto-char $p0) (cond ((eq $eol-count 0) (if $just-1-space-p (delete-horizontal-space) (progn (delete-horizontal-space) (insert " ")))) ((eq $eol-count 1) (if $space-neighbor-p (delete-horizontal-space) (progn (xah-delete-blank-lines) (insert " ")))) ((eq $eol-count 2) (if $space-neighbor-p (delete-horizontal-space) (progn (xah-delete-blank-lines) (insert "\n")))) ((> $eol-count 2) (if $space-neighbor-p (delete-horizontal-space) (progn (goto-char $p2) (search-backward "\n" ) (delete-region $p1 (point)) (insert "\n")))) (t (progn (message "nothing done. logic error 40873. shouldn't reach here" )))))) (global-set-key (kbd "M-\\") 'xah-shrink-whitespaces)
4.3.13 C-k
: Smart kill entire lines
According to this article, killing arbitrary number of lines of text can be done with two keystrokes.
This creates a macro that moves to the beginning of the line and then calls a function given to it. Quite an interesting approach:
(defmacro bol-with-prefix (function) "Define a new function which calls FUNCTION. Except it moves to beginning of line before calling FUNCTION when called with a prefix argument. The FUNCTION still receives the prefix argument." (let ((name (intern (format "endless/%s-BOL" function)))) `(progn (defun ,name (p) ,(format "Call `%s', but move to the beginning of the line when called with a prefix argument." function) (interactive "P") (when p (forward-line 0)) (call-interactively ',function)) ',name)))
And we re-bind them to functions that use them.
(global-set-key [remap paredit-kill] (bol-with-prefix paredit-kill)) (global-set-key [remap sp-kill-hybrid-sexp] (bol-with-prefix sp-kill-hybrid-sexp)) (global-set-key [remap org-kill-line] (bol-with-prefix org-kill-line)) (global-set-key [remap kill-line] (bol-with-prefix kill-line)) (global-set-key (kbd "C-k") (bol-with-prefix kill-line))
With this little macro, C-k
still kills from point, but C-7 C-k
swallows
seven whole line. As a bonus, we get the kill-whole-line
(C-S-backspace
)
behavior by doing C-1 C-k
(I prefer M-1
to C-1
for easy stroke.).
4.3.14 Expand-region
- Smart region selection
Wherever you are in a file, and whatever the type of file, you can slowly increase a region selection by logical segments by using the expand-region project.
However, the normal experience for expand-region
is interactive, expected to
be called repeatedly to expand and contract the regions based on syntax, and
whatnot. Since I am seldom sure what I will select if I give this function a
numeric prefix, I created a wrapper function that will (when given a number),
just select the number of lines for the region. Select the current line with a
0 argument. No argument (well, lines
is given 1 with no argument), then it
just calls original expand-region
(Taken from here):
(use-package expand-region :ensure t :defer t :config (defun ha/expand-region (lines) "Prefix-oriented wrapper around Magnar's `er/expand-region'. Call with LINES equal to 1 (given no prefix), it expands the region as normal. When LINES given a positive number, selects the current line and number of lines specified. When LINES is a negative number, selects the current line and the previous lines specified. Select the current line if the LINES prefix is zero." (interactive "p") (cond ((= lines 1) (er/expand-region 1)) ((< lines 0) (ha/expand-previous-line-as-region lines)) (t (ha/expand-next-line-as-region (1+ lines))))) (defun ha/expand-next-line-as-region (lines) (message "lines = %d" lines) (beginning-of-line) (set-mark (point)) (end-of-line lines)) (defun ha/expand-previous-line-as-region (lines) (end-of-line) (set-mark (point)) (beginning-of-line (1+ lines))) :bind (("C-=" . ha/expand-region) ; wrapped version of `er/expand-region' ("C--" . er/contract-region)))
I chose C-0
instead of C-1
as the prefix argument to select the current
line, because It's easier to stroke C-0
than C-1
.
Give it a try, and you will know what it will do quickly.
4.3.15 Fancy-narrow
- Smart narrowing
Narrowing is one of the fascinating features in Emacs, great for code-reviews and other presentations. It works well but still can be better.
This nifty function is a nice replacement for many other narrowing keybindings that I use, it is smart (do what I mean):
(defun narrow-or-widen-dwim (p) "If the buffer is narrowed, it widens. Otherwise, it narrows intelligently. Intelligently means: region, subtree, or defun, whichever applies first. With prefix P, don't widen, just narrow even if buffer is already narrowed." (interactive "P") (declare (interactive-only)) (cond ((and (buffer-narrowed-p) (not p)) (widen)) ((region-active-p) (narrow-to-region (region-beginning) (region-end))) ((derived-mode-p 'org-mode) (org-narrow-to-subtree)) (t (narrow-to-defun)))) (global-set-key (kbd "C-x n x") 'narrow-or-widen-dwim)
Unlike narrow-to-region
, which completely hides text outside the narrowed
region, this fancy-narrow package simply deemphasizes the text, makes it
readonly, and makes it unreachable (hightlight instead of narrow). With this
fancy-narrow
package, we can define a smart hightlight-section
function
with prefix argument:
(use-package fancy-narrow :ensure t :config (defun ha/highlight-block () "Highlights a 'block' in a buffer defined by the first blank line before and after the current cursor position. Uses the 'fancy-narrow' mode to high-light the block." (interactive) (let (cur beg end) (setq cur (point)) (setq end (or (re-search-forward "^\s*$" nil t) (point-max))) (goto-char cur) (setq beg (or (re-search-backward "^\s*$" nil t) (point-min))) (fancy-narrow-to-region beg end) (goto-char cur))) (defun ha/highlight-section (num) "If some of the buffer is highlighted with the `fancy-narrow' mode, then un-highlight it by calling `fancy-widen'. If region is active, call `fancy-narrow-to-region'. If NUM is 0, highlight the current block (delimited by blank lines). If NUM is positive or negative, highlight that number of lines. Otherwise, called `fancy-narrow-to-defun', to highlight current function." (interactive "p") (cond ((fancy-narrow-active-p) (fancy-widen)) ((region-active-p) (fancy-narrow-to-region (region-beginning) (region-end))) ((= num 0) (ha/highlight-block)) ((= num 1) (fancy-narrow-to-defun)) (t (progn (ha/expand-region num) (fancy-narrow-to-region (region-beginning) (region-end)) (setq mark-active nil))))) :bind (("C-x n ." . ha/highlight-section))) ;; :bind (("C-M-+" . ha/highlight-section) ;; ("C-<f12>" . ha/highlight-section))) ;; (use-package fancy-narrow ;; :ensure t ;; :config ;; (defun ha/highlight-block () ;; "Highlights a 'block' in a buffer defined by the first blank ;; line before and after the current cursor position. Uses the ;; `fancy-narrow' mode to high-light the block." ;; (interactive) ;; (let (cur beg end) ;; (setq cur (point)) ;; (setq end (or (re-search-forward "^\s*$" nil t) (point-max))) ;; (goto-char cur) ;; (setq beg (or (re-search-backward "^\s*$" nil t) (point-min))) ;; (fancy-narrow-to-region beg end) ;; (goto-char cur))) ;; (defun ha/highlight-section (num) ;; "If some of the buffer is highlighted with the `fancy-narrow' ;; mode, then un-highlight it by calling `fancy-widen'. ;; If region is active, call `fancy-narrow-to-region'. ;; If NUM is 0, call `fancy-narrow-to-defun', to highlight ;; current function. If NUM is 1, highlight the current ;; block (delimited by blank lines). Otherwise, highlight that ;; number of lines." ;; (interactive "p") ;; (cond ;; ((fancy-narrow-active-p) (fancy-widen)) ;; ((region-active-p) (fancy-narrow-to-region (region-beginning) (region-end))) ;; ((= num 0) (fancy-narrow-to-defun)) ;; ((= num 1) (ha/highlight-block)) ;; (t (progn (er/expand-region num) ; depend on `er/expand-region' ;; (fancy-narrow-to-region (region-beginning) (region-end)) ;; (setq mark-active nil))))) ;; ;; highlight-section is smart enough ;; :bind (("C-x n ." . ha/highlight-section)))
4.3.16 M-;
: Smart Comment
The smart-comment project has the nice feature of commenting a line without
being at the beginning of the line M-;
(default comment in the middle of the
line is to split it). Also has the ability (with the C-u
prefix) to mark
comments as things to be deleted.
(use-package smart-comment :bind ("M-;" . smart-comment))
4.3.17 M-p
and M-n
: Smart Scan
Use the M-n
to search the buffer for the word the cursor is currently
pointing. M-p
to go backwards. See this essay for details.
(use-package smartscan :ensure t :bind ("M-n" . smartscan-symbol-go-forward) ("M-p" . smartscan-symbol-go-backward))
4.3.18 Better Searching and Visual Regular Expressions
The anzu package enhances query-replace
and query-replace-regexp
by showing
total matches and current match position.
(use-package anzu :diminish anzu-mode :bind (("M-%" . anzu-query-replace) ("C-M-%" . anzu-query-replace-regexp)) :config (global-anzu-mode))
The Visual Regular Expressions project highlights the matches while you try to remember the differences between Perl's regular expressions and Emacs'…
Begin with C-c r
then type the regexp. To see the highlighted matches, type
C-c a
before you hit RET
to accept it.
(use-package visual-regexp :ensure t :init ;; use modern regular expressions instead of Emacs-style regular expressions (use-package visual-regexp-steroids :ensure t) :bind (("C-c r" . vr/replace) ("C-c q" . vr/query-replace)) ;; if you use `multiple-cursors', this is for you: :config (use-package multiple-cursors :bind ("C-c m" . vr/mc-mark)))
4.4 Editing
4.4.1 Coding - always UTF-8
Always, always UTF-8.
(prefer-coding-system 'utf-8) (set-default-coding-systems 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (setq default-buffer-file-coding-system 'utf-8)
4.4.2 Tabs, spaces, enters
- Tabs vs. Space
Tabs are evil! I want spaces instead of tabs, and want exactly 2 spaces instead of a tab. Note to self: Apparently emacs is smart enough to not do this in Python, which is a good thing.
;; make indentation commands use space only (never tab character) (setq-default indent-tabs-mode nil) ;; set current buffer's tab char's display width to 2 spaces (setq tab-width 2)
- Indent or Complete - smart tab behavior
(setq-default tab-always-indent 'complete)
- Sentences end with one space
(setq sentence-end-double-space nil) ; Sentences end with one space
- Bind
ENT
tonewline-and-indent
By default, Emacs won't indent when press RET because the command bound to RET is newline. You can enable automatic indentation by binding
RET
tonewline-and-indent
.(global-set-key (kbd "RET") 'newline-and-indent)
- Always newline at end of file
(setq require-final-newline t)
4.4.3 Delete the selection with a keypress
(delete-selection-mode t)
4.4.4 Whitespace
- show and clean devil
We want to show trailing whitespace. Trailing whitespace is the devil.
(use-package whitespace :bind ("C-c x w" . whitespace-mode) :diminish whitespace-mode :init ;; Indicate trailing empty lines in the GUI (set-default 'indicate-empty-lines t) (setq show-trailing-whitespace t) ;; limit line length (setq whitespace-line-column 80) ;; Here are the things that whitespace-mode should highlight (setq whitespace-style '(face tabs empty trailing lines-tail)) ;; Display pretty things for newlines and tabs (nothing for spaces) (setq whitespace-display-mappings ;; all numbers are Unicode codepoint in decimal. e.g. (insert-char 182 1) ;; 32 SPACE, 183 MIDDLE DOT '((space-mark nil) ;; 10 LINE FEED ;;(newline-mark 10 [172 10]) (newline-mark nil) ;; 9 TAB, MIDDLE DOT (tab-mark 9 [183 9] [92 9]))) ;; Disable it in certain modes where whitespace doesn't make sense. (setq whitespace-global-modes '(not org-mode eshell-mode shell-mode web-mode log4j-mode dired-mode emacs-lisp-mode clojure-mode lisp-mode)))
When you press RET
to create a newline and got indented by
eletric-indent-mode
, you have appropriate whitespace for indenting. But, if
you leave the line blank and move to the next line, the whitespace becomes
useless. Clean-aindent-mode
helps clean up unused whitespace. Turn it on in
prog-mode
by default.
(use-package clean-aindent-mode :init (add-hook 'prog-mode-hook 'clean-aindent-mode))
4.4.5 Smartparents
- Insert closing parens automagically
Smartparents is a minor mode for dealing with pairs, such as automatically insert pairs, wrap, unwrap and rewrap pairs,
(use-package smartparens :ensure t :defer t :diminish "" :init (smartparens-global-mode) (require 'smartparens-config))
4.4.6 Undo-tree
- visualize your undos and branches
Undo-tree-mode lets you use C-x u
(undo-tree-visualize
) to visually walk
through the changes you've made, undo back to a certain point (or redo), and go
down different branches.
(use-package undo-tree :ensure t :diminish undo-tree-mode :init (global-undo-tree-mode) :config (progn (setq undo-tree-visualizer-timestamps t) (setq undo-tree-visualizer-diff t)))
4.4.7 Auto-fill
- warp long lines
Turn on auto-fill-mode to warp long lines automatically, instead of M-q
altogether. Sometimes, toggle-truncate-lines
would be useful.
(setq-default fill-column 79) (add-hook 'text-mode-hook 'turn-on-auto-fill) (add-hook 'prog-mode-hook 'turn-on-auto-fill) (global-set-key (kbd "C-x t f") 'auto-fill-mode) (global-set-key (kbd "C-x t t") 'toggle-truncate-lines)
Sometimes, l want to join all the lines in a paragraph into a single line,
Emacs does not have a unfill
command to do the inverse of fill
. Luckly, Xah
Lee wrote unfill functions for us.
(defun xah-unfill-paragraph () "Replace newline chars in current paragraph by single spaces. This command does the inverse of `fill-paragraph'." (interactive) (let ((fill-column most-positive-fixnum)) (fill-paragraph))) (define-key global-map "\M-Q" 'unfill-paragraph)
4.4.8 Hippie-expand
- Text Expansion
Hippie-expand
looks at the word before point and tries to expand it in
various ways including expanding from a fixed list (like `expand-abbrev’
),
expanding from matching text found in a buffer (like `dabbrev-expand’
) or
expanding in ways defined by your own functions. Which of these it tries and in
what order is controlled by a configurable list of functions.
(setq hippie-expand-try-functions-list '(try-expand-dabbrev try-expand-dabbrev-all-buffers try-expand-dabbrev-from-kill try-complete-file-name-partially try-complete-file-name try-expand-all-abbrevs try-expand-list try-expand-line try-complete-lisp-symbol-partially try-complete-lisp-symbol)) (global-set-key (kbd "M-/") 'hippie-expand)
4.4.9 Company
- Completion for Anything
Company is a text completion framework for Emacs. The name stands for complete
anything. I use company-mode
for all my auto completion needs.
Completion will start automatically after you type a few letters. Use M-n
and
M-p
to select, <RET>
to complete or <TAB>
to complete the common part.
Press M-(digit)
to quickly complete with one of the first 10
candidates.
(use-package company :ensure t :diminish company-mode :bind ("C-:" . company-complete) ; In case I don't want to wait :init (add-hook 'after-init-hook 'global-company-mode) :config (setq company-idle-delay 0.5) (setq company-show-numbers t) (setq company-tooltip-limit 10) (setq company-minimum-prefix-length 2) (setq company-tooltip-align-annotations t) ;; invert the navigation direction if the the completion popup-isearch-match ;; is displayed on top (happens near the bottom of windows) (setq company-tooltip-flip-when-above t))
Take advantage of idle time by displaying some documentation using company-quickhelp project.
(use-package company-quickhelp :ensure t :config (company-quickhelp-mode 1))
This also requires pos-tip.
4.4.10 Yasnippet
- Code Templates
YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates, based on the languages. You can view a bunch of predefined snippet from the yasnippet snippets project.
(use-package yasnippet :ensure :diminish t :init (yas-global-mode 1) :config (add-to-list 'yas-snippet-dirs (expand-file-name "snippets" user-emacs-directory)))
4.4.11 Flyspell
- Spelling Checking
I like spell checking with Flyspell which does spell-checking on the fly as you type using the build-in spell-check settings of ispell.
The ASpell program is better supported than ispell. It automatically configures
a personal dictionary at ~/.aspell.en.pws
, so no need to configure that.
Install ASpell with homebrew first:
brew install aspell
(use-package flyspell :defer t :diminish "" :init (add-hook 'prog-mode-hook 'flyspell-prog-mode) (dolist (hook '(text-mode-hook org-mode-hook)) (add-hook hook (lambda () (flyspell-mode 1)))) (dolist (hook '(change-log-mode-hook log-edit-mode-hook org-agenda-mode-hook)) (add-hook hook (lambda () (flyspell-mode -1)))) :config (setq ispell-program-name "/usr/local/bin/aspell" ; use aspell instead of ispell ispell-dictionary "american" ispell-extra-args '("--sug-mode=ultra" "--lang=en_US" "--ignore=3") ispell-list-command "--list")) (global-set-key (kbd "C-x t s") 'flyspell-mode)
4.4.12 Multiple Cursors
- edit with multiple cursors
Multiple-cursors is an advanced package enable editing with multiple cursors simultaneously. Multiple-cursors is crazy! It doesn't have any default keybindings, so I set up these:
(use-package multiple-cursors :ensure t :bind (("C-c C-. ." . mc/mark-all-dwim) ("C-c C-. C-." . mc/mark-all-like-this-dwim) ("C-c C-. n" . mc/mark-next-like-this) ("C-c C-. C-n" . mc/mark-next-like-this) ("C-c C-. p" . mc/mark-previous-like-this) ("C-c C-. C-p" . mc/mark-previous-like-this) ("C-c C-. a" . mc/mark-all-like-this) ("C-c C-. C-a" . mc/mark-all-like-this) ("C-c C-. N" . mc/mark-next-symbol-like-this) ("C-c C-. C-N" . mc/mark-next-symbol-like-this) ("C-c C-. P" . mc/mark-previous-symbol-like-this) ("C-c C-. C-P" . mc/mark-previous-symbol-like-this) ("C-c C-. A" . mc/mark-all-symbols-like-this) ("C-c C-. C-A" . mc/mark-all-symbols-like-this) ("C-c C-. f" . mc/mark-all-like-this-in-defun) ("C-c C-. C-f" . mc/mark-all-like-this-in-defun) ("C-c C-. l" . mc/edit-lines) ("C-c C-. C-l" . mc/edit-lines) ("C-c C-. e" . mc/edit-ends-of-lines) ("C-c C-. C-e" . mc/edit-ends-of-lines) ("C-M-<mouse-1>" . mc/add-cursor-on-click)))
4.5 Helm - interactive completion and selection
4.5.1 Helm core - amazing utils used everywhere
Helm makes it easy to complete various things. I find it to be easier to
configure than ido
in order to get completion in as many places as possible,
although I prefer ido's way of switching buffers.
This article: A Package in a league of its own: Helm is worth reading. Helm is amazing!
(use-package helm :ensure t :diminish "" :init (require 'helm) (require 'helm-config) ;; The default "C-x c" is quite close to "C-x C-c", which quits Emacs. ;; Changed to "C-c h". Note: We must set "C-c h" globally, because we ;; cannot change `helm-command-prefix-key' once `helm-config' is loaded. (global-set-key (kbd "C-c h") 'helm-command-prefix) (global-unset-key (kbd "C-x c")) ;; rebind tab to run persistent action (define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action) ;; make TAB works in terminal (define-key helm-map (kbd "C-i") 'helm-execute-persistent-action) ;; list actions using C-z (define-key helm-map (kbd "C-z") 'helm-select-action) (when (executable-find "curl") (setq helm-google-suggest-use-curl-p t)) (setq helm-split-window-in-side-p t helm-move-to-line-cycle-in-source t helm-ff-search-library-in-sexp t helm-scroll-amount 8 helm-ff-file-name-history-use-recentf t) (helm-mode 1) :config ;; fuzzy matching (setq helm-recentf-fuzzy-match t helm-locate-fuzzy-match nil ;; locate fuzzy is worthless helm-M-x-fuzzy-match t helm-buffers-fuzzy-matching t helm-semantic-fuzzy-match t helm-apropos-fuzzy-match t helm-imenu-fuzzy-match t helm-lisp-fuzzy-completion t helm-completion-in-region-fuzzy-match t) :bind (("M-x" . helm-M-x) ("M-y" . helm-show-kill-ring) ("C-x b" . helm-mini) ("C-x C-b" . helm-buffers-list) ("C-x C-f" . helm-find-files) ("C-x C-r" . helm-recentf) ("C-c s" . helm-swoop) ("C-c o" . helm-occur) ("C-c h a" . helm-apropos) ("C-c h y" . helm-yas-complete) ("C-c h SPC" . helm-all-mark-rings) ("C-c h i" . helm-semantic-or-imenu) ("C-c h m" . helm-man-woman) ))
4.5.2 Helm-projectile - project maintaining
Read this article Exploring large projects with Projectile and Helm Projectile
(or the official Projectile Manual) See some demos and master the usage. First
of all, you should keep the command helm-projectile
(C-x p h
) in mind. Then
master the command on directories and files.
(use-package helm-projectile :bind ("C-x p h" . helm-projectile) :init (projectile-global-mode) :config (helm-projectile-on) (setq projectile-completion-system 'helm) ;(setq projectile-switch-project-action 'helm-projectile-find-file) )
4.5.3 Helm-swoop - searching tool
This promises to be a fast way to find things.
(use-package helm-swoop :bind (("M-i" . helm-swoop) ("M-I" . helm-swoop-back-to-last-point) ("C-c M-i" . helm-multi-swoop)) :config ;; When doing isearch, hand the word over to helm-swoop (define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch) ;; From helm-swoop to helm-multi-swoop-all (define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop) ;; Save buffer when helm-multi-swoop-edit complete (setq helm-multi-swoop-edit-save t ;; If this value is t, split window inside the current window helm-swoop-split-with-multiple-windows t ;; Split direcion. 'split-window-vertically or 'split-window-horizontally helm-swoop-split-direction 'split-window-vertically ;; If nil, you can slightly boost invoke speed in exchange for text color helm-swoop-speed-or-color nil))
4.5.4 Helm-describe - keybings describe
Helm Descbinds provides an interface to emacs’ describe-bindings making the currently active key bindings interactively searchable with helm.
(use-package helm-descbinds :bind ("C-h b" . helm-descbinds) :init (fset 'describe-bindings 'helm-descbinds) :config (require 'helm-config))
4.5.5 Helm-flyspell - flyspell correct
(use-package helm-flyspell :defer t :config (define-key flyspell-mode-map (kbd "M-S") 'helm-flyspell-correct))
4.6 Backup and autosave
Backup is one of the things people usually want to change right away. By
default, Emacs saves backup files in the current directory. These are the files
ending in ~
that are cluttering up your directory lists. The following code
stashes them all in $HOME/.emacs.d/backup
, where I can find them with C-x
C-f
if I really need to.
;; backup in one place. flat, no tree structure (setq backup-directory-alist `((".*" . ,user-emacs-backup-dir))) (setq make-backup-files t) ;; store the undo-tree history in one place (setq undo-tree-history-directory-alist `((".*" . ,user-emacs-backup-dir))) (setq undo-tree-auto-save-history t) ;; backup misc settings (setq backup-by-copying t) (setq delete-old-versions t) (setq version-control t) (setq vc-make-backup-files t) (setq kept-new-versions 6 kept-old-versions 2)
(setq auto-save-file-name-transforms `((".*" ,user-emacs-autosave-dir t))) (setq auto-save-default t)
4.7 Persistence and history
4.7.1 Recentf - recent files
Recentf
is a minor mode that builds a list of recently opened files. Turn it
on, then call recentf-open-files
to open recently opened files fast.
(require 'recentf) (recentf-mode 1) ; keep a list of recently opened files, for future sessions (setq recentf-save-file (expand-file-name "recentf" user-emacs-savefile-dir)) (setq recentf-max-saved-items 500 recentf-max-menu-items 25 ;; disable recentf-cleanup on Emacs start, because it can cause ;; problems with remote files recentf-auto-cleanup 'never) (global-set-key (kbd "C-c f r") 'recentf-open-files)
4.7.2 Saveplace - save file position
You can save the cursor position for every file you opened. So, next time you open the file, the cursor will be at the position you last opened it.
(require 'saveplace) (save-place-mode 1) (setq save-place-file (expand-file-name "saveplace" user-emacs-savefile-dir))
4.7.3 Savehist - save history
By default, Savehist
saves only your minibuffer histories, but you can
optionally save other histories and other variables as well.
(require 'savehist) (savehist-mode 1) (setq savehist-file (expand-file-name "savehist" user-emacs-savefile-dir)) (setq history-length t) (setq history-delete-duplicates t) (setq savehist-save-minibuffer-history 1) (setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
4.7.4 Desktop - save and restore opened files and windows config
Desktop
can save and restore all previously opened files in last Emacs
session, and also previous windows configuration.
(require 'desktop) (desktop-save-mode 1) (setq desktop-base-file-name (expand-file-name "desktop" user-emacs-savefile-dir)) (setq desktop-base-lock-name (expand-file-name "desktop.lock" user-emacs-savefile-dir)) (setq desktop-save 'ask) (setq desktop-auto-save-timeout nil)
I don't tangle this block anymore because it slow down the startup speed obviously.
4.7.5 Bookmark - emacs bookmark
Bookmarks
lets you easily open frequently needed files. It is similar to
browser's bookmark. Read this article about the usage.
(require 'bookmark) (setq bookmark-default-file (expand-file-name "bookmark" user-emacs-savefile-dir)) (setq bookmark-save-flag 1) ; everytime bookmark is changed, auto save it
4.7.6 Eshell - emacs shell
(require 'eshell) (setq eshell-directory-name (expand-file-name "eshell" user-emacs-savefile-dir))
4.8 Global Key Bindings
4.8.1 Function keys
(global-set-key [f8] 'other-frame) (global-set-key [f9] 'enlarge-window) (global-set-key [f10] 'enlarge-window-horizontally) (global-set-key [f11] 'toggle-frame-fullscreen)
4.8.2 Easy keys for frequently used commands
Split and unsplit window panes are some of the most frequently used commands, because Emacs often generates output in a splits window. So set easy keys for them:
(global-set-key (kbd "s-0") 'delete-window) (global-set-key (kbd "s-1") 'delete-other-windows) (global-set-key (kbd "s-2") 'split-window-below) (global-set-key (kbd "s-3") 'split-window-right)
Change font size:
(global-set-key (kbd "C-s-=") 'text-scale-increase) (global-set-key (kbd "C-s--") 'text-scale-decrease)
4.8.3 Toggles
Bind shortcuts to some mode toggle functions. Inspired by this article, I am a wizard now.
(define-prefix-command 'endless/toggle-map) ;; The manual recommends C-c for user keys, but C-x t is ;; always free, whereas C-c t is used by some modes. (define-key ctl-x-map "t" 'endless/toggle-map) ;; build-in packages (define-key endless/toggle-map "d" #'toggle-debug-on-error) (define-key endless/toggle-map "q" #'toggle-debug-on-quit) (define-key endless/toggle-map "f" #'auto-fill-mode) (define-key endless/toggle-map "t" #'toggle-truncate-lines) (define-key endless/toggle-map "l" #'display-line-numbers-mode) ;; packages installed by `use-packages' (define-key endless/toggle-map "w" #'whitespace-mode) (define-key endless/toggle-map "s" #'flyspell-mode) (define-key endless/toggle-map "c" #'flycheck-mode) (define-key endless/toggle-map "g" #'git-timemachine)
4.8.4 Miscellaneous
Here are some useful global key bindings.
;; Align your code in a pretty way. (global-set-key (kbd "C-x \\") 'align-regexp) ;; Start eshell or switch to it if it's active. (global-set-key (kbd "C-x m") 'eshell) ;; Start a new eshell even if one is active. (global-set-key (kbd "C-x M") (lambda () (interactive) (eshell t))) ;; Start a regular shell if you prefer that. (global-set-key (kbd "C-x M-m") 'shell) ;; use hippie-expand instead of dabbrev (global-set-key (kbd "M-/") 'hippie-expand) ;; replace buffer-menu with ibuffer (global-set-key (kbd "C-x C-b") 'ibuffer)
4.8.5 Which-key
- keys cheat sheet
Many command sequences may be logical, but who can remember them all? Don't worry. Which-key can display the key bindings following your currently entered incomplete command (a prefix) in a popup.
(use-package which-key :ensure t :config (which-key-mode))
5 Aesthetics
5.1 Color Themes
Solarized Theme and Spacemacs Theme are my favorite color themes. And the Zenburn Theme is also really nice. I used these as my default color themes.
According to this Stackoverflow discuss , I can use f12
to switch color
themes.
(use-package zenburn-theme :defer t) (use-package solarized-theme :defer t) (use-package spacemacs-theme :defer t) ;; color theme cycle list (setq my-themes (list 'zenburn 'spacemacs-light 'spacemacs-dark ;; 'solarized-light ;; 'solarized-dark )) (defun my-theme-cycle () (interactive) (disable-theme (car curr-theme)) ;;Nee flickeringded to stop even worse (setq curr-theme (cdr curr-theme)) (if (null curr-theme) (setq curr-theme my-themes)) (load-theme (car curr-theme) t) (message "%s" (car curr-theme))) (global-set-key [f12] 'my-theme-cycle) (setq curr-theme my-themes) (load-theme (car curr-theme) t)
5.2 Modeline Theme
(use-package powerline :ensure t :init (setq powerline-default-separator 'curve powerline-default-separator-dir (quote (left . right)) powerline-height 28 powerline-display-buffer-size nil powerline-display-hud nil powerline-display-mule-info nil powerline-gui-use-vcs-glyph t powerline-inactive1 '((t (:background "grey11" :foreground "#c5c8c6"))) powerline-inactive2 '((t (:background "grey20" :foreground "#c5c8c6")))))
5.3 Icons
According to this, install all-the-icon package for neotree's color theme:
(use-package all-the-icons)
In order for the icons to work it is very important that you install the Resource Fonts included in this package. Call the following command:
M-x all-the-icons-install-fonts
Then use all-the-icons
for neotree
:
(setq inhibit-compacting-font-caches t) (setq neo-theme 'icons)
5.4 Fonts
Choosing a nice and comfortable font is quite important in your whole coding life.
I prefer Monaco. And, as a Chinese, l choose WenQuanYi for Chinese charset.
(when (eq system-type 'darwin) ;; default Latin font (e.g. Consolas) (set-face-attribute 'default nil :family "Monaco") ;; default font size (point * 10) ;; ;; WARNING! Depending on the default font, ;; if the size is not supported very well, the frame will be clipped ;; so that the beginning of the buffer may not be visible correctly. (set-face-attribute 'default nil :height 150) ;; use specific font for Chinese charset. ;; if you want to use different font size for specific charset, ;; add :size POINT-SIZE in the font-spec. (set-fontset-font t 'han (font-spec :name "WenQuanYi Micro Hei Mono")) )
M-x eshell
, then run the command (print (font-family-list))
. You will see a
list of fonts can be used in Emacs.
5.5 Nyan-mode
- Nyan cat in modeline
Let Nyan Cat show you your buffer position in mode line. You can scroll the buffer by clicking on the Nyan Cat’s rainbow and the space in front of it.
(use-package nyan-mode :init (nyan-mode))
5.6 Rainbow-delimiters
- color delimiters for LISP
For lisp like languages, I want to witness the full power of colorful rainbow-delimiters! I will even set them to pastel versions of the rainbow colors.
(use-package rainbow-delimiters :init (rainbow-delimiters-mode 1)) (set-face-attribute 'rainbow-delimiters-depth-1-face nil :foreground "#78c5d6") (set-face-attribute 'rainbow-delimiters-depth-2-face nil :foreground "#bf62a6") (set-face-attribute 'rainbow-delimiters-depth-3-face nil :foreground "#459ba8") (set-face-attribute 'rainbow-delimiters-depth-4-face nil :foreground "#e868a2") (set-face-attribute 'rainbow-delimiters-depth-5-face nil :foreground "#79c267") (set-face-attribute 'rainbow-delimiters-depth-6-face nil :foreground "#f28c33") (set-face-attribute 'rainbow-delimiters-depth-7-face nil :foreground "#c5d647") (set-face-attribute 'rainbow-delimiters-depth-8-face nil :foreground "#f5d63d") (set-face-attribute 'rainbow-delimiters-depth-9-face nil :foreground "#78c5d6")
We also want to make unmatched parens stand out more:
(set-face-attribute 'rainbow-delimiters-unmatched-face nil :foreground 'unspecified :inherit 'show-paren-mismatch :strike-through t)
Now we just need to adjust the hook for lisp-like languages. Possibly have to add clojure, if I ever want to mess with that.
(add-hook 'emacs-lisp-mode-hook 'rainbow-delimiters-mode) (add-hook 'lisp-mode-hook 'rainbow-delimiters-mode)
5.7 Rainbow-mode
- color words for CSS
Rainbow-mode
makes "color words" in my programs appear in the colours they
describe. Particularly good for CSS and the like.
(use-package rainbow-mode :diminish rainbow-mode :config (add-hook 'emacs-lisp-mode-hook 'rainbow-mode) (add-hook 'css-mode-hook 'rainbow-mode) (add-hook 'html-mode-hook 'rainbow-mode) (add-hook 'js2-mode-hook 'rainbow-mode))
6 Programming Environment
6.1 Editing Support
6.1.1 Aggressive Indent
Automatically indent without use of the tab found in this article, and seems to be quite helpful for many types of programming languages.
(use-package aggressive-indent :init (global-aggressive-indent-mode 1))
6.1.2 Indent Guide
Indent Guide project shows vertical lines to guide indentation.
(use-package indent-guide :init (indent-guide-global-mode))
6.1.3 Code Folding
The Hide Show minor mode allows us to fold all functions (hidden), showing only the header lines. We need to turn on the mode, so wrappers are in order:
(defun ha/hs-show-all () (interactive) (hs-minor-mode 1) (hs-show-all)) (defun ha/hs-hide-all () (interactive) (hs-minor-mode 1) (hs-hide-all)) (defun ha/hs-toggle-hiding () (interactive) (hs-minor-mode 1) (hs-toggle-hiding))
Seems that C-c @
is too obnoxious to use, so I'll put my favorite on the
C-c h
prefix:
(global-set-key (kbd "C-x t h") 'hs-minor-mode) (global-set-key (kbd "C-c t h") 'ha/hs-hide-all) (global-set-key (kbd "C-c t s") 'ha/hs-show-all) (global-set-key (kbd "C-c t c") 'ha/hs-toggle-hiding)
6.2 Document
I like ElDoc support (when I can get it), but not needed in the mode line.
(use-package eldoc :diminish eldoc-mode :init (setq eldoc-idle-delay 0.1))
6.3 Error checking
Flycheck seems to be quite superior to Flymake
.
(use-package flycheck :bind ("C-x t c" . flycheck-mode) :ensure t :diminish flycheck-mode :init (add-hook 'after-init-hook 'global-flycheck-mode) :config (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
7 Programming Languages
7.1 Shell
Make a shell script executable automatically on save.
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
Files with .zsh
extension is shell script too.
(add-to-list 'auto-mode-alist '("\\.zsh\\'" . sh-mode))
8 Typesetting Languages
8.1 Markdown
Markdown-mode is a major mode for editing Markdown-formatted text.
(use-package markdown-mode :ensure t :commands (markdown-mode gfm-mode) :mode (("README\\.md\\'" . gfm-mode) ("\\.md\\'" . markdown-mode) ("\\.markdown\\'" . markdown-mode)) :init (setq markdown-command "multimarkdown"))
8.2 LaTeX
9 Git and Magit
9.1 Git basic settings
I like diff-hl. This mode can highlight uncommitted changes on the left side of the window, allows you to jump between and revert them selectively.
(use-package diff-hl :ensure t :init (global-diff-hl-mode) :config (add-hook 'dired-mode-hook 'diff-hl-dired-mode) (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))
I want to have special mode for Git's gitconfig
and gitignore
file:
(use-package gitconfig-mode :ensure t) (use-package gitignore-mode :ensure t)
Play with Git Time Machine project for viewing the different version history of
a file with p
and n
.
(use-package git-timemachine :bind ("C-x t g" . git-timemachine))
Git Messenger can popup commit message at current line.
(use-package git-messenger :bind (("C-x v m" . git-messenger:popup-message)))
9.2 Magit - git interface
Git is already part of Emacs. However, Magit is sweet!
(use-package magit :ensure t :commands magit-status magit-blame :init (defadvice magit-status (around magit-fullscreen activate) (window-configuration-to-register :magit-fullscreen) ad-do-it (delete-other-windows)) :config (setq magit-branch-arguments nil ;; use ido to look for branches magit-completing-read-function 'magit-ido-completing-read ;; don't put "origin-" in front of new branch names by default magit-default-tracking-name-function 'magit-default-tracking-name-branch-only magit-push-always-verify nil ;; Get rid of the previous advice to go into fullscreen magit-restore-window-configuration t) :bind ("C-x g" . magit-status))
10 Org-Mode
10.1 Exporter Setup
I have the following setup for the exporters I use. Alphabetical listing options need to be set before the exporters are loaded for filling to work correctly.
(setq org-alphabetical-lists t) ;; Explicitly load required exporters (require 'ox-html) (require 'ox-latex) (require 'ox-ascii) (require 'ox-md)
The ox-extra
package make it possible to export content of subtrees without
their headings.
(require 'ox-extra) (ox-extras-activate '(ignore-headlines))
11 Acknowledges
- Inspired by Sacha and Bernt, I began to maintain my Emacs configuration using
org-babel
in literate style. - My configuration taken a lot from Howard Abrams's Emacs initialization code
which is well structured and documented with
org-mode
. - Benefit from the Magit project's Themes, I built the pretty nice Emacs Init File Project Page.