Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1770 lines (1335 sloc) 43.6 KB

Rafa’s Emacs settings file

emacs-logo.png

To use this change your init file for something like

(require 'org)
(org-babel-load-file
 (expand-file-name "settings.org"
                   user-emacs-directory))

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-refresh-contents)
  (package-install 'use-package))

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

Homebrew

I’ll add homebrewe’d emacs packages to load path

(let ((default-directory "/usr/local/share/emacs/site-lisp/"))
  (normal-top-level-add-subdirs-to-load-path))

Secrets

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")

Shell

Copy the environment variables from shell’s environment

(use-package exec-path-from-shell
  :ensure t
  :no-require t
  :config (when (memq window-system '(mac ns))
            (exec-path-from-shell-initialize)))

Editing settings

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

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

Visuals

General UI

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))
    ad-do-it))
(defadvice y-or-n-p (around prevent-dialog-yorn activate)
  "Prevent y-or-n-p from activating a dialog"
  (let ((use-dialog-box nil))
    ad-do-it))

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

(global-hl-line-mode)

Whitespace

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 moe-theme
  :ensure t
  :init (setq moe-theme-highlight-buffer-id t)
  :config (progn
            (load-theme 'moe-dark t)
            (moe-theme-set-color 'orange)
            (powerline-moe-theme)
            (moe-dark)))

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 "Iosevka"
                    :height 180
                    :weight 'light
                    :width 'normal)

Manually setting font for managing Unicode symbols

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

Powerline

Let’s powerline.

(setq ns-use-srgb-colorspace nil) ; Needed to display correctly powerline separators

(use-package powerline
  :ensure t
  :config (progn
          (setq powerline-default-separator 'wave)
          (setq powerline-display-hud t)
          (setq powerline-display-buffer-size nil)
          (setq powerline-display-mule-info nil)
          (powerline-center-theme)))

Mouse

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)

Tab bar

(use-package tabbar
  :ensure t
  :bind (("C-M-<left>" . tabbar-backward-tab)
         ("C-M-<right>" . tabbar-forward-tab))
  :config (tabbar-mode 1))

(use-package tabbar-ruler
  :ensure t
  :after (tabbar)
  :config (progn
            (setq tabbar-ruler-global-tabbar t)))

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)

Images

Let’s loop gifs by default

(setq image-animate-loop 1)

Line numbers

Use emacs native line numbers

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

Minibuffer

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)

Keyboard

(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

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"
  (interactive)
  (let
      ((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."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (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)

Windows

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)

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
  :init
  (golden-ratio-mode 1))

Eyebrowse

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))

Undo

Much better undo than the default one.

(use-package undo-tree
  :ensure t
  :diminish undo-tree-mode
  :init
    (progn
      (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 (("s-e" . er/expand-region)
         ("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))

Jump to char

I found this to be super awesome specially in combination with multiple cursors.

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

Goto URL

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

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
                    (cond
                     ((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)

Terminal

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)))

Midnight

(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

(setq
   backup-by-copying t      ; don't clobber symlinks
   backup-directory-alist
    '(("." . "~/.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

Projectile

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 (projectile-global-mode))

Spellchecker

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 ()
             (interactive)
             (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)
             (cond
              ((= 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 personal_notes.org file in root of projectile and F3 to the agenda file.

  (require 'projectile)

  (defun my/projectile-open-personal-notes ()
    "Opens a personal_notes.org file in project folder"
    (interactive)
    (let
        ((folder (car (projectile-get-project-directories))))
      (if folder
          (find-file (concat folder "personal_notes.org"))
        (message "No project folder found"))))

  (defun my/open-org-agenda ()
    "Opens agenda file"
    (interactive)
    (find-file "~/Dropbox/org/index.org"))

  (use-package org
    :ensure t
    :preface
    (defun my/fix-inline-images ()
      (when org-inline-image-overlays
        (org-redisplay-inline-images)))
    :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 "~/Dropbox/org/capture.org")
            (setq org-capture-templates
                  '(("t" "Todo" entry (file+headline "~/Dropbox/org/index.org" "Tasks") "* TODO %?\n  %i\n  %a")
                    ("b" "Book" entry (file "~/Dropbox/org/library.org") "* TODO %?\n:PROPERTIES:\n#+INTERLEAVE_PDF: /Users/rafael/Dropbox/Calibre/\n:END:")
                    ("r" "Retro" entry (file+headline "~/Dropbox/org/retro.org" "Retro") "* %?\nEntered on %U\n  %i\n  %a")))
            (setq org-directory "~/Dropbox/org")
            (setq org-mobile-inbox-for-pull "~/Dropbox/org/index.org")
            (setq org-mobile-directory "~/Dropbox/Apps/MobileOrg")
            (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)
        (restclient . 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."
  (interactive)
  (org-display-inline-images)
  (let ((filename (concat
                  (make-temp-name
                   (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 "]]")))
    (org-display-inline-images)))

Ivy

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 ())

Snippets

(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)

JSON

Awesome package to navigate json

(use-package json-navigator
  :ensure t)

YAML

Just for coloring…

(use-package yaml-mode
  :ensure t
  :diminish)

RAML

(use-package raml-mode
  :load-path "vendor/raml-mode"
  :diminish)

Clojure

;; (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 ";; => ")

Haskell

Let’s add some packages for Haskell coding

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

HTML, templates & CSS

(use-package web-mode
  :ensure t
  :mode (("\\.html?\\'" . web-mode)
         ("\\.html\\.erb\\'" . web-mode))
  :config
    (progn
      (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
  :diminish
  :config (progn
            (add-hook 'css-mode-hook  'emmet-mode)
            (setq emmet-expand-jsx-className? t)))

Markdown

(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."
  (interactive)
  (let ((filename (concat
                  (make-temp-name
                   (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 ")"))))
)

Ruby

We will use RVM’s provided Ruby

(use-package rvm
  :ensure t
  :defer t
  :config (rvm-use-default))

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-hook 'ruby-mode-hook 'yafolding-mode)

(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))

Project navigation with Robe

(use-package robe
  :ensure t
  :init (progn
           (add-hook 'ruby-mode-hook 'robe-mode)
           (eval-after-load 'company
              '(push 'company-robe company-backends))
           (defadvice inf-ruby-console-auto (before activate-rvm-for-robe activate)
              (rvm-activate-corresponding-ruby))))

To not envy RubyMine users

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

Elixir

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

Javascript

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
  :defer)

Coffeescript

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

Typescript

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)
               (tide-format-before-save)))

  :mode ("\\.ts\\'" . typescript-mode)
  :init
  (add-hook 'typescript-mode-hook
            (progn
              ;;(tide-setup)
              (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
         'org-babel-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

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

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

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

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

Elm

(use-package elm-mode
  :ensure t
  :defer
  :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))))

Rust

(use-package rust-mode
  :defer
  :ensure t)

Racer gives us autocompletion. Before using we need:

$ rustup component add rust-src $ cargo install racer

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

Scala

(use-package ensime
  :ensure t)

Python

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
  :init
    (setq
      pipenv-projectile-after-switch-function
      #'pipenv-projectile-after-switch-extended)
  :config
    (add-hook 'python-mode-hook #'pipenv-mode))

Solidity

Ethereum’s programming language

(use-package solidity-mode
  :ensure t)

File formats

For init files we have conf mode

(use-package conf-mode
  :ensure t)

Git

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 (setq magit-display-buffer-function 'magit-display-buffer-fullframe-status-v1))

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))

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)))

Docker

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

Guide key

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

(use-package guide-key
  :ensure t
  :diminish guide-key-mode
  :init (setq guide-key/guide-key-sequence t)
  :config (guide-key-mode 1))

Dash

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"
  (interactive)

  (let ((git-folder (car (projectile-get-project-directories))))
                              (neotree-dir git-folder)))

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

Dired

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
  :config
  (use-package dired+
    :ensure t)
  :init (progn
           (put 'dired-find-alternate-file 'disabled nil)
           (setq ls-lisp-use-insert-directory-program t)
           (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
  :config
  (dired-quick-sort-setup))

Keyfreq

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
            '(self-insert-command
              abort-recursive-edit
              previous-line
              next-line))))

Applications

Restclient

(use-package restclient
  :ensure t)

(use-package ob-restclient
  :ensure t)

Email

We need to install mu with emacs support in OsX with

EMACS=$(which emacs) brew install mu –with-emacs –HEAD

(setq mu4e-maildir "~/.Maildir")
(require 'mu4e)
(setq mu4e-get-mail-command "offlineimap")
(setq message-kill-buffer-on-exit t)

(setq mu4e-contexts
    `( ,(make-mu4e-context
	  :name "Personal"
	  :enter-func (lambda () (mu4e-message "Switch to the Personal context"))
	  ;; leave-func not defined
	  :match-func (lambda (msg)
			(when msg
			  (mu4e-message-contact-field-matches msg
			    :to "rafael@micubiculo.com")))
	  :vars '(  ( user-mail-address	     . "rafael@micubiculo.com"  )
		   ( user-full-name	    . "Rafa de Castro" )
		   ( mu4e-compose-signature .
		     (concat
		       "Rafa de Castro\n"
		       "http://joy.pm\n"))
                   (mu4e-drafts-folder . "/Personal/[Google Mail].Drafts")
                   (mu4e-sent-folder   . "/Personal/[Google Mail].Sent Mail")
                   (mu4e-trash-folder  . "/Personal/[Google Mail].Bin")))
       ,(make-mu4e-context
	  :name "Work"
	  :enter-func (lambda () (mu4e-message "Switch to the Work context"))
	  ;; leave-fun not defined
	  :match-func (lambda (msg)
			(when msg
			  (mu4e-message-contact-field-matches msg
			    :to "rafael.decastro@platform161.com")))
	  :vars '( ( user-mail-address	     . "rafael.decastro@platform161.com" )
		   ( user-full-name	    . "Rafael de Castro" )
		   ( mu4e-compose-signature .
		     (concat
		       "Rafael de Castro\n"))
                   (mu4e-drafts-folder . "/Work/[Gmail].Drafts")
                   (mu4e-sent-folder   . "/Work/[Gmail].Sent Mail")
                   (mu4e-trash-folder  . "/Work/[Gmail].Bin")))))

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"
  (interactive)
  (find-file "~/.emacs.d/elfeed/elfeed.org"))

(defun my/elfeed-send-to-pocket ()
  "Send current article to pocket"
  (interactive)
  (let
    ((url (elfeed-entry-link elfeed-show-entry)))
    (shell-command (concat  "echo '\\n\\n" url "' | msmtp readlater.iliwkd1e3iq@instapaper.com"))
    (message "Saved to Instapaper!")))

(defun my/elfeed-send-to-tts ()
  "Send current article to a text to speech system"
  (interactive)
  (let*
    ((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 )))
    (progn
      (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
                      (elfeed-org)
                      (setq rmh-elfeed-org-files (list "~/.emacs.d/elfeed/elfeed.org"))
                      (setq elfeed-use-curl t))
                      (setf url-queue-timeout 30)))
  :config
       (bind-keys :map elfeed-show-mode-map
                  ("x" . my/elfeed-send-to-pocket)
                  ("t" . my/elfeed-send-to-tts)))

Spotify

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)))

PDFs

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
                '("~/Dropbox/org/library.bib"))
          (setq bibtex-completion-fallback-options
                '(("Lead 2 Amazon" . "http://lead.to/amazon/en/?key=%s&si=all&op=bt&bn=&so=sa&ht=us")
                  ("Google Scholar" . "https://scholar.google.com/scholar?q=%s")))))

(setq debug-on-error t)

Blogging

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/joy.pm/")
          (setq easy-hugo-url "https://joy.pm")
          (setq easy-hugo-root "~/code/sites/joy.pm/")
          (setq easy-hugo-previewtime "300")
          ))

Hydras

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
            (hydra-add-font-lock)

            (defhydra applications-menu (:color blue :hint nil)
              "
^Apps^
------
_f_: elfeed         📰     _b_: Blog          🖊
_m_: mu4e           📧
_r_: restclient     ➤
"
              ("r" restclient-mode :color blue)
              ("m" mu4e :color blue)
              ("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)
                      default-directory
                    (buffer-file-name)))

(defun copy-path-to-clipboard ()
  "Copy the current buffer full file path to the clipboard."
  (interactive)
  (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."
  (interactive)
  (let* ((base_path (car (projectile-get-project-directories)))
         (filename (replace-regexp-in-string base_path "" (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"
  (interactive)
  (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"
  (interactive)
  (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")
(use-package org-jira
  :ensure t
  :config (setq jiralib-url "https://jira.platform161.com"))