- Emacs packages
- Interface
- Buffer editing
- Utilities
- Major modes
- Miscellaneous
- Start-up buffer
- Postface
Emacs now provide an entire ecosystem of packages, in various
repositories, and handles them through the package
utility. Emacs
packages can come from different repositories. We only activate the
official GNU repository, as well as MELPA-stable, MELPA and ORG:
(setq package-archives
'(("gnu" . "https://elpa.gnu.org/packages/")
("non-gnu" . "https://elpa.nongnu.org/nongnu/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("melpa" . "https://melpa.org/packages/")
;; ("org" . "https://orgmode.org/elpa/")
)
package-archive-priorities
'(
("non-gnu" . 20)
("melpa" . 10)
("gnu" . 5)
("melpa-stable" . 0)
))
We now load it and make sure Emacs does not load it automatically a second time at startup, after all configuration is loaded:
(package-initialize)
(setq package-enable-at-startup nil)
We can now automatically install the packages that are not in Debian repositories. We first list these packages:
(setq package-list '(
anzu ; current match and total matches information in the mode-line in various search modes.
auctex ; Write and format TeX files
auctex-latexmk ; Add LatexMk support to AUCTeX
auto-dark ; Switch from 2 themes following Gnome dark mode switch
beginend ; Redefine ~M-<~ (=beginning-of-buffer=) and ~M->~ (=end-of-buffer=)
bonjourmadame ; Say "Hello ma'am!"
buffer-move ; Move buffers to the left/top/right/bottom
centered-window ; Center the text of the window (if only one window)
circadian ; Switch from 2 themes following sunset/sunrise
;; col-highlight ; EmacsWiki not on MELPA anymore
company ; "Complete anything"
company-auctex ; Company support for AUCTeX
company-reftex ; Company support for RefTeX
company-math ; Company support for math mode
counsel ; Various completion functions using Ivy
counsel-world-clock ; Display world clock using Ivy
dimmer ; Visually highlight the selected buffer
dired-narrow ; Filter the listing produced by Dired
dired-quick-sort ; Persistent quick sorting of Dired buffers
dired-single ; Dired in a single buffer
eshell-git-prompt ; Themes for Emacs Shell (Eshell) prompt
ess ; Emacs Speaks Statistics
ess-smart-equals ; Flexible, context-sensitive assignment for R
ess-view-data ; Tidyverse-like view and manipulate data in R
expand-region ; Increase selected region by semantic units
flycheck ; On-the-fly syntax checking
flx ; Fuzzy matching
forge ; Access Git forges (GitHub/GitLab) from Magit
format-sql ; Reformat SQL code using sqlformat or pgformatter
highlight ; Highlighting commands
highlight-indent-guides ; Highlight indentation levels
imenu-list ; Show imenu entries in a separate buffer
ivy-bibtex ; Search and manage bibliographies using Ivy
ivy-prescient ; Simple but effective sorting and filtering
ivy-rich ; More friendly interface for Ivy
magit ; Text-based user interface to Git
magit-gitflow ; GitFlow plugin for Magit
markdown-mode ; Edit Markdown-formatted text
markdown-toc ; Generate a TOC in Markdown file
move-text ; Move current line or region up or down
multiple-cursors ; Multiple cursors
neotree ; File tree plugin
nord-theme ; Arctic, north-bluish clean and elegant theme
org-bullets ; UTF-8 bullets for Org-mode
org-contrib ; Org-mode contributed packages
pandoc-mode ; Interact with Pandoc
pdf-tools ; Support library for PDF files
polymode ; Multiple major modes inside a single buffer
poly-R ; R files support for Polymode
poly-markdown ; Markdown files support for Polymode
poly-noweb ; Noweb files support for Polymode
poly-org ; Org files support for Polymode
powerthesaurus ; Finding synonyms, antonyms, and related terms
redacted ; Hide current text
smex ; Smart M-x enhancement
sql-indent ; Syntax based indentation for SQL files
sqlite3 ; SQLite3 API
sqlup-mode ; Upcase SQL keyword and functions
string-inflection ; underscore -> UPCASE -> CamelCase conversion of names
tango-plus-theme ; Color theme loosely based on the tango palette
toc-org ; Up-to-date table of contents in Org files
web-mode ; Editing web templates
writeroom-mode ; Distraction-free writing
xkcd ; Read xkcd
yaml-mode ; Edit files in the YAML data serialization format
))
;; Markdown-mode from MELPA, and not MELPA stable
;; (setq package-pinned-packages
;; '((markdown-mode . "melpa")
;; (ivy-bibtex . "melpa")))
Then fetch the list of packages available and install the missing packages:
(unless package-archive-contents
(package-refresh-contents))
(dolist (package package-list)
(unless (package-installed-p package)
(package-install package)))
From now on, given that all packages are installed with a purpose, Emacs will silently accept redefinitions of functions by packages:
(setq ad-redefinition-action 'accept)
Additional Lisp functions (.el
files) are placed in the functions
folder of the Emacs profile:
(add-to-list 'load-path (concat user-emacs-directory "functions"))
Disable the splash screen, and open a specific note on startup:
(setq inhibit-startup-screen t)
Menu disabled by default. Show it with C-S-F1
:
(global-set-key [(ctrl shift f1)] 'menu-bar-mode)
Define a my-cache-dir
(~/.emacs.d/cache/
) folder for later use
(all caches, auto-saves, etc.).
(setq my-cache-dir (concat user-emacs-directory "cache/"))
With the help of the package circadian, Emacs can switch themes based on sunrise and sunset. I will use Tango Plus during the day, and Nord Emacs at night (with brightness of comments at 20%). Coordinates are for Southern France. **Note:** There is currently a bug with the switch to Nord theme at night…
(setq nord-comment-brightness 20)
;; (load-theme 'nord t)
;; Montpellier
(setq calendar-location-name "Montpellier, FR")
(setq calendar-latitude 43.6108)
(setq calendar-longitude 3.8767)
(setq circadian-themes '((:sunrise . tango-plus)
(:sunset . nord)))
;; (setq circadian-themes '(
;; (:sunrise . doom-one-light)
;; (:sunset . doom-one)
;; ;; ("11:37" . doom-one-light)
;; ;; ("11:38" . doom-one)
;; ))
(add-hook 'circadian-before-load-theme-hook
#'(lambda (theme)
(setq custom-face-attributes '())))
(circadian-setup)
With auto-dark, Emacs can switch to dark mode when the system itself switches to dark mode (consequently, dark mode needs to be enabled in the system; works for GNOME). I will use Tango Plus during the day, and Nord Emacs at night (with brightness of comments at 20%).
(setq nord-comment-brightness 20)
(setq auto-dark-light-theme 'tango-plus)
(setq auto-dark-dark-theme 'nord)
(auto-dark-mode t)
Frames (generally called windows) have a title instead of
emacs25@<computer>
:
(setq frame-title-format '(buffer-file-name "Emacs: %b (%f)" "Emacs: %b"))
Emacs will split horizontally preferably, instead of vertically:
;; (setq split-height-threshold 20)
;; (setq split-width-threshold 100)
(defun my-split-window-sensibly (&optional window)
(let ((window (or window (selected-window))))
(or (and (window-splittable-p window t)
;; Split window horizontally.
(with-selected-window window
(split-window-right)))
(and (window-splittable-p window)
;; Split window vertically.
(with-selected-window window
(split-window-below)))
(and (eq window (frame-root-window (window-frame window)))
(not (window-minibuffer-p window))
;; If WINDOW is the only window on its frame and is not the
;; minibuffer window, try to split it horizontally disregarding
;; the value of `split-width-threshold'.
(let ((split-width-threshold 0))
(when (window-splittable-p window t)
(with-selected-window window
(split-window-right))))))))
(setq split-window-preferred-function 'my-split-window-sensibly)
Visually highlight selected buffer, by dimming other buffers (package
dimmer
):
(require 'dimmer)
(setq dimmer-fraction 0.25)
(dimmer-configure-which-key)
(dimmer-configure-helm)
(dimmer-mode t)
Use M-<arrows>
to move between windows (package windmove
, built in
Emacs; see Org section to remove conflicts with Org):
(windmove-default-keybindings 'meta)
Next window with C-~
(key above TAB):
(global-set-key [C-dead-grave] 'other-window)
Swap buffers with buffer-move
(C-x <arrows>
):
(global-set-key (kbd "C-x <up>") 'buf-move-up)
(global-set-key (kbd "C-x <down>") 'buf-move-down)
(global-set-key (kbd "C-x <left>") 'buf-move-left)
(global-set-key (kbd "C-x <right>") 'buf-move-right)
Mouse wheel does not accelerate:
(setq mouse-wheel-progressive-speed nil)
Scroll 2 lines from the edge:
(setq scroll-margin 2)
Prevent lateral scrolling from touchpad to beep:
(global-set-key (kbd "<mouse-7>")
(lambda () (interactive)))
(global-set-key (kbd "<mouse-6>")
(lambda () (interactive)))
Visible bells (flashes the frame):
(setq visible-bell t)
Ediff split horizontally instead of vertically, and keep the Ediff window in the same frame:
(setq ediff-split-window-function 'split-window-horizontally)
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
Center text (in the width of the frame) with C-x C
:
(global-set-key (kbd "C-x C") 'centered-window-mode)
Empty scratch buffer:
(setq initial-scratch-message nil)
Lines soft wrapped at word boundary (with fringe indicators in the fringe
column), except for Dired, Grep, and Imenu-list buffers; F10
to toggle line
wrapping (activated by default):
(global-visual-line-mode 1)
(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))
(defun my-truncate-lines-enable ()
"Disable line truncation, even in split windows."
(let ((inhibit-message t) ; No messages in the echo area - needs emacs 25+
message-log-max ; No messages in the *Messages* buffer
truncate-partial-width-windows) ; No truncation in split windows
(visual-line-mode 0)
(toggle-truncate-lines 1)))
(add-hook 'dired-mode-hook #'my-truncate-lines-enable)
(add-hook 'grep-mode-hook #'my-truncate-lines-enable)
(add-hook 'imenu-list-major-mode-hook #'my-truncate-lines-enable)
(global-set-key [(f10)] 'toggle-truncate-lines)
Highlight current line globally (and toggle it with C-F10
):
(global-hl-line-mode)
(global-set-key [(ctrl f10)] 'global-hl-line-mode)
Highlight columns (col-highlight): C-S-F10
to toggle column highlight
mode.
(load-library "col-highlight")
(load-library "vline")
(global-set-key [(ctrl shift f10)] 'column-highlight-mode)
Highlight regions (highlight): F9
to highlight, C-F9
to move to
the next highlighted text, C-S-F9
to unhighlight everything.
;; (set-face-attribute 'highlight nil
;; :background "saddle brown")
(global-set-key [(f9)] 'hlt-highlight)
(global-set-key [(ctrl f9)] 'hlt-next-highlight)
(global-set-key [(ctrl shift f9)] 'hlt-unhighlight-region)
Highlight indentation in Programming mode (highlight-indent-guides
):
(add-hook 'prog-mode-hook 'highlight-indent-guides-mode)
(setq highlight-indent-guides-method 'character) ; use 'column for more visible guides
Count words in region using C-+
:
(global-set-key (kbd "C-+") 'count-words)
Kill THIS buffer with C-x k
:
(global-set-key (kbd "C-x k") 'kill-this-buffer)
Redacted with C-S-escape
; when in redacted
mode, enable read-only-mode
to
ensure that we don’t change what we can’t read:
(global-set-key [(ctrl shift escape)] 'redacted-mode)
(add-hook 'redacted-mode-hook (lambda () (read-only-mode (if redacted-mode 1 -1))))
Recenter with C-l
starts with top, then middle, then bottom:
(setq recenter-positions '(top middle bottom))
Beginend (with Emacs 25.3) to redefine M-<
(beginning-of-buffer
) and M->
(end-of-buffer
) so that point moves to meaningful beginning and end of buffers:
(beginend-global-mode)
Expand region with C-@
(then continue to expand by pressing @
or
contract by pressing -
):
(global-set-key (kbd "C-@") 'er/expand-region)
Saveplace: Go back to last position where the point was in a file
(save positions in <cache>/saved-places
):
(save-place-mode 1)
(setq save-place-file (concat my-cache-dir "saved-places"))
Use position registers (a sort of bookmark) with F1—F4
: C-F1
to
C-F4
to save a register, F1
to F4
to jump to a saved register:
(global-set-key [(f1)]
(lambda () (interactive) (jump-to-register 1 nil)))
(global-set-key [(ctrl f1)]
(lambda () (interactive) (point-to-register 1 nil)))
(global-set-key [(f2)]
(lambda () (interactive) (jump-to-register 2 nil)))
(global-set-key [(ctrl f2)]
(lambda () (interactive) (point-to-register 2 nil)))
(global-set-key [(f3)]
(lambda () (interactive) (jump-to-register 3 nil)))
(global-set-key [(ctrl f3)]
(lambda () (interactive) (point-to-register 3 nil)))
(global-set-key [(f4)]
(lambda () (interactive) (jump-to-register 4 nil)))
(global-set-key [(ctrl f4)]
(lambda () (interactive) (point-to-register 4 nil)))
Imenu lists the main parts of a document (sections, headers, etc.) to
navigate interactively a long document (bound to C-M-=
); we ask
Imenu to stay up to date automatically [NB: counsel-mode
supersedes
imenu
by =counsel-imenu=]:
(global-set-key (kbd "C-M-=") #'imenu)
(setq imenu-auto-rescan t)
;; (global-set-key [mouse-3] 'imenu)
Imenu-list
does the same in a (right-hand) side buffer, with focus in it,
loaded with ~C-F5 (\
and *
fold and unfold all headers):
(setq imenu-list-focus-after-activation t)
(global-set-key [(ctrl f5)] #'imenu-list-smart-toggle)
(add-hook 'imenu-list-major-mode-hook (lambda ()
(define-key imenu-list-major-mode-map (kbd "\\") #'hs-hide-all)
(define-key imenu-list-major-mode-map (kbd "*") #'hs-show-all)
(setq-local hs-hide-comments-when-hiding-all nil)))
Bookmarks are saved in <cache>/bookmarks
, are set with
C-S-F3
and listed with C-S-F4
:
(setq bookmark-default-file (concat my-cache-dir "bookmarks"))
(global-set-key [(ctrl shift f3)] 'bookmark-set)
(global-set-key [(ctrl shift f4)] 'list-bookmarks)
Add column number to the mode line:
(column-number-mode 1)
Anzu: display current match and total matches information in the
mode-line, and show replacement interactively. Replace is bound to
C-r
, and replace using a RegExp is bound to C-M-r
:
(global-anzu-mode 1)
(anzu-mode 1)
(global-set-key (kbd "C-r") 'anzu-query-replace)
(global-set-key (kbd "C-M-r") 'anzu-query-replace-regexp)
Custom mode-line, mostly simplified (shows if file modified, file name, Git branch, remote file, major mode, and position as `line:col (percent)`:
(setq-default mode-line-format '(
"%e" ; Error message about full memory
mode-line-front-space
"%* " ; Modified or read-only buffer
;; mode-line-frame-identification
mode-line-buffer-identification
" "
'(vc-mode vc-mode)
" "
mode-line-remote ; Remote file?
" "
;; mode-line-modes ; This includes minor modes
"%m" ; Only major mode
" "
mode-line-position
;; "%l:%c (%p)" ; line number : column number (percent)
(does not work with PDF mode)
mode-line-misc-info ; Not sure…
mode-line-end-spaces
))
Answer with y/n instead of yes/no:
(fset 'yes-or-no-p 'y-or-n-p)
Ivy for completion: =Ivy= comes with Counsel
as dependencies; needs
to install flx
for better sorting. Ivy mode and Counsel mode
everywhere (using ’prescient’ sorting):
(ivy-mode 1)
(counsel-mode 1)
(ivy-prescient-mode 1)
Simple customization (maximum size of 30% of screen instead of 25%;
add recent files and bookmarks to ivy-switch-buffer
; format counters
with (xx/XX)
; use input with C-p
; use fuzzy matching without space
between letters, except for Swiper (search)):
(setq
max-mini-window-height 0.30
ivy-use-virtual-buffers t
ivy-count-format "(%d/%d) "
ivy-use-selectable-prompt t
ivy-re-builders-alist '(
;; (swiper . ivy--regex-plus)
(counsel-M-x . ivy--regex-fuzzy)
(read-file-name-internal . ivy--regex-fuzzy)
(t . ivy--regex-plus))
ivy-initial-inputs-alist nil)
Ivy-resume (go back to state of last search) with C-S-s
:
(global-set-key (kbd "C-S-s") 'ivy-resume)
Cycle through buffers with Ivy
with C-TAB
(see Magit section to
remove conflicts with Magit; see Org section to remove conflicts with
Org):
(global-set-key (kbd "<C-tab>") 'ivy-switch-buffer)
Use ivy-rich
to add more information to Ivy results (only to switch
buffer so far):
(ivy-rich-mode 1)
(setq ivy-virtual-abbreviate 'full
ivy-rich-switch-buffer-align-virtual-buffer t
ivy-rich-path-style 'abbrev)
M-x
(counsel-M-x
with SMEX
) states are saved in the <cache>
folder:
(setq smex-save-file (concat my-cache-dir "smex-items"))
Use Counsel for enhanced M-x, Find File (C-x C-f
or C-x C-o
in other
window), yank from history (C-S-y
):
(setq counsel-find-file-at-point t)
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file)
(global-set-key (kbd "C-x C-o") 'find-file-other-window)
(global-set-key (kbd "C-S-y") 'counsel-yank-pop)
;; (global-set-key (kbd "<f1> f") 'counsel-describe-function)
;; (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
;; (global-set-key (kbd "<f1> l") 'counsel-find-library)
;; (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
;; (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
;; (global-set-key (kbd "C-c g") 'counsel-git)
;; (global-set-key (kbd "C-c j") 'counsel-git-grep)
;; (global-set-key (kbd "C-c k") 'counsel-ag)
;; (global-set-key (kbd "C-x l") 'counsel-locate)
;; (global-set-key (kbd "C-S-o") 'counsel-rhythmbox)
Use Swiper for enhanced search with C-s
(Swiper comes with Counsel
as a dependency):
(global-set-key (kbd "C-s") 'swiper)
Never use Tabs when indenting, use spaces instead:
(setq-default indent-tabs-mode nil)
C-z
undo:
(global-set-key (kbd "C-z") 'undo)
CUA mode used for rectangle selection with C-S-Ret
; global mark with
C-S-Space
:
(setq cua-rectangle-mark-key (kbd "C-S-RET"))
(cua-selection-mode t)
(global-set-key [(ctrl shift return)] 'cua-set-rectangle-mark)
Electric pair mode: Automatically close double quotes, back quotes, parentheses, square brackets and curly brackets:
(electric-pair-mode 1)
(setq electric-pair-pairs '(
(?\" . ?\")
(?\` . ?\`)
(?\( . ?\))
(?\[ . ?\])
(?\{ . ?\})
) )
Show matching parentheses and other characters (without any delay):
(setq show-paren-delay 0)
(show-paren-mode 1)
Automatically break long lines (set to 80 characters in the variable
fill-column
); turn it on and off with C-c q
:
(setq-default fill-column 80)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
(global-set-key (kbd "C-c q") 'auto-fill-mode)
Consider CamelCase as two words in programming modes:
(add-hook 'prog-mode-hook 'subword-mode)
Cycle between snake_case, lowerCamelCase and kebab-case using C-c
C-u
:
(global-set-key (kbd "C-c C-u") 'string-inflection-custom-cycle)
(setq string-inflection-skip-backward-when-done t)
(defun string-inflection-custom-cycle ()
"foo_bar => fooBar => foo-bar => foo_bar"
(interactive)
(string-inflection-insert
(string-inflection-custom-cycle-function (string-inflection-get-current-word))))
(fset 'string-inflection-cycle 'string-inflection-custom-cycle)
(defun string-inflection-custom-cycle-function (str)
"foo_bar => fooBar => foo-bar => foo_bar"
(cond
((string-inflection-underscore-p str)
(string-inflection-lower-camelcase-function str))
((string-inflection-lower-camelcase-p str)
(string-inflection-kebab-case-function str))
(t
(string-inflection-underscore-function str))))
Complete anything (company
), with TAB
((kbd "TAB")
for terminal;
[tab]
for graphical mode) to complete immediately, no delay and
aggressive completion:
(add-hook 'after-init-hook 'global-company-mode)
(with-eval-after-load 'company
(define-key company-active-map (kbd "TAB") #'company-complete-common)
(define-key company-active-map [tab] #'company-complete-common))
(setq company-idle-delay 0
company-echo-delay 0
company-dabbrev-downcase nil
company-minimum-prefix-length 2
company-selection-wrap-around t
company-transformers '(company-sort-by-occurrence
company-sort-by-backend-importance))
Multiple cursors (multiple-cursors
), choices are saved in the
cache
folder; F11
to have multiple cursors in all lines of a
region; C-F11
tries to be smart about marking everything you want
(can be pressed multiple times); C-S-F11
marks the next item like
the selection (use then arrows to select more/less); C-S-<left
click>
also set multiple cursors at mouse position:
(setq mc/list-file (concat my-cache-dir "mc-lists.el"))
(global-set-key [(f11)] 'mc/edit-lines)
(global-set-key [(ctrl f11)] 'mc/mark-all-dwim)
(global-set-key [(ctrl shift f11)] 'mc/mark-more-like-this-extended)
(global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click)
Magnar Sveen wrote a very useful function to evaluate and directly
replace a Lisp expression. For instance, evaluating (+ 1 2)
replaces
the expression by 3
(works in any buffer). It is bound to C-x C-y
:
(load-library "sexp-eval-and-replace")
(global-set-key (kbd "C-x C-y") 'sexp-eval-and-replace)
Move line(s) up and down with M-S-up~/~M-S-down
:
(global-set-key [M-S-down] 'move-text-down)
(global-set-key [M-S-up] 'move-text-up)
Sudden death! (with C-c C-d
):
(global-set-key (kbd "C-c C-d") 'sudden-death)
sort-lines
is case sensitive by default, which I don’t like. This makes it
case insensitive (to get the default behavior back: M-x set-variable [RETURN]
sort-fold-case [RETURN] nil [RETURN]
):
(custom-set-variables
'(sort-fold-case t t)
)
Emacs built-in spell check package is Ispell. A good approach is to
use Hunspell
as the spell check engine (needs to be installed), with
“en_US” as the default dictionary (C-S-F12
to change
dictionary). Flyspell
(spell check on the fly) is enabled by default
in all text files (C-F12
to toggle Flyspell), and in programming
mode (only in the comments) in programming files. F12
(or middle
click) opens the list of correction suggestions:
(setq ispell-program-name "hunspell"
ispell-local-dictionary "en_US")
(add-hook 'text-mode-hook 'turn-on-flyspell)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(global-set-key [f12] 'flyspell-correct-word-before-point)
(global-set-key [C-f12] 'flyspell-mode) ; + flyspell-buffer when on!
(global-set-key [C-S-f12] 'ispell-change-dictionary)
Syntax can be checked with the Flycheck package (need to install
lintr
package for R); I recommend to turn it on on demand (M-x
flycheck-mode
).
Thesaurus using Power Thesaurus with C-'
:
(global-set-key (kbd "C-'") 'powerthesaurus-lookup-word-dwim)
Default language environment is UTF-8:
(setq current-language-environment "UTF-8")
Don’t lock files and accepts simultaneous editing (no interlocking, which creates tmp lockfiles):
(setq create-lockfiles nil)
Auto-save in <cache>/save
(after 10 seconds or 100 characters):
(setq
auto-save-file-name-transforms `(("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'"
,(concat my-cache-dir "save/\\2") t))
auto-save-list-file-name (concat my-cache-dir "auto-save-list")
auto-save-interval 100
auto-save-timeout 10)
Backups in <cache>/save
(a backup happens everytime a file is open,
and then on each subsequent saves, except for files under version
control). Copy backup files, keep a versioned (numbered) backup, and
only keep the first 2 and last 2 versions of each backup:
(setq
backup-directory-alist `((".*" . ,(concat my-cache-dir "save/")))
backup-by-copying t
version-control t
kept-new-versions 2
kept-old-versions 2
delete-old-versions t)
List of recent files in <cache>/recentf
:
(setq recentf-save-file (expand-file-name "recentf" my-cache-dir))
Abbreviations (Abbrevs) are a way to save keystrokes by expanding words into longer text. Emacs can save abbreviations in the cache directory silently:
(setq abbrev-file-name (concat my-cache-dir "abbrev_defs"))
(setq save-abbrevs 'silently)
Dired
(launched in current directory with with F6
) lists directories first,
use case-insensitive sorting, refreshes automatically directories, intelligently
guesses where to copy (other window), and does not ask for confirmation for
recursive copies and deletes. Switch to WDired mode (to ‘write’ file names) with
C-F6
, go to bookmarks with $
, dynamically filter files and folders with /
(part of Dired-narrow), and ediff
two marked files with e
(with
dired-ediff-files
):
(setq
ls-lisp-use-insert-directory-program nil
ls-lisp-ignore-case t
ls-lisp-use-string-collate nil
dired-quick-sort-suppress-setup-warning t)
(setq
dired-listing-switches "-aBhl --group-directories-first"
;; dired-omit-files "^\\.$"
dired-auto-revert-buffer t
dired-dwim-target t
dired-recursive-copies (quote always)
dired-recursive-deletes (quote always))
(global-set-key (kbd "<f6>")
(lambda ()
(interactive)
(dired ".")))
(add-hook 'dired-mode-hook 'auto-revert-mode)
(eval-after-load "dired"
'(progn
(load-library "dired-ediff-files")
(hl-line-mode)
(define-key dired-mode-map [(ctrl f6)] #'dired-toggle-read-only)
(define-key dired-mode-map "/" 'dired-narrow)
(define-key dired-mode-map "e" 'dired-ediff-files)
))
dired-single reuses the current dired buffer to visit another directory, instead of creating a new buffer for the new directory: dired-quick-sort allows to interactively sort Dired buffers:
(eval-after-load "dired"
'(progn
(define-key dired-mode-map [return] 'dired-single-buffer)
;; (define-key dired-mode-map [mouse-1] 'dired-single-buffer-mouse) ; Does not work
(define-key dired-mode-map [remap dired-mouse-find-file-other-window]
#'dired-single-buffer-mouse)
(define-key dired-mode-map "^" 'dired-single-up-directory)
(define-key dired-mode-map [(backspace)] 'dired-single-up-directory)
))
(dired-quick-sort-setup)
Remove .
from the list of files/folders (and be silent about it):
(setq-default dired-omit-files-p t)
(setq
dired-omit-verbose nil
dired-omit-files "^\\.$"
dired-omit-extensions nil)
Use NeoTree to have a tree explorer on the side (bound to F5
; turn off
wrapping long lines); NeoTree uses case-insensitive sorting:
(setq neo-theme 'ascii)
(defadvice neo-buffer--get-nodes
(after neo-buffer--get-nodes-new-sorter activate)
(setq ad-return-value
(let ((nodes ad-return-value)
(comparator (lambda (s1 s2) (string< (downcase s1)
(downcase s2)))))
(apply 'cons (mapcar (lambda (x) (sort (apply x (list nodes))
comparator))
'(car cdr))))))
(global-set-key [(f5)] 'neotree-toggle)
;; (define-key neotree-mode-map (kb "RET")
;; (neotree-make-executor
;; :file-fn 'neo-open-file
;; :dir-fn 'neo-open-dir))
(add-hook 'neo-after-create-hook
#'(lambda (_)
(with-current-buffer (get-buffer neo-buffer-name)
(setq truncate-lines t))))
TRAMP history of connections in <cache>/tramp
, make completion
faster, shell history in standard location (“$HOME/.sh_history”),
backups of remote files disabled, and just to be sure, version control
is disabled on remote files (although VC is already disable entirely
below:
(setq
tramp-persistency-file-name (concat my-cache-dir "tramp")
remote-file-name-inhibit-cache nil
tramp-histfile-override nil
)
(add-to-list 'backup-directory-alist
(cons tramp-file-name-regexp nil))
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
Magit is a interface to Git completely integrated to Emacs. Once
installed, it pretty much works out of the box, there are just a
couple of settings to make it even smoother (use Ivy to complete;
links to Git-man; automatically refresh the repository’s status after
file save). We also bound Magit to F8
, and integrate Git-flow
(magit-gitflow
, started with C-f
) and Forge
(forge-dispatch-popup
started with '
) to Magit:
(load-library "magit-repository-directories")
(shell-command "git config --global status.showUntrackedFiles all") ; List files in folders
(global-set-key [(f8)] 'magit-status)
;; (setq vc-handled-backends (delq 'Git vc-handled-backends)) ; Remove Git from the list of backends handled by Emacs version control
;; (setq vc-handled-backends nil) ; Remove VC altogether
(setq
transient-history-file (concat my-cache-dir "transient/history.el")
magithub-dir (concat my-cache-dir "magithub/")
magit-completing-read-function 'ivy-completing-read
magit-view-git-manual-method 'man
magit-refs-show-commit-count 'all)
(with-eval-after-load 'magit
(load-library "magit-ls-files")
;; (setq magit-repolist-columns
;; '(("Name" 25 magit-repolist-column-ident nil)
;; ("Version" 25 magit-repolist-column-version nil)
;; ("D" 1 magit-repolist-column-dirty nil)
;; ("B<U" 3 magit-repolist-column-unpulled-from-upstream
;; ((:right-align t)))
;; ("B>U" 3 magit-repolist-column-unpushed-to-upstream
;; ((:right-align t)))
;; ("Path" 99 magit-repolist-column-path nil)))
;; (setcdr (cdr magit-repolist-columns)
;; (cons '("D" 1 magit-repolist-column-dirty nil)
;; (cddr magit-repolist-columns)))
(require 'forge)
(setq forge-database-file (expand-file-name "forge-database.sqlite" my-cache-dir))
(define-key magit-mode-map (kbd "K") 'magit-ls-files)
(add-hook 'after-save-hook 'magit-after-save-refresh-status))
(add-hook 'magit-mode-hook 'turn-on-magit-gitflow)
(with-eval-after-load 'magit-mode
;; C-tab is for ivy-switch-buffer
(define-key magit-mode-map [C-tab] nil)
;; (magithub-feature-autoinject t)
)
Emacs provide different possibilities to embed a Shell (for instance,
M-x shell
, M-x ansi-term
), with different advantages and
drawbacks. Here I setup Eshell (the Emacs shell, M-x eshell
), with
short names to redirect to buffers and completion that ignores
case. eshell-git-prompt enables detection of Git repositories and
brings a nice powerline:
(setq
eshell-buffer-shorthand t
eshell-cmpl-ignore-case t)
(eshell-git-prompt-use-theme 'powerline)
In Shell, use C-l
to send commands directly to the subshell (useful
for screen
for instance):
(with-eval-after-load 'shell
(define-key shell-mode-map (kbd "C-l")
(lambda (seq) (interactive "k") (process-send-string nil seq))))
Finally, a function shell-xterm
(C-F8
) launches a shell with
clearing capabilities (needed for screen
):
(load-library "shell-xterm")
(global-set-key [(ctrl f8)] 'shell-xterm)
Use PDF tools to view PDF (libpoppler-glib-dev
required):
(add-to-list 'auto-mode-alist '("\\.pdf" . pdf-tools-install))
(setq-default pdf-view-display-size 'fit-page) ; Start PDF in full page
(setq pdf-annot-activate-created-annotations t) ; Automatically annotate highlights
(add-hook 'pdf-view-mode-hook
#'(lambda ()
(pdf-misc-size-indication-minor-mode) ; Show Top/Bot number in mode line?
;; (pdf-links-minor-mode) ; Activate links
(pdf-isearch-minor-mode) ; Incremental search using normal isearch
(define-key pdf-view-mode-map (kbd "h") 'pdf-view-fit-height-to-window) ; Fit height with 'h'
(define-key pdf-view-mode-map (kbd "w") 'pdf-view-fit-width-to-window) ; Fit width with 'w'
(define-key pdf-view-mode-map (kbd "f") 'pdf-view-fit-page-to-window) ; Fit page with 'f' DOES NOT WORK!
;; Conflict with Pdf-Links minor mode, which uses 'f' for link search
(define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward) ; bound to `C-s`
;; (cua-mode 0) ; Turn off CUA so copy works
(define-key pdf-view-mode-map (kbd "M-w") 'pdf-view-kill-ring-save) ; Use normal isearch
(define-key pdf-view-mode-map (kbd "<C-home>") 'pdf-view-first-page) ; First page with C-Home
(define-key pdf-view-mode-map (kbd "<C-end>") 'pdf-view-last-page))) ; Last page with C-End
From within a PDF, use P
to fit the zoom to the page; h
or H
to
the height, w
or W
to the width; g
refreshes (reverts) the PDF;
C-s
for a regular text search; ?
opens the help of PDF
tools. Highlight: select text with the mouse, then C-c C-a h
,
annotate, then C-c C-c
to commit; C-c C-a t
and then mouse click
to add a text note somewhere to the pdf page; C-c C-a o
to
strike-through text, and C-c C-a D
and then click to delete an
annotation. List annotations with C-c C-a l
. Don’t forget to save
the PDF (C-x C-s
)!
Emacs comes with a built-in web browser: EWW. Use M-x eww
to run it;
<backspace>
goes to previous page; f
opens the page in external
browser (Firefox for me).
(with-eval-after-load 'eww
(define-key eww-mode-map "f" 'eww-browse-with-external-browser)
(define-key eww-mode-map [backspace] 'eww-back-url))
git clone –depth=1 -b master https://github.com/emacs-eaf/emacs-application-framework.git ~/.emacs.d/site-lisp/emacs-application-framework/
M-x eaf-install-and-update ???
cd emacs-application-framework chmod +x ./install-eaf.py ./install-eaf.py
(add-to-list 'load-path "~/.emacs.d/site-lisp/emacs-application-framework/")
(require 'eaf)
(require 'eaf-browser)
YAML-mode
for YAML headers/files:
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
Org mode comes with its own keybindings, (which can easily conflict
with other settings); RET
follows links.
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cc" 'org-capture)
(global-set-key "\C-cb" 'org-switchb)
(setq
org-replace-disputed-keys t
org-return-follows-link t)
Turn on indent mode, and use nice UTF-8 bullet points:
(setq org-startup-indented 1)
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
#
#
Table of contents with Toc-Org (just add a :TOC:
tag with
C-c C-q
in the first header, and the table of contents will be
automatically updated on file save):
(add-hook 'org-mode-hook 'toc-org-enable)
Org-babel can recognize code blocks from many different languages (Lisp,
Bash, R, etc.) and provides a way to edit them in their respective
mode (C-c '
; and same keybinding to close). However, polymode
provides an even better integration directly in the Org file. We load
a few languages:
(with-eval-after-load 'org
(org-babel-do-load-languages
'org-babel-load-languages
'((css . t)
(ditaa . t)
(emacs-lisp . t)
(latex . t)
(lilypond . t)
(org . t)
(shell . t)
(sql . t)
(R . t))))
Conflict of Org with windmove
(remove meaning or M-<arrows>
in
Org):
(with-eval-after-load 'org
;; C-tab is for ivy-switch-buffer
(define-key org-mode-map (kbd "<C-tab>") nil)
;; Prevent Org from overriding the bindings for windmove.
(define-key org-mode-map (kbd "M-<left>") nil)
(define-key org-mode-map (kbd "M-<right>") nil)
(define-key org-mode-map (kbd "M-<up>") nil)
(define-key org-mode-map (kbd "M-<down>") nil))
;; (define-key org-agenda-mode-map (kbd "M-<up>") nil)
;; (define-key org-agenda-mode-map (kbd "M-<down>") nil)
;; (define-key org-agenda-mode-map (kbd "M-<left>") nil)
;; (define-key org-agenda-mode-map (kbd "M-<right>") nil)
;; Add replacements for the some of keybindings we just removed. It
;; looks like Org already binds C-up and C-down separately from M-{
;; and M-}, so we can't use those. Users will just have to make do
;; with C-c <up> and C-c <down> for now.
;;
;; Now for Org Agenda on the other hand, we could use C-up and
;; C-down because M-{ and M-} are bound to the same commands. But I
;; think it's best to take the same approach as before, for
;; consistency.
;; (define-key org-mode-map (kbd "C-<left>") #'org-shiftleft)
;; (define-key org-mode-map (kbd "C-<right>") #'org-shiftright)
;; (define-key org-agenda-mode-map (kbd "C-<left>") #'org-agenda-do-date-earlier)
;; (define-key org-agenda-mode-map (kbd "C-<right>") #'org-agenda-do-date-later))
Give the correct path to the Ditaa java library:
(setq org-ditaa-jar-path (expand-file-name "/usr/share/ditaa/ditaa.jar"))
Integration of TaskJuggler with org-mode
, as to export projects to
Gantt charts:
(require 'ox-taskjuggler)
The main package for LaTeX in Emacs is AUCTeX. In this configuration,
AUCTeX integrates RefTeX (references), LatexMk and XeLaTeX
(compilation) and PDF Tools (visualization). Note that compilation
logs are not shown by default (use C-c C-l
to see them, or add
(setqTeX-show-compilation t)
in the LaTeX-mode-hook
). We start by
configuring the LaTeX mode (notably RefTeX, fold LaTeX environments
[F], Math mode [M], compilation as PDF [P], forward and inverse search
[S]):
(setq TeX-parse-self t ; Enable parse on load.
TeX-auto-save t ; Enable parse on save.
TeX-auto-local "/home/mathieu/.emacs.d/cache/auctex-auto" ; Parsed information saved in cache folder
TeX-style-local "/home/mathieu/.emacs.d/cache/auctex-style" ; Hand-generated information saved in cache folder
TeX-source-correlate-mode t ; Forward and inverse search with Synctex
TeX-clean-confirm nil ; Don't ask for confirmation to clean intermediary files
reftex-plug-into-AUCTeX t ; Plug RefTeX to AUCTeX
reftex-default-bibliography '("/home/mathieu/.biblio.bib") ; Default bib
TeX-auto-untabify t ; Replace Tabs by spaces on save
)
(add-hook 'LaTeX-mode-hook
(lambda ()
(TeX-global-PDF-mode t) ; Compile as PDF
(add-to-list 'TeX-command-list '("XeLaTeX" "%`xelatex%(mode)%' %t" TeX-run-TeX nil t))
(LaTeX-math-mode) ; Math mode
(turn-on-reftex) ; RefTeX on
(outline-minor-mode 1) ; Fold LaTeX sections
(TeX-fold-mode 1) ; Fold LaTeX environments
))
The compilation by LatexMk (a single call to perform all necessary LaTeX/BibTeX compilations) is performed through the auctex-latexmk package, which allows to have LatexMk as the default engine for LaTeX compilation:
(setq auctex-latexmk-inherit-TeX-PDF-mode t) ; LaTeXMk inherits PDF mode
(auctex-latexmk-setup)
(add-hook 'TeX-mode-hook (lambda () (setq TeX-command-default "LatexMk")))
We also enable completion for LaTeX commands using Company:
(with-eval-after-load "tex"
(company-auctex-init)
)
Finally, we enable the use of PDF tools to visualize the resulting PDF and refresh it automatically:
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))
TeX-source-correlate-start-server t)
(add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)
BibTex is managed with =bibtex-mode=, and searched through ivy-bibtex. It needs to know the location of the main bibliography (can handle several), where associated files are stored (their filename must start with the BibTeX key), and the list of potential extensions used there (PDF, DJVU, ZIP, etc.):
;; (autoload 'ivy-bibtex "ivy-bibtex" "" t)
;; ;; ivy-bibtex requires ivy's `ivy--regex-ignore-order` regex builder, which
;; ;; ignores the order of regexp tokens when searching for matching candidates.
;; ;; Add something like this to your init file:
;; (setq ivy-re-builders-alist
;; '((ivy-bibtex . ivy--regex-ignore-order)
;; (t . ivy--regex-plus)))
(require 'ivy-bibtex)
(setq
;; bibtex-completion-bibliography '("/home/mathieu/Work/Bibliography/BiblioMB.bib")
bibtex-completion-bibliography '("/home/mathieu/.biblio.bib")
;; bibtex-completion-library-path '("/home/mathieu/Work/Bibliography/PDF/")
bibtex-completion-library-path '("/home/mathieu/Public/Basille/Bibliographie/PDF")
bibtex-completion-find-additional-pdfs t
bibtex-completion-pdf-extension '(".pdf" ".djvu" ".ps" ".epub" ".mobi" ".zip")
)
By default a PDF will be open in Emacs (with pdf-tools
); alternatively, Evince
can also be used with P
:
(defun bibtex-completion-open-pdf-external (keys &optional fallback-action)
(let ((bibtex-completion-pdf-open-function
(lambda (fpath) (start-process "evince" "*helm-bibtex-evince*" "/usr/bin/evince" fpath))))
(bibtex-completion-open-pdf keys fallback-action)))
(ivy-bibtex-ivify-action bibtex-completion-open-pdf-external ivy-bibtex-open-pdf-external)
(ivy-add-actions
'ivy-bibtex
'(("P" ivy-bibtex-open-pdf-external "Open PDF file in external viewer (if present)")))
Add keywords
, journal
and booktitle
to fields to be searched (author
,
title
, year
, BibTeX key
, and entry type by default); fields to be
displayed: PDF, author, title, year, and journal/booktitle/type:
(setq bibtex-completion-additional-search-fields '(keywords journal booktitle)
bibtex-completion-display-formats
'(
(article . "${=has-pdf=:1} ${author:36} ${year:4} ${title:*} ${journal:40}")
;; (book . "${=has-pdf=:1} ${author:36} ${year:4} ${title:*} Book ")
(inbook . "${=has-pdf=:1} ${author:36} ${year:4} ${chapter:*} Book: ${title:34}")
(incollection . "${=has-pdf=:1} ${author:36} ${year:4} ${title:*} Book: ${booktitle:34}")
(inproceedings . "${=has-pdf=:1} ${author:36} ${year:4} ${title:*} Book: ${booktitle:34}")
(t . "${=has-pdf=:1} ${author:36} ${year:4} ${title:*} Type: ${=type=:34}")))
BibTeX file displayed in the order of the file (first entries at the top), and
does not use prescient
to sort:
(setq ivy-prescient-sort-commands '(:not swiper swiper-isearch ivy-switch-buffer ivy-bibtex))
(advice-add 'bibtex-completion-candidates
:filter-return 'reverse)
Finally, ivy-bibtex
is bound to C-c b
:
(global-set-key (kbd "C-c b") 'ivy-bibtex)
In BibTeX mode (e.g. when opening and editing the main bibliography), new
entries are created with C-c C-e
, like C-c C-e C-a
for articles, C-c C-e
C-t
for technical reports, and C-c C-e b
for books. When the point is on an
entry, pressing C-j
moves to the next field. C-c C-c
checks and cleans the
entry at point (including generation of key if it does not exist, alignment,
etc.). Use C-c C-q
to only format the entry nicely. If necessary, use M-x
bibtex-validate
to clean the entire bibliography. Note that BibTex is set to
keep alphabetic order of the bibliography; that requires initial sorting of the
.bib
file (use M-x bibtex-sort-buffer
if necessary). Full documentation for
BibTex mode is available here.
(defun current-date ()
(format-time-string "%Y.%m.%d"))
(defun bibtex-add-date-owner ()
;; Tyler https://emacs.stackexchange.com/users/262/tyler
;; https://emacs.stackexchange.com/a/46339
"Adds a timestamp and owner field to a bibtex entry.
Checks to make sure it doesn't exist first."
(interactive)
(save-excursion
(bibtex-beginning-of-entry)
(if (assoc "timestamp" (bibtex-parse-entry))
(message "timestamp already exists!")
(bibtex-make-field '("timestamp" nil current-date) t nil))
(bibtex-beginning-of-entry)
(if (assoc "owner" (bibtex-parse-entry))
(message "owner already exists!")
(bibtex-make-field '("owner" nil user-login-name) t nil))
))
(setq
bibtex-entry-format '(opts-or-alts required-fields numerical-fields whitespace realign unify-case sort-fields) ; Clean optional fields, remove brackets around numerical fields, remove white space, realign, unify case of entry type and fields, sort fields in predefined order
bibtex-align-at-equal-sign t ; Also align = sign
bibtex-autokey-name-year-separator "_" ; Underscore between Name and Year
bibtex-autokey-year-length 4 ; Year as YYYY
bibtex-autokey-name-case-convert-function 'capitalize ; Name with capitale
bibtex-autokey-titlewords 0 ; No title
bibtex-autokey-titleword-length 0 ; No title
bibtex-autokey-edit-before-use nil ; Don't edit before use
bibtex-user-optional-fields '( ; Additional fields: DOI, url, date, owner, abstract
("doi" "DOI for the entry")
("url" "URL for the entry")
("timestamp" "Time the entry was created" current-date)
("owner" "Owner of the entry" user-login-name)
("abstract" "Abstract for the entry"))
)
(add-hook 'bibtex-clean-entry-hook 'bibtex-add-date-owner)
(setq biblio-cleanup-bibtex-function #'bibtex-clean-entry)
(setq bibtex-maintain-sorted-entries t)
With =biblio.el=, we can further check out query CrossRef or arXiv (using
biblio-lookup
, then copy and insert with c
and i
; C
and I
do the same,
but additionally close the search window), or with the DOI (using
doi-insert-bibtex
).
Markdown-mode is used to edit Markdown files (.md
or .markdown
)
and is loaded automatically. We simply enable Math and a couple minor
tweaks:
(setq
markdown-command
(concat ; Use Pandoc to convert Markdown to HTML, to produce a
; standalone HTML document rather than a snippet, to enable
; MathJax (to render LaTeX as MathML), and to use Pygments
; for syntax highlighting of code blocks
"/usr/local/bin/pandoc"
" --from=markdown --to=html"
" --standalone --mathjax --highlight-style=pygments")
markdown-asymmetric-header t ; Asymetric headers (only # on the left)
markdown-enable-math t ; Enable mathematical expressions (LaTeX)
)
Additional home-made functions to deal with to-do items in Markdown (C-c C-t
to insert **TODO**
at beginning of the line, C-c C-d
to switch between
**TODO**/**DONE**, C-S-F5
to display an interactive list of to-do items in a
Grep top buffer):
(add-hook 'markdown-mode-hook
(lambda ()
(load-library "md-todo-library")
(local-set-key (kbd "C-c C-t") 'md-todo)
(local-set-key (kbd "C-c C-d") 'md-todo-done)
(local-set-key [C-S-f5] 'md-todo-list)
))
ESS to use R, edit R script, edit R documentation (Roxygen) and
prepare packages. R is not a prog-mode
, so it needs its own settings
in the ESS hook.
Use current directory as working directory
(setq ess-ask-for-ess-directory nil)
No startup message and no save on exit
(setq inferior-R-args "--quiet --no-save")
Run R dired with C-c r
:
(global-set-key (kbd "C-c r") 'ess-rdired)
All R buffers (including R Dired) except code on the right side; Help, magit also on the right side; Grep sticks to the top:
(setq display-buffer-alist
`(("*R Dired"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . right)
(slot . -1)
(window-width . 0.5)
(reusable-frames . nil))
("*R"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . right)
(slot . 1)
(window-width . 0.5)
(reusable-frames . nil)
(dedicated . t))
("*Help"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . right)
(slot . -1)
(window-width . 0.5)
(reusable-frames . nil))
("magit:"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . right)
(slot . -1)
(window-width . 0.5)
(reusable-frames . nil))
("COMMIT_EDITMSG"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . right)
(slot . -1)
(window-width . 0.5)
(reusable-frames . nil))
("magit-diff:"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . left)
(slot . -1)
(window-width . 0.5)
(reusable-frames . nil))
("*grep"
(display-buffer-reuse-window display-buffer-in-side-window)
(side . top)
(slot . -1)
(window-height . 0.33)
(reusable-frames . nil))
))
Width of R buffer automatically adjusted to window:
(setq ess-auto-width 'window)
When input is sent to the iESS buffer, does not wait for the process to finish, ensuring Emacs is not blocked:
(setq ess-eval-visibly 'nowait)
Evaluate complete chunk with C-c C-x
:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(define-key ess-r-mode-map (kbd "C-c C-x")
#'polymode-eval-chunk)
(define-key inferior-ess-r-mode-map (kbd "C-c C-x")
#'polymode-eval-chunk))))
Try to match the style of the R parser as much as possible; Roxygen string for comments with only one pound for compatibility with RStudio:
(setq ess-style 'OWN)
(custom-set-variables
'(ess-own-style-list
(quote
((ess-indent-offset . 4)
(ess-indent-from-lhs)
(ess-indent-from-chain-start)
(ess-indent-with-fancy-comments . t)
(ess-offset-arguments . prev-line)
(ess-offset-arguments-newline . prev-line)
(ess-offset-block . prev-line)
(ess-offset-continued . straight)
(ess-align-nested-calls)
(ess-align-arguments-in-calls)
(ess-align-continuations-in-calls . prev-line)
(ess-align-blocks control-flow))))
'(ess-roxy-str "#'"))
Use the R parser (ess-indent-region-as-r
), formatR
(ess-indent-region-with-formatr
) or styler
(ess-indent-region-with-styler
) to format R code. The later is bound
to C-M-\
ou M-x indent-region
.
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(load-library "ess-indent-region-r")
(set (make-local-variable 'indent-region-function)
'ess-indent-region-with-styler))))
Automagically delete trailing whitespace when saving R script files:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
#'(lambda()
(add-hook 'write-contents-functions
(lambda ()
(ess-nuke-trailing-whitespace)))
(setq ess-nuke-trailing-whitespace-p t))))
ESS should not use IDO for completion; use company instead:
(setq ess-use-ido nil)
ESS smart equals to cycle smartly through operators with =
(and includes the
new pipe |>
instead of magrittr’s pipe %>%
):
(custom-set-variables
'(ess-smart-equals-contexts
'((t
(comment)
(string)
;; (arglist "=" "==" "!=" "<=" ">=" "<-" "<<-" "%>%")
(arglist "=" "==" "!=" "<=" ">=" "<-" "<<-" "|>")
(index "==" "!=" "%in%" "<" "<=" ">" ">=" "=")
(conditional "==" "!=" "<" "<=" ">" ">=" "%in%")
;; (base "<-" "<<-" "=" "==" "!=" "<=" ">=" "->" "->>" ":=")
(base "<-" "<<-" "=" "==" "!=" "<=" ">=" "->" ":=")
(% "%*%" "%%" "%/%" "%in%" "%>%" "%<>%" "%o%" "%x%")
;; (not-% "<-" "<<-" "=" "->" "->>" "==" "!=" "<" "<=" ">" ">=" "+" "-" "*" "**" "/" "^" "&" "&&" "|" "||")
(not-% "<-" "<<-" "|>" "=" "->" "->>" "==" "!=" "<" "<=" ">" ">=" "+" "-" "*" "**" "/" "^" "&" "&&" "|" "||")
;; (all "<-" "<<-" "=" "->" "->>" "==" "!=" "<" "<=" ">" ">=" "%*%" "%%" "%/%" "%in%" "%x%" "%o%" "%<>%" "%>%" "+" "-" "*" "**" "/" "^" "&" "&&" "|" "||")
(all "<-" "<<-" "=" "|>" "->" "->>" "==" "!=" "<" "<=" ">" ">=" "%*%" "%%" "%/%" "%in%" "%x%" "%o%" "%<>%" "%>%" "+" "-" "*" "**" "/" "^" "&" "&&" "|" "||")
;; (t "<-" "<<-" "->" "->>" "%<>%"))
(t "<-" "|>" "->" "%<>%" "<<-"))
(ess-roxy-mode
(comment "<-" "=" "==" "<<-" "->" "->>" "%<>%")))))
(with-eval-after-load 'ess-r-mode
(require 'ess-smart-equals)
(setq ess-smart-equals-extra-ops '(brace percent)) ; no 'paren'
(ess-smart-equals-activate))
C-=
to insert <-
and then cycle between <-
, |>
and ->
:
(setq ess-assign-list '(" <- " " |> " " -> "))
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(define-key ess-r-mode-map (kbd "C-=") #'ess-cycle-assign)
(define-key inferior-ess-r-mode-map (kbd "C-=") #'ess-cyle-assign))))
Change <-
into ←
, etc.:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(prettify-symbols-mode))))
Turn on flyspell-mode
for comments and strings:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(flyspell-prog-mode))))
Highlight indentation using ‘highlight-indent-guides’:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(highlight-indent-guides-mode))))
Consider CamelCase as two words:
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(subword-mode))))
Data viewer (launch with C-c v
; many operations available via ess-view-data-filter/select/slice/etc.
):
(require 'ess-view-data)
(with-eval-after-load "ess"
(add-hook 'ess-mode-hook
(lambda ()
(define-key ess-r-mode-map (kbd "C-c v")
#'ess-view-data-print)
(define-key inferior-ess-r-mode-map (kbd "C-c v")
#'ess-view-data-print))))
Integration in AUCTeX menu:
(setq ess-swv-plug-into-auctex-p t)
In (R)Markdown, add a fenced R code block (C-return
) or inline R
code (C-S-return
):
(add-hook 'markdown-mode-hook
(lambda ()
(load-library "ess-rmd-library")
(local-set-key [C-return] 'ess-rmd-fenced-r-code-block)
(local-set-key [C-S-return] 'ess-rmd-inline-r-code)
))
Render RMarkdown files (using rmarkdown::render
) with F7
; render
RMarkdown files (using bookdown::render_book
) with C-F7
; regular
Pandoc with C-S-F7
:
(with-eval-after-load 'polymode
(define-key polymode-mode-map [(f7)] #'ess-rmd-render)
(define-key polymode-mode-map [(ctrl f7)] #'ess-rmd-render-book)
(define-key polymode-mode-map [(shift ctrl f7)] #'ess-md-pandoc))
Syntax highlighting in Roxygen examples (removed from source code??!?):
(setq ess-roxy-fontify-examples t)
Remote R buffers
(defun ess-remote-r () ; Associate R remote buffer to ESS buffer
(interactive) (ess-remote nil "R"))
In an ESS inferior buffer, use C-l
to send commands directly to the
subshell (useful for screen
for instance):
(define-key inferior-ess-mode-map (kbd "C-l")
(lambda (seq) (interactive "k")
(process-send-string nil seq)))
Prompt sticks to the bottom of the buffer, not editable above (is this necessary?):
(eval-after-load "comint"
'(progn
(define-key comint-mode-map [up]
'comint-previous-matching-input-from-input)
(define-key comint-mode-map [down]
'comint-next-matching-input-from-input)
(setq comint-move-point-for-output 'others)
;; somewhat extreme, almost disabling writing in *R*, *shell* buffers above prompt:
(setq comint-scroll-to-bottom-on-input 'this)
))
SQL works already well out of the box. I set C-return
to send a
region (if selected) or the current paragraph:
(add-hook 'sql-mode-hook
(lambda ()
(load-library "sql-library")
(local-set-key (kbd "<C-return>") 'sql-send-region-or-paragrap)))
However, more configuration is required to have a beautiful code and readable output. First of all, sql-indent allows to indent correctly SQL code:
(with-eval-after-load 'sql (load-library "sql-indent"))
In addition to it, SQL-up automatically corrects lower case SQL
reserved names (SELECT
, FROM
, etc.). If necessary, it is called
with C-c u
on a region:
(add-hook 'sql-mode-hook 'sqlup-mode)
(add-hook 'sql-interactive-mode-hook 'sqlup-mode)
(add-hook 'sql-mode-hook
(lambda ()
(local-set-key (kbd "C-c u") 'sqlup-capitalize-keywords-in-region)))
To make it a step further, format-sql integrates the Python library of
the same name, and allows to completely format the code in a region
with C-M-]
(an alternative is SQL-beautify):
(add-hook 'sql-mode-hook
(lambda ()
(local-set-key (kbd "C-M-]") 'format-sql-region)))
Set up default PostgreSQL credentials:
(setq sql-postgres-login-params
'((server :default "localhost")
(port :default 5432)
(user :default "mathieu")
(database :default "test")))
In the output, we first make sure that lines are not truncated (DOES NOT WORK):
(add-hook 'sql-interactive-mode-hook
(lambda ()
;; (toggle-truncate-lines t)))
(setq truncate-lines t)))
(see [[https://github.com/hlissner/emacs-counsel-css][counsel-css]]
for integration of CSS selectors with Ivy)
Web-mode is a major mode to edit Web files ([s]HTML, CSS, PHP,
etc.). Here is a standard configuration, with auto-pairing, CSS
colorization and a broad list of file extensions and engines
associated to web-mode
:
(add-to-list 'auto-mode-alist '("\\.htm?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.shtml?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.css\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.jinga\\'" . web-mode))
(setq
web-mode-enable-auto-pairing t
web-mode-enable-css-colorization t
web-mode-engines-alist
'(("php" . "\\.phtml\\'")
("django" . "\\.jinja\\'")
("blade" . "\\.blade\\.")))
Spell check with flyspell can be further integrated to web-mode:
(defun web-mode-flyspell-verify ()
(let* ((f (get-text-property (- (point) 1) 'face))
rlt)
(cond
;; Check the words with these font faces, possibly.
;; this *blacklist* will be tweaked in next condition
((not (memq f '(web-mode-html-attr-value-face
web-mode-html-tag-face
web-mode-html-attr-name-face
web-mode-constant-face
web-mode-doctype-face
web-mode-keyword-face
web-mode-comment-face ;; focus on get html label right
web-mode-function-name-face
web-mode-variable-name-face
web-mode-css-property-name-face
web-mode-css-selector-face
web-mode-css-color-face
web-mode-type-face
web-mode-block-control-face)))
(setq rlt t))
;; check attribute value under certain conditions
((memq f '(web-mode-html-attr-value-face))
(save-excursion
(search-backward-regexp "=['\"]" (line-beginning-position) t)
(backward-char)
(setq rlt (string-match "^\\(value\\|class\\|ng[A-Za-z0-9-]*\\)$"
(thing-at-point 'symbol)))))
;; finalize the blacklist
(t
(setq rlt nil)))
rlt))
(put 'web-mode 'flyspell-mode-predicate 'web-mode-flyspell-verify)
Polymode allows multiple major modes in the same document (e.g. R +
Markdown in .Rmd
files). It is setup for Markdown and LateX files
with R:
(add-to-list 'auto-mode-alist '("\\.md" . poly-markdown-mode))
;; (add-to-list 'auto-mode-alist '("\\.[rR]md\\'" . poly-markdown+r-mode))
(add-to-list 'auto-mode-alist '("\\.[rR]md\\'" . poly-gfm+r-mode))
(add-to-list 'auto-mode-alist '("\\.[sS]nw\\'" . poly-noweb+r-mode))
(add-to-list 'auto-mode-alist '("\\.[rR]nw\\'" . poly-noweb+r-mode))
(add-to-list 'auto-mode-alist '("\\.org\\'" . poly-org-mode))
Navigate through chunks: C-PageUp
/ C-PageDown
go to previous/next
chunk; C-S-PageUp
/ C-S-PageDown
go to previous/next chunk of the
same type:
(with-eval-after-load 'polymode
(define-key polymode-mode-map [(C-prior)] #'polymode-previous-chunk)
(define-key polymode-mode-map [(C-next)] #'polymode-next-chunk)
(define-key polymode-mode-map [(C-S-prior)] #'polymode-previous-chunk-same-type)
(define-key polymode-mode-map [(C-S-next)] #'polymode-next-chunk-same-type))
XKCD: cache folder
(setq xkcd-cache-dir (concat my-cache-dir "xkcd"))
Opens the Start Here.md
file if no file is selected, with NeoTree on the left
(a little bit buggy):
(defun start-here ()
(find-file "/home/mathieu/Public/Notes/Start Here.md")
(neotree-toggle)
;; (other-window)
)
(setq initial-buffer-choice
(lambda ()
(if (buffer-file-name)
(current-buffer) ;; leave as-is
(start-here))))
Of course, the very last part of this init.org
file is the very
function that enables Emacs to regenerate both init.el
and
init.elc
files every time the init.org
file is saved:
(defun tangle-init ()
"If the current buffer is 'init.org' the code-blocks are
tangled, and the tangled file is compiled."
(when (equal (buffer-file-name)
(expand-file-name (concat user-emacs-directory "init.org")))
;; Avoid running hooks when tangling.
(let ((prog-mode-hook nil))
(org-babel-tangle)
(byte-compile-file (concat user-emacs-directory "init.el")))))
(add-hook 'after-save-hook 'tangle-init)