After I created some functions in Emacs to work with Cryogen in a better way, it has become very easy to create blog posts and publish what I'm up to. I will try to leave this page very updated and make some sort of very brief introduction about what was the main changes between each version.

   

I will possibly skip the refactoring in these updates because I'm basically doing it every time.

The goal for this setting is to be Literate and Minimal in the number of third-party packages. Prefer custom functions rather than full-fledged solutions. So, I will always be trying to reduce the number of packages with time.

   

Link to my emacs.d repository. If you want to see only the code generated by the org-tangle, please check the file conf.el at the repository.

   

UPDATES:

2018-09-29 22:52:07 — beginning (27 packages)
2018-09-30 00:01:02 — org and dired manuals (27 packages)
2018-09-30 22:55:49 — ido with imenu, key-chord, multiple-cursors (27 packages)
2018-10-02 08:44:29 — remove pkgs, more docs and custom functions (18 packages)
2018-10-03 06:00:18 — more docs and refactoring (18 packages)
2018-10-08 00:37:49 — persistent info-nodes, sql-beautify and secrets (18 packages)
2018-10-09 07:17:17 — add folding support through hs-minor-mode (18 packages)
2018-10-13 11:03:37 — more docs, custom funcs, 3 new packages (21 packages)

   

Table of Contents

  1. Introduction
    1. packages
    2. custom variables
    3. custom file
    4. security vulnerability
  2. Custom functions
    1. cryogen blog experience
    2. manage lines and text
    3. configuration ease
    4. go to scratch buffer
    5. helper to check spelling errors in buffers
    6. editing mode
    7. compile all your init folder
    8. date management
    9. emacs improve builtins features
    10. configuring builtins emacs modes
    11. osx functions
    12. remember all my custom functions and its documentation
  3. Better defaults
    1. settings
    2. compilation
    3. activate builtin modes
    4. recentf
    5. tramp
    6. uniquify
    7. expand region
    8. dired
    9. diff mode
    10. register
    11. multiple cursors
    12. secrets
    13. flyspell
  4. Org mode
    1. defaults
    2. babel and Export
    3. org agenda
    4. disable some keybindings from org-mode
  5. Macbook setup
    1. default settings
    2. key bindings
  6. Help
  7. Appearance
    1. better default settings
    2. setup custom themes
    3. advices
    4. setup initial frame settings
    5. enabling theme custom functions
    6. activate default theme
    7. highlight some words
  8. Completions
    1. ido mode
    2. company
    3. smex
    4. grep
    5. imenu using ido
    6. occur
  9. Feed RSS
  10. Snippets
  11. Shell
    1. functions to help with shell
    2. defaults
    3. visual commands
    4. aliases
  12. Project
  13. Git
    1. magit settings
    2. magit functions
  14. Tips
  15. Extra modes
    1. fix-words
    2. which-key
    3. yaml
    4. dockerfile
    5. restclient
  16. Instant messaging
  17. Markdown
  18. Latex
  19. Programming
    1. general
    2. fold code block
    3. clojure
      1. cider
      2. clojure mode
      3. refactor
    4. lisp
      1. paredit-mode
      2. racket-mode
      3. elisp
    5. web mode
    6. sql
    7. python
    8. react
  20. Keys
    1. kill a frame easyly
    2. refactor later
    3. more bindings for C-x 8
  21. Finish
    1. garbage collector
    2. org agenda
    3. cleaning up your mode line
    4. server

Introduction

What is Emacs? The only good text editor! Sorry, it's not easy to explain what is exactly is, but the name was intended to be EditorMacros or something like that. It was written in C with very basic functionalities in mind, however the other huge portion of the bundle is the Lisp interpreter, therefore when you type something in your keyboard, you are typing it into this interactive environment where code is data and data is code.

Programming is a work of literature, so why not to document it as a good prose. You can read and find out more explanations about the motivation I had to write a particular segment of this configuration.

packages

The whole idea of this new re-write was to keep the number of packages into a minimum. I want to explore the builtins of Emacs and to extend my knowledge of Elisp. Therefore, I will try to write functions that might help me out in some situations instead of just downloading one more dependency inside the configuration.

Let's stick to melpa stable repository. I use only the stable version for a while, but there are some packages that I had problem to install or didn't existed inside the stable branch, therefore I give higher priority for the stable branch, but I need to keep the regular branch around.

(require 'package)
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/"))
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
(when (not package-archive-contents)
  (package-refresh-contents))

Change the priority of the repositories:

(setq package-archive-priorities
      '(("melpa-stable" . 10)
        ("melpa" . 5)))

Function to install packages when needed. The idea if to verify if the package is already installed when we called it later.

(defun bk/install-maybe (pkg)
  (when (not (package-installed-p pkg))
    (package-install pkg)))

Verify the number of installed packages do I already have.

(defun bk/number-of-packages ()
  "Function to return the number of active packages."
  (interactive)
  (message (concat (number-to-string (length package-selected-packages))
                   " packages installed...")))

custom variables

There are some variables that I need to define at the very beginning.

(defvar is-osx (eq system-type 'darwin))
(defvar bk-home? (equal (system-name) "Wandersons-Air"))
(defvar *authinfo-file* (concat user-emacs-directory "secrets/authinfo.gpg"))
(defvar *mac-gpg2-path* "/usr/local/MacGPG2/bin/gpg2")
(defvar *mac-gpg2-exec* ((lambda ()
                           (if (file-executable-p *mac-gpg2-path*)
                               *mac-gpg2-path*
                             (message "You do not have a GPG executable correctly installed.")))))
(defvar *mac-font* "-apple-Monaco-medium-normal-normal-*-14-*-*-*-m-0-iso10646-1")
(defvar org-links-file "~/Dropbox/links.org")
(defvar org-notes-file "~/Dropbox/notes.org")
(defvar org-todo-file "~/Dropbox/todo.org")
(defvar org-appointments "~/Dropbox/appointments.org")
(defvar org-log-file "~/Dropbox/log.org")

I also have some aliases to common commands that I use from M-x <cmd>.

(defalias 'yes-or-no-p 'y-or-n-p)
(defalias 'qrr 'query-replace-regexp)
(defalias 'vlm 'visual-line-mode)
;; clojure
(defalias 'cquit 'cider-quit)
(defalias 'ctest 'cider-test-run-test)

custom file

Stop cluttering my configuration files. Save all the ‘customize-{variables/faces}‘ into it's own file.

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file :noerror)

security vulnerability

There were an emergency release in Emacs 25.3 to fix a security vulnerability that was introduced in Emacs 19.29 since 1995. The whole idea was that emacs had a support for enriched text that aside from managing properties for the display it also supported evaluation of arbitrary Lisp code.

Just add these lines to your Emacs configuration file:

(eval-after-load "enriched"
  '(defun enriched-decode-display-prop (start end &optional param)
     (list start end)))

You can read more details: here.

Custom functions

Several custom fuctions that I needed to write to ease my life inside emacs. It's preferred to write functions rather than installing more third-party packages. The idea is to fresh up my skills on Emacs Lisp.

cryogen blog experience

Improve my blog experience. The pattern of the markdown file to be processed by the Cryogen package is YYYY-MM-DD-name-of-the-post.md. So let's build a function with receives the name of the post and creates all the boilerplate needed to start blogging.

(defconst *cryogen-post-dir* "/Users/wandersonferreira/personal/webblog/resources/templates/md/posts/")
(defun bk/new-blog-entry ()
  "Function to create a new blog entry.
Change the path to your Cryogen project."
  (interactive)
  (let* ((now (format-time-string "%Y-%m-%d" (current-time)))
         (post-title (read-from-minibuffer "Post title: "))
         (tags (read-from-minibuffer "Tags: "))
         (tags-fmt (string-join (mapcar #'(lambda (arg) (concat "\"" (string-trim arg) "\"")) (split-string tags " ")) ","))
         (title-fmt (replace-regexp-in-string " " "-" (downcase post-title)))
         (file-name (concat now "-" title-fmt ".md"))
         (content (format "{:title \"%s\"\n:layout :post\n:tags [%s]}" post-title tags-fmt)))
    (if (file-exists-p (concat *cryogen-post-dir* file-name))
        (message "File already exists in Cryogen dir.")
      (with-temp-buffer
        (write-region content nil (concat *cryogen-post-dir* file-name))))
    (find-file (concat *cryogen-post-dir* file-name))
    (forward-paragraph)
    (newline 4)))

Change to the Webblog folder easily.

(defun bk/change-blog-dir ()
  "Function to change to Cryogen folder."
  (interactive)
  (find-file *cryogen-post-dir*))
(global-set-key (kbd "C-x c") 'bk/change-blog-dir)

manage lines and text

Regardless of where your cursor is, I might want to copy the whole line for some reason. This pattern keep happening from time to time for me.

(defun bk/copy-whole-line ()
  "Copy the whole line."
  (interactive)
  (save-excursion
    (kill-new (buffer-substring
               (point-at-bol)
               (point-at-eol)))))
(global-set-key (kbd "C-c l c") 'bk/copy-whole-line)

Function to duplicate the current line using the copy function above.

(defun bk/duplicate-line ()
  "Function to duplicate line."
  (interactive)
  (bk/copy-whole-line)
  (save-excursion
    (end-of-line)
    (newline 1)
    (yank))
  (forward-line 1))
(global-set-key (kbd "C-c d") 'bk/duplicate-line)

configuration ease

I need to reload my configuration file from inside org-mode. The literate format poses some needs to customization, but hey… we are in Emacs. There is nothing you can't built with a little help.

(defun bk/config-reload ()
  "Reloads ~/.emacs.d/conf.org at runtime."
  (interactive)
  (org-babel-load-file (expand-file-name "~/.emacs.d/conf.org")))
(global-set-key (kbd "C-c r") 'bk/config-reload)

go to scratch buffer

It's common for Emacs users to find some tricks around the web, get into the scratch buffer and try it out. I've internalized this pattern already, so I want to get there as fast as I can.

If I don't have a scratch buffer, please create one for me.

(defun bk/scratch-buffer ()
  "Function to change buffer to scratch buffer."
  (interactive)
  (let ((buf (get-buffer "*scratch*")))
    (if buf
        (switch-to-buffer buf)
      (switch-to-buffer (get-buffer-create "*scratch*"))
      (lisp-interaction-mode))))

Global key

(global-set-key (kbd "C-c b") 'bk/scratch-buffer)

Remove the text from scratch buffer…

(setq initial-scratch-message "")

helper to check spelling errors in buffers

(defun bk/spell-buffer-pt-BR ()
  "Function to spell checking inside the buffer."
  (interactive)
  (ispell-change-dictionary "brasileiro")
  (flyspell-buffer))
(defun bk/spell-buffer-en ()
  "Function to spell checking the buffer in US language."
  (interactive)
  (ispell-change-dictionary "en_US")
  (flyspell-buffer))

editing mode

(defun bk/normalize-buffer ()
  "Function to organize the buffer."
  (interactive)
  (delete-trailing-whitespace)
  (untabify (point-min) (point-max))
  (indent-region (point-min) (point-max)))
(defun bk/unfill-paragraph ()
  "Take a multi-line paragraph and turns it into a single line."
  (interactive)
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))

compile all your init folder

(defun bk/byte-compile-init-dir ()
  "Byte-compile all your settings."
  (interactive)
  (byte-recompile-directory user-emacs-directory 0))

date management

(defun bk/insert-date ()
  "Function to insert date into buffer."
  (interactive)
  (insert (format-time-string
           "%Y-%m-%d %H:%M:%S" (current-time))))

emacs improve builtins features

(defun bk/uptime-osx ()
  "Uptime of your OS.
Agora tenho duas linhas"
  (interactive)
  (message
   (shell-command-to-string "uptime")))
(defun bk/restclient ()
  "Open the buffer."
  (with-current-buffer (get-buffer-create "*restclient*")
    (restclient-mode)
    (pop-to-buffer (current-buffer))))
(defun bk/eval-buffer ()
  (interactive)
  (eval-buffer)
  (message "buffer evaluated!"))

configuring builtins emacs modes

(defun bk/conf-builtin-packages ()
  "Function to enable or disable builtin modes correctly."
  (dolist (_m bk/builtins-packages)
    (let ((mode (car _m))
          (status (cdr _m)))
      (if (string-equal status "enable")
          (add-hook 'after-init-hook mode)
        (when (fboundp mode)
          (funcall mode -1))))))

osx functions

Open file directory in Finder from current file.

(defun bk/finder ()
  (interactive)
  (let ((file (buffer-file-name)))
    (if file
        (shell-command
         (format "%s %s" (executable-find "open") (file-name-directory file)))
      (error "Buffer is not attached to any file!."))))

remember all my custom functions and its documentation

(defun bk/remember-all-custom-functions ()
  "Function to format a simple table with all custom functions that I created."
  (let* ((custom-list (apropos-internal "^bk/"))
         (func-list (seq-filter 'functionp custom-list))
         (docs (mapcar 'documentation func-list))
         (docs-nnil (mapcar #'(lambda (el) (if el el "There isn't docstrings to this function! Shame!")) docs))
         (docs-fmt (mapcar #'(lambda (el) (string-join (split-string el "\n") " ")) docs-nnil))
         (res '()))
    (dotimes (index (length func-list))
      (push `(,(nth index func-list) ,(nth index docs-fmt)) res))
    res))
;;(append '((Functions Documentation) hline)
;;        (bk/remember-all-custom-functions))

Better defaults

There are a number of unfortunate facts about the way Emacs works out of the box. Therefore, the next lines here are willing to fix some default behaviors.

settings

Enhanced core editing experience.

(setq tab-always-indent 'complete
      ring-bell-function 'ignore
      help-window-select t
      delete-old-versions t
      backup-by-copying t
      ispell-program-name "/usr/local/bin/aspell"
      backup-directory-alist '(("." . "~/.emacs.d/backup"))
      version-control t
      shift-select-mode nil
      query-replace-highlight t
      auto-window-vscroll nil
      set-mark-command-repeat-pop t
      load-prefer-newer t
      global-auto-revert-non-file-buffers t
      auto-revert-verbose t
      echo-keystrokes 0.1)
;; show me empty lines after buffer end
(setq-default indicate-empty-lines t)
;; org-mode: don't ruin S-arrow to switch windows
(setq org-replace-disputed-keys t)
;; fontify org-mode code blocks
(setq org-src-fontify-natively t)
(when is-osx
  (setq ns-alternate-modifier nil
        dired-use-ls-dired nil
        ns-command-modifier 'meta))
;; defaults that need to be set globally
(setq-default truncate-lines t
              indent-tabs-mode nil
              require-final-newline t)
;; shift key to move between windows
(windmove-default-keybindings)
;; utf-8 everywhere
(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8-unix)
;; save point position between sessions
(require 'saveplace)
(setq-default save-place t)
;; warn only when opening files bigger than 100mb
(setq large-file-warning-threshold 100000000)
;; fixing ls from osx
(when (eq system-type 'darwin)
  (require 'ls-lisp)
  (setq ls-lisp-use-insert-directory-program nil))
(setq set-mark-command-repeat-pop t)

I never understood why Emacs has these commands disabled by default. Well, let's change it, they are really useful.

(put 'set-goal-column 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'erase-buffer 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-defun 'disabled nil)

compilation

(setq byte-compile-warnings '(not free-vars unresolved
                                  noruntime lexical make-local))

Prefer newer compiled files

(setq load-prefer-newer t)

activate builtin modes

Toggle the status for some of the builtin modes.

(setq bk/builtins-packages '((menu-bar-mode . "disable")
                             (tool-bar-mode . "disable")
                             (scroll-bar-mode . "disable")
                             (horizontal-scroll-bar-mode . "disable")
                             (blink-cursor-mode . "disable")
                             (tooltip-mode . "disable")
                             (electric-pair-mode . "enable")
                             (show-paren-mode . "enable")
                             (column-number-mode . "enable")
                             (global-auto-revert-mode . "enable")
                             (global-visual-line-mode . "disable")
                             (global-whitespace-mode . "enable")
                             (pending-delete-mode . "enable")
                             (delete-selection-mode . "enable")))
(bk/conf-builtin-packages)

Enable highlight current line.

(add-hook 'prog-mode-hook 'hl-line-mode)
(add-hook 'text-mode-hook 'hl-line-mode)

recentf

(require 'recentf)
(setq recentf-max-saved-items 500
      recentf-max-menu-items 15
      recentf-auto-cleanup 'never)
(recentf-mode +1)

tramp

(setq tramp-default-method "ssh")
(setq tramp-backup-directory-alist backup-directory-alist)
(setq tramp-auto-save-directory "~/tmp/tramp/")
(setq tramp-chunksize 2000)
(setq tramp-use-ssh-controlmaster-options "ssh")

uniquify

Emacs traditional method for making buffer names unique adds <2>, <3>, etc. to the end of the buffers. This mode replaces that behavior. The available styles to improve the separation of conflicting names are:

forward bar/mumble/name quux/mumble/name reverse name\\mumble\\bar name\\mumble\\quux post-forward name|bar/mumble name|quux/mumble post-forward-angle-brackets name name nil name name<2>

For now, I prefer the reverse.

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward
      uniquify-after-kill-buffer-p t
      uniquify-separator "/"
      uniquify-ignore-buffers-re "^\\*")

expand region

(bk/install-maybe 'expand-region)

Don't use expand-region fast keys.

(setq expand-region-fast-keys-enabled nil)

If you change the value of the variable er–show-expansion-message you can easily look at the minibuffer and see what is the kind of expansion that the library is performing as you press any new extra expand key. Good way to become familiarized with the concepts of s-exp, variables and symbols.

(setq er--show-expansion-message t)

dired

Dired makes an Emacs buffer containing a listing of a directory. You can use the normal Emacs commands to move around in this buffer, and special Dired commands to operate on the listed files. Dired works with both local and remote directories.

Materials that I need to master:

Some extra material: WikEmacs - Dired

(require 'dired-x)
(require 'dired)
(setq dired-recursive-copies 'always
      dired-recursive-deletes 'always
      dired-dwim-target t)
(global-set-key (kbd "C-x C-j") 'dired-jump)
;; C-a is nicer in dired if it moves back to start of files
(defun dired-back-to-start-of-files ()
  (interactive)
  (backward-char (- (current-column) 2)))
(define-key dired-mode-map (kbd "C-a") 'dired-back-to-start-of-files)
(define-key dired-mode-map (kbd "k") 'dired-do-delete)
;; enable 'a'-keybinding in dired - which opens the file and closes dired buffer
(put 'dired-find-alternate-file 'disabled nil)
;; delete with C-x C-k to match file buffers and magit
(define-key dired-mode-map (kbd "C-x C-k") 'dired-do-delete)

diff mode

Change some colors for the diff-mode.

(eval-after-load 'diff-mode
  '(progn
     (set-face-foreground 'diff-added "green4")
     (set-face-foreground 'diff-removed "red3")))

register

(set-register ?n '(file . "~/Dropbox/notes.org"))
(set-register ?l '(file . "~/Dropbox/links.org"))
(set-register ?t '(file . "~/Dropbox/todo.org"))
(set-register ?o '(file . "~/Dropbox/log.org"))
(set-register ?i '(file . "~/.emacs.d/conf.org"))

multiple cursors

This is some pretty crazy functionality, so yes, there are kinks. o/ Nice intro about a very good library indeed.

Multiple cursors does not work well when you invoke its commands with M-x. It needs to be bound to keys to work properly.

Some suggestions!

(bk/install-maybe 'multiple-cursors)
(require 'multiple-cursors)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)

The other good pattern is related to editing a region. When you have an active regions that spans multiple lines, the following will add a cursor to each line:

(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
  1. To get out of multiple-cursors-mode, press <return> or C-g.
    1. The first C-g will disable the marked region before editing
  2. If you want to insert a newline in multiple-cursors-mode, use C-j

Episode 13: multiple-cursors

secrets

Settings to setup the usage of authinfo.gpg inside Emacs. The idea is to be as secure as possible when dealing with passwords and private information here.

This whole section only makes sense if you are me =] Or using some pretty similar configuration style. I'll try to isolate the functions that are very specific for my current box.

(require 'epa-file)
(epa-file-enable)
(setq epa-pinetry-mode 'loopback)
(setenv "GPG_AGENT_INFO" nil)
(custom-set-variables '(epg-gpg-program *mac-gpg2-exec*))
(setq authinfo *authinfo-file*)
(setq auth-sources '((:source *authinfo-file*)))
(require 'netrc)
(defun get-authinfo (host)
  "Function to get login and password given a HOST name."
  (let* ((entry (netrc-parse authinfo))
         (hostentry (netrc-machine entry host)))
    (when hostentry
      hostentry)))

Now let's take advantage of the authinfo function above and use it to connect into ERC.

(defun bk/login-irc ()
  "Connecting to my IRC account."
  (let* ((hostentry (get-authinfo "irc.freenode.net"))
         (login (netrc-get hostentry "login"))
         (password (netrc-get hostentry "password")))
    (setq erc-nick login)
    (setq erc-password password)))

If I am running this setup with my GPG key already configured, let's use it.

(when bk-home?
  (bk/login-irc))

flyspell

(require 'flyspell)
(setq ispell-program-name "/usr/local/bin/aspell"
      ispell-extra-args '("--sug-mode=ultra"))
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(add-hook 'text-mode-hook 'flyspell-mode)

Org mode

Org-mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system. <– Or in my own words: WTF? Why u so good?

The amount of different features that org-mode have is unbelievable. You can do pretty much anything … org-mode became a nice framework where people started to build nice software above it.

I'm not using this right now because of the minimalist mantra I'm following right now, but take a look into:

  1. org-reveal
  2. org-super-agenda
  3. org-web-tools
  4. org-protocol-capture-html

The material that I'm more interested right now: FAQ, Manual, Compact Manual, hacks and tutorials.

defaults

Include better defaults for Org mode

(setq-default org-confirm-babel-evaluate nil
              org-confirm-elisp-link-function nil
              org-enforce-todo-dependencies t
              org-log-done t
              org-hide-emphasis-markers t ; remove the markup characters
              org-return-follows-link t)
(add-hook 'org-mode-hook 'org-indent-mode)
(add-hook 'org-mode-hook 'visual-line-mode)

babel and Export

Configure the org-babel options to make better use of the source blocks.

(org-babel-do-load-languages
 'org-babel-do-load-languages
 '((scheme . t)
   (python . t)
   (clojure . t)
   (emacs-lisp . t)
   (sh . t)))

The code block in Org-mode has their own behaviors that can be modified like the default number of spaces for indentations, if you can use shift keys… etc…

(setq org-edit-src-content-indentation 0
      org-src-tab-acts-natively t
      org-src-fontify-natively t
      org-confirm-babel-evaluate nil
      org-support-shift-select 'always)

Let's change some behavior after saving a org-mode buffer.

(defun tangle-on-save-org-mode-file ()
  (when (string= (message "%s" major-mode) "org-mode")
    (org-babel-tangle)))
(add-hook 'after-save-hook 'tangle-on-save-org-mode-file)

If you keep creating org files to manage your programming projects, you will end up with a very messy arrangement of files spread across many places in your computer. Ok, but why this is bad? Actually, I usually do create some TODOs inside the files so I can get back to it and refactor some code or implement some feature. The following code will add the org files to the agenda view as soon as we save the file.

(defun to-agenda-on-save-org-mode-file ()
  (when (string= (message "%s" major-mode) "org-mode")
    (org-agenda-file-to-front)))
(add-hook 'after-save-hook 'to-agenda-on-save-org-mode-file)

Templates for org block

(eval-after-load 'org
  '(add-to-list 'org-structure-template-alist
                (list "em" (concat
                            "#+BEGIN_SRC emacs-lisp\n"
                            "?\n"
                            "#+END_SRC"))))

Enable org-mode to export/convert files into markdown.

(eval-after-load "org"
  '(require 'ox-md nil t))

org agenda

(setq org-return-follows-link t)
(setq org-agenda-files '("~/Dropbox"))
(setq org-agenda-window-setup 'only-window)
(setq org-capture-templates
      '(("a" "Appointment" entry (file+headline org-appointments "Calendar")
         "* APPT %^{Description} %^g\n%?\nAdded: %U")
        ("n" "Notes" entry (file+datetree org-notes-file)
         "* %^{Description} %^g %?\nAdded: %U")
        ("t" "Task Diary" entry (file+datetree org-todo-file)
         "* TODO %^{Description} %^g\n%?\nAdded: %U")
        ("b" "Bookmark" entry (file+headline org-links-file "Bookmarks")
         "* %?  %^g" :empty-lines 1)
        ("l" "Log Time" entry (file+datetree org-log-file)
         "** %U - %^{Activity} :TIME:")))
(setq org-todo-keywords '((sequence "TODO" "IN_PROGRESS" "DONE")))
(setq org-todo-keyword-faces '(("IN_PROGRESS" . "#FF9900")))

disable some keybindings from org-mode

List of keybindings

(define-key org-mode-map (kbd "C-,") nil)
(define-key org-mode-map (kbd "C-'") nil)
(define-key org-mode-map (kbd "C-TAB") nil)
(define-key org-mode-map (kbd "C-c C-r") nil)

Macbook setup

For most of the time I am editing files on a MacOSX, so there are some features that need special care when we change from *unix systems to the osx environment. Most of the time, e-lisp code works pretty much the same way in both environments, but let's see some exceptions.

default settings

For now, the only real change that I need is chaining meta-key to command-key.

(when is-osx
  (setq mac-command-modifier 'meta
        mac-right-option-modifier 'none
        mac-option-modifier 'super))

Change dired settings for listings

(when is-osx
  (setq dired-use-ls-dired nil))

changing emacs frame

(when (memq window-system '(mac))
  (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
  (add-to-list 'default-frame-alist '(ns-appearance . dark)))

key bindings

GNU Emacs has built-in support for fullscreen since version 24.4.

(global-set-key (quote [M-f10]) 'toggle-frame-fullscreen)

let's add more keys… stolen from Purcell's configuration

(global-set-key (kbd "M-`") 'ns-next-frame)
(global-set-key (kbd "M-h") 'ns-hide-emacs)

Help

I am reading the Emacs Info continuously, but I really like the change in font-lock when I visit some nodes at the Info section. Unfortunately, these font-locks are only valid during the current emacs session, so… let's fix it. I want to be able to save the history of the visited Info nodes and also to load it back when I open Emacs.

(defvar bk--name-of-file "bk-info.history")
(defun bk/save-info-history-visited-nodes ()
  (interactive)
  (let ((path (expand-file-name bk--name-of-file user-emacs-directory)))
    (with-temp-file path
      (prin1 Info-history-list (current-buffer)))))
(add-hook 'kill-emacs-hook 'bk/save-info-history-visited-nodes)
(defun bk/load-info-history-visited-nodes ()
  (interactive)
  (let ((path (expand-file-name bk--name-of-file user-emacs-directory)))
    (with-temp-buffer
      (insert-file-contents path)
      (goto-char (point-min))
      (setq Info-history-list (read (current-buffer))))))
(add-hook 'after-init-hook 'bk/load-info-history-visited-nodes)

Appearance

Change how the look and feel of the Emacs buffer works. My default theme looks like this today:

img

better default settings

I like disabling most of the UI during my sessions.

(setq inhibit-splash-screen t
      inhibit-startup-echo-area-message t
      inhibit-startup-message t
      use-dialog-box nil
      ns-pop-up-frames nil
      use-file-dialog nil)

Change the spacing before consecutive lines

(setq-default line-spacing 2)

setup custom themes

I have a folder with custom themes that I find on the web or that I try to customize to myself. I need to transform the honeydew setting into a custom theme by myself.

(setq custom-theme-directory (concat user-emacs-directory "themes"))
(dolist (path (directory-files custom-theme-directory t "\\w+"))
  (when (file-directory-p path)
    (add-to-list 'custom-theme-load-path path)))

advices

The first advice that I use related to appearance in Emacs is assuring that I'll disable completely any theme before loading a new one. If you try to load the leuven theme in your emacs and after that try to change it to the deeper-blue you will notice that there are several faces that do not respect the deeper-blue theme anymore.

(defadvice load-theme (before theme-dont-propagate activate)
  "Disable all theme effects before enabling new ones."
  (mapc #'disable-theme custom-enabled-themes))

setup initial frame settings

This is how I prefer to start my emacs with. The proper size and position on the screen.

(defun bk/initial-frame-setup ()
  (when (display-graphic-p)
    (setq initial-frame-alist
          '((tool-bar-lines . 0)
            (width . 90)
            (height . 40)
            (left . 300)
            (top . 50)))
    (setq default-frame-alist initial-frame-alist)))

enabling theme custom functions

I have some functions that help me setup some themes that I like. I change basically how the font size, borders, background, highlighting looks like.

(defun bk/theme-tsdh-light ()
  "Let's face it... defaults are always better..."
  (interactive)
  (load-theme 'tsdh-light t)
  (when is-osx
    (set-face-attribute 'default nil :font *mac-font*)))
(defun bk/theme-custom-black ()
  "Custom black theme from Emacs Rocks is really cool!"
  (interactive)
  (load-theme 'default-black t)
  (bk/initial-frame-setup)
  (when is-osx
    (set-face-attribute 'default nil :font *mac-font*)))
(defun bk/theme-custom-light ()
  "customize the look and feel a little bit more."
  (interactive)
  (if (display-graphic-p)
      (progn
        (setq initial-frame-alist
              '((tool-bar-lines . 0)
                (width . 90)
                (height . 45)
                (background-color . "honeydew")
                (left . 400)
                (top . 50)))
        (setq default-frame-alist initial-frame-alist)))
  (when is-osx
    (set-face-attribute 'default nil :font *mac-font*)))

activate default theme

Well, I have to start with some theme…

(bk/theme-tsdh-light)

highlight some words

When you are working on large codebases, it is very common to find FIXMEs and TODOs. Whether you are tracking down a bug or implementing new features, you would very much want to be aware of these.

(add-hook 'hi-lock-mode-hook
          (lambda nil
            (highlight-regexp "FIXME" (quote hi-red-b))
            (highlight-regexp "TODO" (quote hi-red-b))))

Completions

I find interesting how each word is well thought of when you deal with Emacs; I just stopped by Google to search for completions in Emacs and I found this incredible Completion wiki entry that explains several meanings for this term inside emacs:

  1. input completions: completion of your input in the minibuffer
  2. text completion: completion of words or abbreviations in a buffer other than the minibuffer
  3. help about completions: the possible completions in the sense of 1 or 2 are displayed; this help is also sometimes referred to as "completion"

ido mode

There are really many to talk about Ido (interactively DO things) mode. With ido you'd type a few characters until you find the match, or until you narrow down your list of matches to a manageable subset, and then press RET.

So many links for good material, but I would definitely start with mastering emacs guide. Really impressive.

The other really great source of information is the Ido) native manual.

(require 'ido)
(ido-mode +1)
(ido-everywhere +1)
(setq-default ido-use-virtual-buffers t
              ido-enable-flex-matching t
              ido-enable-tramp-completion t)
;; always rescan buffer for menu
(setq-default imenu-auto-rescan t)
(add-to-list 'ido-ignore-directories "target")
(add-to-list 'ido-ignore-directories "elpa")
(add-to-list 'ido-ignore-directories "node_modules")
(add-to-list 'ido-ignore-directories "vendor")

You can control the order in which files are sorted when ido displays them in the minibuffer.

(setq ido-file-extensions-order
      '(".clj" ".edn" ".cljs" ".json" ".org" ".md" ".py" ".php" ".rest"))

Ouch, there is something that really annoys me: ido start to make suggestions when I am trying to rename some new file. Thanks for Ergo Emacs. I am one satisfied contributor with your work o/ keep up.

;; when you call `write-file' (C-x C-w)
(define-key (cdr ido-minor-mode-map-entry) [remap write-file] nil)

Stop ido from automatically switching to merged work directories during file name input.

(setq ido-auto-merge-work-directories-length -1)

Let's change the default behavior of ido to show candidates vertically.

(setq ido-decorations (quote ("\n-> " "" "\n   " "\n   ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))

Config the keys too:

(defun ido-disable-line-truncation ()
  (set (make-local-variable 'truncate-lines) nil))
(add-hook 'ido-minibuffer-setup-hook 'ido-disable-line-truncation)
(defun ido-define-keys ()
  (define-key ido-completion-map (kbd "C-n") 'ido-next-match)
  (define-key ido-completion-map (kbd "C-p") 'ido-prev-match))
(add-hook 'ido-setup-hook 'ido-define-keys)

company

(bk/install-maybe 'company)
(global-company-mode +1)

smex

smex is a M-x enhancement for Emacs. Built on top of Ido, it provides a convenient interface to your recently and most frequently used commands. And to all the other commands, too. The commands are displayed in an Ido completion buffer, ordered by relevant.

(bk/install-maybe 'smex)
(require 'smex)
(smex-initialize)
(setq smex-prompt-string "Here be dragons => ")
(global-set-key (kbd "C-x C-m") 'smex)
(global-set-key (kbd "M-x") 'smex)

There is this very nice command that I had never look at it: smex-major-mode-commands which shows limited commands that are relevant to the active major mode.

(global-set-key (kbd "C-c C-m") 'smex-major-mode-commands)

You can also check which commands that have no key binding keep being called over and over again. The idea is to built the history about your usage pattern so you can change your default bindings to improve your text editing experience.

;; use `smex-show-unbound-commands'

grep

grep searches for PATTERN in each FILE. It can perform basic searches and advanced pattern matching using regular expressions. The idea is to process text line by line and print any lines which match the specific pattern.

(eval-after-load "grep"
  '(progn
     (add-to-list 'grep-find-ignored-directories "target")
     (add-to-list 'grep-find-ignored-directories "elpa")
     (add-to-list 'grep-find-ignored-directories "vendor")
     (add-to-list 'grep-find-ignored-directories "node_modules")))

imenu using ido

I found this package at the Emacs Wiki page and it has all the features I needed to improve my Imenu experience. More than that, all the new package was made using only built-ins features of Emacs. So I decided to translate the package here line by line in order to learn how it's done and also to perform modifications to the package.

After learning by reading the package, I figured out that I could perform real changes to it and make it really simpler to my use case. Let's find out how:

Dependencies

(require 'ido)
(require 'imenu)

I was curious about the function that reads a choice from Imenu alist through Ido. I removed the portion of the code that tried to guess a good default value for ido-completing-read.

(defun idomenu--read (index-alist &optional prompt guess)
  (let* ((symatpt (thing-at-point 'symbol))
         (names (mapcar 'car index-alist))
         (name (ido-completing-read (or prompt "imenu ") names
                                    nil t nil nil nil))
         (choice (assoc name index-alist)))
    (if (imenu--subalist-p choice)
        (idomenu--read (cdr choice) prompt nil)
      choice)))

I will try to skip most of the package original code by providing only the function that reads using imenu and the function that actually will be called. If something starts to go wrong, I come back here and improve this function.

(defun bk/ido-menu ()
  (interactive)
  (let ((index-alist (cdr (imenu--make-index-alist))))
    (if (equal index-alist '(nil))
        (message "No imenu tags in buffer")
      (imenu (idomenu--read index-alist nil t)))))

Let's change the global keybinding now.

(global-set-key (kbd "C-x C-i") 'bk/ido-menu)

occur

After reading the reddit post about loccur I took some time to write a small code to mimic the expected behavior of this functions.

The basic idea is to change the following defaults:

  1. Improve the first guess for occur using thing-at-point
  2. Go "full-screen" with the *Occur* buffer
  3. After finding an occurrence, RET go there and kill *Occur* buffer.
(defun bk/improve-occur ()
  "Function to improve `occur' with the default value."
  (interactive)
  (push (let ((syb (thing-at-point 'symbol)))
          (when (stringp syb)
            (regexp-quote syb)))
        regexp-history)
  (call-interactively 'occur))
(add-hook 'occur-hook
          '(lambda ()
             (switch-to-buffer-other-window "*Occur*")
             (delete-other-windows)))
(defadvice occur-mode-goto-occurrence (after occur-goto-after activate)
  (delete-other-windows))

Change the default command-key of occur

(global-set-key (kbd "M-s o") 'bk/improve-occur)

Feed RSS

Elfeed is an extensible web feed reader for Emacs, supporting both Atom and RSS. I really enjoy having all my news aggregated into a single place and what is a better place than here? There are so much you can do with elfeed that we have some links to help with the learning curve:

(bk/install-maybe 'elfeed)
(setq-default elfeed-search-filter "@24-months-ago +unread")
(setq elfeed-feeds
      '(("http://lambda-the-ultimate.org/rss.xml" functional)
        ("https://byorgey.wordpress.com/feed/" functional)
        ("http://gigasquidsoftware.com/atom.xml" clojure)
        ("http://planet.emacsen.org/atom.xml" emacs)
        ("https://nullprogram.com/feed/" programming)
        ("http://feeds.feedburner.com/cognicast" clojure)
        ("http://blog.cognitect.com/blog?format=rss" clojure)
        ("http://feeds.feedburner.com/stevelosh?format=xml" clojure)
        ("https://existentialtype.wordpress.com/feed/" functional)
        ("http://planet.clojure.in/atom.xml" clojure)
        ("http://planet.lisp.org/rss20.xml" lisp)
        ("http://www.scheme.dk/planet/atom.xml" scheme)
        ("http://tonsky.me/blog/atom.xml" clojure)
        ("https://danlebrero.com/feed.rss" programming)
        ("http://www.clojure.net/rss.xml" clojure)
        ("https://www.youtube.com/feeds/videos.xml?user=techguruuk" emacs)
        ("http://emacsrocks.com/atom.xml" emacs)
        ("http://emacs-fu.blogspot.com/feeds/posts/default" emacs)
        ("http://yqrashawn.com/feeds/lazyblorg-all.atom_1.0.links-only.xml" emacs)
        ))

It's recommended that you make a global binding for elfeed

(global-set-key (kbd "C-x w") 'elfeed)

Some functionalities worth mentioning (Press the following letter on *elfeed-search*)

  • g: refresh view of the feed listing
  • G: fetch feed updates from the servers
  • s: update the search filter

Snippets

Yasnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates. The snippet syntax is inspired from TextMate's syntax, you can even import most TextMate templates to Yasnippet.

demo on youtube

(bk/install-maybe 'yasnippet)
(bk/install-maybe 'yasnippet-snippets)
(require 'yasnippet)
(require 'yasnippet-snippets)
(yas-global-mode +1)
;; how do I use alternative keys, i.e. not TAB?
(define-key yas-minor-mode-map (kbd "TAB") nil)
(define-key yas-minor-mode-map (kbd "<tab>") nil)
(define-key yas-minor-mode-map (kbd "M-i") 'yas-expand)
;; no need to be verbose
(setq yas-verbosity 1)
;; wrap around region
(setq yas-wrap-around-region t)

Shell

functions to help with shell

(defun eshell/clear ()
  "Function to clear eshell buffer."
  (let ((eshell-buffer-maximum-lines 0))
    (eshell-truncate-buffer)))

defaults

(setq shell-file-name "/bin/zsh"
      eshell-save-history-on-exit t
      eshell-glob-case-insensitive t
      eshell-error-if-no-glob t
      eshell-cmpl-cycle-completions nil)
(let* ((path (shell-command-to-string ". ~/.zshrc; echo -n $PATH"))
       (path-more (concat path ":/Library/TeX/texbin/")))
  (setenv "PATH" path-more))
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
(add-hook 'eshell-mode-hook (lambda () (hl-line-mode -1)))

remove highlight current line from eshell

(add-hook 'eshell-mode-hook (lambda ()
                              (hl-line-mode -1)))

visual commands

Some commands require a proper terminal to run and eshell can't handle that, therefore it's desired to delegate these commands to a term buffer. Let's define which commands we are talking about.

(add-hook 'eshell-mode-hook
          (lambda ()
            (add-to-list 'eshell-visual-commands "ssh")
            (add-to-list 'eshell-visual-commands "tail")
            (add-to-list 'eshell-visual-commands "htop")
            (add-to-list 'eshell-visual-commands "vim")
            (setq eshell-visual-subcommands '("git" "log"
                                              "l" "diff" "show"))))

aliases

Some default aliases that I'm getting really used to.

(add-hook 'eshell-mode-hook (lambda ()
                              (eshell/alias "e" "find-file $1")
                              (eshell/alias "emacs" "find-file $1")
                              (eshell/alias "ee" "find-file-other-window $1")
                              (eshell/alias "gd" "magit-diff-unstaged")
                              (eshell/alias "gds" "magit-diff-staged")
                              (eshell/alias "d" "dired $1")))

Project

A library to provide a nice set of features operating on a project level without introducing external dependencies. Projectile provides easy project management and navigation.

(bk/install-maybe 'projectile)
(defadvice projectile-project-root (around ignore-remote first activate)
  "Do not look for the name of the project when visiting remote files."
  (unless (file-remote-p default-directory) ad-do-it))

Change the default settings of projectile.

(require 'projectile)
(setq projectile-switch-project-action #'projectile-dired
      projectile-completion-system 'ido
      projectile-mode-line nil
      projectile-project-root-files-bottom-up '(".git" ".projectile")
      projectile-project-search-path '("~/captalys" "~/personal")
      projectile-enable-caching nil)

You need to choose a prefix key to interact with projectile now, it's not a free given anymore.

(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(add-hook 'after-init-hook 'projectile-mode)

Git

Free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

You can read the documentation (the same Git Pro) book online for free.

magit settings

(bk/install-maybe 'magit)

Change some default settins from Magit.

(set-default 'magit-no-confirm '(stage-all-changes
                                 unstage-all-changes))

magit functions

There are some functions that I wrote for dealing with magit in a ease way. The first pattern that I often use is to ignore all the current changes in the repository and just sync with the remote branch.

(defun bk/git-ignore-and-pull ()
  (interactive)
  (magit-reset-hard "HEAD~1")
  (magit-pull (concat "origin/" (magit-get-current-branch)))
  (message "Your repository is syned with your remote branch."))

There are another very common pattern: git add –> git commit -m –> git pull –> git push

(defun bk/git-commit-pull-push ()
  (interactive)
  (magit-stage-modified)
  (let* ((msg-string (read-string "Commit message: "))
         (branch (magit-get-current-branch))
         (origin-branch (concat "origin/" branch)))
    (magit-commit (concat "-m " msg-string))
    (magit-pull origin-branch)
    (magit-push branch origin-branch "-v")
    (message "Your repository is synced with the remote branch now...")))

Tips

(setq bk-tips
      '(
        "<C-c C-SPC> jump to the next active ERC buffer. Switch back to last non-ERC buffer visited."
        "<C-x +> will make windows the same heights and widths."
        "<C-x ^> increases the height by 1 line."
        "<C-h i> to open the info manual."
        "<C-t> to `transpose-chars'."
        "<C-x C-j> to `dired-jump' and goes to dired of file being visited."
        "<C-x C-q> to enter Dired Edit mode. When finished <C-c C-c>!"
        "<C-x C-t> to `transpose-lines'"
        "[Magit] s to stage; u to unstange; c for commit; F for pulling; P for pushing."
        "<C-x n n> narrow to region. Press <C-x n w> to widen (or un-narrow)."
        "<C-x n p> narrow to page. Press <C-x n w> to widen (or un-narrow)."
        "<C-x n s> narrow to subtree in org-mode. Press <C-x n w> to widen."
        "<C-x r SPC R> to save a buffer position in register R; jump back to it later."
        "<C-x r f R> to save frame configuration in register R; jump back to it later."
        "<C-x r w R> to save window configuration in register R; jump back to it later."
        "<C-x s> followed by d to see the diff of your buffer before saving it."
        "<M-=> with a region selected to `count-words'"
        "<M-t> to `transpose-words'."
        "<M-z> to use `zap-up-to-char'. Get used to it. Very useful."
        "<C-x => to display information about the character current under the cursor."
        "<M-x> `info-display-manual' to find information to specific mode."
        "<M-x> `occur' and remember that lines can be edited in place in the occur buffer."
        "<M-x> `write-region' to write a selection to a file."
        "After renaming file with `dired-jump', press <C-x k RET> to go back to the renamed file."
        "Syntax for using TRAMP through SSH: C-x C-f /ssh:username@myhost:/path/to/file."
        "Syntax for using TRAMP through SUDO: C-x C-f /su::/etc/hosts."
        "There is a very handy `sort-lines' command available in built-in Emacs."
        "Use `diff-buffer-with-file' to compare your buffer with the corresponding file at disk."
        "You can ask for a `list-registers' to see what is stored in those little monsters."
        "You can use <M-g TAB> to goto column."
        "You can use <M-x> `find-name-dired' to find all files recursively matching a pattern."
        "t inside a Dired buffer to mark all files in there. And Q to query-replace inside of them."
        "Use <C-x 4 f> when your cursor is over a filename to open in other window."
        "Use <C-x 5 f> when your cursor is over a filename to open in other frame."
        "<C-x d <directory>> to open in Dired."
        "To copy the name of the file at point, use `dired-copy-filename-as-kill'."
        "<C-x C-r> to open file in READ-ONLY mode."
        "To copy the path to the folder you're looking at in dired: <M-< w>"
        "Enable wdired mode in dired to edit the file name by hitting <C-x C-q>"
        "<C-c C-p> to open `find-file-at-point'."
        "<C-c C-w> to move a headline under another top level headline in org mode."
        "<C-c C-t> to show a painel with all the ORG Keyword options."
        "<C-x }> to enlarge window horizontally."
        "<C-x C-n> to `set-goal-column' to freeze the cursor when moving to the next line."
        "<C-c C-m> to call `smex-major-mode-commands' which will enable only relevant commands to your major mode."
        "<C-c> toggles if a searching of buffer and file names should ignore case."
        "<C-t> toggles matching by Emacs regular expression."
        "<C-SPC / C-@> restricts the completion list to anything that matches your current input."
        "<M-s> inside the IDO mode (C-x C-f) to search for a file matching your input."
        "<C-\> run the `org-match-sparse-tree' and filter by tags in Emacs."
        ))

Function to be called when you want to read some free tip lessons from your older-self.

(defun bk/tips ()
  (interactive)
  (random t)
  (message (concat " " (nth (random (length bk-tips)) bk-tips))))

Send a new tips when you start emacs.

(add-hook 'after-init-hook
          '(lambda ()
             (run-at-time 10 nil 'bk/tips)))

Extra modes

fix-words

I often write the words all in lowercase and just after typing I decided which case the word should have. However, the default bindings of emacs for changing capitalization of words are very bad. I'll try some customization before installing out another package called fix-words.

(defun bk/capitalize-word ()
  "captalize word after I typed it."
  (interactive)
  (capitalize-dwim -1))
(defun bk/downcase-word ()
  "downcase word after I typed it."
  (interactive)
  (downcase-dwim -1))
(defun bk/upcase-word ()
  "downcase word after I typed it."
  (interactive)
  (upcase-dwim -1))
(global-set-key (kbd "M-c") #'bk/capitalize-word)
(global-set-key (kbd "M-l") #'bk/downcase-word)
(global-set-key (kbd "M-u") #'bk/upcase-word)

which-key

is a minor mode for Emacs that displayes the key bindings following your currently entered incomplete command in a popup.

(bk/install-maybe 'which-key)
(which-key-mode +1)

yaml

(bk/install-maybe 'yaml-mode)
(autoload 'yaml-mode "yaml-mode" "Major mode for yaml files" t)
(add-to-list 'auto-mode-alist '("\\Jenkinsfile\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))

dockerfile

(bk/install-maybe 'dockerfile-mode)
(autoload 'dockerfile-mode "dockerfile-mode" "Major mode for Dockerfiles" t)
(add-to-list 'auto-mode-alist '("\\Dockerfile\\'" . dockerfile-mode))

restclient

(bk/install-maybe 'restclient)
(autoload 'restclient "restclient" "Send HTTP requests from your Emacs" t)
(add-to-list 'auto-mode-alist '("\\.rest\\'" . restclient-mode))

Instant messaging

The following settings hides some of the channel messages to avoid cluttering the buffer. The other line changes the prompt for each channel buffer to match the channel name, this way you always know who you are typing to.

(setq erc-port 6667)
(setq erc-accidental-paste-threshold-seconds nil)
(setq erc-prompt-for-nickserv-password nil)
(setq erc-prompt-for-password nil)
(setq erc-hide-list '("JOIN" "PART" "QUIT"))

I usually come to the same channels once I log in.

(require 'erc-join)
(erc-autojoin-enable)
(setq erc-autojoin-channels-alist
      '(("freenode.net" "#clojure" "#emacs")))
(setq erc-join-buffer 'bury
      erc-autojoin-timing :indent)

Change some default values to improve the editing experience inside ERC

(setq erc-fill-column 75)

There are also some modes that I can enable after I'm inside an ERC channel.

(eval-after-load 'erc
  '(progn
     (require 'erc-spelling)
     (require 'erc-services)
     (require 'erc-truncate)
     (erc-services-mode +1)
     (erc-truncate-mode +1)
     (add-to-list 'erc-modules 'spelling)
     (set-face-foreground 'erc-input-face "dim gray")
     (set-face-foreground 'erc-my-nick-face "blue")))

One nice thing about ERC and the #emacs channel is the running bots around. They are very useful for asking for help and pointing at the documentation for some specific problem/feature. You can access the fsbot using the /msg fsbot to start a private conversation with him and ask him questions using comma. e.g ,dired

<bartuka> ,dired
<fsbot> I think Dired is [0] (info "(emacs)Dired")
<fsbot> [1] at http://www.emacswiki.org/emacs/DiredMode

Markdown

(bk/install-maybe 'markdown-mode)
(autoload 'markdown-mode "markdown-mode" "Major mode for Markdown files" t)
(autoload 'gfm-mode "markdown-mode" "Major mode for GitHub files t")
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode))

Changing default behaviors of the markdown-mode. Not much.

(require 'markdown-mode)
(setq markdown-enable-wiki-links t
      markdown-hide-urls t
      markdown-hide-markup nil)

Latex

Some small configuration for latex editing.

(bk/install-maybe 'auctex)
(setq TeX-auto-save t
      TeX-parse-self t)
(setq-default TeX-master nil)

There are some minor modes that I wish to enable on tex editing.

(add-hook 'LaTeX-mode-hook 'visual-line-mode)
(add-hook 'LaTeX-mode-hook 'flymake-mode)
(add-hook 'LaTeX-mode-hook 'flyspell-mode)
(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)

In order to compile documents to PDF by default:

(setq TeX-PDF-mode t)

I've being using this simple template in order to create TeX files. TODO: I need to change this template to a yasnippet template

(defun bk/latex-template-article ()
  "Personal LaTeX template."
  (interactive)
  (insert "\\documentclass[11pt]{article}\n")
  (insert "\\usepackage[brazilian]{babel}\n")
  (insert "\\usepackage[utf8]{inputenc}\n")
  (insert "\\usepackage[T1]{fontenc}\n")
  (insert "\\usepackage{graphicx}\n")
  (insert "\\usepackage{cite}\n")
  (insert "\\title{INSERT YOUR TITLE HERE}\n")
  (insert "\\author{Wanderson Ferreira}\n")
  (insert "\\date{\\today}\n")
  (insert "\\begin{document}\n")
  (insert "\\maketitle\n\n\n")
  (insert "\\bibliographystyle{plain}\n")
  (insert "\\bibliography{NAME-BIB-FILE}\n")
  (insert "\\end{document}\n\n")
  (insert "This text will not show up in the output"))

Template for Beamer.

(defun bk/latex-template-beamer ()
  (interactive)
  (insert "\\documentclass{beamer}\n")
  (insert "\\mode<presentation>\n")
  (insert " {\n")
  (insert "\\setheme{Madrid}\n")
  (insert "\\secolortheme{default}\n")
  (insert "\\sefonttheme{serif}\n")
  (insert "\\setbeamertemplate{navigation symbols}{}\n")
  (insert "\\setbeamertemplate{caption}[numbered]\n")
  (insert " }\n")
  (insert "\\usepackage[english]{babel}\n")
  (insert "\\usepackage[utf8x]{inputenc}\n")
  (insert "\\usepackage{chemfig}\n")
  (insert "\\usepackage[version=3]{mhchem}\n")
  (insert "\n")
  (insert "\\title[teste]{Descricao}}\n")
  (insert "\\author{Wanderson Ferreira}\n")
  (insert "\\institute{bartuka.com}\n")
  (insert "\\date{\\today}\n")
  (insert "\n")
  (insert "\\begin{document}\n")
  (insert "\n")
  (insert "\\begin{frame}\n")
  (insert "\\titlepage\n")
  (insert "\\end{frame}\n")
  (insert "\n")
  (insert "\\begin{frame}{Outline}\n")
  (insert "\\tableofcontents\n")
  (insert "\\end{frame}\n")
  (insert "\\end{document}\n"))

Programming

Emacs has specialized major modes for many programming languages. Each of this language modes specifies the syntax of expressions and custom rules for indentation, syntax highlighting and moving definitions for that particular programming language.

Ideally, Emacs should have a major mode for each programming language that you might want to edit. If it doesn't have a mode, it can be implemented in a package not distributed in Emacs.

general

(add-hook 'prog-mode-hook (defun bk--add-watchwords ()
                            (font-lock-add-keywords
                             nil `(("\\<\\(FIX\\(ME\\))?\\|TODO\\)"
                                    1 font-lock-warning-face t)))))
(setq whitespace-style '(trailing lines face tabs tab-mark lines-tail)
      whitespace-line-column 300)
(add-hook 'before-save-hook 'whitespace-cleanup)

fold code block

HideShow is a minor mode that hides and shows blocks of text. In particular, it hides balanced-expression code blocks and multi-line comment blocks.

Let's make it available.

(add-hook 'prog-mode-hook 'hs-minor-mode)

So, the keybindings that are used by default are really complicated.

Keys M-x version
C-c @ C-M-s show-all
C-c @ C-M-h hide-all
C-c @ C-s show-block
C-c @ C-h hide-block
C-c @ C-c toggle hide/show

I'll try to keep with the defaults for a while, specially because I can handle most of my use case wiht the toggle form.

I'd like to change the default values for the behavior of isearch. I don't like the idea of the searching inside buffers to open folded code.

(setq hs-isearch-open nil)

clojure

cider

(bk/install-maybe 'cider)
(require 'cider)
(setq cider-repl-result-prefix ";; => ")
(setq cider-repl-popup-stacktraces t)
(setq cider-repl-use-pretty-printing t)
(add-hook 'cider-repl-mode-hook 'eldoc-mode)

By default, interactive commands that require a symbol, e.g. cider-cod will prompt for the symbol, with the prompt defaulting to the symbol at point. Now, I wish to try the command with symbol at point right a way.

(setq cider-prompt-for-symbol nil)

Hide the *nrepl-connection* and nrepl-server buffers from appearing in some buffer switching commands.

(setq nrepl-hide-special-buffers t)

Please, just save my clojure buffer before C-c C-k, you know what you are doing.

(setq cider-save-file-on-load t)

I don't like a lot of text being displayed at the minibuffer without any real information. Just remove the eldoc on symbol at point.

(setq cider-eldoc-display-for-symbol-at-point nil)

We need to enable and disable some keys that are automatically taken over by cider when we enable it.

(define-key cider-mode-map (kbd "C-c C-Q") 'cider-quit)
(define-key cider-mode-map (kbd "C-<return>") 'hs-toggle-hiding)
(define-key cider-mode-map (kbd "C-:") nil)
(define-key cider-mode-map (kbd "C-c C-c") nil)
(define-key cider-repl-mode-map (kbd "C-c C-l") 'cider-repl-clear-buffer)
(define-key cider-repl-mode-map (kbd "C-:") nil)
(define-key cider-repl-mode-map (kbd "C-c C-c") nil)

Small workaround until updates in cider and seisman can get into work. issue#10

(defalias 'sesman-linked-sessions 'sesman--linked-sessions)

clojure mode

(bk/install-maybe 'clojure-mode)
(add-to-list 'exec-path "/Users/wandersonferreira/dotfiles/scripts")
(add-to-list 'exec-path "/usr/local/bin")
(add-hook 'clojure-mode-hook 'cider-mode)
;; hide nrepl buffers when switching buffers
(setq nrepl-hide-special-buffers t)
;;; list of clojure snippets to master at dates
;; 2018-09-26 23:58:28: defn, def, let, if, require

Support for subword movements and deletions

(with-eval-after-load 'clojure-mode
  (subword-mode +1))

refactor

A collection of clojure refactoring functions for Emacs

(bk/install-maybe 'clj-refactor)
(require 'clj-refactor)
(defun my-clojure-mode-hook ()
  (clj-refactor-mode 1)
  (cljr-add-keybindings-with-prefix "C-c C-m"))
(add-hook 'clojure-mode-hook #'my-clojure-mode-hook)

There are several mnemonics to use with clojure refactor. Let's write down some of them and build this muscle memory slowly. Please, remember that all this key chords are done after you hit the prefix sequence key C-c C-m.

key chord description
ad add declaration for current top-level form
ai add import to namespace declaration, then jump back
ap add a dependency to your project.clj and hotload into repl

lisp

paredit-mode

I think paredit deserves it only section. This package is really amazing and I can't remember how things works before it.

(bk/install-maybe 'paredit)

I also want to enable it when using the eval-expression at the minibuffer. Trying to expend more time at M-: (info "something")

(defun bk/cond-enable-paredit ()
  (if (eq this-command 'eval-expression)
      (paredit-mode 1)))
(add-hook 'minibuffer-setup-hook 'bk/cond-enable-paredit)

Usually I enable delete-selection-mode but every time I try to rely on this functionality I get blocked by paredit in one way or the other. Let's fix it.

(put 'paredit-forward-delete 'delete-selection 'supersede)
(put 'paredit-backward-delete 'delete-selection 'supersede)
(put 'paredit-newline 'delete-selection t)

Enabling the mode for some special major modes.

(autoload 'enable-paredit-mode "paredit" "turn on pseudo-structure" t)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'clojure-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)

racket-mode

(bk/install-maybe 'racket-mode)
(setq racket-program "/usr/local/bin/racket")

elisp

define some keys

(define-key emacs-lisp-mode-map (kbd "C-c C-c") 'eval-defun)
(define-key emacs-lisp-mode-map (kbd "C-c C-b") 'eval-buffer)

web mode

(bk/install-maybe 'php-mode)
(autoload 'php-mode "php-mode" "Major mode for PHP files." t)
(add-to-list 'auto-mode-alist '("\\.php\\'" . php-mode))

sql

I basically followed the Emacs Wiki page about how to format SQL buffers with the right syntax.

Basically I installed a gem package running the following command.

gem install anbt-sql-formatter

The idea now, is to call this library using the shell-command from within Emacs. There are basically two helper functions to format your buffer or region

(defun bk/sql-beautify-region (beg end)
  "Beautify SQL in region between BEG and END."
  (interactive "r")
  (save-excursion
    (shell-command-on-region beg end "anbt-sql-formatter" nil t)))
(defun bk/sql-beautify-buffer ()
  "Beautify SQL in buffer."
  (interactive)
  (bk/sql-beautify-region (point-min) (point-max)))
(defun bk/beautify-region-or-buffer ()
  "Beautify sql for the entire buffer or the marked region."
  (interactive)
  (if (use-region-p)
      (bk/sql-beautify-region (region-beginning) (region-end))
    (bk/sql-beautify-buffer)))

I also think it's a good idea to have mode-specific keybindings for some tasks. Let's bind these functions to the SQL Mode.

(add-hook 'sql-mode-hook '(lambda ()
                            (local-set-key (kbd "C-M-]") 'bk/beautify-region-or-buffer)))

python

Yeah, I need to have a proper Python mode configured at my Emacs. I've been trying to avoid elpy, but this package is just to good to be true. It handles every situation that I usually have with Emacs.

(bk/install-maybe 'elpy)
(eval-after-load "python"
  '(elpy-enable))

Remove some default modules from elpy

(eval-after-load "python"
  '(progn
     (delete `elpy-module-highlight-indentation elpy-modules)
     (delete `elpy-module-django elpy-modules)))

There are some other nice libraries when working with Python that I got used to.

(bk/install-maybe 'pythonic)
(eval-after-load "python"
  '(pythonic-activate "~/miniconda3"))

react

some settings to start editing React files.

(bk/install-maybe 'rjsx-mode)
(add-to-list 'auto-mode-alist '(".*\.js\'" . rjsx-mode))
(add-to-list 'auto-mode-alist '("components\/.*\.js\'" . rjsx-mode))
(add-to-list 'auto-mode-alist '("containers\/.*\.js\'" . rjsx-mode))

disable warnings and reinforce the usage of spaces instead of tabs.

(require 'rjsx-mode)
(add-hook 'rjsx-mode-hook (lambda ()
                            (setq indent-tabs-mode nil
                                  js-indent-level 2
                                  js2-strict-missing-semi-warning nil)))

Keys

global keys

kill a frame easyly

I am using the Emacs anywhere plugin for OSX and I have configured the new frames to show up at some specific position. After I typed something that I want to, I have to kill the buffer.

Let's make it easier.

(global-set-key (kbd "<f12>") 'delete-frame)

refactor later

(global-set-key (kbd "M-n") 'highlight-symbol-at-point)
(global-set-key (kbd "M-p") 'unhighlight-regexp)
;; shells
(global-set-key (kbd "C-x \"") 'eshell)
(global-set-key (kbd "C-c e") 'eshell)
;; git
(global-set-key (kbd "C-c m s") 'magit-status)
;; better M-x
(global-set-key (kbd "C-c C-p") 'find-file-at-point)
;; selections
(global-set-key (kbd "C-=") 'er/expand-region)
;; defaults
(global-set-key (kbd "M-z") 'zap-up-to-char)
(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-set-key (kbd "C-x p") 'pop-to-mark-command)
;; org
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
;; search
(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)
;; change between window
(global-set-key (kbd "C-x 2") (lambda ()
                                (interactive)
                                (split-window-vertically)
                                (other-window 1)))
(global-set-key (kbd "C-x 3") (lambda ()
                                (interactive)
                                (split-window-horizontally)
                                (other-window 1)))
(global-set-key (kbd "C-x k") 'kill-this-buffer)
(global-set-key (kbd "C-x r q") 'save-buffers-kill-terminal)

more bindings for C-x 8

Macro to avoid writing the same thing when dealing with interactive lambda expressions. I don't need to copy and paste all this boilerplate code, we already know macros.

(defmacro bk/lambda (form)
  "Custom macro to avoid typing unnecessary boilerplate."
  (list 'lambda 'nil
        (list 'interactive)
        form))

All the extra bindings!

(global-set-key (kbd "C-x 8 - >") (bk/lambda (insert "→")))
(global-set-key (kbd "C-x 8 v") (bk/lambda (insert "✓")))
(global-set-key (kbd "C-x 8 8") (bk/lambda (insert "∞")))

Finish

There are some commands/settings that need to be run only by the end of the config file.

garbage collector

restore the changed value for

;; restore garbage collector variable
(setq gc-cons-threshold 800000)

org agenda

start agenda on start up.

(org-agenda nil "a")

cleaning up your mode line

this trick was removed from mastery emacs which is a very good book by the way. you probably are using a lot of different minor/major modes and all of this text is showing up in your mode line for no good reason.

there is the package diminish.el which is very good to perform this kind of clening up. however, i am on my minimalist journey, therefore let's write some functions!

list of modes that i want to hide or rename.

(defvar mode-line-cleaner-alist
  `((yas-minor-mode . "")
    (paredit-mode . " π")
    (flyspell-mode . "")
    (org-indent-mode . "")
    (visual-line-mode . "")
    (hs-minor-mode . "")
    (global-company-mode . "")
    (company-mode . "")
    (global-visual-line-mode . "")
    (flyspell-prog-mode . "")
    (global-whitespace-mode . "")
    (eldoc-mode . "")))

actual function… with some modifications, i like dolist form.

(defun clean-mode-line ()
  (interactive)
  (dolist (cleaner mode-line-cleaner-alist)
    (let* ((mode (car cleaner))
           (mode-str (cdr cleaner))
           (old-mode-str (cdr (assq mode minor-mode-alist))))
      (when old-mode-str
        (setcar old-mode-str mode-str))
      (when (eq mode major-mode)
        (setq mode-name mode-str)))))

start the function after every change major mode.

(add-hook 'after-change-major-mode-hook 'clean-mode-line)

server

(require 'server)
(unless (server-running-p)
  (server-start))