- Introduction
- Meta
- Package Management
- Utils
- Configurations
- About Emacs
- About Me
- Aggressive Indent
- Blog
- Buffer
- Clojure
- ClojureScript
- Comint
- Comment
- Common Lisp
- Company
- Compilation
- CSS
- Cursor
- Default Functionality
- Default Major Mode
- Dired
- Discover My Major
- Ediff
- Edit Server
- Elisp
- Emmet
- Eshell
- Expand Region
- Font
- Fill Column
- File Files
- Frame
- Fringe
- Helm
- Helm Dash
- Helm Descbinds
- Image
- Info
- JavaScript
- Keyboard Macro
- LaTeX
- Line and Column Numbers
- Macros
- Magit
- Markdown
- Menubar and Toolbar
- Mode Line
- Modes
- Multiple Cursors
- Octave
- Open
- Org
- Pages
- PDF Tools
- Performance
- Popwin
- Projectile
- Python
- Quit
- Sass
- Scheme
- Scratch Buffer
- Scroll
- Search and Replace
- Sexp
- SGML
- Shell
- Smartparens
- Spelling
- Splash Screen
- Tabs
- Terminal Mode
- Theme
- Toggle
- Whitespace Cleanup
- Window Management
- YASnippet
- Microsoft Windows
- Mac OSX
- License
This is an Emacs configuration file written in Org-mode. It is adapted from Lars Tveito’s excellent configuration file on GitHub.
After cloning from GitHub, there is no init.el
file, only an init.org
file (this file).
To produce an init.el
file, either:
- Open
init.org
and useC-c C-v t
to callorg-babel-tangle
, which extracts code blocks from the current file intoinit.el
, then restart Emacs, or - Run the following command in a shell before starting Emacs:
emacs --batch \ --load "/usr/local/share/emacs/25.1/lisp/org/ob-tangle.elc" \ --eval "(org-babel-tangle-file \"~/.emacs.d/init.org\")"
This assumes Emacs 25.1 built from source on GNU/Linux. Otherwise, swap out the load path of
ob-tangle.elc
for whatever is appropriate.
To avoid having to tangle manually each time a change is made, we can add a
function to after-save-hook
to tangle the init.org
after saving.
(defun *-tangle-init-file ()
"Tangle the current buffer if it is the init.org file."
(when (equal (buffer-file-name)
(expand-file-name (concat user-emacs-directory "init.org")))
(org-babel-tangle)))
(add-hook 'after-save-hook #'*-tangle-init-file)
Managing extensions in Emacs is simplified using package
, which is built
into Emacs 24 and newer. To load downloaded packages, we need to initialize
package
.
- First, we list the package archives we’d like to install packages from.
(customize-set-variable 'package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/")))
- If the variable
package-enable-at-startup
is non-nil, package initialization occurs after the init file is loaded, but beforeafter-init-hook
. We want to load packages before the init file is loaded, because we’ll be referencing packages in the init file. Therefore, we need to initialize our packages manually.(customize-set-variable 'package-enable-at-startup nil) (package-initialize)
- Make sure that we have the list of packages available.
(unless package-archive-contents (package-refresh-contents))
- Define a list of packages that we want to install.
Package
is smart enough to install dependencies automatically.(setq *-package-list '(aggressive-indent auctex cider clojure-mode company company-auctex company-quickhelp discover-my-major dockerfile-mode edit-server elpy emmet-mode eros expand-region flycheck flycheck-color-mode-line haskell-mode helm helm-cider helm-dash helm-descbinds helm-describe-modes helm-org helm-pages helm-projectile htmlize hydra js2-mode json-mode key-chord less-css-mode macrostep magit markdown-mode mediawiki multiple-cursors page-break-lines pdf-tools popwin projectile quick-peek rainbow-mode scss-mode slime slime-company smartparens toc-org use-package yaml-mode yasnippet zenburn-theme))
- Install the missing packages.
(dolist (package *-package-list) (unless (package-installed-p package) (package-install package)))
- Define a function to easily upgrade all packages and delete obsolete
ones. Thanks to @basil for pointers on
package-menu-async
!(defun *-package-upgrade () "Refresh, upgrade and delete obsolete packages synchronously." (interactive) (save-window-excursion (let (package-menu-async) (package-list-packages))) (with-current-buffer "*Packages*" (package-menu-mark-upgrades) (package-menu-mark-obsolete-for-deletion) (condition-case err (package-menu-execute t) ;; Don't barf if there is nothing to do (user-error (message "Nothing to do")) ;; But allow other errors through (error (signal (car err) (cdr err))))))
- Use a hydra, along with
helm
, to create a package-related menu.(defhydra hydra-package (:color blue) " Packages [_q_] quit ^^--------------------------------------------------------------------------- [_d_] describe [_i_] install [_l_] list [_L_] list (no fetch) [_U_] upgrade all " ("d" describe-package nil) ("i" package-install nil) ("l" package-list-packages nil) ("L" package-list-packages-no-fetch nil) ("U" *-package-upgrade nil) ("q" nil nil)) (define-key help-map "p" 'hydra-package/body)
Utility functions, etc. that need to be fined ahead of time.
Require various libraries.
(require 'cl-lib)
(require 'subr-x)
Macro to create function that provides documentation in a pop-up window.
(require 'quick-peek)
(set-face-attribute 'quick-peek-border-face nil :height 20)
(defmacro *-make-doc-command (doc-fun sym-fun)
"Return an command that uses `quick-peek' to preview docs.
DOC-FUN is a unary function that takes a loop-up string and
returns the doc string.
SYM-FUN is a nullary function that gets the symbol at point as a
string."
`(lambda ()
(interactive)
(let ((doc (funcall ,doc-fun (funcall ,sym-fun))))
(if (string-empty-p doc)
(message "Unknown symbol, or no documentation available.")
(let ((map (make-sparse-keymap)))
(set-transient-map map
(lambda ()
(eq #'mwheel-scroll this-command))
(lambda ()
(quick-peek-hide)
(setq this-command #'ignore))))
(let ((pos (save-excursion
(beginning-of-line)
(point))))
(quick-peek-show doc pos nil (frame-height)))))))
- Replace the
*About GNU Emacs*
buffer with Emacs and user info.
(defhydra hydra-about-emacs ()
"
About Emacs [_q_] quit
^^---------------------------------------------------------------------------
PID: %s(emacs-pid)
Uptime: %s(emacs-uptime)
Init time: %s(emacs-init-time)
Directory: %s(identity user-emacs-directory)
Invoked from: %s(concat invocation-directory invocation-name)
Version: %s(identity emacs-version)
User Info
^^---------------------------------------------------------------------------
User name: %s(user-full-name)
Login (real): %s(user-login-name) (%s(user-real-login-name))
UID (real): %s(user-uid) (%s(user-real-uid))
GID (real): %s(group-gid) (%s(group-real-gid))
Mail address: %s(identity user-mail-address)
"
("q" nil nil))
(global-set-key (kbd "C-h C-a") #'hydra-about-emacs/body)
- System info
(defhydra hydra-system-info () " System Info [_q_] quit ^^--------------------------------------------------------------------------- System name: %s(system-name) System type: %s(identity system-type) System config: %s(identity system-configuration) Memory ^^--------------------------------------------------------------------------- Used: %s(format \"%0.0f percent\" (* 100 (- 1 (/ (cl-second (memory-info)) (float (cl-first (memory-info))))))) Free RAM: %s(format \"%0.1f GB (of %0.1f GB)\" (/ (float (cl-second (memory-info))) 1048576) (/ (float (cl-first (memory-info))) 1048576)) Free swap: %s(format \"%0.1f GB (of %0.1f GB)\" (/ (float (cl-fourth (memory-info))) 1048576) (/ (float (cl-third (memory-info))) 1048576)) Pure memory: %s(format \"%0.1f GB\" (/ (float pure-bytes-used) 1048576)) Garbage Collection ^^--------------------------------------------------------------------------- GCs done: %`gcs-done GCs elapsed: %s(format-seconds \"%M, %S\" gc-elapsed) Cons threshold: %`gc-cons-threshold Cons percentage: %`gc-cons-percentage " ("q" nil nil)) (global-set-key (kbd "C-h C-s") #'hydra-system-info/body)
- Set personal information, like name and e-mail.
(customize-set-variable 'user-full-name "Tianxiang Xiong") (customize-set-variable 'user-mail-address "[email protected]")
- Use aggressive-indent to keep source code aligned.
(aggressive-indent-global-mode 1)
- Disable
aggressive-indent-mode
in shells, REPLs, etc.(dolist (mode '(cider-repl-mode comint-mode eshell-mode slime-repl-mode term-mode)) (add-to-list 'aggressive-indent-excluded-modes mode))
- Use
org-publish
to manage my GitHub blog. We need to set theorg-publish-project-alist
variable to publish projects.(customize-set-variable 'org-publish-project-alist '(("blog posts" :base-directory "~/github/xiongtx.github.io/_org/" :base-extension "org" :body-only t :html-extension "html" :publishing-directory "~/github/xiongtx.github.io/" :publishing-function org-html-publish-to-html :recursive t) ("blog static" :base-directory "~/github/xiongtx.github.io/_org/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg" :publishing-directory "~/github/xiongtx.github.io/" :publishing-function org-publish-attachment :recursive t) ("blog" :components ("blog posts" "blog static"))))
- Kill current buffer.
(global-set-key (kbd "C-c k") #'kill-this-buffer)
- Use unique buffer names. The
post-forward
style displays the buffer name asbuffer|dir1/dir2
.(customize-set-variable 'uniquify-buffer-name-style 'post-forward)
- Revert buffer with
<f5>
(refresh).(global-set-key (kbd "<f5>") #'revert-buffer)
- Recognize boot files as Clojure.
(add-to-list 'auto-mode-alist '("\\.boot\\'" . clojure-mode)) ;; Boot script files (add-to-list 'magic-mode-alist '(".* boot" . clojure-mode))
- Custom indent special forms and macros.
(with-eval-after-load 'clojure-mode (define-clojure-indent (defrecord '(2 nil nil (1))) (deftype '(2 nil nil (1))) (implement '(1 (1))) (letfn '(1 ((:defn)) nil)) (match 1) (proxy '(2 nil nil (1))) (reify '(:defn (1))) (specify '(1 (1))) (specify '(1 (1)))))
- Use CIDER when visiting Clojure files.
(with-eval-after-load 'clojure-mode (add-hook 'clojure-mode-hook #'cider-mode)) (customize-set-variable 'cider-prompt-for-symbol nil) (customize-set-variable 'cider-repl-display-help-banner nil) (customize-set-variable 'cider-repl-use-pretty-printing t)
- Bind keys for browsing Clojure namespaces.
(with-eval-after-load 'cider-doc (define-key cider-doc-map (kbd "n") #'cider-browse-ns-all) (define-key cider-doc-map (kbd "C-n") #'cider-browse-ns-all))
- Use helm-cider.
(with-eval-after-load 'cider-mode (add-hook 'cider-mode-hook #'helm-cider-mode))
- Look up Clojure documentation in a pop-up with CIDER.
(defun *-cider-symbol-full-doc (symbol) "Return a string of the full documentation of SYMBOL, as given by `cider-create-doc-buffer'." (let ((buf (cider-create-doc-buffer symbol))) (when buf (with-current-buffer buf (buffer-substring (point-min) ;; `-10' to exclude "[source]" line (- (point-max) 10)))))) (defun *-cider-doc-popup () "Display CIDER documentation in a popup." (interactive) (funcall (*-make-doc-command #'*-cider-symbol-full-doc #'cider-symbol-at-point))) (defun *-cider-doc-popup-on () "Turn `*-cider-doc-popup' by binding it to an appropriate key." (define-key cider-mode-map (kbd "C-h j") #'*-cider-doc-popup) (define-key cider-mode-map (kbd "C-h C-j") #'*-cider-doc-popup)) ;; Only use pop-up documentation when CIDER is connected (add-hook 'cider-connected-hook #'*-cider-doc-popup-on)
- Use Figwheel when after
cider-jack-in-clojurescript
. Thanks to Mark Hudnall.(customize-set-variable 'cider-cljs-lein-repl "(do (require 'figwheel-sidecar.repl-api) (figwheel-sidecar.repl-api/start-figwheel!) (figwheel-sidecar.repl-api/cljs-repl))")
- Make prompt read-only.
(customize-set-variable 'comint-prompt-read-only t)
- Use
comint-bol
instead ofmove-beginning-of-line
(with-eval-after-load 'comint-mode (define-key comint-mode-map (kbd "C-a") #'comint-bol))
- Comment or uncomment a region or line in a “do what I mean” fashion.
(defun *-comment-or-uncomment-region-or-line () "Comments or uncomments the region or the current line if there's no active region." (interactive) (let (beg end) (if (region-active-p) (setq beg (region-beginning) end (region-end)) (setq beg (line-beginning-position) end (line-end-position))) (comment-or-uncomment-region beg end) (forward-line)))
- Set convenient key binding to comment/uncomment line.
(global-set-key (kbd "C-;") #'*-comment-or-uncomment-region-or-line)
- Open files in
lisp-mode
.;; The SBCL configuration file is in Common Lisp (add-to-list 'auto-mode-alist '("\\.sbclrc\\'" . lisp-mode)) ;; Open files with .cl extension in lisp-mode (add-to-list 'auto-mode-alist '("\\.cl\\'" . lisp-mode))
- Settings for SLIME (Superior Lisp Interaction Mode for Emacs).
(setq inferior-lisp-program "/usr/bin/sbcl --noinform") (setq slime-contribs '(slime-fancy))
- Use slime-company, which integrates
company-mode
with SLIME.(add-to-list 'slime-contribs 'slime-company)
- Set up SLIME contribs.
(slime-setup)
- Create SLIME REPL when visiting Common Lisp file.
(defun *-slime-create-or-switch-to () "Start an inferior Lisp process and connect to its Swank server if none exists, or switch to existing one. This is always done in another window. If there is only one window, it is split horizontally. Do not switch to SLIME window if Helm is active; this allows previewing files in Helm without trouble." (interactive) (save-selected-window (if (not (slime-connected-p)) (slime) (if (> (length (window-list)) 1) (other-window 1) (split-window-horizontally) (other-window 1) (*-rotate-buffers-in-windows)) (unless (helm-alive-p) (set-window-buffer (selected-window) (slime-output-buffer)))))) ;; (add-hook 'lisp-mode-hook #'*-slime-create-or-switch-to)
- Use
hyperspec
commands with SLIME.(with-eval-after-load 'slime (define-key slime-mode-map (kbd "C-c C-d C-s") #'common-lisp-hyperspec))
- Look up Common Lisp documentation in a pop-up with SLIME.
(defun *-slime-symbol-full-doc (symbol) "Return a string of the full documentation of SYMBOL. First `slime-documentation' is tried. If there is no documentation, `slime-describe-symbol' is tried." (let ((symbol (if (stringp symbol) symbol (symbol-name symbol))) (package (slime-current-package))) (let ((doc (slime-eval `(swank:documentation-symbol ,symbol) package))) (if (string-prefix-p "No such symbol" doc) "" (if (string-suffix-p "Not documented." doc) (slime-eval `(swank:describe-symbol ,symbol) package) doc))))) (defun *-slime-doc-popup () "Display CIDER documentation in a popup." (interactive) (funcall (*-make-doc-command #'*-slime-symbol-full-doc #'slime-symbol-at-point))) (defun *-slime-doc-popup-on () "Use `*-slime-doc-popup' by binding it to an appropriate key." (define-key slime-mode-map (kbd "C-h j") #'*-slime-doc-popup) (define-key slime-mode-map (kbd "C-h C-j") #'*-slime-doc-popup)) (add-hook 'slime-connected-hook #'*-slime-doc-popup-on)
- Use company-mode, a modular in-buffer completion framework for Emacs.
(add-hook 'after-init-hook #'global-company-mode)
- Reduce completion menu time delay to minimum.
(customize-set-variable 'company-idle-delay 0)
- More easily navigate the completion menu.
(with-eval-after-load 'company (define-key company-active-map (kbd "C-n") #'company-select-next) (define-key company-active-map (kbd "C-p") #'company-select-previous))
- Show quick-access numbers of completion options.
(customize-set-variable 'company-show-numbers t)
- Align annotations.
(customize-set-variable 'company-tooltip-align-annotations t)
- Use company-quickhelp, which shows a documentation pop-up during
company-mode
completion.(company-quickhelp-mode t) ;; Do not show pop-up automatically (customize-set-variable 'company-quickhelp-delay nil) ;; Define binding for showing pop-up manually in company-active-map instead of ;; company-quickhelp-mode-map; this activates it only when we want completion. (with-eval-after-load 'company (define-key company-active-map (kbd "C-j") #'company-quickhelp-manual-begin))
There’s also
company-show-doc-buffer
, which is built intocompany-mode-map
, but the selections disappear when the doc buffer appears (maybe it just doesn’t play nice withpopwin
?). Furthermore, it’s easier to read the documentation when it’s right next to the candidate.
- Use more convenient bindings for
previous-error
andnext-error
.(dolist (key (append (where-is-internal #'previous-error) (where-is-internal #'next-error))) (global-unset-key key)) (global-set-key (kbd "M-N") #'next-error) (global-set-key (kbd "M-P") #'previous-error)
- Quickly bring up last compilation buffer.
(defun *-last-compilation-buffer () "Display last compilation buffer in current window." (interactive) (if (buffer-live-p compilation-last-buffer) (set-window-buffer (get-buffer-window) compilation-last-buffer) (message "Last compilation buffer is killed."))) (global-set-key (kbd "C-x c") #'*-last-compilation-buffer)
- Use
emmet-mode
.(add-hook 'css-mode-hook #'emmet-mode)
- Use
rainbow-mode
.(add-hook 'css-mode-hook #'rainbow-mode)
- Do not blink the cursor.
(blink-cursor-mode 0)
- Some functionality is turned off by default to avoid confusing new
users. Turn them back on.
(put 'erase-buffer 'disabled nil) (put 'narrow-to-defun 'disabled nil) (put 'narrow-to-page 'disabled nil) (put 'narrow-to-region 'disabled nil)
- Set the default major mode to
emacs-lisp-mode
.(customize-set-variable 'initial-major-mode #'emacs-lisp-mode)
- Omit uninteresting files; see
dired-omit-files
.(require 'dired-x) (add-hook 'dired-mode-hook #'dired-omit-mode)
- Use discover-my-major, which displays key bindings and their meaning for
the current Emacs major mode.
(define-key help-map (kbd "C-k") #'discover-my-major)
- Better defaults for
ediff
.;; Show control panel in single frame (customize-set-variable 'ediff-window-setup-function 'ediff-setup-windows-plain) ;; Split windows horizontally (customize-set-variable 'ediff-split-window-function 'split-window-horizontally) ;; Only highlight one diff (customize-set-variable 'ediff-highlight-all-diffs nil)
- Useful diff commands.
(global-set-key (kbd "C-x d") #'ediff-current-file)
- Expand
outline-mode
(includingorg-mode
) buffers when diffing.(add-hook 'ediff-prepare-buffer-hook #'outline-show-all)
- Use emacs-chrome, which allows editing of text areas and other editable
text elements of a page with Emacs.
Obviously, we need to install the Edit with Emacs extension for Chrome.
For this to work, we need to run an “edit server” on our machine. This is because, as a security measure, extensions in Chrome(ium) cannot spawn new processes.
;; Start edit-server (when (require 'edit-server nil t) ;; Edit in a new buffer instead of a new frame (customize-set-variable 'edit-server-new-frame nil) (edit-server-start))
- Associated common websites with major modes.
(customize-set-variable 'edit-server-url-major-mode-alist '(("github\\.com" . markdown-mode) ("reddit\\.com" . markdown-mode) ("stackexchange\\.com" . markdown-mode) ("stackoverflow\\.com" . markdown-mode)))
- Use eros, which displays evaluation result overlays.
(eros-mode 1)
- Use eldoc-mode, which shows function signatures in the echo area.
;; Don't delay `eldoc' display
(customize-set-variable 'eldoc-idle-delay 0)
;; Activate `eldoc' for certain modes
(add-hook 'emacs-lisp-mode-hook #'eldoc-mode)
(add-hook 'lisp-interaction-mode-hook #'eldoc-mode)
- Use quick-peek to create documentation pop-up for Emacs Lisp. Heavily
inspired by Popup Help in Emacs Lisp and clippy.
(defmacro *-symbol-full-doc (symbol) "Return a string of the full documentation of SYMBOL, as given by `help-xref-interned'. If `popwin-mode' is active, disable it temporarily. The value of `popwin-mode' is thus always nil, even when the mode is active.'" (let* ((sym (cl-gensym "doc")) (form `(let ((,sym ,symbol)) (save-window-excursion (with-temp-buffer (let ((help-xref-following t)) (help-mode) (help-xref-interned ,sym) (buffer-string))))))) (if (fboundp #'popwin-mode) `(let ((old-popwin popwin-mode)) (popwin-mode -1) (unwind-protect ,form (popwin-mode (or old-popwin -1)))) ,form))) (defun *-describe-symbol-popup () "Display full documentation of symbol in a pop-up window." (interactive) (funcall (*-make-doc-command (lambda (symbol) (*-symbol-full-doc symbol)) #'symbol-at-point))) (define-key help-map "j" #'*-describe-symbol-popup) (define-key help-map (kbd "C-j") #'*-describe-symbol-popup)
- Switch to IELM buffer in other window.
(defun *-switch-to-ielm-buffer () "Interactively evaluate Emacs Lisp expressions. Switches to the buffer `*ielm*' in another window." (interactive) (require 'ielm) (let (old-point) (unless (comint-check-proc "*ielm*") (with-current-buffer (get-buffer-create "*ielm*") (unless (zerop (buffer-size)) (setq old-point (point))) (inferior-emacs-lisp-mode))) (pop-to-buffer "*ielm*") (when old-point (push-mark old-point)))) (define-key emacs-lisp-mode-map (kbd "C-c C-z") #'*-switch-to-ielm-buffer)
- Eval and pretty print in other buffer.
(define-minor-mode *-pp-buffer-mode "Mode for `pp' buffers." :init-value nil :keymap '(("q" . (lambda () (interactive) (quit-restore-window))))) (defun *-pp-eval-last-sexp () "Like `pp-eval-last-sexp', but better handles output buffer." (interactive) (pp-eval-expression (pp-last-sexp)) (pop-to-buffer "*Pp Eval Output*") (goto-char (point-min)) (setq buffer-read-only t) (*-pp-buffer-mode)) (define-key emacs-lisp-mode-map (kbd "C-c C-p") #'*-pp-eval-last-sexp)
- Move cursor between first pair of quotes after expansion.
(customize-set-variable 'emmet-move-cursor-between-quotes t)
- Do not use certain keybindings.
(with-eval-after-load 'emmet-mode (define-key emmet-mode-keymap (kbd "C-j") nil) (define-key emmet-mode-keymap (kbd "C-M-<left>") nil) (define-key emmet-mode-keymap (kbd "C-M-<right>") nil))
- Remove banner.
(customize-set-variable 'eshell-banner-message "")
- Function to switch Eshell directory to other window’s buffer’s default
directory.
(defun *-eshell-next-window-default-directory (&optional previous) "Return next window's buffer's `default-directory', if it exists. Nil otherwise. If optional argument PREVIOUS is non-nil, use previous instead of next window." (let ((window (if previous (previous-window nil 'no-minibuf) (next-window nil 'no-minibuf)))) (with-current-buffer (window-buffer window) default-directory)))
- Clear Eshell buffer, preserving current input.
(defun *-eshell-clear () "Clear `eshell' buffer, comint-style." (interactive) (goto-char (point-max)) (let ((input (eshell-get-old-input))) (eshell/clear-scrollback) (eshell-emit-prompt) (insert input)))
- Start Eshell in other window, switching to useful directory.
(defun *-eshell-other-window () "Start Eshell in other window's buffer's `default-directory'. If current buffer is in `eshell-mode', `cd' to previous window's buffer's default directory." (interactive) (cl-flet ((switch-dir (dir) (cd dir) (*-eshell-clear))) (if (eq 'eshell-mode major-mode) (switch-dir (*-eshell-next-window-default-directory 'previous)) (let ((dir default-directory)) (other-window 1) (eshell) (switch-dir dir))))) (global-set-key (kbd "M-$") #'*-eshell-other-window)
- Eshell initializations.
(defun *-eshell-init () "Init forms to run as part of `eshell-mode-hook'." (yas-minor-mode -1) (toggle-truncate-lines 1) (smartparens-mode t) (define-key eshell-mode-map (kbd "C-c M-o") #'*-eshell-clear) (define-key eshell-mode-map [remap eshell-list-history] #'helm-eshell-history) (define-key eshell-mode-map [remap eshell-pcomplete] #'company-manual-begin)) (add-hook 'eshell-mode-hook #'*-eshell-init)
- Use expand-region, which increases selected region by semantic units.
(global-set-key (kbd "M-[") #'er/expand-region) (global-set-key (kbd "M-]") #'er/contract-region)
- Change the default font.
(when (member "DejaVu Sans Mono" (font-family-list)) (let ((height (if (string= system-type "darwin") 120 110))) (set-face-attribute 'default nil :font "DejaVu Sans Mono" :height height)))
- Fill column to 78 chars.
The width of 78 is chosen so that text centered on an 80-char-wide interface will have a column of white space on each side.
(customize-set-variable 'fill-column 78)
- Bind
C-x C-l
tofind-file-literally
instead ofdowncase-region
, which is rarely used.(define-key ctl-x-map (kbd "C-l") #'find-file-literally)
- Bind
C-x f
tofind-file
instead ofset-fill-column
, which is rarely used. Also, I hitC-x f
instead ofC-x C-f
way too often.(define-key ctl-x-map "f" #'find-file)
- Make frame full-screen. We cannot use
toggle-frame-fullscreen
because no frame has been created when the init file is loaded.(add-to-list 'default-frame-alist '(fullscreen . fullboth))
- Set keybinding to iconify (minimize) or de-iconify frame.
(global-set-key (kbd "s--") #'iconify-or-deiconify-frame)
- Resize pixel-wise. This is particularly useful on Mac.
(customize-set-variable 'frame-resize-pixelwise t)
- Hide fringes.
(require 'fringe) (fringe-mode 0)
- Give
fringe
same color asdefault
face.This is useful for centered-window-mode.
(set-face-background 'fringe (face-background 'default))
- Configure helm, an incremental completion and selection narrowing
framework. See the author’s config file as a reference.
(helm-mode t) ;;; Let helm use current window (customize-set-variable 'helm-split-window-default-side 'same) ;; Auto-complete file names when finding files (customize-set-variable 'helm-ff-auto-update-initial-value t)
- Change the prefix key for
helm
fromC-x c
to something else, becauseC-x c
is too close toC-x C-c
, which is bound to the commandsave-buffers-kill-terminal
.(global-set-key (kbd "C-c h") 'helm-command-prefix) (global-unset-key (kbd "C-x c"))
- Bind common
helm
commands to more accessible key sequences.;; Resume helm (global-set-key (kbd "M-r") #'helm-resume) ;; Navigate between sources (define-key helm-map (kbd "C-o") #'helm-previous-source) (define-key helm-map (kbd "C-l") #'helm-next-source) ;; Commands (global-set-key (kbd "<menu>") #'helm-M-x) (global-set-key (kbd "M-<menu>") #'helm-run-external-command) (global-set-key (kbd "M-x") #'helm-M-x) (global-set-key (kbd "M-X") #'helm-run-external-command) ;; Buffers (define-key ctl-x-map "b" #'helm-mini) (global-set-key [remap list-buffers] #'helm-buffers-list) ;; Files (global-set-key [remap find-file] #'helm-find-files) (define-key ctl-x-map (kbd "C-r") #'helm-recentf) ;; Search (global-set-key (kbd "M-i") #'helm-semantic-or-imenu) (global-set-key (kbd "M-I") #'helm-imenu-in-all-buffers) (global-set-key (kbd "M-o") #'helm-occur) (global-set-key (kbd "M-s f") #'helm-find) (global-set-key (kbd "M-s g") #'helm-do-grep-ag) ;; Apropos (global-set-key [remap apropos-command] #'helm-apropos) (global-set-key [remap describe-function] #'helm-apropos) (global-set-key [remap describe-variable] #'helm-apropos) ;; Regexp (define-key help-map "r" #'helm-regexp) ;; Source code (global-set-key [remap find-library] #'helm-locate-library) (define-key help-map "l" #'helm-locate-library) ;; Kill ring (global-set-key (kbd "M-y") #'helm-show-kill-ring) ;; Mark rings (define-key help-map (kbd "SPC") #'helm-all-mark-rings) ;; Registers (global-set-key [remap insert-register] #'helm-register) ;; Bookmarks (define-key ctl-x-r-map "b" #'helm-filtered-bookmarks) ;; Chars (global-set-key [remap insert-char] #'helm-ucs) ;; Evaluation (define-key (current-global-map) [remap eval-expression] #'helm-eval-expression-with-eldoc) ;; Processes (define-key help-map "t" #'helm-top)
- Reduce sources for
helm-apropos
, which should improve speed.(customize-set-variable 'helm-apropos-function-list '(helm-def-source--emacs-commands helm-def-source--emacs-functions helm-def-source--emacs-variables helm-def-source--emacs-faces))
- Turn off popwin for Help buffers when using Helm and restore it after
existing Helm.
In a two-window configuration, Helm will display the Help buffer from persistent action in the other window. Having
popwin
for Help buffers brings up another, pop-up Help buffer.(defun *-popwin-help-mode-off () "Turn `popwin-mode' off for *Help* buffers." (when (boundp 'popwin:special-display-config) (customize-set-variable 'popwin:special-display-config (delq 'help-mode popwin:special-display-config)))) (defun *-popwin-help-mode-on () "Turn `popwin-mode' on for *Help* buffers." (when (boundp 'popwin:special-display-config) (customize-set-variable 'popwin:special-display-config (add-to-list 'popwin:special-display-config 'help-mode nil #'eq)))) (add-hook 'helm-minibuffer-set-up-hook #'*-popwin-help-mode-off) (add-hook 'helm-cleanup-hook #'*-popwin-help-mode-on)
- Use helm-dash, a Helm interface for Dash docsets.
To use
helm-dash
, first install docsets viahelm-dash-install-docset
. Docsets are installed tohelm-dash-docsets-path
, which is~/.docsets
by default.;; Set `helm-dash' to `C-h d', which is normally `apropos-documentation' (define-key help-map "d" 'helm-dash) ;; Set minimum entry length to display docset elements ;; 0 facilitates discoverability, but can be slow with too many docsets (customize-set-variable 'helm-dash-min-length 0)
- Use helm-descbinds to present keybindings.
(helm-descbinds-mode) ;; Show binding descriptions in same window (customize-set-variable 'helm-descbinds-window-style 'split-window)
- Fit image to window width.
(customize-set-variable 'image-auto-resize 'fit-width)
- Don’t cache images. The cache often causes Emacs to show an older version, leading to confusion.
(customize-set-variable 'image-cache-eviction-delay 0)
- Use better faces.
(set-face-attribute 'Info-quoted nil :family "Monospace" :inherit 'org-special-keyword :slant 'italic)
- Access commonly-used Info files through a hydra.
(defhydra hydra-helm-info (:color blue) " Common Lisp [_a_] all [_d_] dir [_r_] resume ^^^^^^--------------------------------------------------------------------------- [_s_] slime (SLIME) Emacs ^^^^^^--------------------------------------------------------------------------- [_e_] emacs (The Emacs Editor) [_i_] eintr (An Introduction to Programming in Emacs Lisp) [_l_] elisp (Emacs Lisp) [_o_] org (Org Mode Manual) Scheme ^^^^^^--------------------------------------------------------------------------- [_g_] guile (The Guile Reference Manual) " ("a" helm-info nil) ("d" Info-directory nil) ("e" helm-info-emacs nil) ("g" helm-info-guile nil) ("i" helm-info-eintr nil) ("l" helm-info-elisp nil) ("o" helm-info-org nil) ("r" info nil) ("s" helm-info-slime nil)) (define-key help-map "i" #'hydra-helm-info/body)
- Use
js2-mode
instead of the defaultjs-mode
.(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
- Style configs.
(with-eval-after-load 'js (customize-set-value 'js-indent-level 2))
- Use
helm
for keyboard macros.(define-key kmacro-keymap "h" #'helm-execute-kmacro)
- Use company-auctex for LaTeX completion.
(company-auctex-init)
- Display column numbers.
(column-number-mode t)
- Use macrostep, an interactive macro expanding tool. Great for checking
what your macro is expanding to!
;; `C-x e' is usually kmacro-end-and-call-macro, which we never use (define-key ctl-x-map "e" #'macrostep-expand) ;; Exit macrostep via macrostep-collapse-all with `C-g' (with-eval-after-load 'macrostep (define-key macrostep-keymap (kbd "C-g") #'macrostep-collapse-all))
- Bind the
magit-status
command, which is Magit’s entry point.(global-set-key (kbd "C-c m") #'magit-status)
- Don’t ask to save repository buffers.
(customize-set-variable 'magit-save-repository-buffers 'dontask)
- Bind
magit-section-toggle
to more convenient key.(defvar *-magit-spc-toggle-maps '(magit-diff-mode-map magit-revision-mode-map magit-status-mode-map magit-stash-mode-map) "`magit'-related mode maps in which `SPC' should be bound to toggle.") (with-eval-after-load 'magit (dolist (map *-magit-spc-toggle-maps) (define-key (symbol-value map) (kbd "SPC") #'magit-section-toggle)))
- Use pandoc as Markdown converter.
(if (executable-find "pandoc") (customize-set-variable 'markdown-command "pandoc"))
- Don’t hide URLs.
(customize-set-variable 'markdown-hide-urls nil)
- Disable the menu bar, but make it toggleable, since menus can be useful
for exploring new modes.
(menu-bar-mode -1) ;; Toggle menu bar (global-set-key (kbd "<f10>") #'menu-bar-mode) ;; F10 was originally `menu-bar-open'; bind that to C-<f10> instead (global-set-key (kbd "C-<f10>") #'menu-bar-open)
- Disable the toolbar.
(tool-bar-mode 0)
- Show time in the mode line.
;; Display time (display-time-mode t) ;; Time format (customize-set-variable 'display-time-string-forms '((propertize (concat dayname " " 12-hours ":" minutes " " (upcase am-pm)) 'help-echo (format-time-string "%a, %b %e %Y" now)))) ;; Update display-time-string (display-time-update) ;; Remove display-time-string from global-mode-string (setq global-mode-string (delq 'display-time-string global-mode-string))
- Show battery information in the mode line.
(display-battery-mode t) ;; Remove battery-mode-line-string from global-mode-string (setq global-mode-string (delq 'battery-mode-line-string global-mode-string))
- Modify mode line.
To get the battery and time information to align on the right end of the mode line, we fill the mode line with spaces. This is adapted from Nicolas Rougier’s StackOverflow Answer on this issue.
(defun *-mode-line-fill (reserve) "Return empty space using FACE and leaving RESERVE space on the right." (unless reserve (setq reserve 20)) (when (and window-system (eq 'right (get-scroll-bar-mode))) (setq reserve (- reserve 3))) (propertize " " 'display `((space :align-to (- (+ right right-fringe right-margin) ,reserve))))) (customize-set-variable 'mode-line-format '("%e" mode-line-front-space mode-line-client mode-line-remote mode-line-mule-info mode-line-modified " " ;; Buffer name (:propertize mode-line-buffer-identification face font-lock-builtin-face) " " ;; Position "%p (%l,%c)" " " ;; Mode, recursive editing, and narrowing information "(" (:propertize "%[" face font-lock-warning-face) mode-name (:propertize "%]" face font-lock-warning-face) (:eval (if (buffer-narrowed-p) (concat " " (propertize "Narrow" 'face 'font-lock-warning-face)))) ")" ;; Version control (:eval (when vc-mode (concat " " vc-mode))) ;; Miscellaneous information " " mode-line-misc-info (:eval (*-mode-line-fill (+ (length battery-mode-line-string) 1 (length display-time-string)))) battery-mode-line-string " " display-time-string))
- Use helm-describe-modes, which provides a Helm interface to Emacs’s
describe-mode
.(global-set-key [remap describe-mode] #'helm-describe-modes)
- Use multiple-cursors to easily mark things.
;; Define C-x m prefix (C-x m is usually `compose-mail') (define-prefix-command '*-mc-map) (define-key ctl-x-map "m" '*-mc-map) ;; Globally useful (define-key *-mc-map "m" #'mc/mark-all-dwim) ;; Sometimes useful (define-key *-mc-map "i" #'mc/insert-numbers) (define-key *-mc-map "h" #'mc-hide-unmatched-lines-mode) (define-key *-mc-map "a" #'mc/mark-all-like-this) ;; Rarely useful (define-key *-mc-map "d" #'mc/mark-all-symbols-like-this-in-defun) (define-key *-mc-map "r" #'mc/reverse-regions) (define-key *-mc-map "s" #'mc/sort-regions) (define-key *-mc-map "l" #'mc/edit-lines) (define-key *-mc-map "\C-a" #'mc/edit-beginnings-of-lines) (define-key *-mc-map "\C-e" #'mc/edit-ends-of-lines)
- Open files in
octave-mode
.(add-to-list 'auto-mode-alist '("\\.m\\'" . octave-mode))
- Change keybindings.
(with-eval-after-load 'octave (define-key octave-mode-map (kbd "C-h a") nil) (define-key octave-mode-map (kbd "C-c C-z") #'inferior-octave) (define-key inferior-octave-mode-map (kbd "C-h a") nil) (define-key inferior-octave-mode-map [remap inferior-octave-dynamic-list-input-ring] #'helm-comint-input-ring))
- Look up Octave documentation in a pop-up.
(defun *-octave-help (f) "Return docs of function F as string." (inferior-octave-send-list-and-digest (list (format "help ('%s');\n" f))) (string-join inferior-octave-output-list "\n")) (defun *-octave-doc-popup () "Display documentation of an Octave function in a pop-up window." (interactive) (funcall (*-make-doc-command #'octave-help #'symbol-at-point))) (defun *-octave-doc-popup-on () "Turn `*-octave-doc-popup' by binding it to an appropriate key." (dolist (map (list octave-mode-map inferior-octave-mode-map)) (define-key map (kbd "C-h j") #'*-octave-doc-popup) (define-key map (kbd "C-h C-j") #'*-octave-doc-popup))) (add-hook 'octave-mode-hook #'*-octave-doc-popup-on) (add-hook 'inferior-octave-mode-hook #'*-octave-doc-popup-on)
- Universal open command.
(defun *-open-at-point () (interactive) (condition-case nil (org-open-at-point-global) (user-error (helm-find-files nil)))) (global-set-key (kbd "C-c o") #'*-open-at-point)
- Use Org-suggested keybindings for global Org commands.
(global-set-key (kbd "C-c a") #'org-agenda) (global-set-key (kbd "C-c c") #'org-capture) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c L") #'org-insert-link-global)
- Get back old structured templates behavior, which was removed in Orgmode 9.2.
(require 'org-tempo)
- Use Helm to jump to headlines.
(with-eval-after-load 'org (customize-set-variable 'helm-org-headings-fontify t) (define-key org-mode-map (kbd "M-i") #'helm-org-in-buffer-headings) (define-key org-mode-map (kbd "C-M-i") #'helm-org-parent-headings))
- Move across headlines more easily.
(with-eval-after-load 'org (define-key org-mode-map (kbd "M-p") #'outline-previous-visible-heading) (define-key org-mode-map (kbd "M-n") #'outline-next-visible-heading) (define-key org-mode-map (kbd "M-P") #'org-backward-heading-same-level) (define-key org-mode-map (kbd "M-N") #'org-forward-heading-same-level) (define-key org-mode-map (kbd "M-U") #'outline-up-heading))
- Automatically adjust footnotes after insert or delete. Simple
fn:N
will be renumbered, and all footnotes will be sorted.(customize-set-variable 'org-footnote-auto-adjust t)
- Set Org babel languages.
(org-babel-do-load-languages 'org-babel-load-languages '((clojure . t) (emacs-lisp . t) (lisp . t) (scheme . t)))
- Set Org export backends. This determines what options are available when
the export framework is used.
(customize-set-variable 'org-export-backends '(ascii html icalendar latex md))
- Replace ellipsis with less annoying symbol.
(customize-set-variable 'org-ellipsis "↴")
- Use toc-org to automatically generate a table of contents for Org
files. Useful mainly for GitHub.
(defun *-org-insert-toc () "Create table of contents (TOC) if current buffer is in `org-mode'." (when (eq major-mode 'org-mode) (toc-org-insert-toc))) (when (require 'toc-org nil t) (add-hook 'org-mode-hook #'toc-org-enable) (add-hook 'before-save-hook #'*-org-insert-toc))
- Don’t fontify source blocks natively.
(customize-set-variable 'org-src-fontify-natively nil)
- Use page-break-lines to convert form feed characters into
horizontal rules.
(with-eval-after-load 'page-break-lines (dolist (mode '(clojure-mode clojurec-mode clojurescript-mode clojurex-mode)) (cl-pushnew mode page-break-lines-modes))) (global-page-break-lines-mode)
- Use helm-pages to navigate pages.
(global-set-key (kbd "M-p") #'helm-pages)
- Use pdf-tools, a support library for PDF files that features fast
rendering, etc. Need to install external dependencies
first. Linux-only.
(if (string= system-type "gnu/linux") (pdf-tools-install t nil t))
- Increase garbage collection (GC) threshold to reduce frequency.
Taken from Bozhidar Batsov’s config file.
;; Reduce the frequency of garbage collection by making it happen on each 50MB ;; of allocated data (the default is on every 0.76MB) (customize-set-variable 'gc-cons-threshold 50000000)
- Use popwin, a popup window manager for Emacs which makes you free from
annoying buffers such like
*Help*
,*Completions*
,*compilation*
, etc.(require 'popwin) (popwin-mode t) ;; Set popup window height to 1/2 of frame height (customize-set-variable 'popwin:popup-window-height 0.5)
- Use projectile, a project interaction library, with
helm-projectile
.(projectile-global-mode t) (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map) ;; Use helm-projectile (customize-set-variable 'projectile-completion-system 'helm) (helm-projectile-on) ;; Truncate long lines with helm ;; Only seems to affect helm-projectile (customize-set-variable 'helm-truncate-lines t)
- Use
python3
when available.(let ((python3-cmd (if (string= system-type "windows-nt") "py" "python3"))) (when (executable-find python3-cmd) (customize-set-variable 'elpy-rpc-python-command python3-cmd) (customize-set-variable 'python-shell-interpreter python3-cmd)))
- Use ELPY.
(elpy-enable)
- Remap some ELPY commands.
(define-key elpy-mode-map (kbd "C-x C-e") #'elpy-shell-send-statement) (define-key elpy-mode-map (kbd "C-M-x") #'elpy-shell-send-top-statement) (define-key elpy-refactor-map (kbd "f") (cons (format "%sormat" (propertize "f" 'face 'bold)) #'elpy-format-code))
- Use the Black formatter when available.
(with-eval-after-load 'elpy (when (elpy-config--package-available-p 'black) (customize-set-variable 'elpy-formatter 'black)))
- Unbind
C-z
,C-x C-z
, which by default are bound tosuspend-frame
. No need to waste a preciousC-
key on this.(global-unset-key (kbd "C-z")) (global-unset-key (kbd "C-x C-z"))
- Unbind
C-x C-c
, which issave-buffers-kill-terminal
. Why would we ever want to quit Emacs?(global-unset-key (kbd "C-x C-c"))
- Define a function to clean up a Sass file using the
sass-convert
tool.(defun *-cleanup-sass () "Clean up Sass file" (interactive) (shell-command (format "/usr/local/bin/sass-convert %s %s" (shell-quote-argument (buffer-file-name)) (shell-quote-argument (buffer-file-name)))) (revert-buffer t t t))
- Specify Scheme program name.
(customize-set-variable 'scheme-program-name "guile")
- Function to run inferior Scheme process in other window.
(defun *-run-scheme-other-window () "Run Scheme inferior process in other window" (interactive) (other-window 1) (run-scheme scheme-program-name))
- Run Inferior Scheme in other window immediately after entering
scheme-mode
.(add-hook 'scheme-mode-hook (lambda () (save-selected-window (*-run-scheme-other-window)))) ;; Replace switch-to-scheme with *-run-scheme-other-window (with-eval-after-load 'scheme (define-key scheme-mode-map (kbd "C-c C-z") #'*-run-scheme-other-window))
- Inhibit scratch buffer text.
(customize-set-variable 'initial-scratch-message "")
- Disable the scrollbar.
(require 'scroll-bar) (scroll-bar-mode 0)
- Use convenient binding for
scroll-other-window-down
.(global-set-key (kbd "C-M-y") #'scroll-other-window-down)
- Prefer regexp versions of search and replace functions.
;; Search (global-set-key (kbd "C-s") #'isearch-forward-regexp) (global-set-key (kbd "C-r") #'isearch-backward-regexp) ;; Replace (global-set-key (kbd "M-%") #'query-replace-regexp)
- Bind
C-M-2
tomark-sexp
, becauseC-M-@
can be hard to reach on certain keyboards.(global-set-key (kbd "C-M-2") #'mark-sexp)
- Use custom pair insertion commands.
;; Without an argument, `insert-parentheses' inserts a pair of parentheses at ;; point. We don't need that since we use `smartparens', so make wrapping next ;; sexp the default behavior. (defun *-insert-pair (&optional arg open close) (interactive "p") (setq arg (or arg 1)) (save-excursion (condition-case nil (forward-sexp) (scan-error (setq arg nil)))) (insert-pair arg open close)) (defun *-insert-parentheses (&optional arg) (interactive "p") (*-insert-pair arg ?\( ?\))) (defun *-insert-brackets (&optional arg) (interactive "p") (*-insert-pair arg ?\[ ?\])) (defun *-insert-braces (&optional arg) (interactive "p") (let ((parens-require-spaces nil)) (*-insert-pair arg ?\{ ?\}))) (global-set-key (kbd "C-M-9") #'*-insert-parentheses) (global-set-key (kbd "M-ESC [") #'*-insert-brackets) (global-set-key (kbd "C-M-{") #'*-insert-braces)
- Use custom
move-past-close-and-reindent
(defun *-move-past-close-and-reindent () "Like `move-past-close-and-reindent', but insert a pair of parentheses." (interactive) (move-past-close-and-reindent) (insert-parentheses)) (defun *-move-past-close-and-reindent-brackets () "Like `move-past-close-and-reindent', but inserts a pair of brackets." (interactive) (move-past-close-and-reindent) (*-insert-brackets)) (defun *-move-past-close-and-reindent-braces () "Like `move-past-close-and-reindent', but inserts a pair of braces." (interactive) (move-past-close-and-reindent) (*-insert-braces)) (global-set-key (kbd "C-M-0") #'*-move-past-close-and-reindent) (global-set-key (kbd "C-M-]") #'*-move-past-close-and-reindent-brackets) (global-set-key (kbd "C-M-}") #'*-move-past-close-and-reindent-braces)
- Use
emmet-mode
for all markup.(add-hook 'sgml-mode-hook #'emmet-mode)
- View markup buffer in browser.
(with-eval-after-load 'sgml-mode (define-key sgml-mode-map (kbd "C-c w u") #'browse-url-of-buffer))
- In
shell-mode
, usehelm-comint-input-ring
forcomint-dynamic-list-input-ring
, which lists the input history.(define-key comint-mode-map [remap comint-dynamic-list-input-ring] #'helm-comint-input-ring)
- Use smartparens, a minor mode for Emacs that deals with parens pairs and
tries to be smart about it.
(require 'smartparens-config) ;; Use smartparens (smartparens-global-mode t) ;; Use show-smartparens, which highlights matched pairs (show-smartparens-global-mode) ;; Use smartparens-strict-mode for certain modes (mapc (lambda (hook) (add-hook hook #'smartparens-strict-mode)) '(markdown-mode-hook prog-mode-hook scss-mode-hook))
- Keybinding for
smartparens
, taken from the author’s config file.;; Foward/backward (defun *-forward-sexp () "Move forward sexp, depending on major mode." (interactive) (pcase major-mode (`clojure-mode (clojure-forward-logical-sexp)) (_ (sp-forward-sexp)))) (defun *-backward-sexp () "Move backward sexp, depending on major mode." (interactive) (pcase major-mode (`clojure-mode (clojure-backward-logical-sexp)) (_ (sp-backward-sexp)))) (define-key smartparens-mode-map (kbd "C-M-f") #'*-forward-sexp) (define-key smartparens-mode-map (kbd "C-M-b") #'*-backward-sexp) ;; Up/down (define-key smartparens-mode-map (kbd "C-M-d") #'sp-down-sexp) (define-key smartparens-mode-map (kbd "C-M-e") #'sp-up-sexp) (define-key smartparens-mode-map (kbd "C-M-a") #'sp-backward-down-sexp) (define-key smartparens-mode-map (kbd "C-M-q") #'sp-backward-up-sexp) (define-key smartparens-mode-map (kbd "C-M-`") #'beginning-of-defun) ;; Transpose (define-key smartparens-mode-map (kbd "C-M-t") 'sp-transpose-sexp) ;; Mark/kill/copy (global-set-key [remap mark-sexp] #'sp-mark-sexp) (define-key smartparens-mode-map (kbd "C-M-k") #'sp-kill-sexp) (define-key smartparens-mode-map (kbd "C-M-w") #'sp-copy-sexp) ;; Unwrap (define-key smartparens-mode-map (kbd "M-<delete>") #'sp-unwrap-sexp) (define-key smartparens-mode-map (kbd "M-<backspace>") #'sp-backward-unwrap-sexp) ;; Slurp/barf (define-key smartparens-mode-map (kbd "C-<right>") #'sp-forward-slurp-sexp) (define-key smartparens-mode-map (kbd "C-<left>") #'sp-forward-barf-sexp) (define-key smartparens-mode-map (kbd "C-S-<left>") #'sp-backward-slurp-sexp) (define-key smartparens-mode-map (kbd "C-S-<right>") #'sp-backward-barf-sexp) (define-key smartparens-mode-map (kbd "C-M-<backspace>") #'sp-splice-sexp-killing-backward) (define-key smartparens-mode-map (kbd "C-S-<backspace>") #'sp-splice-sexp-killing-around) ;; Indent (define-key smartparens-mode-map (kbd "C-M-<tab>") #'sp-indent-defun)
- Use
flyspell
withtext-mode
and its derivatives, andflyspell-prog-mode
with programming modes.(defun *-flyspell-mode-setup () "Hook function for `flyspell-mode'." (customize-set-variable 'flyspell-auto-correct-binding (kbd "C-;")) (flyspell-mode) (with-eval-after-load 'flyspell (define-key flyspell-mode-map (kbd "C-M-i") nil))) (defun *-flyspell-prog-mode-setup () "Hook function for `flyspell-prog-mode'." (customize-set-variable 'flyspell-auto-correct-binding (kbd "C-'")) (flyspell-prog-mode) (with-eval-after-load 'flyspell (define-key flyspell-mode-map (kbd "C-M-i") nil))) (add-hook 'text-mode-hook #'*-flyspell-mode-setup) (add-hook 'prog-mode-hook #'*-flyspell-prog-mode-setup)
- Inhibit the splash screen.
(customize-set-variable 'inhibit-splash-screen t)
- Use 4 spaces by default.
(setq-default tab-width 4)
- Do not use
yasnippet
interm-mode
.(add-hook 'term-mode-hook (lambda () (yas-minor-mode -1)))
- Use theme.
(load-theme 'zenburn t)
- Eliminate
vertical-border
by giving it the same color asdefault
face.(set-face-foreground 'vertical-border (face-background 'default))
- Use a better face for
eldoc-highlight-function-argument
.(custom-set-faces '(eldoc-highlight-function-argument ((t (:inherit font-lock-variable-name-face)))))
- Keys for toggling modes. Inspired by article from Endless Parentheses.
;; Toggle common modes (defhydra hydra-toggle (:color amaranth) " Appearance [_q_] quit ^^--------------------------------------------------------------------------- [_r_] rainbow-mode: %s(if (boundp 'rainbow-mode) rainbow-mode 'nil) [_w_] whitespace-mode: %s(if (boundp 'whitespace-mode) whitespace-mode 'nil) Debug ^^--------------------------------------------------------------------------- [_d_] debug-on-error: %`debug-on-error Editing ^--------------------------------------------------------------------------- [_%_] read-only-mode: %`buffer-read-only [_f_] auto-fill-mode: %`auto-fill-function [_s_] smartparens-mode: %`smartparens-mode [_S_] smartparens-strict-mode: %`smartparens-strict-mode [_t_] toggle-truncate-lines: %`truncate-lines [_v_] visual-line-mode: %`visual-line-mode Expansion ^^--------------------------------------------------------------------------- [_y_] yas-global-mode: %`yas-global-mode Spelling and Syntax ^^--------------------------------------------------------------------------- [_c_] flycheck-mode: %s(if (boundp 'flycheck-mode) flycheck-mode 'nil) [_p_] flyspell-mode: %s(if (boundp 'flyspell-mode) flyspell-mode 'nil) [_P_] flyspell-prog-mode: %s(if (boundp 'flyspell-prog-mode) flyspell-prog-mode 'nil) " ("%" read-only-mode nil) ("c" flycheck-mode nil) ("d" toggle-debug-on-error nil) ("f" auto-fill-mode nil) ("p" flyspell-mode nil) ("P" flyspell-prog-mode nil) ("r" rainbow-mode nil) ("s" smartparens-mode nil) ("S" smartparens-strict-mode nil) ("t" toggle-truncate-lines nil) ("v" visual-line-mode nil) ("w" whitespace-mode nil) ("q" nil nil :color blue) ("y" yas-global-mode nil)) (define-key ctl-x-map "t" #'hydra-toggle/body)
- Use spaces, not tabs, by default.
(customize-set-variable 'indent-tabs-mode nil)
- Clean up whitespace in the buffer before saving.
(add-hook 'before-save-hook #'whitespace-cleanup)
- Split the frame into two windows, left and right, if the frame is
maximized or fullscreen.
For some reason, simply adding our function to
after-make-frame-functions
does not work for the intial frame. It does work when usingemacsclient
, because the Emacs daemon always creates an invisible frame. We therefore make an explicit call to the function to make sure it gets called.See this article from EmacsNinja for more information.
(defun *-split-window (&optional frame) "Split the current frame into two windows horizontally." (with-selected-frame (or frame (selected-frame)) (split-window-horizontally) (other-window 1))) ;; Add function to after-make-frame-functions, which works only when using ;; emacsclient (add-hook 'after-make-frame-functions #'*-split-window) ;; Call function to split window explicitly if not using emacsclient (if (not (daemonp)) (*-split-window))
- Function to rotate buffers between windows in the current frame. When
there are two windows (which is most of the time), swap the buffers in
the windows. The cursor remains in the same buffer.
(defun *-rotate-buffers-in-windows (&optional arg) "Rotate buffers displayed in windows by ARG windows. If ARG is positive, rotate ARG windows clockwise. If ARG is negative, rotate -ARG windows counterclockwise. Nil defaults to 1 window. Raw prefix argumnt \\[universal-argument] defaults to -1. By 'clockwise', we mean that if windows W1, W2, W3 are displaying buffers B1, B2, and B3 respectively, then the result of calling this function without an argument is that W1 <- B3, W2 <- B1, W3 <- B2." (interactive "P") (require 'dash) (unless (minibufferp) (let* ((windows (window-list)) (numrot (cond ((consp arg) -1) (t (mod (prefix-numeric-value arg) (length windows)))))) (cl-mapcar (lambda (window buffer) (set-window-buffer window buffer)) windows (mapcar #'window-buffer (-rotate numrot windows))) (select-window (nth numrot windows)))))
- Hydra for working with windows.
(defhydra hydra-window (:color pink) " Windows [_q_] quit ^------------------------------------------------------------------------------ [_c_] ^^center [_-_]/[_=_] vertical shrink / enlarge [_[_]/[_]_] horizontal shrink / enlarge [_b_] ^^balance [_o_]/[_O_] point to other window / reverse [_r_]/[_R_] rotate buffers / counterclockwise [_v_]/[_V_] vertical split / delete " ("[" (shrink-window-horizontally 5) nil) ("]" (enlarge-window-horizontally 5) nil) ("-" (shrink-window 3) nil) ("=" (enlarge-window 3) nil) ("b" balance-windows nil) ("c" (centered-window-mode-toggle) nil) ("o" (other-window 1) nil) ("O" (other-window -1) nil) ("r" *-rotate-buffers-in-windows nil) ("R" (*-rotate-buffers-in-windows -1) nil) ("v" split-window-vertically nil) ("V" delete-other-windows-vertically nil) ("q" nil nil)) (define-key ctl-x-map "w" #'hydra-window/body)
- Use yasnippet, a template system.
(yas-global-mode t)
- Use
whitespace-mode
when writting snippets for YASnippet.(add-hook 'snippet-mode-hook #'whitespace-mode)
Microsoft Windows specific configurations. These should only apply when Emacs is being used on a Windows system.
- The
<menu>
key on Linux is referred to as the<apps>
key on Windows. We bindhelm-M-x
to this key.(if (string= system-type "windows-nt") (global-set-key (kbd "<apps>") #'helm-M-x))
- Use
Command
keys asMeta
instead ofSuper
.(when (string= system-type "darwin") (customize-set-variable 'mac-command-modifier 'meta) (customize-set-variable 'mac-option-modifier nil))
My Emacs configurations written in Org mode.
Copyright (c) 2014-2017 Tianxiang Xiong
This program 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 program 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.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.