Hippocamplus My Second Memory

Emacs

I use Emacs for almost everything: coding, writing, taking notes, preparing presentations. I’m using it right now ! Well I mean, at the time I’m writing this. There is also a good chance I’m using it now now.

Basic configuration

Some of the basic tweaks in my .emacs file:

;; Disable startup screen
(setq inhibit-splash-screen t)
;; Turn the blinking off
(blink-cursor-mode 0)
;; Turn off the tool bar
(tool-bar-mode 0)
;; Change the font
(set-default-font "DejaVu Sans Mono 12")
;; Show column number
(setq column-number-mode t)

General commands

  • Counting words: select a region and press M-=. There are other ways for LaTeX.
  • In a console (R, Shell), previous/next line in the history is accessed by M-p/M-n. (Useful when ssh-tunneling with broken key-bindings).
  • Search for a regular expression in files using M-x lgrep command.
  • Evaluate lisp commands: C-M-x.
  • List key bindings currently available: C-h b.
  • List key bindings currently available starting with C-c: C-c C-h.
  • Narrow down to a region with C-x n n and widen back to the entire buffer with C-x n w (e.g. when refactoring).
  • Accents with C-x 8 (C-x 8 C-h for list).
  • Shift a selected chunk with spaces: C-x TAB or C-4 C-x TAB to add a specific number of spaces (here 4).
  • To insert a tab: C-q <tab>

Regexp replace :

  • Command: C-M-%.
  • \( and \) to define groups.
  • \1 to refer to the first group.

Console-size split screen

I put this function and key binding in my .emacs:

(defun consoleSplit ()
  (interactive)
  (save-excursion
    (split-window-below)
    (enlarge-window 15)))
(global-set-key (kbd "C-x 9") 'consoleSplit)

It splits the buffer in two and reduce the bottom buffer by 15 lines resulting in a large and a small buffer for example for a script and the console.

MELPA package repository

Usually packages are just .el files to download and add in the folder defined in .emacs (e.g. (add-to-list 'load-path "~/.emacs.d/lisp/")). However, there is easier way: MELPA package manager !

To install it, add to .emacs:

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

Then to find and install a new package, use M-x list-packages, find the package in the list and click on Install.

Solarized theme

I use Solarized theme palette. I installed the color-theme-sanityinc-solarized pacakge directly from MELPA. Then I added the dark version as default with (load-theme 'sanityinc-solarized-dark t). To change it interactively I run M-x load-theme and then for example sanityinc-solarized-light.

I also have an alias in my .bashrc to open emacs directly in light mode:

alias emacsl="emacs --eval \"(load-theme 'sanityinc-solarized-light t)\""

Note: a theme can be unloaded using M-x disable-theme.

For R

Emacs Speaks Statistics

ESS can be installed through MELPA. Otherwise, see below.

To install ESS, without needing the admin rights, the easiest way is to download and compile it in a dedicated folder (e.g. .emacs.d/lisp/ess):

git clone https://github.com/emacs-ess/ESS.git .emacs.d/lisp/ess
cd .emacs.d/lisp/ess
make

Then add these lines to ~/.emacs:

(add-to-list 'load-path "~/.emacs.d/lisp/ess/lisp/")
(load "ess-site")

I also have these ESS config:

(setq ess-default-style 'DEFAULT)
(setq ess-indent-level 2)
(setq ess-r-package-auto-set-evaluation-env nil)

The last one took me some times to figure out: when developing a R package, commands were evaluated in another environment so the objects didn’t exist in the usual R buffer (which was driving me crazy).

Auto-complete

To get auto-completion (with objects, functions or parameters) I use auto-complete. It’s also available through MELPA.

Then I configure it in my .emacs:

(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/lisp/ac-dict")
(ac-config-default)
(setq ac-auto-start nil)
(define-key ac-mode-map [C-tab] 'auto-complete)
(define-key ac-completing-map "\t" 'ac-complete)
(define-key ac-completing-map "\r" nil)
(setq ac-quick-help-delay 0.1)

Smart underscores

By default, pressing underscore will insert a <- instead of a _. This was supposed to ease the pain of writing assignments with the arrow. However now we want a _ most of the time (e.g. for ggplot2 functions). Using smart underscore, <- will be inserted only when following a space.

Available in MELPA. Otherwise simply put this .el file in the load path and add these lines to ~/.emacs:

(require 'ess-smart-underscore)
(setq ess-S-underscore-when-last-character-is-a-space t)

Poly-mode for R + Markdown

With polymode (MELPA), the mode depends on the position of the cursor in the document. For R + Markdown it means that we can edit the Markdown part in the markdown-mode and run the R code as if in a R script.

I added this to my .emacs:

(require 'poly-R)
(require 'poly-markdown)
(add-to-list 'auto-mode-alist '("\\.Rmd\\'" . poly-markdown+r-mode))

Custom keyboard shortcuts

To render RMarkdown

I tweaked a function to run rmarkdown::render on the current buffer and I created a shortcut for it.

In .emacs:

(defun renderRmd ()
  (interactive)
  (save-excursion
    (message "Rendering %S" (buffer-file-name))
    (setq ess-command (format "rmarkdown::render(%S)" (buffer-file-name)))
    (ess-execute ess-command 'buffer nil nil)))
(add-hook 'ess-mode-hook
          (lambda ()
            (local-set-key (kbd "C-c C-d C-r") 'renderRmd)))

To send a dev.off()

When working remotely, I send dev.off() to the R buffer using C-c C-d C-d to “update” the PDF opened from the mounted server.

In .emacs:

(defun devoff ()
  (interactive)
  (save-excursion
    (message "Closing device")
    (setq ess-command "dev.off()")
    (ess-execute ess-command 'buffer nil nil)))
(add-hook 'ess-mode-hook
          (lambda ()
            (local-set-key (kbd "C-c C-d C-d") 'devoff)))

Note: I use options(device=function() pdf(width=9, height=7)) to specify the dimensions of the default Rplots.pdf created.

For writing

Spell checking

I use ispell and flyspell.

To turn on automatically the live spell check for Latex and markdown documents:

(add-hook 'LaTeX-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode)

I use the american dictionary by default:

(setq ispell-dictionary "american")
(setq ispell-local-dictionary "american")

Thesaurus and synonyms

I use the synosaurus package available in MELPA. It’s not as user friendly as some online resources but a good offline alternative. It uses the WordNet database through the wn command line. The shortcut to list synonyms is C-c C-s l.

In my .emacs I added the synosaurus-mode minor mode:

(add-hook 'LaTeX-mode-hook 'synosaurus-mode)

Grammar checking

The langtool package is available in MELPA. It uses the LanguageTool JAR to highlight potential grammar problems. In my .emacs:

(require 'langtool)
(setq langtool-language-tool-jar "/usr/local/Cellar/languagetool/3.8/libexec/languagetool-commandline.jar")
(setq langtool-default-language "en-US")
(setq langtool-mother-tongue "fr")
(setq langtool-disabled-rules '("MORFOLOGIK_RULE_EN_US"))

MORFOLOGIK_RULE_EN_US corresponds to spelling mistakes, which I don’t want to see because I do the spell-checking separately better with ispell. The list of rules is here. For example, I could disabled WHITESPACE_RULE for LaTeX.

Then:

  • M-x langtool-check to highlight problems.
  • M-x langtool-check-done to remove highlighting.

For LaTeX

I put some Emacs tricks (e.g. for table manipulation) on the LaTeX page.

I general I prefer to use AUCTeX (available through MELPA). It handles multi-file documents and keeps the annoying compilation buffer closed. My configuration is:

(setq TeX-PDF-mode t)
(setq-default TeX-master nil)
(setq LaTeX-verbatim-environments-local '("lstlisting"))

Word count

To count the full document, including \include/\input documents, I call texcount with M-x latex-word-count after adding this to the .emacs configuration:

(defun latex-word-count ()
  (interactive)
  (shell-command (concat "texcount " "-sum -inc -sub=section " (buffer-file-name))))

To count words in a selected region, I use detex to strip LaTeX commands and wc to count words:

(defun latex-wc-region (&optional b e) 
  (interactive "r")
  (shell-command-on-region b e "detex | wc -w"))

Chunk folding

Sometimes I like to fold chunk of the document to improve clarity, e.g. frames in beamer document or figure/table in a manuscript. I added to my .emacs:

(add-hook 'LaTeX-mode-hook (lambda ()
                 (add-to-list 'LaTeX-fold-env-spec-list '("[frame]" ("frame")))
                 (setq TeX-fold-macro-spec-list (list ()))
                 (TeX-fold-mode 1)))

Then the main key bindings are:

  • C-c C-o C-e folds an environment.
  • C-c C-o C-r folds a region.
  • C-c C-o i unfold an item.
  • C-c C-o C-f to switch the fold-mode on/off

Because I added frame in the list, I can select a bunch of frames, press C-c C-o C-r and they all get folded (but not the rest). Otherwise, I manually fold the frames/figures/tables that are distracting.

For Markdown

  • C-c C-s s bold (strong).
  • C-c C-s e italic (emphasis).
  • C-c C-s s code (code).
  • C-c C-o follow a link.
  • C-c C-x C-l to toggle the hide-url mode to get shorter links.
  • C-c C-p/C-c C-n jump to previous/next outline.

Table formatting

Pressing TAB when the cursor is in a heading will cycle through heading-only/full view.

M-x orgtbl-mode to format markdown tables.

Markdown live preview

markdown-preview-mode opens a page on the web browser and update it every time the buffer is saved.

For Python

Elpy python mode

Elpy combines several packages to provide a lot of nice features, e.g. code coloring, completion, syntax checks, formatting recommendations.

To install the dependencies for elpy:

pip install jedi autopep8 flake8

Then I have in my .emacs:

(package-initialize) ;; if not present already
(elpy-enable)
(setq elpy-company-add-completion-from-shell t)
(setq elpy-shell-use-project-root nil)
(setq elpy-shell-display-buffer-after-send t)

Keybindings that I use:

  • C-RET or C-c C-y C-e to send line to python and step.
  • C-c C-y r sends region to python. Same for function, class or buffer.
  • C-up/C-down navigates between lines with same indentation as the current line.
  • C-c C-d open doc for symbol on point.
  • C-c C-z switch to Python shell (or start one).
  • C-c C-n go to next flymake error (previous with p).
  • C-c C-e edit all occurrences of symbol on point for refactoring (narrow if needed).

Of note, I use the Jupyter console instead of the default interpreter. So pip install jupyter and in my .emacs:

(setq python-shell-interpreter "jupyter"
      python-shell-interpreter-args "console --simple-prompt"
      python-shell-prompt-detect-failure-warning nil)
(add-to-list 'python-shell-completion-native-disabled-interpreters
             "jupyter")

Send commands to a specific buffer

Sometimes I want to send the commands to a specific buffer. For example, when testing new packages within a Docker container, I start a shell buffer, run docker and python.

I installed isend from MELPA. Then I simply go to the code buffer and run M-x isend-associate RET *shell* RET. At this point C-Enter will send the command to the shell buffer.

For C/CPP

I’m following this tutorial.

  • The speedbar is nice to get an overview of the files. M-x speedbar.
  • A better speedbar is provided by sr-speedbar and toogled with M-x sr-speedbar-toggle.

Tags

I installed GNU Global and the ggtags package from MELPA. Then added to .emacs:

(require 'ggtags)
(add-hook 'c-mode-common-hook
          (lambda ()
            (when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'asm-mode)
              (ggtags-mode 1))))

(define-key ggtags-mode-map (kbd "C-c g s") 'ggtags-find-other-symbol)
(define-key ggtags-mode-map (kbd "C-c g h") 'ggtags-view-tag-history)
(define-key ggtags-mode-map (kbd "C-c g r") 'ggtags-find-reference)
(define-key ggtags-mode-map (kbd "C-c g f") 'ggtags-find-file)
(define-key ggtags-mode-map (kbd "C-c g c") 'ggtags-create-tags)
(define-key ggtags-mode-map (kbd "C-c g u") 'ggtags-update-tags)

Useful shortcuts:

  • M-. to jump to a definition or reference file.
    • M-p/M-n to switch among files with results.
    • M-, to go back to the previous positions.

More soon…

List occurrences of current word in the buffer.

For Shell

To open a shell buffer, type M-x shell.

Then I use the Emacs Speaks SHELL package, that adds all the nice commands to send lines/regions from a script to a Shell buffer. In my .emacs I added:

(require 'essh)
(defun essh-sh-hook ()
  (define-key sh-mode-map "\C-c\C-r" 'pipe-region-to-shell)
  (define-key sh-mode-map "\C-c\C-b" 'pipe-buffer-to-shell)
  (define-key sh-mode-map "\C-c\C-j" 'pipe-line-to-shell)
  (define-key sh-mode-map "\C-c\C-n" 'pipe-line-to-shell-and-step)
  (define-key sh-mode-map "\C-c\C-f" 'pipe-function-to-shell)
  (define-key sh-mode-map "\C-c\C-d" 'shell-cd-current-directory))
(add-hook 'sh-mode-hook 'essh-sh-hook)

The shortcuts are self-explanatory.

For WDL workflows

Install through MELPA:

  • wdl-mode for syntax highlighting and indentation.
  • poly-wdl to switch to “shell” mode within command chunks.

In my .emacs file:

  • (setq wdl-indent-level 4) to change the indentation size.
  • (setq-default indent-tabs-mode nil) to make sure tabs are made of spaces (WDL doesn’t like mixing spaces and tabs).

Eventually the minor mode whitespace-mode is useful to explicitly show spaces and double-check that none of the indentations are made of tabs.

There is also an LSP implementation for WDL that can be used by Emacs to provide syntax validation and (some) auto-completion.

  • Install through MELPA: lsp-mode, lsp-ui and company-lsp.
  • Install the LSP server for WDL: pip install wdl-lsp (or pip3).
  • Add to .emacs file:
(require 'lsp-mode)
(add-to-list 'lsp-language-id-configuration '(wdl-mode . "wdl"))
(defgroup lsp-wdl nil
  "LSP support for WDL."
  :group 'lsp-mode
  :link '(url-link "https://github.com/broadinstitute/wdl-ide"))
(defcustom lsp-wdl-server-command "wdl-lsp"
  "Command to start wdl-lsp."
  :group 'lsp-wdl
  :risky t
  :type 'file)
(lsp-register-client
 (make-lsp-client :new-connection (lsp-stdio-connection
                                   (lambda () lsp-wdl-server-command))
                  :major-modes '(wdl-mode)
                  :priority -1
                  :server-id 'wdl))
(add-hook 'wdl-mode-hook #'lsp)
;; Syntax validation interface
(require 'lsp-ui)
(add-hook 'lsp-mode-hook 'lsp-ui-mode)
(setq lsp-ui-sideline-enable nil)
;; To get some auto-completion
(require 'company-lsp)
(push 'company-lsp company-backends)

The first time a file is opened, lsp will ask what is the root of the project. This can be changed later using M-x lsp-workspace-folders-remove and M-x lsp-workspace-folders-add.

For file manipulation

To compare and merge two files, use Ediff mode by calling M-x ediff (or M-x ediff-buffers when diff should be done between existing buffers). Once launched press:

  • | to change the split mode (vertical/horizontal).
  • n/p to go to the next/previous difference.
  • a to put A’s version to B.
  • b to put B’s version to A.
  • q to quit.
  • ? to get the full list of shortcuts.

To visualize blanks (tabs, spaces, new lines) I use the minor mode whitespace-mode.

To insert a tab: C-q <tab>

CSV/TSV

I use the csv-mode and the command c-c c-a to align columns. By default it understand ,, ; and \t as separator. If not I think the variable to customize is csv-separators.

Dired mode

When opening a directory (C-x C-f), Emacs shows the files in Dired mode:

  • d/u mark/unmark files for deletion.
  • x deletes files marked for deletion.
  • % d regexp <RET> flags file matching a regexp.
  • R rename a file.
  • C copy a file.

For Version Control

The built-in interface supports Git:

  • C-x v + to pull.
  • C-x v d to show the status.
  • C-x v v to commit.
  • C-x v P to push.
  • C-x v i to add.
  • C-x v = to see differences.

A more popular Git interface is Magit. After installing magit using MELPA, invoke the main buffer with M-x magit-status (or C-x g) and then:

  • ? to list keystroke/commands.
  • F u to pull.
  • g to refresh.
  • s to stage file.
  • c c to commit.
  • P u to push.

Magit configuration in my .emacs:

(setq vc-handled-backends (delq 'Git vc-handled-backends))
(global-set-key (kbd "C-x g") 'magit-status)

For online notes

Evernote

I use Evernote for easily keep notes synchronized across computer, tablet and smartphone. And there is a Emacs mode for it (of course!).

To install it, first run:

gem install evernote_oauth
git clone https://github.com/pymander/evernote-mode
cd evernote-mode/ruby
ruby setup.rb

I had an error with the last command and fixed it by changing ::Config::CONFIG with ::RbConfig::CONFIG in setup.rb.

Then, copy evernote-mode.el to the load path and add to .emacs:

(require 'evernote-mode)
(setq evernote-developer-token "<MYTOKEN>")
(setq evernote-username "<MYUSERNAME>")
(setq evernote-enml-formatter-command '("w3m" "-dump" "-I" "UTF8" "-O" "UTF8"))
(global-set-key "\C-cec" 'evernote-create-note)
(global-set-key "\C-ceo" 'evernote-open-note)
(global-set-key "\C-ces" 'evernote-search-notes)
(global-set-key "\C-ceS" 'evernote-do-saved-search)
(global-set-key "\C-cew" 'evernote-write-note)
(global-set-key "\C-cep" 'evernote-post-region)
(global-set-key "\C-ceb" 'evernote-browser)

I retrieved my developer token (to use instead of <MYTOKEN>) there.

Side notes:

  1. I also had to install w3m software.
  2. By default the notes are in read-only XHTML mode, I use M-x evernote-change-edit-mode TEXT to change the edit mode to text.

Simplenote

I now use Simplenote instead of Evernote, in order to make sure that I have an offline version of my notes at all time. Moreover it integrates (almost completely) the Markdown format. It makes it easy to take notes and to transfer them in our wiki (e.g. for conference notes). It’s also easier to clean the notes through emacs compared to the online page or apps.

There is a Emacs package that can be installed using MELPA: M-x package-install [RET] simplenote2 [RET].

The Simplenote buffer can be summoned by M-x simplenote2-browse or M-x simplenote2-list.

In list mode, the relevant commands are:

  • g: sync with the server.
  • a: create a new note
  • d: mark note on the current line for deletion
  • u: unmark note on the current line for deletion
  • t: set tags for filtering
  • ^: toggle tags filtering condition between “AND” and “OR”

Other general commands include:

  • simplenote2-add-tag and simplenote2-delete-tag
  • simplenote2-set-markdown

File encryption

Encryption is integrated directly. Just add the extension .gpg to a file.

On HPCs

  • See how to setup GNU screen to avoid visual glitches in the Shell section.
  • M-x ess-remote to use a shell buffer as R buffer to send commands to. For example to send commands from a local R script to an R session on a server (connected through ssh in the shell buffer), or on an interactive job (launched in the shell buffer).

For OSX

Here are some bits of configuration specific to OSX.

Maximize window at opening

Using the maxframe elisp from Ryan McGeary. I’ll copy the maxframe.el in the master branch of this repo in case it disappears.

(require 'maxframe)
(add-hook 'window-setup-hook 'maximize-frame t)

Keybindings

To change the annoying OSX bindings: paragraph jumping, home/end for line not page.

(define-key function-key-map (kbd "M-<down>") 'forward-paragraph)
(define-key function-key-map (kbd "M-<up>") 'backward-paragraph)
(global-set-key (kbd "<home>") 'beginning-of-line)
(global-set-key (kbd "<end>") 'end-of-line)

Ispell

To specify where is ispell located.

(setq ispell-program-name "/usr/local/Cellar/ispell/3.4.00/bin/ispell")

Also something about the right-click (I don’t remember why I have that).

(eval-after-load "flyspell"
    '(progn
       (define-key flyspell-mouse-map [down-mouse-3] #'flyspell-correct-word)
       (define-key flyspell-mouse-map [mouse-3] #'undefined)))

Explicit path definition

For LaTeX, I specified the PATH in .emacs:

(setenv "PATH" (concat (getenv "PATH") ":/usr/texbin"))
(setq exec-path (append exec-path '("/usr/texbin")))

For pandoc and ESS, I defined a RSTUDIO_PANDOC in .emacs:

(setenv "RSTUDIO_PANDOCPATH" (concat (getenv "RSTUDIO_PANDOC") ":/usr/local/bin"))