Choosing a suitable editor can be a hard problem. At least it is for me. For several years now, I am constantly switching back and forth between vim, Atom.io, and Visual Studio Code. Lastly, I really enjoyed using Atom due to its nice looking interface. However, on my system using my set of plugins, VScode was way faster. Realizing this, I remembered there is another editor many people prefer which I never had a closer look at. So, in this post I will dive into how I setup emacs to suit my writing needs for academia and coding needs for developers.
For now, let us start with the set of plugins I use, why I use them and how I configured them. I am pretty sure there might be better options for some tasks. If you know one, give me a hint in the comments section so that I can have a look at it.
This list only contains my absolute highlights in my config. There are some more plugins I use which you will notice when we have a closer look at the config itself. Following, however, I just want to note some of the commands I frequently use inside these plugins to manage my day-to-day tasks. Each plugin has detailed descriptions on how to use it, so check the links provided.
Important commands I use quite often:
Important commands I use quite often:
Now, the most interesting part is probably the setup in emacs itself. Together, let’s go through my .emacs file and see, what’s there and why. I am afraid I do not comment every line but will try the best to give an impression on what is done and why.
1(require 'package) 2(savehist-mode 1) 3(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/")) 4(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) 5(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/")) 6 7(add-to-list 'custom-theme-load-path "~/.emacs.d/themes") 8(load-theme 'atom-one-light t)
The block above ensures we can load plugins (l. 1, 3-5), the history of commands used is stored across sessions (l. 2). Finally, we load our favorite color/syntax theme
1(setq package-enable-at-startup nil) 2(setq inhibit-startup-message t) 3(setq-default left-margin-width 2 right-margin-width 2) 4(set-window-buffer nil (current-buffer)) 5(global-linum-mode t) 6(package-initialize) 7(unless (package-installed-p 'use-package) 8 (package-refresh-contents) 9 (package-install 'use-package)) 10(eval-when-compile (require 'use-package))
Next, we setup the window to start cleanly (l. 2-5) and initialize the package management (l. 1, 6-12).
1(use-package evil 2 :ensure t 3 :init 4 (setq evil-want-keybinding nil) 5 :config 6 (evil-mode t) 7 (modify-syntax-entry ?_ "w") 8 (use-package evil-commentary 9 :ensure t 10 :config 11 (evil-commentary-mode)) 12 (use-package evil-leader 13 :ensure t 14 :config 15 (global-evil-leader-mode) 16 (evil-leader/set-leader ",") 17 (evil-leader/set-key 18 "m" 'helm-M-x)) 19 (use-package evil-collection 20 :ensure t 21 :config 22 (evil-collection-init 'outline)))
The above code initializes the evil plugin as well as some additions to that. Note the special directives of the
:ensure t clause installs the necessary plugin if it is not present. This enables the reuse of the
.emacs config on a different machine as long as
use-package is installed there.
:init are executed before the packet is actually loaded, commands in
:config right after loading.
In the case of evil, I define the word text object to include underscores like it does in vim. Additionally, I define
, to be my leader key and map the helm plugin to
1(use-package magit 2 :ensure t 3 :config 4 (evil-leader/set-key 5 "g" 'magit))
We use magit and map it to
1(use-package darkroom 2 :ensure t) 3(use-package markdown-mode 4 :ensure t 5 :commands (markdown-mode gfm-mode) 6 :mode (("README\\.md\\'" . gfm-mode) 7 ("\\.md\\'" . markdown-mode) 8 ("\\.markdown\\'" . markdown-mode)) 9 :init (setq markdown-command "pandoc --natbib")) 10(use-package graphviz-dot-mode 11 :ensure t) 12(use-package sublimity 13 :ensure t 14 :config 15 (sublimity-mode 1))
We use darkroom and the markdown mode. The
:mode directive binds the markdown-mode to the provided file extensions. Additionally, we modify the default compile command to our needs, i. e.
pandoc --natbib (see also Academic Writing using Pandoc). As I like graphing with graphviz, we install a graphviz plugin.
Sublimity then provides us with smoother scrolling. However, this is not working very well for me. I am still looking for better options.
1(use-package powerline :ensure t :config (powerline-center-evil-theme))
We use the powerline module with the evil theme to not get lost in emacs’ mode universe.
1(use-package projectile 2 :ensure t 3 :config 4 (evil-leader/set-key 5 "p" 'projectile-command-map) 6 (projectile-mode +1)) 7(use-package better-defaults 8 :ensure t) 9(use-package helm 10 :ensure t 11 :config 12 (helm-mode 1) 13 (global-set-key (kbd "M-x") 'helm-M-x)) 14(use-package helm-projectile 15 :after helm 16 :ensure t 17 :config 18 (helm-projectile-on))
We use projectile for project management and map it to
,p. Additionally, we activate helm and remap the default
M-x command to
helm-M-x. This is done, to ensure we always run helm with its awesome fuzzy search. Finally, we activate helm’s projectile plugin.
1(use-package flycheck 2 :ensure t 3 :init 4 (global-flycheck-mode)) 5(use-package elpy 6 :ensure t 7 :config 8 (setq elpy-modules (delq 'elpy-module-flymake elpy-modules)) 9 (add-hook 'elpy-module-hook 'flycheck-mode) 10 (elpy-enable) 11 :bind(("M-g" . elpy-goto-definition)))
For python development, we install flycheck, a syntax checker with python support and enable it globally. As primary python development mode, I prefer elpy where we need to activate the corresponding flycheck mode and remap one of my favorite commands, i. e.
1(use-package php-mode 2 :ensure t) 3(use-package web-mode 4 :ensure t 5 :config 6 (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode)) 7 (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode)) 8 (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode)) 9 (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode)) 10 (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode)) 11 (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode)) 12 (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)) 13 (add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode)) 14 (add-hook 'web-mode-hook 15 (lambda () 16 (outline-minor-mode))) 17 (add-hook 'php-mode-hook 18 (lambda () 19 (outline-minor-mode))) 20 (setq web-mode-engines-alist 21 '(("php" . "\\.php\\'"))) 22 (setq web-mode-enable-current-column-highlight t) 23 (setq web-mode-enable-current-element-highlight t)) 24(defun my-web-mode-hook () 25 (set (make-local-variable 'company-backends) '(company-css company-web-html company-yasnippet company-files)) 26 ) 27(add-hook 'web-mode-hook 'my-web-mode-hook) 28(use-package emmet-mode 29 :ensure t 30 :config 31 (add-hook 'sgml-mode-hook 'emmet-mode) 32 (add-hook 'css-mode-hook 'emmet-mode) 33 (add-hook 'web-mode-hook 'emmet-mode) 34 (setq emmet-move-cursor-between-quotes t)) 35(add-hook 'web-mode-before-auto-complete-hooks 36 '(lambda () 37 (let ((web-mode-cur-language 38 (web-mode-language-at-pos))) 39 (if (string= web-mode-cur-language "php") 40 (yas-activate-extra-mode 'php-mode) 41 (yas-deactivate-extra-mode 'php-mode)) 42 (if (string= web-mode-cur-language "css") 43 (setq emmet-use-css-transform t) 44 (setq emmet-use-css-transform nil)))))
As I am also doing web development for some projects, I included configuration for the web-mode as well as a php-mode. The awesome emmet plugin is also great. However, I do not have much experience with any of them so don’t blame me for errors in that part of the config.
1(use-package all-the-icons 2 :ensure t) 3(use-package neotree 4 :ensure t 5 :config 6 (evil-leader/set-key 7 "t" 'neotree-toggle) 8 (setq neo-theme (if (display-graphic-p) 'icons 'arrow)) 9 (setq neo-smart-open t) 10 (setq projectile-switch-project-action 'neotree-projectile-action)) 11 12(evil-define-key 'normal neotree-mode-map (kbd "TAB") 'neotree-enter) 13(evil-define-key 'normal neotree-mode-map (kbd "SPC") 'neotree-quick-look) 14(evil-define-key 'normal neotree-mode-map (kbd "q") 'neotree-hide) 15(evil-define-key 'normal neotree-mode-map (kbd "RET") 'neotree-enter) 16(evil-define-key 'normal neotree-mode-map (kbd "g") 'neotree-refresh) 17(evil-define-key 'normal neotree-mode-map (kbd "n") 'neotree-next-line) 18(evil-define-key 'normal neotree-mode-map (kbd "p") 'neotree-previous-line) 19(evil-define-key 'normal neotree-mode-map (kbd "A") 'neotree-stretch-toggle) 20(evil-define-key 'normal neotree-mode-map (kbd "H") 'neotree-hidden-file-toggle)
Finally, we setup neotree to use
all-the-icons, map it to
,t and bind it to the projectile project management. This adds custom behavior to open the neotree view always we switch to a different project. I think that is quite handy to get a quick overview, where you just moved to.