My dockerized emacs ...
Switch branches/tags
Nothing to show
Clone or download

README.org

Dockemacs - the minimal emacs noX

https://coveralls.io/repos/github/AfsmNGhr/dockemacs/badge.svg?branch=master https://travis-ci.org/AfsmNGhr/dockemacs.svg?branch=master https://images.microbadger.com/badges/version/afsmnghr/dockemacs.svg https://images.microbadger.com/badges/image/afsmnghr/dockemacs.svg https://img.shields.io/docker/pulls/afsmnghr/dockemacs.svg?style=flat-square https://img.shields.io/docker/stars/afsmnghr/dockemacs.svg?style=flat-square

https://i.imgur.com/V6vlv7Q.gif

Table of Contents

Installation

Install Docker Engine:

Setup overlay2 storage driver. See docs.

// /etc/docker/daemon.json

{
  "storage-driver": "overlay2"
}

Create emacs data volume:

docker volume create emacs_data

Add alias:

# ~/.bash_aliases or etc ...

alias dockemacs='
  docker run -it --rm --net=host \
       --cpuset-cpus 0-3 \
       --env-file $HOME/.dockemacs \
       --entrypoint initialize "$@" \
       -v $HOME:/mnt/workspace \
       -v emacs_data:/home/emacser/.emacs.d \
       -v /etc/localtime:/etc/localtime:ro \
       afsmnghr/dockemacs:1.9.4 startup
'

Prepare $HOME/.dockemacs, check your env:

# default by

echo "UID=$(id -u)" >> $HOME/.dockemacs # 1000
echo "GID=$(id -g)" >> $HOME/.dockemacs # 100
echo "UNAME=emacser" >> $HOME/.dockemacs
echo "GNAME=emacs" >> $HOME/.dockemacs
echo "HOME=/home/emacser" >> $HOME/.dockemacs
echo "WORKSPACE=/mnt/workspace" >> $HOME/.dockemacs

# required

echo "TERM=xterm-256color" >> $HOME/.dockemacs
echo "ORG_FILES=Documents/org/" >> $HOME/.dockemacs
echo "HOST_USER=afsmnghr" >> $HOME/.dockemacs
echo "HOST_IP=127.1" >> $HOME/.dockemacs # only work with --net=host
echo "HOST_PORT=22" >> $HOME/.dockemacs
echo "DISPLAY=:0.0" >> $HOME/.dockemacs # required for web browser
echo "WEB_BROWSER=chromium" >> $HOME/.dockemacs
echo "REPOSITORY=git@github.com:AfsmNGhr/dockemacs.git" >> $HOME/.dockemacs
echo "BRANCH=master" >> $HOME/.dockemacs
echo "CORE_COUNT=4" >> $HOME/.dockemacs # 1

# optional

echo "HEAD_FORCE=true" >> $HOME/.dockemacs # git reset --hard
  • UID and GID - transparent permissions
  • UNAME and GNAME - user & group name in container
  • HOME - rewrite home path for new user
  • WORKSPACE - mount path from host
  • TERM - set terminal env
  • ORG_FILES - only relative path
  • HOST_USER, HOST_IP, HOST_PORT - remote management through ssh
  • DISPLAY - for GUI application
  • WEB_BROWSER - setup browser for emacs
  • REPOSITORY - our repository dotemacs (first clone)
  • BRANCH - our active branch
  • HEAD_FORCE - force update our branch
  • CORE_COUNT - use multiple cores

Setup ssh server and restart:

# /etc/ssh/sshd_config

ListenAddress 127.1

Setup ssh client:

Create sockets path.

mkdir ~/.ssh/sockets

Speedup local connection.

# ~/.ssh/config

Host *
     ControlMaster auto
     ControlPath ~/.ssh/sockets/%r@%h:%p
     ControlPersist 4h
     PreferredAuthentications publickey

Host 127.1
     Hostname 127.1
     User $HOST_USER
     Port $HOST_PORT
     Compression no
     Ciphers aes128-gcm@openssh.com
     ForwardX11 no

Check permissions of config file.

sudo chmod 600 ~/.ssh/config

Add our ssh pub key to authorized_keys.

ssh-copy-id "$HOST_USER@$HOST_IP" -p "$HOST_PORT"

For SSH_CONNECTION set TERM. Fixed tramp issues.

# ~/.bashrc

if [ "$SSH_CONNECTION" ]; then
    TERM='dumb'
fi

case "$TERM" in
    *)
        PS1='> '
        ;;
esac

Run and wait until the boot:

$ dockemacs

https://asciinema.org/a/148959.png

Wrappers for container workflow

https://i.imgur.com/wmDvJbq.png?1

  • WEB_BROWSER from env with DISPLAY
  • Docker

Bundle

;; .dir-locals.el in root project

((nil . ((eval .
               (progn
                 (setenv "PROJECT_LOCAL_PATH" "/mnt/workspace/local/path")
                 ;; local path in dockemacs container
                 (setenv "PROJECT_REMOTE_PATH" "/remote/path")
                 ;; remote path in project container
                 (setenv "PROJECT_BUNDLE_CMD" "docker exec -it PROJECT_CONTAINER bundle"))))))

Rubocop

;; .dir-locals.el in root project

((nil . ((eval .
               (progn
                 (setenv "PROJECT_LOCAL_PATH" "/mnt/workspace/local/path")
                 ;; local path in dockemacs container
                 (setenv "PROJECT_REMOTE_PATH" "/remote/path")
                 ;; remote path in project container
                 (setenv "PROJECT_RUBOCOP_CMD" "docker exec -it PROJECT_CONTAINER rubocop"))))))

node

;; .dir-locals.el in root project

((nil . ((eval .
               (progn
                 (setenv "PROJECT_LOCAL_PATH" "/mnt/workspace/local/path")
                 ;; local path in dockemacs container
                 (setenv "PROJECT_REMOTE_PATH" "/remote/path")
                 ;; remote path in project container
                 (setenv "PROJECT_NODE_CMD" "docker exec -it PROJECT_CONTAINER node"))))))

tslint

;; .dir-locals.el in root project

((nil . ((eval .
               (progn
                 (setenv "PROJECT_LOCAL_PATH" "/mnt/workspace/local/path")
                 ;; local path in dockemacs container
                 (setenv "PROJECT_REMOTE_PATH" "/remote/path")
                 ;; remote path in project container
                 (setenv "PROJECT_TSLINT_CMD" "docker exec -it PROJECT_CONTAINER sh -c '\$(npm bin)/tslint'")
                 ;; container workflow
                 (setenv "PROJECT_TSLINT_CMD" "cd /remote/path && '\$(npm bin)/tslint'")
                 ;; host application
)))))

Pylint

;; .dir-locals.el in root project

((nil . ((eval .
               (progn
                 (setenv "PROJECT_LOCAL_PATH" "/mnt/workspace/local/path")
                 ;; local path in dockemacs container
                 (setenv "PROJECT_REMOTE_PATH" "/remote/path")
                 ;; remote path in project container
                 (setenv "PROJECT_PYLINT_CMD" "docker exec -it PROJECT_CONTAINER pylint"))))))

Configurations

Initialize

Tangling with emacs script. See emacs script pitfalls.

#!/usr/bin/env sh
":"; exec emacs --quick --script "$0" "$@" # -*-emacs-lisp-*-

(require 'org)
(setq gc-cons-threshold most-positive-fixnum
      gc-cons-percentage 0.6)
(find-file (concat user-emacs-directory "init.org"))
(org-babel-tangle)
(load-file (concat user-emacs-directory "init.el"))
(byte-compile-file (concat user-emacs-directory "init.el"))
(setq gc-cons-threshold 3000000
      gc-cons-percentage 0.1)

Set lexical scoping for the init file.

;;; -*- lexical-binding: t -*-

Avoid garbage collection during startup.

(setq gc-cons-threshold most-positive-fixnum
      gc-cons-percentage 0.6)

Clear files, temporarily.

(defvar afsmnghr/file-name-handler-alist file-name-handler-alist)

(setq file-name-handler-alist nil)

Package Management

Don’t auto-initialize!

(setq package-enable-at-startup nil
      package--init-file-ensured t)

The use-package declarative and performance-oriented.

(require 'package)
(package-initialize)

(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
                         ("org" . "http://orgmode.org/elpa/")
                         ("melpa" . "https://melpa.org/packages/")
                         ("melpa-stable" . "https://stable.melpa.org/packages/"))
      use-package-always-ensure t)

(unless (version< emacs-version "25.1")
  (setq package-archive-priorities '(("melpa-stable" . 10)
                                     ("gnu" . 10)
                                     ("melpa" . 20))))

(unless package-archive-contents
  (package-refresh-contents))

(let ((afsmnghr/packages '(use-package delight)))
  (dolist (p afsmnghr/packages)
    (unless (package-installed-p p)
      (package-install p))))

(eval-when-compile
  (require 'use-package))
(require 'delight)
(require 'bind-key)

Benchmarking init.el.

(use-package benchmark-init
  :init (benchmark-init/activate))

Encoding

Set utf-8 everywhere.

(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setq buffer-file-coding-system 'utf-8
      file-name-coding-system 'utf-8
      x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))

Indentation

Prefer space indentation.

(setq-default tab-width 2
              tab-always-indent 'complete
              indent-tabs-mode nil)

Autopair

(setq electric-pair-pairs '((?\" . ?\")
                            (?\` . ?\`)
                            (?\( . ?\))
                            (?\{ . ?\})))

(electric-pair-mode 1)

Whitespace

(custom-set-variables
 '(whitespace-style '(face lines-tail)))

(add-hook 'prog-mode-hook #'whitespace-mode)

Interface

Set custom file and few variables.

(setq custom-file (concat user-emacs-directory "custom.el"))

(custom-set-variables
 '(org-babel-load-languages
   (quote ((emacs-lisp . t) (python . t) (shell . t) (ruby . t) (js . t))))
 '(org-confirm-babel-evaluate nil))

Short, answering yes or no.

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

Clear UI.

(menu-bar-mode -1)
(if tool-bar-mode
    (tool-bar-mode -1))
(column-number-mode -1)
(blink-cursor-mode -1)
(line-number-mode -1)
(size-indication-mode -1)
(setq ring-bell-function 'ignore)

Time in the modeline.

(setq display-time-interval 1
      display-time-format "%H:%M"
      display-time-default-load-average nil)

(display-time-mode)

Dialogs stay in emacs.

(setq use-dialog-box nil
      use-file-dialog nil
      epa-pinentry-mode 'loopback)

Enable built-in modes.

(global-visual-line-mode t)
(global-font-lock-mode t)
(global-auto-revert-mode t)
(delete-selection-mode t)
(global-linum-mode t)
(auto-fill-mode 1)

Set external browser.

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program "/usr/local/sbin/browser-remote")

Dired listing settings.

(setq dired-listing-switches "-lhvA")

Unsorted settings.

(setq show-paren-style 'mixed
      word-wrap t
      search-highlight t
      query-replace-highlight t
      select-enable-clipboard t
      echo-keystrokes 0.1
      enable-local-eval t
      garbage-collection-messages t)
Themes

Load my themes. Enable theme on the frame type.

(defun afsmnghr/load-theme ()
  "load my theme"
  (add-to-list 'custom-theme-load-path "~/.emacs.d/themes")

  (if (display-graphic-p)
      (load-theme 'spolsky t)
    (load-theme 'spolsky-term t)))

(defun afsmnghr/enable-theme (frame)
  "enable theme the current frame depending on the frame type"
  (with-selected-frame frame
    (if (window-system)
        (progn
          (unless (custom-theme-enabled-p 'spolsky)
            (if (custom-theme-enabled-p 'spolsky-term)
                (disable-theme 'spolsky-term))
            (enable-theme 'spolsky)))
      (progn
        (unless (custom-theme-enabled-p 'spolsky-term)
          (if (custom-theme-enabled-p 'spolsky)
              (disable-theme 'spolsky))
          (enable-theme 'spolsky-term))))))

(add-hook 'after-init-hook 'afsmnghr/load-theme)
(add-hook 'after-make-frame-functions 'afsmnghr/enable-theme)
Spolsky

images/spolsky-theme.png

Spolsky Term

images/spolsky-term-theme.png

Window management

Named buffers.

(use-package ace-window :defer t
  :config (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
                aw-background nil))

Keyboard

Add comment fn.

(defun comment-or-uncomment-region-or-line ()
  "Comments or uncomments the region or the current line if there's no active region."
  (interactive)
  (let (beg end)
    (if (region-active-p)
        (setq beg (region-beginning) end (region-end))
      (setq beg (line-beginning-position) end (line-end-position)))
    (comment-or-uncomment-region beg end)
    (forward-line)))

My keybindings almost defaulted.

(global-set-key (kbd "C-v") 'end-of-buffer)
(global-set-key (kbd "M-v") 'beginning-of-buffer)

(global-set-key (kbd "C-b") 'backward-char)
(global-set-key (kbd "C-f") 'forward-char)
(global-set-key (kbd "C-p") 'previous-line)
(global-set-key (kbd "C-M-b") 'backward-paragraph)
(global-set-key (kbd "C-M-f") 'forward-paragraph)

(global-set-key (kbd "C-x w") 'kill-buffer-and-window)
(global-set-key (kbd "C-z") 'undo)

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

(global-set-key (kbd "C-w") 'clipboard-kill-region)
(global-set-key (kbd "M-w") 'clipboard-kill-ring-save)

(global-set-key (kbd "C-y") 'clipboard-yank)
(global-set-key (kbd "M-q") 'query-replace-regexp)

(global-set-key [remap comment-dwim] 'comment-or-uncomment-region-or-line)

Reverse input.

(use-package reverse-im :defer t :commands reverse-im-activate)

Hooks

(defadvice save-buffers-kill-emacs (around no-query-kill-emacs activate)
  "Prevent annoying \"Active processes exist\" query when you quit Emacs."
  (cl-letf (((symbol-function #'process-list) (lambda ())))
    ad-do-it))

(defun tangle-init ()
  "If the current buffer is 'init.org' the code-blocks are
tangled, and the tangled file is compiled."
  (when (equal (buffer-file-name)
               (expand-file-name (concat user-emacs-directory "init.org")))
    ;; Avoid running hooks when tangling.
    (let ((prog-mode-hook nil))
      (org-babel-tangle)
      (byte-compile-file (concat user-emacs-directory "init.el")))))

(defun afsmnghr/minibuffer-setup-hook ()
  (setq gc-cons-threshold most-positive-fixnum
        gc-cons-percentage 0.6))

(defun afsmnghr/minibuffer-exit-hook ()
  (setq gc-cons-threshold 3000000
        gc-cons-percentage 0.1))

(defun afsmnghr/emacs-startup-hook ()
  "make faster startup"
  (benchmark-init/deactivate)
  (reverse-im-activate "russian-computer")
  (setq file-name-handler-alist afsmnghr/file-name-handler-alist
        gc-cons-threshold 3000000
        gc-cons-percentage 0.1))

(add-hook 'emacs-startup-hook #'afsmnghr/emacs-startup-hook)
(add-hook 'minibuffer-setup-hook #'afsmnghr/minibuffer-setup-hook)
(add-hook 'minibuffer-exit-hook #'afsmnghr/minibuffer-exit-hook)
(add-hook 'focus-out-hook #'garbage-collect)
(add-hook 'after-save-hook #'tangle-init)
(add-hook 'before-save-hook #'delete-trailing-whitespace)

History

(setq history-length t
      history-delete-duplicates t
      savehist-save-minibuffer-history 1
      savehist-autosave-interval 60
      savehist-additional-variables '(search-ring regexp-search-ring
                                                  comint-input-ring))

(savehist-mode 1)

Backups

(setq backup-directory-alist '(("." . "~/.emacs.d/backups"))
      auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t))
      delete-old-versions t
      version-control t
      vc-make-backup-files t
      backup-by-copying t
      kept-new-versions 2
      kept-old-versions 2)

Completion

IDO

Enable ido (or “Interactively DO things”) everywhere.

(use-package ido-hacks
  :config
  (use-package flx-ido
    :config
    (ido-mode 1)
    (ido-everywhere 1)
    (flx-ido-mode 1)
    (setq flx-ido-threshold 1000
          ido-enable-flex-matching t
          ido-use-faces t
          ido-virtual-buffers t
          ido-auto-merge-work-directories-length -1))
  (use-package ido-completing-read+ :pin melpa-stable
    :config (ido-ubiquitous-mode 1)))
Company

Use modern completion framework.

(use-package company :defer 30
  :init (global-company-mode t)
  :config
  (defvar company-mode/enable-yas t
    "Enable yasnippet for all backends.")

  (defun company-mode/backend-with-yas (backend)
    (if (or (not company-mode/enable-yas)
            (and (listp backend)
                 (member 'company-yasnippet backend)))
        backend
      (append (if (consp backend) backend (list backend))
              '(:with company-yasnippet))))

  (setq company-backends
        (mapcar #'company-mode/backend-with-yas
                '((company-capf company-shell company-dabbrev company-abbrev
                                company-files company-etags company-keywords)))
        company-idle-delay 1.0
        company-tooltip-flip-when-above t)
  (use-package company-flx :defer t
    :config (with-eval-after-load 'company
              (company-flx-mode +1)))
  (use-package company-ycmd :defer t
    :config (company-ycmd-setup))
  (use-package company-shell :defer t)
  (use-package company-statistics :defer t
    :init (company-statistics-mode)))

Recent files

(use-package recentf :defer t
  :init (recentf-mode 1)
  :config
  (setq recentf-max-saved-items 30
        recentf-keep '(file-remote-p file-readable-p))

  (defun ido-recentf-open ()
    "Use `ido-completing-read' to find a recent file."
    (interactive)
    (find-file (ido-completing-read "Open recent file: " recentf-list nil t)))

  (global-set-key (kbd "C-c r") 'ido-recentf-open))

Bookmarks

(use-package bookmark
  :config
  (setq bookmark-save-flag t)
  (global-set-key (kbd "C-x r b")
                  (lambda ()
                    (interactive)
                    (bookmark-jump
                     (ido-completing-read "jump to bookmark: "
                                          (bookmark-all-names))))))

VCS

Magit

It’s Magit! A Git porcelain inside Emacs.

(unless (version< emacs-version "24.4")
  (use-package magit :defer t
    :init
    (global-set-key (kbd "C-c j") #'afsmnghr/visit-pull-request-url)

    (defun afsmnghr/visit-pull-request-url ()
      "Visit the current branch's PR."
      (interactive)
      (let ((repo (magit-get "remote" (magit-get-remote) "url")))
        (if (not repo)
            (setq repo (magit-get "remote" (magit-get-push-remote) "url")))
        (if (string-match "github\\.com" repo)
            (visit-gh-pull-request repo)
          (visit-bb-pull-request repo))))

    (defun visit-gh-pull-request (repo)
      "Visit the current branch's PR on Github."
      (interactive)
      (message repo)
      (browse-url
       (format "https://github.com/%s/compare/%s?expand=1"
               (replace-regexp-in-string
                "\\`.+github\\.com:\\(.+\\)\\.git\\'" "\\1"
                repo)
               (magit-get-current-branch))))

    (defun visit-bb-pull-request (repo)
      "Visit the current branch's PR on BitBucket."
      (message repo)
      (browse-url
       (format "https://bitbucket.org/%s/pull-request/new?source=%s&t=1"
               (replace-regexp-in-string
                "\\`.+bitbucket\\.org:\\(.+\\)\\.git\\'" "\\1"
                repo)
               (magit-get-current-branch))))

    (setq magit-completing-read-function 'magit-ido-completing-read
          magit-branch-arguments nil
          magit-default-tracking-name-function 'magit-default-tracking-name-branch-only
          magit-set-upstream-on-push t
          magit-push-always-verify nil
          magit-restore-window-configuration t
          vc-handled-backends nil)))
Git time machine

Travel back and forward in git history with git time machine.

(unless (version< emacs-version "24.4")
  (use-package git-timemachine :defer t))
Smerge-mode

Merging conflicts.

(use-package smerge-mode :ensure f
  :config (setq smerge-command-prefix "\C-cv"))

Project management

Setup projectile.

(use-package projectile :defer 30
  :init (projectile-mode)
  :delight '(:eval
             (propertize (concat " " (projectile-project-name))
                         'face '(:foreground "#FD971F")))
  :config
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)

  (setq projectile-enable-caching t
        projectile-use-git-grep t
        projectile-indexing-method 'default
        projectile-switch-project-action 'projectile-dired
        projectile-file-exists-remote-cache-expire (* 10 60)
        projectile-file-exists-local-cache-expire (* 5 60)
        projectile-require-project-root nil
        projectile-idle-timer-seconds 60
        projectile-completion-system 'ido))

Linters

Use modern flycheck.

(use-package flycheck :defer t
  :config
  (flycheck-def-config-file-var flycheck-typescript-tsconfig
      typescript-tslint "tslint.json"
    :safe #'stringp
    :package-version '(flycheck . "27"))

  (defun flycheck-parse-tslint (output checker buffer)
    "Parse TSLint errors from JSON OUTPUT.

CHECKER and BUFFER denoted the CHECKER that returned OUTPUT and
the BUFFER that was checked respectively.

See URL `https://palantir.github.io/tslint/' for more information
about TSLint."
    (let ((json-array-type 'list))
      (seq-map (lambda (message)
                 (let-alist message
                   (flycheck-error-new-at
                    (+ 1 .startPosition.line)
                    (+ 1 .startPosition.character)
                    'warning .failure
                    :id .ruleName
                    :checker checker
                    :buffer buffer
                    :filename .name)))
               ;; Don't try to parse empty output as JSON
               (and (not (string-empty-p output))
                    (car (flycheck-parse-json output))))))

    (flycheck-define-checker typescript-tslint
      "TypeScript style checker using TSLint."
      :command ("tslint" "--type-check" "--format" "json"
                (config-file "--config" flycheck-typescript-tslint-config)
                (config-file "--project" flycheck-typescript-tsconfig)
                (option "--rules-dir" flycheck-typescript-tslint-rulesdir)
                (eval flycheck-tslint-args)
                source-original)
      :error-parser flycheck-parse-tslint
      :modes (typescript-mode)))

Snippets

No comments. Yasnippet.

(use-package yasnippet :defer 30
  :init (yas-global-mode t))

Search

Ag

Use it for projectile and dumb-jump.

(use-package ag :defer t)
Keyword search

Browser style keyword search.

(use-package keyword-search :defer t
  :bind ("C-c s" . keyword-search)
  :config
  (setq afsmnghr/search-alist
        '((t/ya-en-ru . "https://translate.yandex.ru/m/translate?text=%s&lang=en-ru")
          (t/ya-ru-en . "https://translate.yandex.ru/m/translate?text=%s&lang=ru-en")
          (reddit . "https://www.reddit.com/search?q=%s"))
        keyword-search-alist (append keyword-search-alist afsmnghr/search-alist)))

Tags

Grepping tags.

(use-package dumb-jump :defer t
  :bind (("M-g o" . dumb-jump-go-other-window)
         ("M-g j" . dumb-jump-go)
         ("M-g i" . dumb-jump-go-prompt)
         ("M-g x" . dumb-jump-go-prefer-external)
         ("M-g z" . dumb-jump-go-prefer-external-other-window))
  :config (setq dumb-jump-selector 'ido
                dumb-jump-prefer-searcher 'git-grep
                dumb-jump-force-searcher 'ag))

DevOps

Docker

Simple management docker containers.

(unless (version< emacs-version "24.4")
  (use-package docker :defer t))

Major mode for Dockerfile.

(use-package dockerfile-mode :defer t
  :mode (("Dockerfile.*" . dockerfile-mode)))

Remote management

(use-package tramp :defer t :ensure f
  :config
  (setq auto-revert-remote-files t
        shell-file-name "/bin/sh")) ;; alpine based

Languages

Ruby
(use-package ruby-mode :defer t
  :mode (("\\.cr\\'" . ruby-mode)
         (".irbrc" . ruby-mode)))

(use-package bundler :defer t)
(use-package rvm :defer t
  :init (rvm-use-default)
  (defadvice inf-ruby-console-auto (before activate-rvm-for-robe activate)
    (rvm-activate-corresponding-ruby)))

(use-package company-inf-ruby :defer t)
(use-package rubocop :defer t
  :init (add-hook 'ruby-mode-hook 'rubocop-mode)
  (add-to-list 'ruby-mode-hook 'flycheck-mode)
  (if (version< emacs-version "24.4")
      (eval-after-load 'flycheck-mode
        '(progn (flycheck-add-mode 'ruby-rubocop 'ruby-mode)))
    (with-eval-after-load 'flycheck-mode
      (flycheck-add-mode 'ruby-rubocop 'ruby-mode))))
Python
(use-package python :defer t
  :config
  (add-to-list 'python-mode-hook 'flycheck-mode)
  (setq flycheck-python-pylint-executable "pylint"))
Javascript
(use-package coffee-mode :defer t
  :config (setq-default coffee-js-mode 'js2-mode coffee-tab-width 2))

(use-package typescript-mode :defer t
  :config
  ;; (add-to-list 'typescript-mode-hook 'flycheck-mode)
  (setq typescript-indent-level 2))

(use-package json :config (setq js-indent-level 2))

(use-package js2-mode :ensure t :defer t
  :mode (("\\.js\\'" . js2-mode)
         ("\\.json\\'" . javascript-mode))
  :commands js2-mode
  :config (setq-default js2-basic-offset 2
                        js2-indent-switch-body t
                        js2-auto-indent-p t
                        js2-highlight-level 3
                        js2-global-externs '("angular")
                        js2-indent-on-enter-key t)
  (setq flycheck-disabled-checkers '(javascript-jshint))
  (add-to-list 'js2-mode-hook 'flycheck-mode))

Templates

(use-package markdown-mode :defer t)
(use-package css-mode :defer t)
(use-package sass-mode :defer t
  :mode (("\\.scss" . sass-mode)))
(use-package haml-mode :defer t)
(use-package slim-mode :defer t)
(use-package csv-mode :defer t)
(use-package yaml-mode :defer t)
(use-package company-web :defer t)
(use-package web-mode :defer t
  :config
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
  (setq web-mode-markup-indent-offset 2
        web-mode-enable-auto-pairing t
        web-mode-enable-current-element-highlight t
        web-mode-enable-block-face t
        web-mode-enable-part-face t))

Org

Save org buffers.

(defun afsmnghr/before-kill-emacs ()
  (if (fboundp 'org-save-all-org-buffers)
      (org-save-all-org-buffers)))

(add-hook 'kill-emacs-hook #'afsmnghr/before-kill-emacs)

Run org task.

(defun afsmnghr/org-todo-activate ()
  "Stop the current and activate the selected task."
  (interactive)
  (when (org-clocking-p)
    (org-clock-goto)
    (org-todo "HOLD")
    (org-clock-out)
    (save-buffer)
    (switch-to-prev-buffer))
  (org-todo org-clock-in-switch-to-state))

Main org.

(use-package org :defer 30 :ensure f
  :init
  (setq org-log-done t
        org-directory (getenv "ORG_PATH")
        org-startup-indented t
        org-indent-mode-turns-on-hiding-stars nil
        org-todo-keywords
        '((sequence "TODO(t!)" "NEXT(n@/!)" "INPROGRESS(i!)" "HOLD(h@/!)"
                    "DONE(d!)" "CANCELLED(c@/!)")))
  :bind
  (:map global-map ("C-c a" . org-agenda)))

Org colors.

(use-package org-faces :ensure f
  :after org
  :init
  (setq org-todo-keyword-faces
        '(("INPROGRESS" :foreground "DodgerBlue2" :weight bold)
          ("HOLD" :foreground "firebrick2" :weight bold)
          ("NEXT" :foreground "OrangeRed2" :weight bold))
        org-priority-faces '((?A . (:foreground "firebrick2" :weight 'bold))
                             (?B . (:foreground "OrangeRed2"))
                             (?C . (:foreground "DodgerBlue2")))))

Org blocks.

(use-package org-src :ensure f
  :after org
  :init
  (setq org-src-fontify-natively t
        org-edit-src-content-indentation 2
        org-src-tab-acts-natively t
        org-src-preserve-indentation t
        org-src-window-setup 'current-window
        org-src-ask-before-returning-to-edit-buffer nil))

Org agenda.

(use-package org-agenda :ensure f
  :after org
  :config
  (setq org-agenda-files (list org-directory (concat org-directory "orgzly"))
        org-agenda-custom-commands
        '(("d" "List of the projects" ((tags "+LEVEL>=2&+project/-DONE-CANCELLED"))))
        org-agenda-start-on-weekday 1
        org-agenda-dim-blocked-tasks nil
        org-agenda-compact-blocks t
        org-agenda-skip-scheduled-if-done nil
        org-agenda-clockreport-parameter-plist
        (quote (:link t :maxlevel 9 :fileskip0 t :compact t :narrow 80))))

Org protocol.

(use-package org-protocol :ensure f :defer t
  :after org
  :init
  (setq org-protocol-default-template-key "L"))

Org capture.

(use-package org-capture :ensure f :defer t
  :after org
  :init
  (setq afsmnghr/org-diary (concat org-directory "diary.org")
        afsmnghr/org-links (concat org-directory "links.org")
        afsmnghr/org-work (concat org-directory "work.org"))
  (defconst afsmnghr/org-capture-templates
    '(("L" "Links" entry (file+datetree afsmnghr/org-links)
       "* %c :LINK:\n%U %?%:initial")
      ("d" "Diary" entry (file+datetree afsmnghr/org-diary)
       "* %?\n%U\n"
       :clock-in t :clock-resume t :jump-to-captured t)
      ("w" "Work" entry (file+datetree afsmnghr/org-work)
       "* TODO %? :WORK:\n%U\n"
       :clock-in t :clock-resume t :jump-to-captured t)))
  (setq org-capture-templates afsmnghr/org-capture-templates)
  :bind
  (:map global-map ("C-c c" . org-capture)))

Org clock.

(use-package org-clock :ensure f :defer t
  :after org
  :init
  (setq org-clock-history-length 30
        org-clock-in-switch-to-state "INPROGRESS"
        org-clock-continuously t
        org-clock-in-resume t
        org-clock-into-drawer t
        org-clock-out-remove-zero-time-clocks t
        org-clock-out-when-done t
        org-clock-persist 'history
        org-clock-clocked-in-display 'mode-line
        org-clock-persist-query-resume nil
        org-clock-report-include-clocking-task t)
  (org-clock-persistence-insinuate))