Introduction

What is Emacs? The only good text editor that is! Sorry, it's not easy to explain what it exactly is, but the name was intended to be EditorMacros. 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 on your keyboard, you are typing into an 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 re-write is to keep the number of packages to a minimum. I want to explore the builtins of Emacs and to extend my knowledge of Elisp. Therefore, I will try to write functions to help me out with some situations instead of downloading one more dependency for this 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 in the stable branch, therefore I gave higher priority to stable, 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/"))
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)

(package-initialize)

(when (not package-archive-contents)
  (package-refresh-contents))

Change the priority of the repositories:

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

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

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

function to load packages from specific folder

(defun load-packages-from-folder (folder-name)
  (dolist (l (directory-files (concat user-emacs-directory folder-name) nil "^[^\.]"))
    (add-to-list 'load-path (concat user-emacs-directory folder-name "/" l))
    (autoload (intern l) (concat l ".el"))))

dependencies

Load all dependencies for third-packages submodules and my own custom packages.

(load-packages-from-folder "dependencies")

3rd-party packages

I'll keep all the packages that handles unsupported major modes in Emacs inside this separate folder /lib

(load-packages-from-folder "major-modes")

These are the major modes available right now.

language description link
PHP Major mode for PHP editing php-mode
React A major mode for editing JSX files rjsx-mode
Markdown Editing markdown format markdown-mode
Clojure Emacs support for the clojure prog clojure-mode
Yaml Editing files in the YAML format yaml-mode
Racket Major mode for Racket racket-mode
Dockerfile Editing Dockerfiles dockerfile-mode
Restclient Tool to explore HTTP REST restclient

maintainer

(load-packages-from-folder "maintainer")
package description link
helm-spotify-plus control your spotify application from emacs helm-spotify-plus
python-experiment package to ease the dev of python code python-experiment
grep-folder better way to grep some specific folders grep-folder
bartuka-mode my own custom minor-mode local

bartuka-mode

(require 'bartuka-mode)
(add-hook 'after-init-hook 'bartuka-mode)

spotify

(require 'helm-spotify-plus)

python-experiment

(require 'python-experiment)

grep-folder settings

(require 'grep-folder)
(setq grep-folder-setup-files '(("~/.emacs.d" . (".gitmodules"))))
(setq grep-folder-setup-dirs '(("~/.emacs.d" . nil)
                               ("~/captalys" . nil)))
(global-set-key (kbd "C-c g") 'grep-folder)

custom variables

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

(defvar osx? (eq system-type 'darwin))
(defvar bk-home? (equal (system-name) "Wandersons-Air"))
(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)

(defalias 'cquit 'cider-quit)
(defalias 'ctest 'cider-test-run-test)

Some very important settings:

(when bk-home?
  (setq user-mail-address "wanderson.ferreira@protonmail.com")
  (setq user-full-name "Wanderson Ferreira"))

custom file

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

(setq custom-file (expand-file-name "etc/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.

Copy without selection

Let's try to make usage of the advices put in the EmacsWiki website. I agree that selecting what you want accurately is the most time-consuming thing when working in Emacs. I'll try to experience this functions.

base functions

(defun get-point (symbol &optional arg)
  "get the point"
  (funcall symbol arg)
  (point))

(defun copy-thing (begin-of-thing end-of-thing &optional arg)
  "Copy thing between beg & end into kill ring."
  (save-excursion
    (let ((beg (get-point begin-of-thing 1))
          (end (get-point end-of-thing arg)))
      (copy-region-as-kill beg end))))

copy word

(defun copy-word (&optional arg)
  "Copy words at point into kill-ring"
  (interactive "P")
  (copy-thing 'backward-word 'forward-word arg)
  (message "Copied WORD"))
(global-set-key (kbd "C-c w") 'copy-word)

copy backward word

(defun copy-backward-word ()
  "copy word before point - rocky @ stackexchange"
  (interactive "")
  (save-excursion
    (let ((end (point))
          (beg (get-point 'backward-word 1)))
      (copy-region-as-kill beg end)))
  (message "Copied backward WORD"))
(global-set-key (kbd "C-c W") 'copy-backward-word)

copy line

(defun copy-line (&optional arg)
  "Save current line into kill-ring without mark the line."
  (interactive "P")
  (copy-thing 'beginning-of-line 'end-of-line arg)
  (message "Copied LINE."))
(global-set-key (kbd "C-c l") 'copy-line)

copy paragraph

(defun copy-paragraph (&optional arg)
  "Copy paragraphs at point"
  (interactive "P")
  (copy-thing 'backward-paragraph 'forward-paragraph arg)
  (message "Copied PARAGRAPH"))
(global-set-key (kbd "C-c P") 'copy-paragraph)

copy string

(defun beginning-of-string (&optional arg)
  (when (re-search-backward "[ \t]" (line-beginning-position) :noerror 1)
    (forward-char 1)))

(defun end-of-string (&optional arg)
  (when (re-search-forward "[ \t]" (line-end-position) :noerror arg)
    (backward-char 1)))


(defun thing-copy-string-to-mark (&optional arg)
  "Try to copy a string and paste it to the mark
When used in shell-mode, it will paste string on shell prompt by default."
  (interactive "P")
  (copy-thing 'beginning-of-string 'end-of-string)
  (message "Copied STRING"))
(global-set-key (kbd "C-c s") 'thing-copy-string-to-mark)

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* "~/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

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

(defun bk/duplicate-line ()
  "Function to duplicate line."
  (interactive)
  (copy-line)
  (save-excursion
    (end-of-line)
    (newline 1)
    (yank))
  (forward-line 1))

(global-set-key (kbd "C-c d") 'bk/duplicate-line)

Unfill paragraph. I can't remember why this was useful once, but I've being using this for a while again.

(defun bk/unfill-paragraph ()
  "Take a multi-line paragraph and make it into a single line."
  (interactive)
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))

(global-set-key (kbd "M-Q") 'bk/unfill-paragraph)

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.elc at runtime!"
  (interactive)
  (let ((conf-file (expand-file-name "conf.org" user-emacs-directory)))
    (org-babel-load-file conf-file)))

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

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

rename file and buffer

(defun bk/rename-this-file-and-buffer (new-name)
  "Renames both current buffer and file it's visiting to new-name."
  (interactive "sNew name: ")
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (unless filename
      (error "Buffer '%s' is not visiting a file!" name))
    (progn
      (when (file-exists-p filename)
        (rename-file filename new-name 1))
      (set-visited-file-name new-name)
      (rename-buffer new-name))))

delete this file

(defun bk/delete-this-file ()
  "Delete the current file, and kill the buffer."
  (interactive)
  (unless (buffer-file-name)
    (error "No file is currently being edited"))
  (when (yes-or-no-p (format "Really delete '%s'?"
                             (file-name-nondirectory buffer-file-name)))
    (delete-file (buffer-file-name))
    (kill-this-buffer)))

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
      backup-directory-alist '(("." . "~/.emacs.d/backup"))
      create-lockfiles nil
      shift-select-mode nil
      global-auto-revert-non-file-buffers t
      auto-revert-verbose t
      large-file-warning-threshold 100000000
      org-replace-disputed-keys t
      org-src-fontify-natively t)

(setq-default truncate-lines t
              indicate-empty-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)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

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)

Save point position between sessions:

(require 'saveplace)
(setq-default save-place t)
(setq save-place-file (expand-file-name "etc/places" user-emacs-directory))

bookmarks:

(setq bookmark-default-file (expand-file-name "etc/bookmarks" user-emacs-directory))

change the autosave directory:

(setq auto-save-list-file-prefix (expand-file-name
                                  "etc/auto-save-list/saves-" user-emacs-directory))

makes C-n insert newlines if the point is at the end of the buffer. useful, as it means you won't have to reach for the return key to add newlines.

(setq next-line-add-newlines t)

global line highlight

(global-hl-line-mode +1)

ediff

(require 'ediff)
(setq-default ediff-split-window-function 'split-window-horizontally
              ediff-window-setup-function 'ediff-setup-windows-plain)

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

recentf

(require 'recentf)

(add-hook 'after-init-hook 'recentf-mode)

make usage of ido mode for reading the recentf-list

(defun ido-recentf-open ()
  "Use `ido-completing-read' to find file."
  (interactive)
  (if (find-file (ido-completing-read "Find recent file: " recentf-list))
      (message "Opening file...")
    (message "Aborting")))
(global-set-key (kbd "C-x C-r") 'ido-recentf-open)

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<bar/mumble> name<quux/mumble> nil name name<2>

For now, I prefer the reverse.

(require 'uniquify)

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

hippie expand

use hippie expand instead of dabbrev, it is a better version

(require 'hippie-exp)
(setq hippie-expand-try-functions-list '(try-expand-dabbrev
                                         try-expand-dabbrev-all-buffers
                                         try-expand-dabbrev-from-kill
                                         try-complete-file-name-partially
                                         try-complete-file-name
                                         try-expand-all-abbrevs
                                         try-expand-list
                                         try-expand-line
                                         try-complete-lisp-symbol-partially
                                         try-complete-lisp-symbol))

(global-set-key (kbd "M-/") #'hippie-expand)
(global-set-key (kbd "s-/") #'hippie-expand)


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)

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

Emacs registers are compartments where you can save text, rectangles, positions, and other things for later use. Once you save text or a rectangle in a register, you can copy it into the buffer once or many times; once you save a position in a register, you can jump back to that position once or many times.

;; (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 ?e '(file . "~/.emacs.d/conf.org"))
(set-register ?i '(file . "~/gtd/inbox.org"))
(set-register ?p '(file . "~/gtd/gtd.org"))
commands description
C-x r w r save the state of the selected frame's windows in r
C-x r f r save the state of all frames, including all their window in r
C-x r j r to restore a window or frame configuration

flyspell

Flyspell enables on-the-fly spell checking in Emacs by the means of a minor mode.

(require 'flyspell)

(if osx?
    (setq ispell-program-name "/usr/local/bin/aspell")
  (setq ispell-program-name "/usr/bin/aspell"))

(setq ispell-extra-args '("--sug-mode=ultra"))

(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(add-hook 'text-mode-hook 'flyspell-mode)

stop printing messages for every word when checking the whole buffer. It's extremely slow process.

(setq flyspell-issue-message-flag nil)
keybindings function description
M-$ M-x ispell-word correct a word using ispell
- M-x flyspell-auto-correct-word auto correct current word
- M-x flyspell-correct-word display a popup with correct word suggestions
- M-x flyspell-region runs flyspell on the selected region
- M-x flyspell-buffer runs flyspell on the current buffer

mark

Amazing article: Fixing the mark command in transient mark mode. Sometimes you just want to explicitly set a mark into one place, so you can get back to it latter with C-u SPC.

(defun push-mark-no-activate ()
  (interactive)
  (push-mark (point) t nil)
  (message "Pushed mark to ring."))

(global-set-key (kbd "C-'") 'push-mark-no-activate)

eldoc

(global-eldoc-mode +1)

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)

From active region to multiple cursors:

(global-set-key (kbd "C-c m r") 'set-rectangular-region-anchor)
(global-set-key (kbd "C-c m c") 'mc/edit-lines)
(global-set-key (kbd "C-c m e") 'mc/edit-ends-of-lines)
(global-set-key (kbd "C-c m a") 'mc/edit-beginnings-of-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

change the default location to save the mc-list.el which is automatically generated by multiple cursors. It keeps track of your preferences for running commands with mc.

(setq mc/list-file (expand-file-name "etc/mc-list.el" user-emacs-directory))

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: Dired Manual 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)

Advices

When you need to modify a function defined in another library, or when you need to modify a hook like foo-function, a process filter, or basically any variable or object field which holds a function.

Avoid killing the scratch buffer.

(defadvice kill-buffer (around kill-buffer-around-advice activate)
  "When calling `kill-buffer' always bury the scratch buffer."
  (let ((buffer-to-kill (ad-get-arg 0)))
    (if (equal buffer-to-kill "*scratch*")
        (bury-buffer)
      ad-do-it)))

Improve a little better the org agenda view.

(defadvice org-agenda (around split-vertically activate)
  (let ((split-width-threshold 80))
    ad-do-it))

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

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-use-speed-commands t
              org-return-follows-link t)

hooks:

(add-hook 'org-mode-hook 'org-indent-mode)
(add-hook 'org-mode-hook 'visual-line-mode)

basic config to change how the source window changes when we hit C-'.

(setq org-src-window-setup 'current-window)

Check this list of Conflicts that happens between org and others features.

make the windmove.el package works in Org-mode.

(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)

after changing the state of any TODO item, save the current buffer.

(add-hook 'org-trigger-hook 'save-buffer)

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)
   (emacs-lisp . t)
   (shell . 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"))))

Nice python template to tangle the code from org files.

(eval-after-load 'org
  '(add-to-list 'org-structure-template-alist
                (list "pl" (concat
                            "#+BEGIN_SRC python :noweb yes :tangle <FILENAME> :results output :exports both\n"
                            "?\n"
                            "#+END_SRC"))))

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

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

Getting Things Done

change the defaults for the org agenda functionality

(setq org-return-follows-link t
      org-agenda-window-setup 'only-window)

Following some tutorials to complete GTD workflows.

(setq org-agenda-files '("~/gtd/inbox.org"
                         "~/gtd/gtd.org"
                         "~/gtd/tickler.org"))

capture data into the inbox and tickler files.

(setq org-capture-templates '(("t" "Todo [inbox]" entry
                               (file+headline "~/gtd/inbox.org" "Tasks")
                               "* TODO %i%?")
                              ("T" "Tickler" entry
                               (file+headline "~/gtd/tickler.org" "Tickler")
                               "* %i%? \n %U")))

The inbox should be processed and emptied daily. When processing the inbox, I'd refile each entry that is actionable and belongs to a project using C-c C-w, moving the entry to the appropriate place.

(setq org-refile-targets '(("~/gtd/gtd.org" :maxlevel . 3)
                           ("~/gtd/someday.org" :maxlevel . 1)
                           ("~/gtd/tickler.org" :maxlevel . 2)))

The main file is the gtd.org. That's where all the active projects are kept. Each project contains actions to be performed. The first action of each project is called its "next action", and that's always the one I will do when working on a project.

Tags -— Tagging is done using C-c C-c on a headline, whether it's a project or action. Purposes of he tags:

  • regular categories, like :emacs:
  • tags that link to people, like :veridiana:
  • GTD contexts

GTD contexts are just regular tags, starting with @. Some useful ones, @home, @office, @travelling, @email..

TODO keywords

(setq org-todo-keywords '((sequence "TODO(t)" "WAITING(w)" "NEXT(n)" "STARTED(s)" "|" "DONE(d)" "CANCELLED(c)")))

closing items… keep a CLOSE tag with a timestamp

(setq org-log-done 'time)

Custom agenda views

(setq org-agenda-custom-commands
      '(("g" . "GTD contexts")
        ("ga" "All TODO" alltodo nil
         ((org-agenda-sorting-strategy '(tag-up priority-up))))

        ("gc" "Clojure" tags-todo "clojure"
         ((org-agenda-sorting-strategy '(priority-up))
          (org-agenda-prefix-format "[ ] %T: ")
          (org-agenda-compact-blocks t)
          (org-agenda-remove-tags t)))

        ("gs" "Study Time" tags-todo "@study"
         ((org-agenda-sorting-strategy '(priority-up))))

        ("ge" "Emacs Time" tags-todo "@emacs")

        ("gp" "Personal stuff" tags-todo "@personal")))

blogging

(require 'ox-publish)

(defun bk/my-blog-footer (arg)
  (with-temp-buffer
    (insert-file-contents "~/Documents/bkblog/org/footer.html")
    (buffer-string)))

(defun bk/my-blog-header (arg)
  (with-temp-buffer
    (insert-file-contents "~/Documents/bkblog/org/header.html")
    (buffer-string)))

(setq org-publish-project-alist
      '(("blog-notes"
         :base-directory "~/Documents/bkblog/org"
         :base-extension "org"
         :publishing-directory "~/Documents/bkblog/public"
         :recursive t
         :publishing-function org-html-publish-to-html
         :headline-label 4
         :section-numbers nil
         :html-head nil
         :html-head-include-default-style nil
         :html-head-include-scripts nil
         :html-postamble bk/my-blog-footer
         :html-preamble bk/my-blog-header)

        ("blog-static"
         :base-directory "~/Documents/bkblog/org"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|eot\\|svg\\|woff\\|woff2\\|ttf"
         :publishing-directory "~/Documents/bkblog/public"
         :recursive t
         :publishing-function org-publish-attachment)

        ("blog"
         :components ("blog-notes" "blog-static"))))

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 osx?
  (setq mac-command-modifier 'meta
        mac-right-option-modifier 'none
        mac-option-modifier 'super))

Change dired settings for listings

(when osx?
  (require 'ls-lisp)
  (setq ls-lisp-use-insert-directory-program nil)
  (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)))

Move to trash when deleting stuff

(setq delete-by-moving-to-trash t
      trash-directory "~/.Trash/emacs")

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)

motion

The C-M-d is a global keybinding in OSX which prevents me to use the down-list sexp motion. Let's disable the following chord to get it back.

defaults write com.apple.symbolichotkeys AppleSymbolicHotKeys -dict-add 70 '<dict><key>enabled</key><false/></dict>'

Karabiner

Ok, I just ran over this post from EmacsRedux about remapping Return to Control key and it's just great. But, the really cool idea was to install the Karabiner software on MacOS and use the neat functionality that allows you to have two behaviors on the CAPSLOCK key:

  1. If held, act like a CONTROL key
  2. If pressed once, act like a META key

This is really useful. I've been using for some days, already like it.

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 "etc/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:

emacs_screen.png

Figure 1: This is the caption for the next figure link (or table)

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

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 . 35)
            (left . 300)
            (top . 40)))
    (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 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 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 . 100)
                (height . 40)
                (background-color . "honeydew")
                (left . 400)
                (top . 40)))
        (setq default-frame-alist initial-frame-alist)))
  (when osx?
    (set-face-attribute 'default nil :font *mac-font*)))

activate default theme

Well, I have to start with some theme…

;;(bk/theme-tsdh-light)
;;(bk/theme-deeper-blue)
(bk/theme-custom-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"

electric completions

Let's make electric help me out with some completiongs

(setq electric-pair-pairs '(
                            (?\* . ?\*)
                            (?\~ . ?\~)
                            ))

Let's activate the electric pair mode.

(electric-pair-mode +1)

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 ido-use-virtual-buffers t
      ido-enable-flex-matching 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)

this sorts an IDO filelist by mtime instead of alphabetically.

(defun ido-sort-mtime ()
  "Reorder the IDO file list to sort from most recently modified."
  (setq ido-temp-list
        (sort ido-temp-list
              (lambda (a b)
                (ignore-errors
                  (time-less-p
                   (sixth (file-attributes (concat ido-current-directory b)))
                   (sixth (file-attributes (concat ido-current-directory a))))))))
  (ido-to-end
   (delq nil (mapcar
              (lambda (x) (and (char-equal (string-to-char x) ?.) x))
              ido-temp-list))))

(add-hook 'ido-make-file-list-hook 'ido-sort-mtime)
(add-hook 'ido-make-dir-list-hook 'ido-sort-mtime)

company

(bk/install-maybe 'company)

(setq company-global-modes '(not eshell-mode shell-mode
                                 org-mode term-mode))
(setq company-idle-delay 0.1)
(setq company-transformers '(company-sort-by-occurrence))
(setq company-require-match 'never)
(setq company-show-numbers t)
(global-company-mode +1)

I've stolen from the ora-company solution to select a suggestion from the number of the suggestion.

(defun ora-company-number ()
  (interactive)
  (let* ((k (this-command-keys))
         (re (concat "^" company-prefix k)))
    (if (cl-find-if (lambda (s) (string-match re s))
                    company-candidates)
        (self-insert-command 1)
      (company-complete-number (string-to-number k)))))

(defun ora-activate-number ()
  (interactive)
  (let ((map company-active-map))
    (mapc
     (lambda (x)
       (define-key map (format "%d" x) 'ora-company-number))
     (number-sequence 0 9))
    (define-key map " " (lambda ()
                          (interactive)
                          (company-abort)
                          (self-insert-command 1)))
    (define-key map (kbd "<return>") nil)))

(ora-activate-number)

remove the default select candidates keys… always confusing them.. control is always better (?)

(with-eval-after-load 'company
  (define-key company-active-map (kbd "M-n") nil)
  (define-key company-active-map (kbd "M-p") nil)
  (define-key company-active-map (kbd "C-n") #'company-select-previous)
  (define-key company-active-map (kbd "C-p") #'company-select-previous))

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://endlessparentheses.com/atom.xml" emacs)
        ("https://www.reddit.com/r/emacs/.rss" emacs)
        ("https://www.reddit.com/r/orgmode/.rss" emacs)
        ("http://www.blackhats.es/wordpress/?feed=rss2" emacs)
        ("http://www.howardism.org/index.xml" emacs)
        ("http://www.masteringemacs.org/feed/" emacs)
        ("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

Let's be honest, the Mastering Emacs article about Shell is awesome.

"If you use Emacs as your shell you will have all the functionality that Emacs provides plus you get almost all of the advantages provided by the shell itself."

Your choices:

mode description
ansi-term faithful emulator
eshell dumb terminal that behaves like an Emacs buffer
eshell fancier for customizations

terminal emulators

Due to the way terminal emulators work, most of Emacs's common keybindings are reserved for the subshell itself; to get around this you can switch between line mode and char mode. In the line mode the terminal buffer will behave much like shell mode and normal Emacs buffers. In the char mode each character is sent directly to the underslying inferior shell without preprocessing by Emacs.

keybinding effect
C-c C-j change to line mode
C-c C-k change to char mode

functions to help with shell

(defun eshell-clear-buffer ()
  "Clear terminal"
  (interactive)
  (let ((inhibit-read-only t))
    (erase-buffer)
    (eshell-send-input)))

(add-hook 'eshell-mode-hook
          '(lambda ()
             (local-set-key (kbd "C-l") 'eshell-clear-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)

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.

(require 'em-term)

(nconc eshell-visual-commands
       '("bower" "htop" "top" "ssh" "ranger" "npm" "tail"))

(nconc eshell-visual-subcommands '(("docker" "build")
                                   ("git" "log" "diff" "show")
                                   ("npm" "init" "install")))

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 "gsm" "git submodule add $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-completion-system 'ido
      projectile-switch-project-action 'projectile-find-file
      projectile-project-root-files-bottom-up '(".git" ".projectile")
      projectile-project-search-path '("~/captalys" "~/personal"))

change the default location where known projects are stored.

(setq projectile-known-projects-file (expand-file-name "etc/projectile-bookmarks.eld" user-emacs-directory))

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

Extras

time

definition for some timezones I'm interested on

(require 'time)

(setq display-time-24hr-format t
      display-time-world-list
      '(("Etc/GMT+3" "São Paulo")
        ("America/New_York" "New York")
        ("Etc/GMT-1" "Potenza Piccena")
        ("Etc/GMT-3" "Helsinki")))

Add timestamps before saving some buffers. You need to add the tag ;;; Time-stamp: <> to be able to have your time updated.

(require 'time-stamp)

(setq time-stamp-line-limit 20)
(add-hook 'before-save-hook #'time-stamp)

yaml

Activate the yaml-mode.

(require 'yaml-mode)

Add more extensions to be handled by yaml-mode.

(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))
(add-hook 'yaml-mode-hook 'goto-address-prog-mode)

dockerfile

(add-to-list 'auto-mode-alist '("\\Dockerfile\\'" . dockerfile-mode))

restclient

(require 'restclient)
(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

(require 'markdown-mode)

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

(setq markdown-enable-wiki-links t
      markdown-hide-urls t
      markdown-command "pandoc"
      markdown-asymmetric-header t
      markdown-unordered-list-item-prefix "* "
      markdown-hide-markup t)

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-display-help-banner nil
      cider-repl-wrap-history t
      cider-auto-select-error-buffer t
      cider-show-error-buffer t
      cider-repl-use-clojure-font-lock t
      cider-repl-pop-to-buffer-on-connect nil
      cider-repl-use-pretty-printing t
      cider-repl-popup-stacktraces t)

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)

figwheel

Let's create a function to start the figwheel repl for a ClojureScript project.

(setq cider-default-cljs-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))")

clojure mode

(add-to-list 'exec-path "~/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)

(add-to-list 'auto-mode-alist '("\\.edn$\\'" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.boot$\\'" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.cljs$\\'" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.clj$\\'" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.lein-env$\\'" . clojure-mode))

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

(require '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

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

(defun bk--set-python-environment ()
  (interactive)
  (elpy-enable)
  (pyvenv-activate "~/miniconda3")
  (message "Python environment activated!!"))

(eval-after-load "python"
  '(bk--set-python-environment))

Remove some default modules from elpy

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

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)

several keibindings

Help me search a little better.

(global-set-key (kbd "C-*") #'isearch-forward-symbol-at-point)
(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 this config file.

garbage collector

restore the changed value for the garbage collector threshold.

(setq gc-cons-threshold 800000)

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 . "")
    (abbrev-mode . "")
    (visual-line-mode . "")
    (hs-minor-mode . "")
    (global-company-mode . "")
    (company-mode . "")
    (subword-mode . "")
    (global-visual-line-mode . "")
    (flyspell-prog-mode . "")
    (global-whitespace-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

Running emacs in server mode is very important to me because I have some shell scripts to open files from Terminal in Emacs. Never using vim again, lol.

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

start eshell

Just start on the Eshell at the beginning.

(eshell)