Skip to content
Go to file
Cannot retrieve contributors at this time
1849 lines (1393 sloc) 45.1 KB

Rafa’s Emacs settings file


To use this change your init file for something like

(require 'org)
 (expand-file-name ""

Then you will only have your org file to handle all your emacs configuration. It may sound overkill in the beginning. It is not.

Use package

Bootstrapping use-package. This looks for use package in the system ans installs it if it is not there. This is the only package we need to install this way.

(unless (package-installed-p 'use-package)
  (package-install 'use-package))

  (require 'use-package))
(require 'diminish)                ;; if you use :diminish
(require 'bind-key)                ;; if you use any :bind variant


I’ll add homebrewe’d emacs packages to load path. We only have to do this in a Mac.

(if (eq system-type 'darwin)
  (let ((default-directory "/usr/local/share/emacs/site-lisp/"))


Unfortunately I can’t store any secret in this file since it will go to Github. I’ll leave a secrets file apart to define variables.

(load-file "~/.emacs.d/secrets.el")


Copy the environment variables from shell’s environment

(use-package exec-path-from-shell
  :ensure t
  :no-require t
  :config (progn
            (when (memq window-system '(mac ns))
            (exec-path-from-shell-copy-env "GEM_PATH")))

Editing settings

Let’s copy and paste in a regular Linux way

(cua-mode t)

I’ll add a function to edit file. I don’t need a shortcut since this is not such a common task now.

(defun settings ()
  "Edits file"
  (find-file "~/.emacs.d/"))


General UI

Make window undecorated

(set-frame-parameter nil 'undecorated t)

Remove scrollbars. One extra character per line and goodbye to that unthemed thing :P

(scroll-bar-mode -1)

Disable menu and icon bar

(menu-bar-mode -1)
(tool-bar-mode -1)

Show full path of file in status bar

(setq frame-title-format '(:eval (if (buffer-file-name) (abbreviate-file-name (buffer-file-name)) "%b")))

Paren highlight

(show-paren-mode 1)
(setq show-paren-delay 0)

Asking y/n instead of yes/no. Also preventing the dialog when on macos from being shown.

(defalias 'yes-or-no-p 'y-or-n-p)

(defadvice yes-or-no-p (around prevent-dialog activate)
  "Prevent yes-or-no-p from activating a dialog"
  (let ((use-dialog-box nil))
(defadvice y-or-n-p (around prevent-dialog-yorn activate)
  "Prevent y-or-n-p from activating a dialog"
  (let ((use-dialog-box nil))

We will use rainbow delimiters when possible

(use-package rainbow-delimiters
  :ensure t
  :init (add-hook 'prog-mode-hook #'rainbow-delimiters-mode))

Highlight current line


Do not show splash screen

(setq inhibit-splash-screen t)

Removing top bar in MacOS

(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))

Tab bar

(use-package centaur-tabs
  :ensure t
  :config (progn
            (setq centaur-tabs-style "chamfer"
                  centaur-tabs-set-bar 'under
                  centaur-tabs-height 20
                  centaur-tabs-set-icons t
                  centaur-tabs-set-modified-marker t)
            (centaur-tabs-mode t)
            (defun centaur-tabs-hide-tab (x)
              (let ((name (format "%s" x)))
                 (string-prefix-p "*epc" name)
                 (string-prefix-p "*helm" name)
                 (string-prefix-p "*Compile-Log*" name)
                 (string-prefix-p "*lsp" name)
                 (and (string-prefix-p "magit" name)
                      (not (file-name-extension name)))
  ("C-M-j" . centaur-tabs-backward)
  ("C-M-l" . centaur-tabs-forward))


Use spaces instead of tabs

(setq-default indent-tabs-mode nil)

Nothing bigger than 120 lines. This is nice also for code. ;). Anyway we can avoid the org node since this may make sense for longer texts.

(use-package whitespace
  :ensure t
  :diminish whitespace-mode
  :config (progn (setq whitespace-line-column 120)
                 (setq whitespace-style '(face empty tabs lines-tail trailing))
                 (setq whitespace-global-modes '(not org-mode web-mode "Web" emacs-lisp-mode))
                 (global-whitespace-mode t)))

Enable word wrap globally.

(global-visual-line-mode t)
(diminish 'visual-line-mode)

Theme and fonts

(use-package doom-themes
  :ensure t
  :config (progn
            (load-theme 'doom-one t)

(use-package doom-modeline
  :ensure t
  :hook (after-init . doom-modeline-mode)
  :config (setq doom-modeline-height 15))

Font. I like a ton of different fonts and I use them a lot. My choices are:

  • Hermit / light: Playful. Coding must be fun.
  • M+ 1mn / light: When you are feeling professional
  • Iosevka / normal (180): A shorter alternative to M+
  • Input Mono Compressed: Somewhat old school but really readable.
  • Source code pro: Wide but nice

To show the list of available fonts you can eval (print (font-family-list))

(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8)

(set-face-attribute 'default nil
                    :family "IBM Plex Mono"
                    :height 165
                    :weight 'regular
                    :width 'normal)

Manually setting font for managing Unicode symbols

(use-package unicode-fonts
  :ensure t
  :init (unicode-fonts-setup))

(set-fontset-font t 'unicode "Apple Color Emoji" nil 'prepend)


Smoother scrolling with mouse. This is the only thing I still miss from Sublime text

(setq mouse-wheel-follow-mouse 't)
(setq scroll-conservatively 101)
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1)))

Scrolling with keyboard before touching bottom.

(setq redisplay-dont-pause t
      scroll-margin 2
      scroll-step 1
      scroll-conservatively 10000
      scroll-preserve-screen-position 1)

(use-package smooth-scrolling
  :ensure t
  :init (setq smooth-scroll-margin 10))

Buffer listing

Let’s use ibuffer for buffer listing

(defalias 'list-buffers 'ibuffer)

Column indentation

This is useful in huge config files. In one project I’m dealing with huge yamls and this is great

(use-package highlight-indentation
  :ensure t)


Let’s loop gifs by default

(setq image-animate-loop 1)

Line numbers

Use emacs native line numbers

(global-display-line-numbers-mode t)


Incremental search in minibuffer

(iswitchb-mode 1)

By default arrow keys do not work in iswitchb This can solve it

(defun iswitchb-local-keys ()
  (mapc (lambda (K)
	  (let* ((key (car K)) (fun (cdr K)))
	    (define-key iswitchb-mode-map (edmacro-parse-keys key) fun)))
	'(("<right>" . iswitchb-next-match)
	  ("<left>"  . iswitchb-prev-match)
	  ("<up>"    . ignore             )
	  ("<down>"  . ignore             ))))
(add-hook 'iswitchb-define-mode-map-hook 'iswitchb-local-keys)


(setq mac-option-key-is-meta t)
(setq mac-right-option-modifier nil)
(setq mac-command-modifier 'super)

This is not too useful but it is awesome. This makes Fn key in Mac to be Hyper. I must admit that this is only here so I can make an hyper-space combo.

(setq ns-function-modifier 'hyper)  ; make Fn key do Hyper

There are some default mac bindings that are annoying to me. I will disable s-P for printing and all the function keys.

(global-unset-key (kbd "s-p"))
(global-unset-key (kbd "<f1>"))
(global-unset-key (kbd "s-w"))
(global-unset-key (kbd "<f2>"))
(global-unset-key (kbd "C-z"))

Mouse in terminal

This takes back mouse and makes it work in a terminal. Commented until I make terminal mode to work as I want.

(require 'mouse)
(xterm-mouse-mode t)
(defun track-mouse (e))
(setq mouse-sel-mode t)

Manipulating text

I like macos copy and paster better

(define-key global-map (kbd "s-x") 'kill-region)
(define-key global-map (kbd "s-c") 'kill-ring-save)
(define-key global-map (kbd "s-v") 'yank)
(define-key global-map (kbd "s-a") 'mark-whole-buffer)

This is a small script so ALT key drags lines up and down.

(use-package move-text
  :ensure t
  :bind (("M-<up>" . move-text-up)
         ("M-<down>" . move-text-down)))

Line duplication

(defun duplicate-line ()
  "Duplicates current line"
      ((text-to-insert (thing-at-point 'line)))
    (forward-line 1)
    (insert text-to-insert)
    (forward-line -1)))

(global-set-key (kbd "C-*") 'duplicate-line)

(defun eval-and-replace ()
  "Replace the preceding sexp with its value."
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))

(global-set-key (kbd "C-c C-e") 'eval-and-replace)

I don’t want ALT-backspace to change my kill ring since I don’t often want that there.

(defun delete-word (arg)
  "Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (backward-word arg) (point))))

(global-set-key (kbd "<M-backspace>") 'delete-word)


Moving in windows

This is a small snippet to move to next or previous windows with C-x p and C-x o

(global-set-key (kbd "C-x p") 'other-window)

(defun other-window-previous (&optional n)
  "Moves to previous window"
  (interactive "p")
  (other-window (if n (- n) -1)))

(global-set-key (kbd "C-x o") 'other-window-previous)

(global-set-key (kbd "C-x l") 'next-buffer)
(global-set-key (kbd "C-x j") 'previous-buffer)

Enabling winner mode to restore the configuration of window layout.

(winner-mode t)

Golden Ratio

This is a cool package to help in making the current window more prominent

(use-package golden-ratio
  :ensure t
  :diminish golden-ratio-mode
  (golden-ratio-mode 1))


Eyebrowse is extremely useful for temporarily maximize a window and then go back to its previous split state.

(use-package eyebrowse
  :ensure t
  :init (eyebrowse-mode t))


Much better undo than the default one.

(use-package undo-tree
  :ensure t
  :diminish undo-tree-mode
      (global-undo-tree-mode 1)
      (defalias 'redo 'undo-tree-redo)

      (global-set-key (kbd "s-z") 'undo)
      (global-set-key (kbd "s-Z") 'redo)))

This is binding the visualization to C-s-z but instead of that combo I need to use that strange status number.

(global-set-key (kbd "<C-s-268632090>") 'undo-tree-visualize)

Selecting text

Typing over a selection deletes text

(delete-selection-mode 1)

Expand region key binding.

(use-package expand-region
  :ensure t
  :bind (("C-s-e" . er/expand-region)
         ("C-s-E" . er/contract-region)))

These are multiple cursors bindings.

(use-package multiple-cursors
  :ensure t
  :bind (("C-d" . mc/mark-next-like-this)
         ("C-S-d" . mc/mark-previous-like-this)
         ("C-M-d" . mc/mark-all-like-this)
         ("H-SPC" . set-rectangular-region-anchor)))

Moving around

Avy jump

Avy jump is great for moving around. I use the new timer version. This was introduced in avy 0.4.0 and it is a really beautiful way of moving around. A combination of classical avy jump + isearch

(use-package avy
  :ensure t
  :bind ("C-c j" . avy-goto-char-timer))

Jumping with multiple cursors

Multiple cursors has smoe weird requirements. We can use jump to char or phi search in order to make it easier to move backwars and forward

(use-package jump-char
  :ensure t
  :bind (("C-c u" . jump-char-backward)
         ("C-c i" . jump-char-forward)))

(use-package phi-search
  :ensure t
  :bind (("C-S-s" . phi-search)
         ("C-S-r" . phi-search-backward)))

Goto URL

(add-hook 'text-mode-hook 'goto-address-mode)
(add-hook 'prog-mode-hook 'goto-address-prog-mode)

Dumb jump

For a personn that works in different languages this is awesome

(use-package dumb-jump
  :bind (("C-." . dumb-jump-go)
         ("C-:" . dumb-jump-quick-look)
         ("M-g b" . dumb-jump-quick-look))
  :config (setq dumb-jump-selector 'ivy)


(use-package yafolding
  :ensure t
  :init (add-hook 'ruby-mode-hook 'yafolding-mode)
  :bind (("<C-return>" . yafolding-toggle-element)))

Open in external editor

A small snippet to open current file in external editor.

TODO: give credit for this.

(defun open-with (arg)
  "Open visited file in default external program.
With a prefix ARG always prompt for command to use."

  (interactive "P")
  (when buffer-file-name
    (shell-command (concat
                     ((and (not arg) (eq system-type 'darwin)) "open")
                     ((and (not arg) (member system-type '(gnu gnu/linux gnu/kfreebsd))) "xdg-open")
                     (t (read-shell-command "Open current file with: ")))
                    " "
                    (shell-quote-argument buffer-file-name)))))

(global-set-key (kbd "C-c o") 'open-with)

White space handling

Remove trailing whitespace of the file

(add-hook 'before-save-hook 'delete-trailing-whitespace)


I am not very happy with no emacs terminal so I will stay using tmux and have some shortcuts here

(use-package emamux
  :ensure t
  :bind (("C-ç" . emamux:send-command)))


(require 'midnight)

Kill buffers if they were last disabled more than this seconds ago

(setq clean-buffer-list-delay-special 900)

(defvar clean-buffer-list-timer nil
  "Stores clean-buffer-list timer if there is one. You can disable clean-buffer-list by (cancel-timer clean-buffer-list-timer).")

;; run clean-buffer-list every 4 hours
(setq clean-buffer-list-timer (run-at-time t 14400 'clean-buffer-list))

;; kill everything, clean-buffer-list is very intelligent at not killing
;; unsaved buffer.
(setq clean-buffer-list-kill-regexps '("^.*$"))

Backup files

This will create a folder called $HOME/.saves-emacs that will contain all backups.

This is done so we avoid cluttering the folder where the file is being edited

   backup-by-copying t      ; don't clobber symlinks
    '(("." . "~/.saves-emacs"))    ; don't litter my fs tree
   delete-old-versions t
   kept-new-versions 6
   kept-old-versions 2
   version-control t)       ; use versioned backups


Enabling projectile for project management

(use-package projectile
  :ensure t
  :diminish projectile-mode ""
  :init (progn
          (setq projectile-enable-caching nil)
          (setq projectile-switch-project-action 'projectile-dired))
  :config (progn
            (projectile-mode +1)
            (define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
            (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)))


Let’s use Flycheck’s integration with ispell

(use-package flyspell
  :ensure t
  :bind (("C-S-s-<f8>" . cycle-ispell-languages)
         ("<f8>" . ispell-word))
  :init (progn
           (add-hook 'text-mode-hook 'flyspell-mode)
           (add-hook 'markdown-mode-hook 'flyspell-mode)

           (let ((langs '("english" "spanish")))
             (setq lang-ring (make-ring (length langs)))
             (dolist (elem langs) (ring-insert lang-ring elem)))

           (defun cycle-ispell-languages ()
             (let ((lang (ring-ref lang-ring -1)))
               (ring-insert lang-ring lang)
               (ispell-change-dictionary lang)))

           (ispell-change-dictionary "english")
           (setq flyspell-default-dictionary "english"))
  :config (unbind-key "C-," flyspell-mode-map))

And we can provide a thesaurus

(use-package synonyms
  :ensure t
  :bind ("S-<f8>" . synonyms)
  :init (progn
           (setq synonyms-file "~/.emacs.d/resources/synonyms/mthesaur.txt")
           (setq synonyms-cache-file "~/.emacs.d/resources/synonyms/mthesaur.cache")))

Writing mode

;;(use-package minimal-theme
;;  :ensure t)

(use-package writeroom-mode
  :ensure t
  :preface (defun my-writeroom-theme (arg)
              ((= arg 1)
                 (enable-theme 'minimal-light))
              ((= arg -1)
                 (disable-theme 'minimal-light)))))

Org mode

Org mode is one of the most awesome things in emacs.

Binding F7 to open a file in root of projectile and F3 to the agenda file.

  (require 'projectile)

  (defun my/projectile-open-personal-notes ()
    "Opens a file in project folder"
        ((folder (projectile-project-root)))
      (if folder
             (other-window 1)
             (find-file (concat folder "")))
        (message "No project folder found"))))

  (defun my/open-org-agenda ()
    "Opens agenda file"
             (other-window 1)
             (find-file "~/Nextcloud/org/")))

  (use-package org
    :ensure t
    (defun my/fix-inline-images ()
      (when org-inline-image-overlays
    :bind (("<f3>" . my/open-org-agenda)
           ("<f7>" . my/projectile-open-personal-notes)
           ("C-c c" . org-capture)
           ("C-c a" . org-agenda))
    :init (progn
            (setq org-startup-with-inline-images t)
;;            (setq org-hide-emphasis-markers t)  <- This is causing problems with asterisks in headers
            (setq org-default-notes-file "~/Nextcloud/org/")
            (setq org-capture-templates
                  '(("t" "Todo" entry (file+headline "~/Nextcloud/org/" "Tasks") "* TODO %?\n  %i\n  %a")
                    ("r" "Retro" entry (file+headline "~/Nextcloud/org/" "Retro") "* %?\nEntered on %U\n  %i\n  %a")))
            (setq org-directory "~/Nextcloud/org")
            (setq org-mobile-inbox-for-pull "~/Nextcloud/org/")
            (setq org-todo-keywords
                  '((sequence "TODO" "INPROGRESS" "DONE(!)" )))
    :config (progn
              (unbind-key "C-," org-mode-map)
              (add-hook 'org-babel-after-execute-hook 'my/fix-inline-images)))

Org bullets will display bullet points as UTF characters

(use-package org-bullets
  :ensure t
  :config (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

The export to HTML of org mode requires htmlize

(use-package htmlize
  :ensure t)

Let’s configure some languages to run in org-babel mode.

  • Ditta: To draw diagrams
  • Haskell
  • Ruby
  • A REST client
  • Python
  • Digraph
(org-babel-do-load-languages 'org-babel-load-languages '(
        (ruby . t)
        (ditaa . t)
        (haskell . t)
        (python . t)
        (dot . t)))

(setq org-ditaa-jar-path "/usr/local/Cellar/ditaa/0.10/libexec/ditaa0_10.jar")

I can never accept code from external sources :P161

(defun my-org-confirm-babel-evaluate (lang body) nil)
(setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate)

Adding bibliography. I’m starting to write a lot these days so a bibliography plugin is nice.

(use-package org-ref
  :ensure t)

Adding a function to save images in clipboard to a doc

(defun org-image-from-clipboard ()
  "Takes a screenshot into a time stamped unique-named file in the
same directory as the org-buffer and insert a link to this file."
  (let ((filename (concat
                   (concat (file-name-nondirectory (buffer-file-name)) "_imgs/" (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")))
    (unless (file-exists-p (file-name-directory filename))
      (make-directory (file-name-directory filename)))
    (call-process "pngpaste" nil nil nil filename)
    (if (file-exists-p filename)
        (insert (concat "[[file:" filename "]]")))


Back to Ivy. It is faster than Helm and that is enough for me these days.

Swiper is beautiful. Better than standard search.

(use-package ivy
    :ensure t
    :diminish ivy-mode
    :bind (("C-x b" . ivy-switch-buffer)
           ("C-c v" . ivy-push-view)
           ("C-c V" . ivy-pop-view))
    :config (progn
               (setq ivy-use-virtual-buffers t)
               (define-key ivy-minibuffer-map (kbd "M-j") 'ivy-immediate-done))
    :init (ivy-mode 1))

(use-package counsel
    :ensure t
    :bind (
           ("M-x" . counsel-M-x)
           ("C-S-f" . counsel-rg))
    :init (setq counsel-rg-base-command "rg -i --no-heading --line-number --color never %s ."))

(use-package swiper
    :ensure t
    :bind ("C-s" . swiper))

Using projectile mode

(setq projectile-completion-system 'ivy)

(use-package counsel-projectile
  :ensure t
  :bind (("C-p" . counsel-projectile-find-file)
         ("C-f" . counsel-projectile-rg))
  :init ()
  :config ())


(use-package yasnippet
  :ensure t
;;  :diminish yas-minor-mode "Ⓨ "
  :config (progn (setq yas-snippet-dirs '("~/.emacs.d/snippets"))
                 (add-hook 'term-mode-hook (lambda() (setq yas-dont-activate t)))
                 (yas-global-mode 1)))

Programming languages

Globally we will enable electric pair to match parentheses.

(electric-pair-mode 1)

We will globally enable syntax highlight

(use-package flycheck
  :ensure t
  :diminish flycheck-mode ""
  :config (add-hook 'after-init-hook #'global-flycheck-mode))

Company mode

Company mode is used for autocompletion

I set the delay to 0 to prevent any waiting for the autocompletion popup to show

Usually it is not needed at the start (remember I use emacs daemon).

(use-package company
  :ensure t
  :diminish company-mode ""
  :init (global-company-mode)
  :config (progn
                (setq company-idle-delay .3)
                (setq company-echo-delay 0)
                (setq company-tooltip-limit 15)
                (setq company-minimum-prefix-length 1)
                (setq company-dabbrev-downcase nil)))

C Mode

This comes with emacs by default so I won’t be use packaging

;(define-key c-mode-map "\C-d/" nil)


Awesome package to navigate json

(use-package json-navigator
  :ensure t)


Just for coloring…

(use-package yaml-mode
  :ensure t


;; (add-hook 'cider-mode-hook #'eldoc-mode)

;; In case of errors with nREPL you can enable this
;; (setq nrepl-log-messages t)

;; Hide cider special buffers
(setq nrepl-hide-special-buffers t)

;; Print a maximum of 100 items per collection
(setq cider-repl-print-length 100)

(setq cider-repl-result-prefix ";; => ")
(setq cider-interactive-eval-result-prefix ";; => ")


Let’s add some packages for Haskell coding

(use-package haskell-mode
  :ensure t
  :init (progn
          (add-hook 'haskell-mode-hook 'flycheck-mode)))

HTML, templates & CSS

(use-package web-mode
  :ensure t
  :mode (("\\.html?\\'" . web-mode)
         ("\\.html\\.erb\\'" . web-mode))
      (setq web-mode-markup-indent-offset 2)
      (setq web-mode-css-indent-offset 2)
      (setq web-mode-code-indent-offset 2)
      (setq web-mode-enable-auto-pairing t))
      (setq web-mode-enable-current-element-highlight t))

Also for SASS

(use-package scss-mode
  :ensure t
  :mode (("\\.scss\\'" . scss-mode))
  :config (setq scss-compile-at-save nil))

Some projects I do use HAML

(use-package haml-mode
  :ensure t)

And our good old Emmet. Previously called Zencoding

(use-package emmet-mode
  :ensure t
  :config (progn
            (add-hook 'css-mode-hook  'emmet-mode)
            (setq emmet-expand-jsx-className? t)))


(use-package markdown-mode
  :ensure t
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (progn
          (setq markdown-command "multimarkdown")
          (setq markdown-max-image-size '(700 . 300)))

Saving images from clipboard in markdown

(defun md-image-from-clipboard ()
  "Takes a screenshot into a time stamped unique-named file in the
same directory as the org-buffer and insert a link to this file."
  (let ((filename (concat
                   (concat (file-name-nondirectory (buffer-file-name)) ".images/" (format-time-string "%Y%m%d_%H%M%S_")) ) ".png")))
    (unless (file-exists-p (file-name-directory filename))
      (make-directory (file-name-directory filename) t))
    (call-process "pngpaste" nil nil nil filename)
    (if (file-exists-p filename)
        (insert (concat "![](" filename ")"))))


Adding file types with no rb extension: rake files, irbrc…

(add-to-list 'auto-mode-alist
	     '("\\.\\(?:gemspec\\|irbrc\\|gemrc\\|rake\\|rb\\|ru\\|thor\\)\\'" . ruby-mode))

(add-to-list 'auto-mode-alist
               '("\\(Capfile\\|Gemfile\\(?:\\.[a-zA-Z0-9._-]+\\)?\\|[rR]akefile\\)\\'" . ruby-mode))

;; Adding syntax checking
;(add-hook 'ruby-mode-hook 'flymake-ruby-load)

(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))

(use-package projectile-rails
  :ensure t
  :diminish projectile-rails-mode "RoR "
  :config (add-hook 'projectile-mode-hook 'projectile-rails-on))

Some customizations of highlight

  • Highlight equal sign
  • Mark a debug
(font-lock-add-keywords 'ruby-mode
  '(("\\<\\(binding.pry\\|binding.irb\\)\\>" . font-lock-warning-face)
    ("\\<\\(=\\>\\)" . font-lock-keyword-face)))

For editing code in Ruby in electric mode

(use-package ruby-electric
  :ensure t
  :init (add-hook 'ruby-mode-hook #'ruby-electric-mode))

Use Rubocop for Ruby code linting

(use-package rubocop
  :ensure t
  :diminish rubocop-mode
  :init (add-hook 'ruby-mode-hook #'rubocop-mode))

To not envy RubyMine users

(use-package ruby-refactor
  :ensure t
  :init (add-hook 'ruby-mode-hook 'ruby-refactor-mode-launch))

To avoid adding comments at the beginning of file

(setq ruby-insert-encoding-magic-comment nil)


(use-package crystal-mode
  :ensure t)


(use-package alchemist
  :ensure t
  :config (setq alchemist-hooks-test-on-save t)
  :bind (("C-c m" . alchemist-mix)))


Linting and syntax checking.

Before having it available you need to run

npm install -g eslint babel-eslint eslint-plugin-react

(use-package js2-mode
  :ensure t
  :init (setq js-indent-level 2)
  :config (add-hook 'js-mode-hook 'js2-minor-mode))

React specific settings

(add-to-list 'auto-mode-alist '("\\.jsx$" . web-mode))

(setq web-mode-content-types-alist
  '(("jsx" . "\\.js[x]?\\'")))

And for Vue.js

(use-package vue-mode
  :ensure t


(use-package coffee-mode
  :ensure t
  :config (custom-set-variables
            '(coffee-tab-width 2)))


Both adding support for coding and babel to accept it

(use-package tide
  :ensure t
  :preface (defun my/tide-save-hook ()
             (when (eq major-mode 'typescript-mode)

  :mode ("\\.ts\\'" . typescript-mode)
  (add-hook 'typescript-mode-hook
              (eldoc-mode +1)
              (company-mode +1)
              (flycheck-mode +1)
              (tide-hl-identifier-mode +1)
              (add-hook 'before-save-hook 'my/tide-save-hook)
              (setq typescript-indent-level 4
                    typescript-expr-indent-offset 4
                    js-indent-level 4
                    company-tooltip-align-annotations t)

(use-package ob-typescript
  :ensure t
  :init (org-babel-do-load-languages
         '((typescript . t))))

I will add angular support here since I play with angular only from typescript

(use-package ng2-mode
  :ensure t)


Go mode. This will also autoformat after saving following go standards

We need to run the following commands in a new machine

“` go get “`

(use-package go-mode
  :ensure t
  :bind ("C-c C-r" . go-remove-unused-imports)
  :init (setq gofmt-command "goimports")
  :config (add-hook 'before-save-hook 'gofmt-before-save))

(use-package go-guru
  :ensure t

(use-package go-complete
  :ensure t
  :config (add-hook 'completion-at-point-functions 'go-complete-at-point))

Autocomplete for Go. We will be using company mode too.

(use-package company-go
  :ensure t
  :config (add-hook 'go-mode-hook (lambda ()
                                    (set (make-local-variable 'company-backends) '(company-go))


(use-package elm-mode
  :ensure t
  :init (progn
           (add-hook 'elm-mode-hook #'elm-oracle-setup-completion)
           (setq elm-format-on-save t)
           (with-eval-after-load 'company
              (add-to-list 'company-backends 'company-elm))))


(use-package rust-mode
  :ensure t)

Racer gives us autocompletion. Before using we need:

$ rustup component add rust-src $ cargo install racer

(use-package racer
  :ensure t
  :init (progn
           (add-hook 'rust-mode-hook #'racer-mode)
           (add-hook 'racer-mode-hook #'eldoc-mode)))

Flycheck rust checker

(use-package flycheck-rust
  :ensure t
  :config (with-eval-after-load 'rust-mode
            (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)))


Even though python-mode is good enough we need to do some linting

(use-package flymake-python-pyflakes
  :ensure t
  :init (setq flymake-python-pyflakes-executable "flake8"))

Using python3 exporting babel

(setq org-babel-python-command "python3")

All our projects.

(use-package pipenv
  :ensure t
    (add-hook 'python-mode-hook #'pipenv-mode))


Ethereum’s programming language

(use-package solidity-mode
  :ensure t)


We have to install Dart in order to use this. Just remember to follow instructions at

(use-package dart-mode
  :config (setq dart-format-on-save t)
  :ensure t)


(use-package lua-mode
  :ensure t)


(use-package zig-mode
  :ensure t)


(defun my/init-nim-mode ()
  "Local init function for `nim-mode'."

  ;; Remember: Only enable either `flycheck-mode' or `flymake-mode' at the same time.
  ;; (flycheck-mode 1)
  ;; (flymake-mode 1)

  ;; The following modes are disabled for Nim files just for the case
  ;; that they are enabled globally.
  ;; Anything that is based on smie can cause problems.
  (auto-fill-mode 0)
  (electric-indent-local-mode 0)

(use-package nim-mode
  :ensure t
  :init (add-hook 'nim-mode-hook 'my/init-nim-mode))

Protocol buffers

(use-package protobuf-mode
  :ensure t)

File formats

For init files we have conf mode

(use-package conf-mode
  :ensure t)


We will use Magit for git. Also opening timemachine is a nice binding to have.

(define-prefix-command 'magit-map)
(global-set-key (kbd "C-,") 'magit-map)

(use-package magit
  :ensure t
  :bind (("<f6>" . magit-status)
         ("H-6" . magit-status)
         ("C-, ," . magit-status)
         ("C-, s" . magit-stage-file)
         ("C-, c" . magit-commit)
         ("C-, b" . magit-checkout)
         ("C-, l" . magit-log-buffer-file))
  :config (progn
            (setq magit-display-buffer-function 'magit-display-buffer-fullframe-status-v1)
            (setq magit-revision-show-gravatars t)))

(use-package forge
  :ensure t
  :after magit)

Since I use github a lot let’s use this layer over magit

;; (use-package magithub
;;   :ensure t
;;   :after magit
;;   :config
;;   (magithub-feature-autoinject t)
;;   (setq magithub-clone-default-directory "~/code"))

Time machine is a nice package to browse the story of a file

(use-package git-timemachine
  :ensure t
  :bind (("C-<f6>" . git-timemachine)))

Also for some projects it is nice to be able to browse the file on Github.

(use-package github-browse-file
  :ensure t
  :bind (("C-c g f" . github-browse-file)))


Emacs is great for managing docker images. Also I will use the syntax help for Dockerfiles

(use-package docker
  :ensure t)

(use-package dockerfile-mode
  :ensure t
  :config (add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode)))

Help and documentation

Which key

When I start typing a combo a help with the possible continuations appear if I wait for a while.

(use-package which-key
  :ensure t
  :defer 0.2
  :config (which-key-mode))


Integration with Dash

(add-to-list 'load-path "~/.emacs.d/vendor/dash-at-point")
(autoload 'dash-at-point "dash-at-point"
  "Search the word at point with Dash." t nil)
(global-set-key "\C-cd" 'dash-at-point)
(global-set-key "\C-ce" 'dash-at-point-with-docset)

File navigation

Neo tree

(defun neotree-to-root ()
  "Moves neotree to root of project"

  (let ((git-folder (projectile-project-root)))
                              (neotree-dir git-folder)))

(use-package neotree
  :ensure t
  :bind ("<C-tab>" . neotree-toggle))


Start using dired+

Making dired to open the file in the current buffer instead of opening a new one

Dired likes gnu ls more than ls in osx so let’s make it use it

Wdired mode is awesome. Let’s bind a key to it. It allows us to write the buffer to rename files.

Also I prefer passing some switches to ls

(use-package dired
  (use-package dired+
    :load-path "vendor/dired+/")
  :init (progn
           (put 'dired-find-alternate-file 'disabled nil)
           (setq ls-lisp-use-insert-directory-program t)
           (if (eq system-type 'darwin)
             (setq insert-directory-program "gls"))
           (setq dired-listing-switches "-lah")

(define-key dired-mode-map (kbd "C-w") 'wdired-change-to-wdired-mode)

Adding sort options to dired

(use-package dired-quick-sort
  :ensure t


This is just for measuring the frequency for the commands run

(use-package keyfreq
  :ensure t
  :init (progn
          (keyfreq-mode 1)
          (keyfreq-autosave-mode 1)
          (setq keyfreq-excluded-commands


RSS reader

I use elfeed to read RSS. It can be configured via and org mode file. Extra awesomeness!

(defun elfeed-feeds ()
  "Open the elfeed feeds file"
  (find-file "~/.emacs.d/elfeed/"))

(defun my/elfeed-send-to-pocket ()
  "Send current article to pocket"
    ((url (elfeed-entry-link elfeed-show-entry)))
    (shell-command (concat  "echo '\\n\\n" url "' | msmtp"))
    (message "Saved to Instapaper!")))

(defun my/elfeed-send-to-tts ()
  "Send current article to a text to speech system"
    ((html-to-read (elfeed-deref (elfeed-entry-content elfeed-show-entry)))
     (text-to-read (replace-regexp-in-string "<.*?>" "" html-to-read))
     (temp-input-file (make-temp-file "elfeed-input-tts"))
     (temp-output-file (make-temp-file "elfeed-output-tts" nil ".mp3"))
     (polly-command (concat "aws polly synthesize-speech --region eu-west-1 --output-format mp3 --voice-id Joanna --text \"$(< " temp-input-file ")\" " temp-output-file )))
      (write-region text-to-read nil temp-input-file)
      (shell-command polly-command)
      (shell-command (concat "open -g " temp-output-file)))))

(use-package elfeed
  :ensure t
  :init (progn
          (use-package elfeed-org
              :ensure t
              :init (progn
                      (setq rmh-elfeed-org-files (list "~/.emacs.d/elfeed/"))
                      (setq elfeed-use-curl t))
                      (setf url-queue-timeout 30)))
       (bind-keys :map elfeed-show-mode-map
                  ("x" . my/elfeed-send-to-pocket)
                  ("t" . my/elfeed-send-to-tts)))


Why leaving emacs? The most useful thing I can have here is just to stop current song if I have to pay attention to a different thing or stop the noise.

(use-package spotify
  :ensure t
  :bind (("C-c s" . spotify-playpause)))


To read PDFs let’s switch to pdf-tools. It is much much faster than docview. Also There is the interleave mode to ease the note taking.

(use-package pdf-tools
  :ensure t
  :init ()
  :config (add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode)))

(use-package interleave
  :ensure t)

(use-package ivy-bibtex
  :ensure t
  :init (progn
          (setq bibtex-completion-bibliography
          (setq bibtex-completion-fallback-options
                '(("Lead 2 Amazon" . "")
                  ("Google Scholar" . "")))))

(setq debug-on-error t)


I migrated not so long ago my blog to hugo to be able to write posts in org mode.

(use-package easy-hugo
  :ensure t
  :init (progn
          (setq easy-hugo-basedir "~/code/sites/")
          (setq easy-hugo-url "")
          (setq easy-hugo-root "~/code/sites/")
          (setq easy-hugo-previewtime "300")


I’m starting to use org-reveal for presentations

(use-package ox-reveal
  :ensure t
  :init ()
  :config (setq org-reveal-root "vendor/reveal.js"))


I will create a pair of hydras.

  • f1: Navigates between apps installed in emacs like twitter or email
  • f2: Navigate between most used projects
(use-package hydra
  :ensure t
  :bind (("<f1>" . applications-menu/body))
  :config (progn

            (defhydra applications-menu (:color blue :hint nil)
_f_: elfeed         📰     _b_: Blog          🖊
              ("f" elfeed :color blue)
              ("b" easy-hugo :color blue)
              ("q" nil))))

Some general purpose functions

These are some general functions that are useful and have no better place to be in

Copy file to clipboard

Copies the file to the clipboard.

(defun current_buffer_file_name ()
  (if (equal major-mode 'dired-mode)

(defun copy-path-to-clipboard ()
  "Copy the current buffer full file path to the clipboard."
  (let ((filename (current_buffer_file_name)))
    (when filename
      (kill-new filename)
      (message "Copied buffer file name '%s' to the clipboard." filename))))

(defun copy-filename-to-clipboard ()
  "Copy the current buffer file name relative to projectile root to the clipboard."
  (let* ((filename (replace-regexp-in-string (projectile-project-root) "" (current_buffer_file_name))))
     (when filename
       (kill-new filename)
       (message "Copied buffer file name '%s' to the clipboard." filename))))

Chrome reload

This function just reloads chrome. This is useful to avoid too much alt-tab

(defun chrome-reload ()
  "Reloads current chrome window"
  (shell-command "chrome-cli reload"))

(define-prefix-command 'manage-browser-map)
(global-set-key (kbd "C-b") 'manage-browser-map)

(defun chrome-reload ()
  "Reloads current chrome window"
  (shell-command "chrome-cli reload"))

(define-key manage-browser-map "r" 'chrome-reload)

Custom scripts

These are scripts that are worthy of their own source file and I’m not including them here.

(use-package copy-rtf
  :load-path "src/copy-rtf/"
  :commands (copy-rtf))

(use-package p161-mode
  :load-path "src/p161-mode/"
  :commands p161-mode)

(defun turn-on-p161-mode-hook ()
  (cond ((string-match "^//Users/rafael/code/platform161/" buffer-file-name)
         (p161-mode 1))))

;; (add-hook 'text-mode-hook 'turn-on-p161-mode-hook)

(load-file "~/.emacs.d/src/emacs-presentation-mode/emacs-presentation-mode.el")
(load-file "~/.emacs.d/src/gif-me.el/gif-me.el")
(use-package org-jira
  :ensure t
  :config (setq jiralib-url ""))
You can’t perform that action at this time.