Giter Site home page Giter Site logo

emacs.d's Introduction

Emacs configuration file

Credits

Inspired by freetonik’s setup.

Warning

This config is not intended to be used by anyone other than me. I would not recommend using this configuration as-is.

Setup

Clone the repo:

git clone --recurse-submodules -j8 --depth=1 https://github.com/vyorkin/emacs.d

Make a backup of your old .emacs.d:

mv ~/.emacs.d ~/.emacs.d-bak
  • Symlink init.org to ~/.emacs.d/init.org
  • Symlink init.el to ~/.emacs.d/init.el
ln -sf $(pwd)/init.org ~/.emacs.d/init.org
ln -sf $(pwd)/init.el ~/.emacs.d/init.el

On the first run Emacs will install some packages. It’s best to restart Emacs after that process is done for the first time.

There is no reason to track the init.el that is generated; by running the following command git will not bother tracking it:

git update-index --assume-unchanged init.el

If one wishes to make changes to the repo-version of init.el start tracking again with:

git update-index --no-assume-unchanged init.el

When this configuration is loaded for the first time, the init.el is the file that is loaded. It looks like this:

;; We can't tangle without org!
(require 'org)
;; Open the configuration
(find-file (concat user-emacs-directory "init.org"))
;; tangle it
(org-babel-tangle)
;; load it
(load-file (concat user-emacs-directory "init.el"))
;; finally byte-compile it
(byte-compile-file (concat user-emacs-directory "init.el"))

Startup timer

(add-hook 'emacs-startup-hook
  (lambda ()
    (message
     "Emacs ready in %s with %d GC's."
     (format
      "%.2f seconds"
      (float-time (time-subtract after-init-time before-init-time)))
     gcs-done)))

Config

Intro

Lexical binding for the init-file is needed, it can be specified in the header. This is the first line of the actual configuration.

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

Make startup faster by reducing the frequency of garbage collection. The default is 800 kilobytes. Measured in bytes. These are the first lines of the actual configuration.

(setq gc-cons-threshold (* 50 1000 1000))

Customization

Let’s keep all customizations in one place.

Location

Location name and coordinates.

(defvar my/lat 55.84)
(defvar my/lon 37.34)
(defvar my/location "Moscow, RU")

Utils

Utility functions.

(defun my/emacs-path (path)
  "Expands `path` with Emacs home directory."
  (expand-file-name path user-emacs-directory))

(defun my/tmp-path (path)
  "Expand `path` with Emacs temporary directory."
  (my/emacs-path (format "tmp/%s" path)))

(defun my/lisp-path (path)
  "Expand `path` with Emacs `/lisp` directory."
  (my/emacs-path (format "lisp/%s" path)))

Auto-tangling

Tangle and compile this file on save automatically:

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

(add-hook 'after-save-hook 'tangle-init)

Use package

Initialize package and add package archives.

(require 'package)

Set package-enable-at-startup to nil for slightly faster startup. See this post on Reddit.

(setq package-enable-at-startup nil)
;; Try to uncomment this if you have TLS-related issues
;; (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3")

(let* ((no-ssl (and (memq system-type '(windows-nt ms-dos))
                    (not (gnutls-available-p))))
    (proto (if no-ssl "http" "https")))
    ;; Comment/uncomment these two lines to disable/enable MELPA and MELPA Stable as desired
    (add-to-list 'package-archives (cons "melpa" (concat proto "://melpa.org/packages/")) t)
    ;; (add-to-list 'package-archives (cons "melpa-stable" (concat proto "://stable.melpa.org/packages/")) t)
    (when (< emacs-major-version 24)
      ;; For important compatibility libraries like cl-lib
      (add-to-list 'package-archives '("gnu" . (concat proto "://elpa.gnu.org/packages/")))))

It is ok to use both package-initialize and use-package for a well behaved package: package-initialize will not load the whole package, but only autoload functions selected by the package author.

(package-initialize)

Install use-package.

Install missing packages automatically if not already present on the system and be less verbose.

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

(eval-when-compile (require 'use-package))

(setq
 use-package-always-ensure t
 use-package-verbose nil)

Statistics gathering

Run the M-x use-package-report command to see the results. Read the docs for more info.

(use-package-compute-statistics)

Quelpa

Setup quelpa.

(if (require 'quelpa nil t)
  ;; Prevent quelpa from doing anyting that requires network connection.
  (setq
   quelpa-update-melpa-p nil    ; Don't update MELPA git repo
   quelpa-checkout-melpa-p nil  ; Don't clone MELPA git repo
   quelpa-upgrade-p nil         ; Don't try to update packages automatically
   quelpa-self-upgrade-p nil)   ; Don't upgrade quelpa automatically

(unless (package-installed-p 'quelpa)
  (with-temp-buffer
    (url-insert-file-contents "https://github.com/quelpa/quelpa/raw/master/quelpa.el")
    (eval-buffer)
    ;; Comment/uncomment line below to disable/enable quelpa auto-upgrade.
    (quelpa-self-upgrade))))

Install use-package and the quelpa handler.

(quelpa
 '(quelpa-use-package
   :fetcher github
   :repo "quelpa/quelpa-use-package"))
(require 'quelpa-use-package)

Advice setting :ensure nil for use-package + quelpa.

(quelpa-use-package-activate-advice)

System shell env

Pass system shell environment to Emacs. This is important primarily for shell inside Emacs, but also things like Org mode export to Tex PDF don’t work, since it relies on running external command pdflatex, which is loaded from PATH. Also this is required for use-package-ensure-system-package extension.

(use-package exec-path-from-shell
 :commands
 (exec-path-from-shell-copy-envs
  exec-path-from-shell-initialize)
 :init
 (setq exec-path-from-shell-check-startup-files nil)
 :config
 (exec-path-from-shell-copy-envs '("WAKATIME_API_KEY"))
 (when (memq window-system '(mac ns x))
   (exec-path-from-shell-initialize)))

System packages (disabled)

Ensure system binaries exist alongside package declarations. It uses the system-packages to make handling installed system packages more convenient. system-packages supports nix by using nix-env (which I don’t recommend) and many other operating systems.

Currently disabled, because on NixOS I use declarative configuration instead of nix-env.

(use-package system-packages)
(use-package use-package-ensure-system-package)

Warnings

Decrease the obsolete warnings annoyance level.

(setq byte-compile-warnings '(not obsolete))

This helps to get rid of functions might not be defined at runtime warnings. See this issue for details.

(eval-when-compile
  (setq use-package-expand-minimally byte-compile-current-file))

Suppress ad-handle-definition warnings.

(setq ad-redefinition-action 'accept)

Defaults

Backups & lock files

Don’t create lock files.

(setq create-lockfiles nil)

I don’t care about auto save and backup files. Also I don’t like distracting alarms.

(setq
 make-backup-files nil        ; disable backup files
 auto-save-list-file-name nil ; disable .saves files
 auto-save-default nil        ; disable auto saving
 ring-bell-function 'ignore)  ; turn off alarms completely

Misc

Use y/n instead of yes/no.

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

Don’t prompt for non existent name when creating new buffers.

(setq-default confirm-nonexistent-file-or-buffer t)

Enable recentf-mode and remember a lot of files.

(setq
 recentf-auto-cleanup 'never
 recentf-max-menu-items 0
 recentf-max-saved-items 300
 recentf-filename-handlers '(file-truename abbreviate-file-name))

(recentf-mode 1)

Automatically save place in each file.

(setq
 save-place-forget-unreadable-files t
 save-place-limit 400)

(save-place-mode 1)

Performance

Disable bidirectional text for tiny performance boost.

(setq-default bidi-display-reordering nil)

Update UI less frequently.

(setq
 idle-update-delay 2
 jit-lock-defer-time 0
 jit-lock-stealth-time 0.2
 jit-lock-stealth-verbose nil)

Location

Set the location name and coordinates.

(setq
 calendar-location-name my/location
 calendar-latitude my/lat
 calendar-longitude my/lon)

Core

Builtin

Files

On save/write file:

  • Automatically delete trailing whitespace.
  • Silently put a newline at the end of file if there isn’t already one there.
(use-package files
  :ensure nil
  :preface
  (defun my/files/setup ()
    (add-hook 'before-save-hook 'delete-trailing-whitespace))
  :commands
  (generate-new-buffer
   executable-find
   file-name-base
   file-name-extension)
  :custom
  (require-final-newline t)
  :hook
  (prog-mode . my/files/setup))

Reverting

Diminish autorevert mode.

(use-package autorevert
 :ensure nil
 :custom
 ;; Don't generate any messages whenever a buffer is reverted
 (auto-revert-verbose nil)
 ;; Operate only on file-visiting buffers
 (global-auto-revert-non-file-buffers t)
 :diminish auto-revert-mode)

Uniquify

The forward buffer name style includes part of the file’s directory name at the beginning of the buffer name. Using this method, buffers visiting the files /u/rms/tmp/Makefile and /usr/projects/hooy/Makefile would be named ‘tmp/Makefile’ and ‘hooy/Makefile’.

(use-package uniquify
 :ensure nil
 :custom
 ;; use "foo/bar/qux"
 (uniquify-buffer-name-style 'forward))

History

Many editors (e.g. Vim) have the feature of saving minibuffer history to an external file after exit. This package provides the same feature in Emacs. When set up, it saves recorded minibuffer histories to a file (~/.emacs-history by default).

(use-package savehist
  :ensure nil
  :custom
  (savehist-additional-variables
   '(kill-ring
     ;; search entries
     search-ring
     regexp-search-ring))
  ;; save every minute
  (savehist-autosave-interval 60)
  (savehist-save-minibuffer-history t)
  :init
  (savehist-mode 1))

Frame

  • Disable blinking cursor.
  • Disable suspending on C-z.
(use-package frame
 :ensure nil
 :config
 (blink-cursor-mode 0)
 :bind
 ("C-z" . nil))

Delsel

C-c C-g always quits minibuffer.

(use-package delsel
 :ensure nil
 :bind
 ("C-c C-g" . minibuffer-keyboard-quit))

Simple

(use-package simple
  :ensure nil
  :diminish
  ((visual-line-mode . "")
   (auto-fill-function . ""))
  :bind
  ;; remap ctrl-w/ctrl-h
  (("C-c h" . help-command)
   ("C-x C-k" . kill-region)
   ("C-h" . delete-backward-char)))

VC hooks

(use-package vc-hooks
  :ensure nil
  :config
  (setq
   vc-follow-symlinks t
   vc-make-backup-files nil))

Pixel scroll

Global minor mode which makes mouse-wheel scroll a line smoothly.

(use-package pixel-scroll
 :ensure nil
 :commands
 (pixel-scroll-mode)
 :config
 (pixel-scroll-mode 1))

Prog mode

Prettify symbols.

(use-package prog-mode
 :ensure nil
 :commands
 (global-prettify-symbols-mode)
 :init
 (setq prettify-symbols-unprettify-at-point 'right-edge)
 :config
 ;; convert certain words into symbols, e.g. lambda becomes λ.
 (global-prettify-symbols-mode t))

IBuffer

Use the ibuffer in place of the default list-buffers command. This provides tremendous amount of additional functionality in terms of filtering, grouping, and acting upon the listed buffers. Also, it opens the list of buffers in the same window.

(use-package ibuffer
 :ensure nil
 :bind
 ;; Set all global list-buffers bindings to use ibuffer
 ([remap list-buffers] . ibuffer))

Mule

(use-package mule
 :commands
 (set-terminal-coding-system)
 :ensure nil
 :config
 (prefer-coding-system 'utf-8)
 (set-terminal-coding-system 'utf-8)
 (set-language-environment "UTF-8"))

ETags

Setup Emacs tags.

(use-package etags
 :ensure nil
 :custom
 ;; Reread a TAGS table without querying, if it has changed
 ;; (tag-revert-without-query 1)
 ;; Don't add a new tags to the current list.
 ;; Always start a new list.
 (tags-add-tables nil))

Man

(use-package man
 :ensure nil
 :custom-face
 (Man-overstrike ((t (:inherit font-lock-type-face :bold t))))
 (Man-underline ((t (:inherit font-lock-keyword-face :underline t)))))

Calendar

(use-package calendar
 :ensure nil
 :custom
 (calendar-week-start-day 1))

Face remap

(use-package face-remap
 :commands
 (buffer-face-mode-face
  face-remap-add-relative
  buffer-face-mode)
 :ensure nil
 :diminish buffer-face-mode)

CC mode

Note that “.m” conflicts with mercury-mode.

(use-package cc-mode
 :ensure nil
 :config
 ;; (add-to-list 'auto-mode-alist '("\\.m\\'" . objc-mode))
 (add-to-list 'auto-mode-alist '("\\.mm\\'" . objc-mode)))

Compile

Kill compilation process before starting another and save all buffers on compile.

(use-package compile
  :custom
  (compilation-always-kill t)
  (compilation-ask-about-save nil)
  (compilation-scroll-output t)
  :init
  (make-variable-buffer-local 'compile-command)
  (put 'compile-command 'safe-local-variable 'stringp))

Shell

Hide the “Indentation setup for shell type sh” message in the minibuffer.

(advice-add
 'sh-set-shell :around
 (lambda (orig-fun &rest args)
   (let ((inhibit-message t))
     (apply orig-fun args))))

Libraries

cl-lib

(require 'cl-lib)

async

Simple library for asynchronous processing in Emacs.

(use-package async
  :demand t
  :config
  (autoload 'dired-async-mode "dired-async.el" nil t)
  (dired-async-mode 1)
  (async-bytecomp-package-mode 1))

UI

Basics

(setq
 inhibit-startup-screen t ; Don't show splash screen
 use-dialog-box nil       ; Disable dialog boxes
 use-file-dialog nil)     ; Disable file dialog

Titlebar

Make titlebar transparent.

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

Scroll

More procedural scrolling.

(setq
 auto-window-vscroll nil
 hscroll-margin 5
 hscroll-step 5
 scroll-conservatively 101
 scroll-margin 0
 scroll-preserve-screen-position t)

(setq-default
 scroll-down-aggressively 0.01
 scroll-up-aggressively 0.01)

UI elements

Hide toolbar and scrollbars.

(tool-bar-mode -1)
(scroll-bar-mode -1)
(when (fboundp 'horizontal-scroll-bar-mode)
  (horizontal-scroll-bar-mode -1))

I generally prefer to hide the menu bar, but doing this on OS X simply makes it update unreliably in GUI frames, so we make an exception.

(if (eq system-type 'darwin)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (set-frame-parameter frame 'menu-bar-lines
                                     (if (display-graphic-p frame) 1 0))))
  (when (fboundp 'menu-bar-mode)
    (menu-bar-mode -1)))

Disable bidirectional text for tiny performance boost.

(setq-default bidi-display-reordering nil)

Don’t blink matching paren, it’s too distracting.

(setq-default blink-matching-paren nil)

Cursor

Hide cursor in inactive windows.

(setq-default cursor-in-non-selected-windows nil)
  • Display vertical bar cursor with default width.
  • Draw block cursor as wide as the glyph under it.
(setq-default
 cursor-type 'bar
 x-stretch-cursor t)

Show full path in the title bar.

(setq-default frame-title-format "%b (%f)")

Don’t implicitly resize the frame’s display area in order to preserve the number of columns or lines the frame displays when changing font, menu bar, tool bar, internal borders, fringes or scroll bars. Read this for more info.

(setq-default frame-inhibit-implied-resize t)

Fringe

Set fringe size.

(fringe-mode '(12 . 12))

Setup fringes on both sides and display an indicator for buffer boundaries on the left side. Display fringes outside margins to have the padding on the inside.

(setq-default
 fringes-outside-margins t
 left-fringe-width 8
 right-fringe-width 8
 indicate-buffer-boundaries 'left)

Remove continuation arrow on right fringe.

(setq-default
 fringe-indicator-alist
 (delq (assq 'continuation fringe-indicator-alist) fringe-indicator-alist))

Window-divider

Hide the window-divider (a line separating windows).

(when (boundp 'window-divider-mode)
  (setq window-divider-default-places t
        window-divider-default-bottom-width 0
        window-divider-default-right-width 0)
  (window-divider-mode +1))

Line-spacing

Non-zero values for line-spacing can mess up ansi-term and co, so we zero it explicitly in those cases.

(add-hook
 'term-mode-hook
 (lambda () (setq line-spacing 0)))

Highlight parens.

(setq show-paren-style 'parenthesis)
(show-paren-mode 1)

Treat an Emacs region much like a typical text selection outside of Emacs.

(setq delete-selection-mode t)

Set left and right margins for every window.

(setq-default
 left-margin-width 1
 right-margin-width 1)

Startup

Start maximized.

(toggle-frame-maximized)

Mode line

Turn-off tooltips on cursor hover-over.

(setq mode-line-default-help-echo nil)
(setq
 mode-line-position
 '((line-number-mode ("%l" (column-number-mode ":%c")))))

Time

(use-package time
  :ensure nil
  :custom
  (display-time-default-load-average nil)
  (display-time-24hr-format t)
  :config
  (display-time-mode t))

Echo area

Alert

(use-package alert)

Editor

Customizations

I don’t use the customizations UI. Lets keep those automated customizations in a separate file. The ~’noerror~ argument passed to load prevents errors if the file doesn’t exist.

(setq custom-file (my/emacs-path "custom.el"))
(load custom-file 'noerror)

Basics

Some basic things.

(setq
 ;; sentences should end in one space
 sentence-end-double-space nil
 ;; empty scratch buffer
 initial-scratch-message nil
 ;; show keystrokes right away,
 ;; don't show the message in the scratch buffer
 echo-keystrokes 0.1
 ;; disable native fullscreen support
 ns-use-native-fullscreen nil)

Minibuffer

Give some more room to the minbuffer.

(setq
 max-mini-window-height 0.3
 resize-mini-windows 'grow-only)

Enable recursive minibuffers and keep the point out of the minibuffer.

(setq
 ;; allow minibuffer commands in the minibuffer
 enable-recursive-minibuffers t
 ;; keep the point out of the minibuffer
 minibuffer-prompt-properties
 '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt))

Auto executable scripts.

(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)

Tabs & spaces

  • Use spaces instead of tabs everywhere.
  • One tab is 2 spaces.
(setq-default
 indent-tabs-mode nil
 tab-width 2)

Display line and column numbers in the mode-line.

(setq
  line-number-mode t
  column-number-mode t)

Line wrapping

Long lines will show a continuation character in the right margin at the window’s edge to indicate that one can scroll to see the rest.

(setq-default truncate-lines t)

Break line at N characters.

(setq-default fill-column 64)

Enable automatic line breaking for all text mode buffers.

(add-hook 'text-mode-hook 'turn-on-auto-fill)

Always wrap lines.

;; (global-visual-line-mode)

Benchmarking

Usage: M-x benchmark-init/show-durations-tabulated or M-x benchmark-init/show-durations-tree

(use-package benchmark-init
 :hook
 ;; To disable collection of benchmark data after init is done.
 (after-init . benchmark-init/deactivate))

Use-package plugins

All credit to a13.

Works as :custom keyword, but instead of a value takes update function or the second (the first is the original one) argument to the default updater.

(use-package use-package-custom-update
 :quelpa
 (use-package-custom-update
   :repo "a13/use-package-custom-update"
   :fetcher github
   :version original))
(use-package use-package-secrets
 :custom
 (use-package-secrets-directories '("~/.emacs.d/secrets"))
 :quelpa
 (use-package-secrets
   :repo "a13/use-package-secrets"
   :fetcher github
   :version original))

Font

Faces

(use-package faces
  :ensure nil
  :custom
  (face-font-family-alternatives
   '(("Hack" "Consolas" "Monaco" "Monospace")))
  :init
  (set-face-attribute
   'default nil
   :family (caar face-font-family-alternatives)
   :weight 'regular
   :height 120
   :width 'semi-condensed)
  (set-fontset-font
   "fontset-default"
   'cyrillic
   (font-spec :registry "iso10646-1" :script 'cyrillic)))

Theme

Base-16 themes

(use-package base16-theme
  :config
  ;; (load-theme 'base16-default-dark t)
  (load-theme 'base16-grayscale-dark t)
  ;; (load-theme 'base16-grayscale-light t)
  ;; (load-theme 'base16-gruvbox-light-hard t)
  ;; (load-theme 'base16-material-palenight t) ;; ****
  ;; (load-theme 'base16-rebecca t)
  ;; (load-theme 'base16-pop t)
  ;; (load-theme 'base16-tomorrow-night t)
  ;; (load-theme 'base16-twilight t)
  ;; (load-theme 'base16-irblack t)

base16-chalk + customizations.

(load-theme 'base16-chalk t)
(custom-set-faces
 '(proof-queue-face ((t (:foreground "#eee"))))
 '(proof-declaration-name-face ((t (:foreground "#55aaff"))))
 '(company-coq-comment-h1-face ((t (:size 1.5))))
 '(proof-locked-face ((t (:background "#252525"))))
 '(proof-mouse-highlight-face  ((t (:background "#555" :foreground "#fff")))))

base16-black-metal + customizations.

(load-theme 'base16-black-metal t)
(custom-set-faces
 '(proof-queue-face ((t (:foreground "#eee"))))
 '(company-coq-comment-h1-face ((t (:size 1.5))))
 '(font-lock-comment-face ((t (:foreground "#999"))))
 '(proof-locked-face ((t (:background "#151515"))))
 '(proof-mouse-highlight-face  ((t (:background "#555" :foreground "#fff")))))

base16-one-light + customizations.

(load-theme 'base16-one-light t)
(custom-set-faces
 '(proof-queue-face ((t (:foreground "#f0f0f0"))))
 '(proof-locked-face ((t (:background "#faebd7" :foreground "#4a473d"))))
 '(proof-locked-face ((t (:background "#faebd7" ))))
 '(proof-mouse-highlight-face  ((t (:background "#555" :foreground "#fff")))))
)

Customizations for vimish-fold and base16-grayscale-dark theme.

(eval-after-load 'vimish-fold
 (custom-set-faces
  '(vimish-fold-mouse-face ((t (:box (:line-width 1 :color "#555")))))
  '(vimish-fold-overlay ((t (:box (:line-width 1 :color "#222")))))))

Base-16 customizations for company-mode. I’ve used this custom colors some time ago, but it seems that I don’t need those anymore (see my company config to understand why). So the code block below is untangled.

(eval-after-load 'company
 '(custom-set-faces
  '(company-preview ((t (:foreground "#171717" :underline t))))
  '(company-preview-common ((t (:inherit company-preview))))
  '(company-tooltip ((t (:background "#171717" :foreground "#ddd"))))
  '(company-tooltip-selection ((t (:background "#1f1f1f" :foreground "#eee"))))
  '(company-tooltip-common
    ((((type x)) (:inherit company-tooltip :weight bold))
     (t (:inherit company-tooltip))))
  '(company-tooltip-common-selection
    ((((type x)) (:inherit company-tooltip-selection :weight bold))
     (t (:inherit company-tooltip-selection))))
  '(company-scrollbar-bg ((t (:background "#111"))))
  '(company-scrollbar-fg ((t (:background "#1a1a1a"))))))

Doom themes

(use-package doom-themes
 :init
 (setq
  doom-themes-enable-bold nil
  doom-themes-enable-italic nil)
 :config
 (load-theme 'doom-dracula t)
 (load-theme 'doom-challenger-deep t)
 ;; Enable flashing mode-line on errors
 (doom-themes-visual-bell-config)
 (doom-themes-neotree-config)
 ;; Corrects (and improves) org-mode's native fontification
 (doom-themes-org-config)
 (load-theme 'doom-moonlight)
)

Apropospriate theme

(use-package apropospriate-theme
 :config
 (load-theme 'apropospriate-dark))

Nord theme

(use-package nord-theme)

Zero dark theme

(use-package zerodark-theme
  :config
  (load-theme 'zerodark t nil)
  (zerodark-setup-modeline-format)
  ;; Customizations
  (with-eval-after-load 'idle-highlight-mode
    ;; (set-face-background 'idle-highlight "#c51060")
    (set-face-foreground 'idle-highlight "#999")
    (set-face-background 'idle-highlight "#222"))

  (with-eval-after-load 'company))
(with-eval-after-load 'proof-general
    (custom-set-faces
     '(proof-queue-face ((t (:foreground "#eee"))))
     '(proof-locked-face ((t (:background "#001800" :foreground "#aaccbb"))))
     '(proof-locked-face ((t (:background "#0d3360" ))))
     '(proof-mouse-highlight-face  ((t (:background "#555" :foreground "#fff"))))))

Lor theme

Just another Tango theme based on linux.org.ru colors.

(use-package lor-theme
 :ensure nil
 :custom-face
 (variable-pitch ((t (:family "Serif"))))
 (fixed-pitch ((t (:family "Monospace"))))
 :config
 (load-theme 'lor)
 :quelpa
 (lor-theme :repo "a13/lor-theme" :fetcher github :version original))

Sorcery

(use-package sorcery-theme)

Other themes

(use-package dracula-theme :defer t)
(use-package gotham-theme :defer t)
(use-package sublime-themes :defer t)
(use-package color-theme-modern :defer t)
(use-package twilight-theme :defer t)
(use-package gruber-darker-theme :defer t)
(use-package monokai-theme :defer t)
(use-package faff-theme :defer t)
(use-package badwolf-theme :defer t)
(use-package boron-theme :defer t)
(use-package bliss-theme :defer t)
(use-package busybee-theme :defer t)
(use-package color-theme-sanityinc-tomorrow :defer t)
(use-package badger-theme :defer t)
(use-package atom-one-dark-theme :defer t)
(use-package zenburn-theme :defer t)
(use-package hemisu-theme :defer t)
(use-package paganini-theme :defer t)
(use-package yoshi-theme :defer t)
(use-package rebecca-theme :defer t) ;; *****
(use-package moe-theme :defer t)
(use-package arjen-grey-theme :defer t)
(use-package darkmine-theme :defer t)
(use-package flatland-theme :defer t)
(use-package tao-theme :defer t)
(use-package liso-theme :defer t)
(use-package jazz-theme :defer t)
(use-package material-theme :defer t)
(use-package challenger-deep-theme :defer t) ;; ***
(use-package ample-theme
  :disabled
  :init
  (progn
    (load-theme 'ample t t)
    (load-theme 'ample-flat t t)
    (load-theme 'ample-light t t)
    (enable-theme 'ample-flat))
  :defer t)
(use-package cyberpunk-theme :defer t)
(use-package phoenix-dark-mono-theme :defer t) ;; *** (like grayscale-dark)
(use-package phoenix-dark-pink-theme :defer t) ;; **
(use-package cyberpunk-theme :defer t)
(use-package blackboard-theme :defer t) ;; ***
(use-package mustard-theme :defer t) ;; ****
(use-package labburn-theme :defer t) ;; *****
(use-package green-phosphor-theme :defer t) ;; *****
(use-package exotica-theme :defer t) ;; **
(use-package lush-theme :defer t) ;; ****

Theme changer

Sunrise/sunset theme changer. Given a location and day/night color themes, this file provides a change-theme function that selects the appropriate theme based on whether it is day or night. It will continue to change themes at sunrise and sunset.

(use-package theme-changer
  :config
  (change-theme 'base16-gruvbox-light-hard 'labburn))

Kurecolor

A collection of color tools aimed at those working with (normal 6 digit) hex color codes, useful for CSS, Emacs themes, etc. etc.

Features include interactive step modification of hue, sat, val on hex colors. Color conversion algorithms, for 6 digit hex colors, hsv, rgb, cssrgb. Get/set h s v values from/for a color.

It’s recommend you use this in conjunction with rainbow-mode, for instant feedback on color changes.

(use-package kurecolor)

Key bindings

Use SPC as a “leader” key and C-SPC as a second leader (I call it “leader+” here).

(defvar my/leader "SPC")
(defvar my/leader+ "C-SPC")
(use-package general
 :config

Basic keybindings.

(general-define-key
 "C-h" 'windmove-left
 "C-l" 'windmove-right
 "C-k" 'windmove-up
 "C-j" 'windmove-down
 "C-c C-k" 'kill-region)

MacOS X - specific keybindings.

(when (eq system-type 'darwin)
  (general-define-key
   "s-<backspace>" 'kill-whole-line
   "M-S-<backspace>" 'kill-word
   ;; Use Super for movement and selection just like in macOS
   "s-<right>" (kbd "C-e")
   "S-s-<right>" (kbd "C-S-e")
   "s-<left>" (kbd "M-m")
   "S-s-<left>" (kbd "M-S-m")
   "s-<up>" 'beginning-of-buffer
   "s-<down>" 'end-of-buffer
   ;; Basic things you should expect from macOS
   "s-a" 'mark-whole-buffer       ; select all
   "s-s" 'save-buffer             ; save
   "s-S" 'write-file              ; save as
   "s-q" 'save-buffers-kill-emacs ; quit
   ;; Go to other windows easily with one keystroke
   ;; s-something instead of C-x something
   "s-o" (kbd "C-x o")
   "s-w" (kbd "C-x 0") ; just like close tab in a web browser
   "s-W" (kbd "C-x 1") ; close others with shift
   ;; Move between windows with Control-Command-Arrow and
   ;; with Cmd just like in iTerm
   "s-[" 'windmove-left   ; Cmd+[ go to left window
   "s-]" 'windmove-right  ; Cmd+] go to right window
   "s-{" 'windmove-up     ; Cmd+Shift+[ go to upper window
   "<s-}>" 'windmove-down ; Ctrl+Shift+[ go to down window
   ;; Prev/next buffer
   "s-<" 'previous-buffer
   "s->" 'next-buffer))

Set up some basic equivalents for vim mapping functions. This creates global key definition functions for the evil states.

(general-evil-setup t)

Swap : and ; to make colon commands easier to type in Emacs.

(nmap
 ";" 'evil-ex
 ":" 'evil-repeat-find-char)

Remap 0 for convenience.

(nmap 'messages-buffer-mode-map
  "0" 'evil-digit-argument-or-evil-beginning-of-line)

Process menu.

(nmap 'process-menu-mode-map
  "M-d" 'process-menu-delete-process
  "q" 'kill-buffer-and-window)

Leader-prefixed.

(nmap
  :prefix my/leader
  "v" 'split-window-horizontally
  "s" 'split-window-vertically
  "p" 'list-processes
  "\\" 'widen
  "P s" 'profiler-start
  "P S" 'profiler-stop
  "P r" 'profiler-report
  "E e" 'eval-expression
  "E l" 'eval-last-sexp
  "h k" 'describe-key-briefly
  "h K" 'describe-key
  "h M" 'describe-mode
  "h m" 'info-display-manual))

Behavior

Garbage collection

Enforce a sneaky Garbage Collection strategy to minimize GC interference with the activity. During normal use a high GC threshold is set. When idling GC is immediately triggered and a low threshold is set.

A more detailed explanation of the rationale behind this can be found at: http://akrl.sdf.org/

(use-package gcmh
  :config
  (gcmh-mode 1))

Server

(use-package server
  :ensure nil
  :commands server-running-p
  :preface
  (defun my/server-ensure-running (frame)
    "Ensure server is running when launching FRAME."
    (with-selected-frame frame
      (unless (server-running-p)
        (server-start))))
  :init
  (add-hook 'after-make-frame-functions #'my/server-ensure-running))

Trashing

(setq
  delete-by-moving-to-trash t
  trash-directory (my/emacs-path "trash"))

Automatic updates

Automatically update Emacs packages. Useful if you’re working in multiple machines and tend to forget to manually update packages from time to time.

The main idea is that you set a desired periodicity for the updates, and when you start Emacs, the packages will be automatically updated if enough days have passed since the last update.

See the package repo for more info.

(use-package auto-package-update
  :config
  (setq
   ;; Delete residual old version directory when updating
   auto-package-update-delete-old-versions t
   ;; Update packages every 10 days
   auto-package-update-interval 10)
  ;; Don’t check for updates on startup
  ;; (auto-package-update-maybe)
  ;; Update at 5:30
  (auto-package-update-at-time "05:30"))

Buffer

Hide async shell command buffers.

(cl-pushnew
 '("^*Async Shell Command*" . (display-buffer-no-window))
 display-buffer-alist
 :test #'equal)

Popups (disabled)

Always display pop up buffers at the bottom and regard all star buffers as such buffers. (Not always that useful)

(let ((rule
       `(,(rx bos "*" (one-or-more anything) "*" (optional "<" (one-or-more anything) ">") eos)
         (display-buffer-reuse-window
          display-buffer-in-side-window)
         (reusable-frames . visible)
         (side . bottom)
         (window-height . 0.4))))
  (cl-pushnew rule display-buffer-alist :test #'equal))

Visual fill column

Wrap lines according to fill-column in visual-line-mode.

(use-package visual-fill-column
  :custom
  (visual-fill-column-center-text t))

Clipboard (disabled)

Make emacs kill ring and system clipboard independent. Currenly untangled.

(use-package simpleclip
 :disabled
 :after general
 :config
 (simpleclip-mode 1)
 (nmap
   "s-c" 'simpleclip-copy
   "s-v" 'simpleclip-paste)
 (imap
   "s-c" 'simpleclip-copy
   "s-v" 'simpleclip-paste))

auto-minor-mode

Enable minor modes by buffer name and contents. It provides the use-package keyword :minor and :magic-minor where you can specify these rules.

(use-package auto-minor-mode
  :demand t)

Copy as

Allows to copy buffer locations as GitHub/Slack/JIRA/HipChat/… formatted code.

(use-package copy-as-format
 :after general
 :config
 (vmap
   :prefix "C-c f"
   "f" 'copy-as-format
   "a" 'copy-as-format-asciidoc
   "b" 'copy-as-format-bitbucket
   "d" 'copy-as-format-disqus
   "g" 'copy-as-format-github
   "l" 'copy-as-format-gitlab
   "h" 'copy-as-format-html
   "j" 'copy-as-format-jira
   "m" 'copy-as-format-markdown
   "w" 'copy-as-format-mediawiki
   "o" 'copy-as-format-org-mode
   "p" 'copy-as-format-pod
   "r" 'copy-as-format-rst
   "s" 'copy-as-format-slack))

Posframe

Pop a posframe (just a child-frame) at point.

(use-package posframe
  :custom
  (posframe-mouse-banish nil))

Extra whitespace trimming

Unobtrusively trim extraneous whitespace only in lines edited.

(use-package ws-butler
 :hook
 (prog-mode . ws-butler-mode)
 :diminish ws-butler-mode)

Aggressive indent

Emacs minor mode that keeps your code always indented. More reliable than electric-indent-mode. More info in the package repository.

(use-package aggressive-indent
 :hook
 ((emacs-lisp-mode css-mode c++-mode) . aggressive-indent-mode)
 :config
 ;; Prevent lines jumping around in c++-mode when you haven't typed the ";" yet
 (add-to-list
  'aggressive-indent-dont-indent-if
  '(and
    (derived-mode-p 'c++-mode)
    (null (string-match
           "\\([;{}]\\|\\b\\(if\\|for\\|while\\)\\b\\)"
           (thing-at-point 'line))))))

Auto-save buffers (disabled)

Save buffers when they lose focus.

(use-package super-save
 :config
 (super-save-mode +1)
 :diminish)

Auto read-only

(use-package auto-read-only
 :config
 (auto-read-only-mode 1)
 (add-to-list 'auto-read-only-file-regexps "~/.emacs.d/init.el"))

Zoom

text-scale-increase and text-scale-decrease doesn’t play well with company-mode (suggestions popup alignment issue) more info: company-mode/company-mode#299 (comment)

frame-fns and frame-cmds are dependencies of zoom-frm.

(use-package frame-fns
 :demand t
 :quelpa (frame-fns :fetcher github :repo "emacsmirror/frame-fns"))
(use-package frame-cmds
 :demand t
 :quelpa (frame-cmds :fetcher github :repo "emacsmirror/frame-cmds"))

(use-package zoom-frm
 :after (frame-fns frame-cmds)
 :quelpa (zoom-frm :fetcher github :repo "emacsmirror/zoom-frm")
 :config
 (nmap
   "C-=" 'zoom-frm-in
   "C--" 'zoom-frm-out
   "<s-triple-wheel-up>" 'zoom-frm-in
   "<s-triple-wheel-down>" 'zoom-frm-out))

Fixed and automatic balanced window layout for Emacs. TL;DR: Zooms current pane.

(use-package zoom
 :custom
 (zoom-size '(0.8 . 0.8))
 (zoom-ignored-major-modes '(dired-mode pomidor-mode))
 (zoom-ignored-buffer-name-regexps '("^*calc"))
 (zoom-ignore-predicates '((lambda () (> (count-lines (point-min) (point-max)) 20)))))

Transparency

Allows easily change Emacs transparency. See the package repo for more info.

(use-package seethru
 :demand t
 :commands
 (seethru)
 :config
 (seethru 100)
 ;; C-c 8, C-c 9
 (seethru-recommended-keybinds))

Go to last change

Goto last change in current buffer.

(use-package goto-chg
 :after general
 :config
 (nmap
   :prefix my/leader
   "." 'goto-last-change
   "," 'goto-last-change-reverse)
 ;; additional keybindings for macOS
 (when (eq system-type 'darwin)
   (nmap
     "s-." 'goto-last-change
     "s-," 'goto-last-change-reverse)))

Fullframe

Makes it possible to advice commands to execute fullscreen, restoring the window setup when exiting.

(use-package fullframe
 :config
 (fullframe list-packages quit-window)
 (fullframe package-list-packages quit-window))

Folding

Vim-like text folding for Emacs.

(use-package vimish-fold
 :after evil
 :commands
 (vimish-fold-global-mode)
 :init
 (setq
  vimish-fold-blank-fold-header "<...>"
  vimish-fold-indication-mode 'right-fringe)
 :config
 (vimish-fold-global-mode 1))

Which key

Key bindings are provided by evil-collection.

(use-package which-key
 :diminish which-key-mode
 :init
 (setq
  which-key-idle-delay 0.5
  which-key-sort-order 'which-key-prefix-then-key-order-reverse
  ;; hack to make this work with Evil
  which-key-show-operator-state-maps t
  which-key-prefix-prefix ""
  which-key-side-window-max-width 0.5
  which-key-popup-type 'side-window
  which-key-side-window-location 'bottom)
 :config
 (which-key-mode)
 (with-eval-after-load 'evil-collection
   (add-to-list 'evil-collection-mode-list 'while-key)))

Let which-key use posframe to show its popup. Disabled for now, not sure is really like how it looks.

(use-package which-key-posframe
  :after (posframe which-key)
  :config
  (setq which-key-posframe-poshandler 'posframe-poshandler-frame-top-center)
  (which-key-posframe-mode))

Free keys

Show free bindings in current buffer. To use, call the command M-x free-keys. See the package repo for more info.

(use-package free-keys)

VLF

Large file support. This can view/edit/search and compare large files.

(use-package vlf)

Sudo edit

Utilities for opening files with sudo.

(use-package sudo-edit)

Try

Allows you to try out Emacs packages without installing them.

(use-package try)

Restart

(use-package restart-emacs
 :after general
 :demand t
 :config
 (nmap
   :prefix my/leader
   "Z" 'restart-emacs))

Appearance

Customization

Define an interactive function for customizing appearance.

(defun my/customize-appearance ()
  (interactive)
  ;; set the background or vertical border to the main area background color
  (set-face-background 'vertical-border (face-background 'default))
  ;; set the foreground and background of the vertical-border face to
  ;; the same value so there is no line up the middle
  (set-face-foreground 'vertical-border (face-background 'vertical-border))
  ;; set the fringe colors to whatever is the background color
  (set-face-attribute
   'fringe nil
   :foreground (face-foreground 'default)
   :background (face-background 'default))
  ;; comment/uncomment the lines below to
  ;; set the highlight color for selected text
  ;; (set-face-attribute 'region nil :foreground "#fff")
  ;; (set-face-attribute 'region nil :background "#282828")
  ;; comment/uncomment the line below to
  ;; set the highlight color and foreground color for matching search results
  ;; (set-face-attribute 'lazy-highlight nil :foreground "black" :background "#ffd700")
  )

Required for emacsclient.

(if (display-graphic-p)
    (my/customize-appearance)
  (add-hook
   'after-make-frame-functions
   (lambda (frame)
     (when (display-graphic-p frame)
       (with-selected-frame frame
         (my/customize-appearance))))))

Page break lines

Display ugly ^L page breaks as tidy horizontal lines.

(use-package page-break-lines
 :init
 (global-page-break-lines-mode 1)
 :diminish page-break-lines-mode)

Rainbow delimiters

(use-package rainbow-delimiters
 :commands
 (rainbow-delimiters-unmatched-face)
 :config
 ;; Pastels..
 (set-face-attribute 'rainbow-delimiters-depth-1-face nil :foreground "#78c5d6")
 (set-face-attribute 'rainbow-delimiters-depth-2-face nil :foreground "#bf62a6")
 (set-face-attribute 'rainbow-delimiters-depth-3-face nil :foreground "#459ba8")
 (set-face-attribute 'rainbow-delimiters-depth-4-face nil :foreground "#e868a2")
 (set-face-attribute 'rainbow-delimiters-depth-5-face nil :foreground "#79c267")
 (set-face-attribute 'rainbow-delimiters-depth-6-face nil :foreground "#f28c33")
 (set-face-attribute 'rainbow-delimiters-depth-7-face nil :foreground "#c5d647")
 (set-face-attribute 'rainbow-delimiters-depth-8-face nil :foreground "#f5d63d")
 (set-face-attribute 'rainbow-delimiters-depth-9-face nil :foreground "#78c5d6")
 ;; Make unmatched parens stand out more
 (set-face-attribute
  'rainbow-delimiters-unmatched-face nil
   :foreground 'unspecified
   :inherit 'show-paren-mismatch
   :strike-through t)
 (set-face-foreground 'rainbow-delimiters-unmatched-face "magenta")
 :hook
 (prog-mode . rainbow-delimiters-mode)
 :diminish rainbow-delimiters-mode)

Rainbow identifiers

(use-package rainbow-identifiers
 :hook
 (prog-mode . rainbow-identifiers-mode)
 :diminish rainbow-identifiers-mode)

Rainbow mode

(use-package rainbow-mode
 :diminish rainbow-mode
 :hook prog-mode)

Idle highlight mode (disabled)

Basically its the same as highlight-thing but seems to be smarter and less distracting.

(use-package idle-highlight-mode
 :custom
 (idle-highlight-idle-time 0.2)
 ;; :hook
 ;; (prog-mode . idle-highlight-mode)
 :config
 (nmap
   :prefix my/leader
   "t H" 'idle-highlight-mode))

Hl-line

(use-package hl-line
  :custom
  ;; Only highlight in selected window
  (hl-line-sticky-flag nil)
  (global-hl-line-sticky-flag nil)
  :config
  (nmap
    :prefix my/leader
    "t l" 'hl-line-mode))

Col highlight

(use-package vline
  :quelpa
  (vline :fetcher github :repo "emacsmirror/vline"))

(use-package col-highlight
  :after (vline)
  :quelpa
  (col-highlight :fetcher github :repo "emacsmirror/col-highlight"))

Column marker

(use-package column-marker
  :quelpa
  (column-marker :fetcher github :repo "emacsmirror/column-marker"))

Hl-todo

Highlight TODO and similar keywords in comments and strings. See the package repository for more info.

(use-package hl-todo
 :config
 (global-hl-todo-mode))

Highlight indentation

Provides two minor modes highlight-indentation-mode and highlight-indentation-current-column-mode:

  • highlight-indentation-mode - displays guidelines indentation (space indentation only).
  • highlight-indentation-current-column-mode - displays guidelines for the current-point indentation (space indentation only).

See the package repository for more info.

(use-package highlight-indentation
 :after general
 ;; :hook
 ;; (yaml-mode . highlight-indentation-mode)
 ;; (haskell-mode . highlight-indentation-mode)
 ;; (prog-mode . highlight-indentation-current-column-mode)
 :config
 ;; theme: zerodark
 (set-face-background 'highlight-indentation-face "#24282f")
 (set-face-background 'highlight-indentation-current-column-face "#22252c")
 ;; theme: grayscale dark
 ;; (set-face-background 'highlight-indentation-face "#121212")
 ;; (set-face-background 'highlight-indentation-current-column-face "#111111")
 (nmap
   :prefix my/leader
   "t i" 'highlight-indentation-mode)
 :diminish
 (highlight-indentation-mode
  highlight-indentation-current-column-mode))

Highlight chars

Highlight specified sets of characters, including whitespace. Package repo is here.

(use-package highlight-chars
 :commands
 (hc-highlight-tabs
  hc-highlight-trailing-whitespace
  hc-highlight-hard-spaces
  hc-highlight-hard-hyphens)
 :preface
 (defun my/highlight-chars/setup ()
   (hc-highlight-tabs)
   (hc-highlight-trailing-whitespace)
   (hc-highlight-hard-spaces)
   (hc-highlight-hard-hyphens))
 :quelpa
 (highlight-chars :fetcher github :repo "emacsmirror/highlight-chars")
 :hook
 ((lisp-mode-hook prog-mode-hook) . my/highlight-chars/setup))

Highlight leading spaces

Higlight leading spaces that are part of the indentation. See the package repo for more info.

(use-package highlight-leading-spaces
 :custom-face
 (highlight-leading-spaces ((t (:foreground "#2a2a2a"))))
 :config
 (nmap
   :prefix my/leader
   "t s" 'highlight-leading-spaces-mode))

Highlight numbers

Minor mode that highlights numeric literals in source code.

(use-package highlight-numbers
 :hook
 (prog-mode . highlight-numbers-mode))

VI Tilde fringe (disabled)

Display tildes on empty lines in the Emacs fringe a la Vi. See the package repo for more info.

(use-package vi-tilde-fringe
 :config
 (global-vi-tilde-fringe-mode)
 :diminish vi-tilde-fringe-mode)

Info colors

(use-package info-colors
 :hook
 (Info-selection #'info-colors-fontify-node))

Fill column

I keep it disabled, because it is too slow.

(use-package fill-column-indicator
 :config
 (setq fci-rule-column 120)
 (setq fci-rule-color "#ff6c6b")
 (setq fill-column 80))

All the icons

A utility package to collect various Icon Fonts and propertize them within Emacs.

Don’t forget to run M-x all-the-icons-install-fonts.

Disabled, it slows down dired.

(use-package all-the-icons
 :config
 (setq
   all-the-icons-mode-icon-alist
   `(,@all-the-icons-mode-icon-alist
     (package-menu-mode all-the-icons-octicon "package" :v-adjust 0.0)
     (jabber-chat-mode all-the-icons-material "chat" :v-adjust 0.0)
     (jabber-roster-mode all-the-icons-material "contacts" :v-adjust 0.0)
     (telega-chat-mode all-the-icons-fileicon "telegram" :v-adjust 0.0
                       :face all-the-icons-blue-alt)
     (telega-root-mode all-the-icons-material "contacts" :v-adjust 0.0))))

Emojify

Add emoji support. This is useful when working with HTML.

(use-package emojify
 :hook
 (text-mode . emojify-mode))

Mode line

Simple-modeline

(use-package simple-modeline
 ;; TODO: https://github.com/melpa/melpa/pull/6818
 :quelpa
 (simple-modeline :fetcher github :repo "gexplorer/simple-modeline")
  :hook (after-init . simple-modeline-mode))

Telephone-line

(use-package telephone-line
  :init
  (setq
   telephone-line-lhs
   '((evil . (telephone-line-evil-tag-segment))
     (accent . (telephone-line-vc-segment
                telephone-line-erc-modified-channels-segment
                telephone-line-process-segment))
     (nil . (telephone-line-minor-mode-segment
             telephone-line-buffer-segment))))
  (setq
   telephone-line-rhs
   '((nil . (telephone-line-misc-info-segment))
     (accent . (telephone-line-major-mode-segment))
     (evil . (telephone-line-airline-position-segment))))
  :config
  :hook (after-init . telephone-line-mode))

Mood-line

A minimal mode-line configuration that aims to replicate some of the features of the doom-modeline package.

(use-package mood-line
 :hook
 (after-init . mood-line-mode))

Moody + minions

Another option is moody + minions as an attractive minimalist mode line replacement.

(use-package minions
 :config
 (setq minions-mode-line-lighter "[+]")
 (minions-mode 1))

(use-package moody
 :config
 (moody-replace-mode-line-buffer-identification)
 (moody-replace-vc-mode)
 (setq-default
  x-underline-at-descent-line t
  column-number-mode t))

Spaceline

A very cool mode line that I used previously.

(use-package spaceline
 :init
 (setq
  powerline-default-separator 'bar
  spaceline-highlight-face-func 'spaceline-highlight-face-evil-state)
 :config
 (require 'spaceline-config)
 (spaceline-spacemacs-theme))

Flycheck color

Colors the mode-line according to the Flycheck state of the current buffer.

(use-package flycheck-color-mode-line
  :after (flycheck)
  :commands
  (flycheck-color-mode-line-mode)
  :hook
  (flycheck-mode . flycheck-color-mode-line-mode))

Indent info

Display information about the current indentation settings.

(use-package indent-info
  :defer 2
  :custom
  (indent-info-prefix " ")
  (indent-info-suffix " ")
  :config
  (global-indent-info-mode 1))

Hide mode line

Support hiding the mode line, this can be useful for different modes displaying documents or presentation.

(use-package hide-mode-line
 :config
 (nmap
   :prefix my/leader
   "m h" 'hide-mode-line))

Volatile highlights (disabled)

Doesn’t seem to work. See this issue for more info.

(use-package volatile-highlights
  :config
  (volatile-highlights-mode t)
  ;; evil
  (vhl/define-extension
   'evil 'evil-paste-after 'evil-paste-before
   'evil-paste-pop 'evil-move)
  (vhl/install-extension 'evil)
  ;; undo-tree
  (vhl/define-extension 'undo-tree 'undo-tree-yank 'undo-tree-move)
  (vhl/install-extension 'undo-tree))

Beacon

Visualizes cursor position. Might slow (or not so), but it works good without evil mode.

(use-package beacon
 :after (general)
 :demand t
 :commands (beacon-mode)
 :custom
 ;; (beacon-size 12)
 ;; (beacon-blink-delay 0.0)
 ;; (beacon-blink-duration 0.5)
 (beacon-color "#ffd700")
 (beacon-blink-when-window-scrolls nil)
 (beacon-dont-blink-commands nil)
 :config
 (beacon-mode 1)
 (nmap
   :prefix my/leader
   "t b" 'beacon-mode)
 :diminish beacon-mode)

Evil

Main

(use-package evil
 :preface
 (defvar my/evil/esc-hook '(t)
   "A hook run after ESC is pressed in normal mode (invoked by `evil-force-normal-state').
   If a hook returns non-nil, all hooks after it are ignored.")
 (defun my/evil/attach-esc-hook ()
   "Run all escape hooks, if any returns non-nil, then stop there"
   (run-hook-with-args-until-success 'my/evil/esc-hook))
 :init
 (setq
  ;; Required by evil-collection
  evil-want-keybinding nil
  evil-want-integration t
  ;; To restore missing C-u in evil
  evil-want-C-u-scroll t
  evil-want-C-w-delete t
  evil-want-fine-undo "No"
  evil-want-visual-char-semi-exclusive t
  evil-want-Y-yank-to-eol t
  evil-magic t
  evil-want-abbrev-expand-on-insert-exit nil
  evil-echo-state t
  evil-indent-convert-tabs t
  evil-ex-search-vim-style-regexp t
  evil-overriding-maps nil
  evil-ex-substitute-global t
  ;; Column range for ex commands
  evil-ex-visual-char-range t
  evil-insert-skip-empty-lines t
  evil-search-module 'evil-search
  evil-mode-line-format 'nil
  ;; More vim-like behavior
  evil-symbol-word-search t
  ;; Cursors
  evil-default-cursor (face-background 'cursor nil t)
  evil-normal-state-cursor 'box
  evil-emacs-state-cursor `(,(face-foreground 'warning) box)
  evil-insert-state-cursor 'bar
  evil-visual-state-cursor 'box)
 :config
 ;; Enable evil-mode globally,
 ;; good for ex-vimmers like me
 (evil-mode t)
 ;; Special
 (evil-make-overriding-map special-mode-map 'normal)
 ;; Compilation
 (evil-set-initial-state 'compilation-mode 'normal)
 ;; Occur
 (evil-make-overriding-map occur-mode-map 'normal)
 (evil-set-initial-state 'occur-mode 'normal)
 (advice-add 'evil-force-normal-state :after 'my/evil/attach-esc-hook)
 ;; Unbind  evil-paste-pop and evil-paste-pop-next
 ;; which breaks evil-mc
 (with-eval-after-load 'evil-maps
   (define-key evil-normal-state-map (kbd "C-n") nil)
   (define-key evil-normal-state-map (kbd "C-p") nil)))

Evil collection

(use-package evil-collection
  :init
  (setq
   ;; Don't enable vim key bindings in minibuffer
   ;; its a default setting, just want it to be explicitly stated here
   evil-collection-setup-minibuffer nil
   ;; If you don't need everything - uncomment and add everything you want
   ;; evil-collection-mode-list '()
   evil-collection-company-use-tgn nil)
  :config
  (evil-collection-init)
  (nmap
    "C-M-l" 'evil-window-increase-width
    "C-M-h" 'evil-window-decrease-width
    "C-M-k" 'evil-window-increase-height
    "C-M-j" 'evil-window-decrease-height))

Alignment

This package provides gl and gL align operators:

  • gl MOTION CHAR - left alignment.
  • gL MOTION CHAR - right alignment.

Go to the package repo for more info.

(use-package evil-lion
 :after evil
 :commands
 (evil-lion-mode
  evil-lion-left
  evil-lion-right)
 :init
 (setq evil-lion-squeeze-spaces t))

Sentence navigation

Provides alternatives to forward-sentence, backward-sentence, and sentence text objects that work with sentences separated by one (or two) space(s) and is aware of abbreviations.

See the package repo for more info.

(use-package sentence-navigation
 :after evil
 :commands
 (sentence-nav-evil-forward)
 :config
 (mmap
   ")" 'sentence-nav-evil-forward
   "(" 'sentence-nav-evil-backward
   "g)" 'sentence-nav-evil-forward-end
   "g(" 'sentence-nav-evil-backward-end)
 (mmap evil-outer-text-objects-map
   "s" 'sentence-nav-evil-outer-sentence)
 (mmap evil-inner-text-objects-map
   "s" 'sentence-nav-evil-inner-sentence))

Multiple cursors

(use-package evil-mc
 :after (general evil)
 :commands
 (global-evil-mc-mode)
 :preface
 (defun my/evil-mc/esc ()
   "Clear evil-mc cursors and restore state."
   (when (evil-mc-has-cursors-p)
     (evil-mc-undo-all-cursors)
     (evil-mc-resume-cursors)
     t))
 :demand t
 :config
 (global-evil-mc-mode 1)
 (add-hook 'my/evil/esc-hook 'my/evil-mc/esc)
 (mmap
   "C-n" 'evil-mc-make-and-goto-next-match)
 (when (eq system-type 'darwin)
   ;; unbind isearch commands
   (unbind-key "s-d")
   (unbind-key "s-g")
   (mmap
     "s-d" 'evil-mc-make-and-goto-next-match
     "s-D" 'evil-mc-make-all-cursors))
 :diminish evil-mc-mode)

Matchit

(use-package evil-matchit
 :after evil
 :demand t
 :commands
 (evilmi-jump-items
  evilmi-text-object
  global-evil-matchit-mode)
 :config
 (global-evil-matchit-mode 1))

String inflection

(use-package evil-string-inflection)

Surround

(use-package evil-surround
 :after evil
 :demand t
 :commands
 (global-evil-surround-mode
   evil-surround-edit
   evil-Surround-edit
   evil-surround-region)
 :config
 (global-evil-surround-mode 1))

Args

(use-package evil-args
 :after evil
 :config
 (add-to-list 'evil-args-delimiters " ")
 ;; Bind evil-args text objects
 (define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
 (define-key evil-outer-text-objects-map "a" 'evil-outer-arg)
 ;; Bind evil-forward/backward-args
 (define-key evil-normal-state-map "L" 'evil-forward-arg)
 (define-key evil-normal-state-map "H" 'evil-backward-arg)
 (define-key evil-motion-state-map "L" 'evil-forward-arg)
 (define-key evil-motion-state-map "H" 'evil-backward-arg)
 ;; Bind evil-jump-out-args
 (define-key evil-normal-state-map "K" 'evil-jump-out-args))

Embrace

(use-package evil-embrace
 :after evil
 :commands
 (evil-embrace-enable-evil-surround-integration)
 :demand t
 :init
 (setq evil-embrace-show-help-p nil)
 :config
 (evil-embrace-enable-evil-surround-integration))

Visualstar

(use-package evil-visualstar
 :after evil
 :commands
 (global-evil-visualstar-mode
   evil-visualstar/begin-search
   evil-visualstar/begin-search-forward
   evil-visualstar/begin-search-backward)
 :config
 (global-evil-visualstar-mode))

Vimish fold

(use-package evil-vimish-fold
  :after (evil vimish-fold)
  :commands
  (evil-vimish-fold-mode)
  :config
  (evil-vimish-fold-mode 1)
  :diminish evil-vimish-fold-mode)

Indent plus

(use-package evil-indent-plus
 :after evil
 :demand t
 :commands
 (evil-indent-plus-i-indent
  evil-indent-plus-a-indent
  evil-indent-plus-i-indent-up
  evil-indent-plus-a-indent-up
  evil-indent-plus-i-indent-up-down
  evil-indent-plus-a-indent-up-down))

Commentary

(use-package evil-commentary
 :after evil
 :demand t
 :commands
 (evil-commentary-mode
  evil-commentary-yank
  evil-commentary-line)
 :config (evil-commentary-mode)
 :diminish evil-commentary-mode)

Exchange

(use-package evil-exchange
 :after evil
 :demand t
 :commands
 (evil-exchange
  evil-exchange-install)
 :config
 (evil-exchange-install))

Numbers

(use-package evil-numbers
 :demand t
 :after evil)

Diff

Diff mode is a standard Emacs major mode for highlighting and navigating diff output.

(use-package diff-mode
 :mode "/patch$"
 :init
 (setq
  ;; Open patches in read-only mode by default
  diff-default-read-only t))

Eldoc

Overlay

Eldoc displays the function signature of the closest function call around point either in the minibuffer or in the modeline. This package modifies Eldoc to display this documentation inline using a buffer text overlay.

(use-package eldoc-overlay
 :after general
 :init
 (setq eldoc-overlay-in-minibuffer-flag t)
 :config
 (nmap
   :prefix my/leader
   "t E" 'eldoc-overlay-toggle)
 :diminish "eo")

Posframe

Display eldoc in a child frame.

(use-package eldoc-posframe
  :after (posframe)
  :quelpa (eldoc-posframe :fetcher github :repo "gexplorer/eldoc-posframe")
  :diminish eldoc-posframe-mode
  :custom
  (eldoc-posframe-left-fringe 0)
  (eldoc-posframe-poshandler #'posframe-poshandler-point-bottom-left-corner))

Bookmarks

Most of the keybindings are set by the evil-collection package.

(use-package bookmark
  :after general
  :init
  (setq
   bookmark-version-control t
   bookmark-save-flag 1)
  :config
  ;; Uncomment if you prefer going straight to bookmarks on Emacs startup.
  ;; (bookmark-bmenu-list)
  ;; (switch-to-buffer "*Bookmark List*")
  (nmap
    :prefix my/leader
    "b" 'bookmark-set))

Completion

Company

Some of the key bindings are provided by the evil-collection.

(defun my/company-mode/setup-faces ()
  "Style company-mode nicely"
  (let* ((bg (face-attribute 'default :background))
         (bg-light (color-lighten-name bg 2))
         (bg-lighter (color-lighten-name bg 5))
         (bg-lightest (color-lighten-name bg 10))
         (ac (face-attribute 'match :foreground)))
    (custom-set-faces
     `(company-tooltip
       ((t (:inherit default :background ,bg-light))))
     `(company-scrollbar-bg ((t (:background ,bg-lightest))))
     `(company-scrollbar-fg ((t (:background ,bg-lighter))))
     `(company-tooltip-selection
       ((t (:inherit font-lock-function-name-face))))
     `(company-tooltip-common
       ((t (:inherit font-lock-constant-face))))
     `(company-preview-common
       ((t (:foreground ,ac :background ,bg-lightest)))))))
(use-package company
 :hook
 ;; Use company-mode in all buffers
 (after-init . global-company-mode)
 :custom
 (company-dabbrev-ignore-case nil)
 (company-dabbrev-code-ignore-case nil)
 (company-dabbrev-downcase nil)
 (company-idle-delay 0.2 "adjust this setting according to your typing speed")
 (company-minimum-prefix-length 1)
 (company-tooltip-align-annotations t)

 ;; Disable in org
 (company-global-modes '(not org-mode))
 :config
 (my/company-mode/setup-faces)
 (unbind-key "C-SPC")
 (imap
  "C-SPC" 'company-complete
  "M-SPC" 'company-complete)
 (general-define-key
  :keymaps 'company-active-map
  "C-j" 'company-select-next-or-abort
  "C-k" 'company-select-previous-or-abort
  "C-o" 'company-other-backend
  "C-f" 'company-abort
  "C-d" 'company-show-doc-buffer
  "C-w" 'backward-kill-word)
 :diminish company-mode)

Company quickhelp

(use-package company-quickhelp
 :after company
 :custom
 (company-quickhelp-delay 3)
 :config
 (general-define-key
  :keymaps 'company-active-map
  "C-c h" 'company-quickhelp-manual-begin))

Company FLX

FLX fuzzy matching for company. This only works with the company-capf backend.

(use-package flx)

(use-package company-flx
 :after (company flx)
 :commands
 (company-flx-mode)
 :demand t
 :config
 ;; use C-o to switch backend and
 ;; enable company mode fuzziness
 (company-flx-mode +1))

Writing

Spellcheck

(use-package ispell
  :ensure nil
  :preface
  (defun my/ispell/org-setup ()
    "Skip regions for ispell checking"
    (make-local-variable 'ispell-skip-region-alist)
    (add-to-list 'ispell-skip-region-alist '("~" . "~"))
    (add-to-list 'ispell-skip-region-alist '("=" . "="))
    (add-to-list 'ispell-skip-region-alist '("\\[" . "\\]"))
    (add-to-list 'ispell-skip-region-alist '("^ *#\\+OPTIONS:" . "$"))
    (add-to-list 'ispell-skip-region-alist '("^ *#\\+ATTR_" . "$"))
    (add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:"))
    ;; Don’t spell check in org source code blocks, example, latex
    (add-to-list 'ispell-skip-region-alist '("^ *#\\+begin_src" . "^ *#\\+end_src"))
    (add-to-list 'ispell-skip-region-alist '("^ *#\\+BEGIN_EXAMPLE" . "^ *#\\+END_EXAMPLE"))
    (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_LATEX" . "#\\+END_LATEX")))
  :hook
  (org-mode . my/ispell/org-setup)
  :custom
  (ispell-program-name "aspell")
  ;; (ispell-dictionary "english")
  ;; (ispell-local-dictionary "russian")
  (ispell-really-aspell t)
  (ispell-really-hunspell nil)
  (ispell-extra-args '("--sug-mode=ultra"))
  (ispell-encoding8-command t)
  (ispell-silently-savep t)
  (ispell-have-new-look t)
  (ispell-enable-tex-parser t)
  :config
  (nmap
    "C-c i w" 'ispell-word
    "C-c i c" 'ispell-comments-and-strings
    "C-c i d" 'ispell-change-dictionary
    "C-c i k" 'ispell-kill-ispell
    "C-c i m" 'ispell-message
    "C-c i r" 'ispell-region)
  (when (eq system-type 'darwin)
    (general-define-key
     "s-\\" 'ispell-word)))

Writegood

Minor mode for Emacs to improve English writing.

(use-package writegood-mode
  :hook
  (text-mode)
  :config
  (nmap
    :prefix my/leader
    "W g" 'writegood-grade-level
    "W r" 'writegood-reading-ease))

Misc

(use-package wc-mode)

Provides predictive abbreviation expansion with no configuration.

(use-package pabbrev)

Transform words in Emacs (upcase, downcase, capitalize, etc).

(use-package fix-word)

Minor mode for typographical editing.

(use-package typo
  :hook
  (text-mode . typo-mode))

Flycheck

Mode

On-the-fly syntax checking for GNU Emacs. See the flycheck.org for more info.

(use-package flycheck
  :after (general)
  :demand t
  :commands
  (global-flycheck-mode)
  :init
  (setq-default
   flycheck-disabled-checkers
   '(emacs-lisp-checkdoc
     javascript-jshint
     haskell-stack-ghc
     haskell-ghc
     haskell-hlint))
  (setq
   flycheck-highlighting-mode 'lines
   flycheck-indication-mode 'left-fringe
   flycheck-mode-line-prefix "fly"
   flycheck-javascript-eslint-executable "eslint_d")
  :config
  (global-flycheck-mode 1)
  (nmap
    :prefix my/leader
    "t e" 'flycheck-mode
    "e e" 'flycheck-list-errors
    "e c" 'flycheck-clear
    "e i" 'flycheck-manual
    "e C" 'flycheck-compile
    "e n" 'flycheck-next-error
    "e p" 'flycheck-previous-error
    "e b" 'flycheck-buffer
    "e s" 'flycheck-select-checker
    "e v" 'flycheck-verify-setup
    "e V" 'flycheck-verify-checker)
  ;; Make the error list display like similar lists in contemporary IDEs
  ;; like VisualStudio, Eclipse, etc.
  (add-to-list
   'display-buffer-alist
   `(,(rx bos "*errors*" eos)
     ;; (display-buffer-reuse-window
     ;;  display-buffer-in-side-window)
     (side . bottom)
     (reusable-frames . visible)
     (window-height . 0.33)))
  (unbind-key "C-j" flycheck-error-list-mode-map)
  :diminish flycheck-mode)

Flycheck indicator

(use-package flycheck-indicator
  :hook (flycheck-mode . flycheck-indicator-mode))

Posframe

Cool package, but I prefer to enable it manually, when needed.

(use-package flycheck-posframe
  :after (flycheck)
  :config
  (flycheck-posframe-configure-pretty-defaults)
  (add-to-list
   'flycheck-posframe-inhibit-functions
   #'(lambda () (bound-and-true-p company-backend)))
  (setq flycheck-posframe-border-width 1)
  (set-face-attribute 'flycheck-posframe-background-face nil :inherit nil :background "#111")
  (set-face-attribute 'flycheck-posframe-error-face nil :inherit nil :foreground "red")
  (set-face-attribute 'flycheck-posframe-warning-face nil :foreground "skyblue")
  (set-face-attribute 'flycheck-posframe-info-face nil :foreground "white")
  :custom-face (flycheck-posframe-border-face ((t (:foreground "#353535"))))
  ;; :hook
  ;; (flycheck-mode . flycheck-posframe-mode)
)

Popup (flycheck-popup-tip)

Display Flycheck error messages using popup.el. Can be used together with the flyheck-pos-tip.

(use-package flycheck-popup-tip
  :after (flycheck)
  :custom
  (flycheck-popup-tip-error-prefix "* ")
  :config
  (flycheck-popup-tip-mode))

Popup (flycheck-pos-tip)

Displays flycheck errors in tooltip. However, it does not display popup if you run Emacs under TTY. It displays message on echo area and that is often used for ELDoc. Also, popups made by pos-tip library does not always look good, especially on macOS and Windows.

Can be used together with the flyheck-popup-tip.

(use-package flycheck-pos-tip
  :after (flycheck flycheck-popup-tip)
  :commands
  (flycheck-pos-tip-error-messages)
  :config
  (setq
   flycheck-pos-tip-display-errors-tty-function
   #'flycheck-popup-tip-show-popup)
  (flycheck-pos-tip-mode))

Proselint

Add prose linting to Flycheck. Depends on the proselint command line tool.

TODO: Find a way to disable it in code regions.

(with-eval-after-load 'flycheck
  (flycheck-define-checker proselint
    "A linter for prose."
    :command ("proselint" source-inplace)
    :error-patterns
    ((warning line-start (file-name) ":" line ":" column ": "
              (id (one-or-more (not (any " "))))
              (message) line-end))
    :modes (text-mode markdown-mode gfm-mode))
  (add-to-list 'flycheck-checkers 'proselint))

Colorguard

(use-package flycheck-css-colorguard
  :after (flycheck)
  :hook
  (flycheck-mode . flycheck-css-colorguard-setup))

Flyspell

(use-package flyspell
  :ensure nil
  :after (general ispell)
  :custom
  (flyspell-delay 1)
  (flyspell-always-use-popup t)
  :init
  (setq
   ;; flyspell-default-dictionary "russian"
   ;; flyspell-dictionary "russian"
   flyspell-use-meta-tab nil
   flyspell-mode-line-string ""
   flyspell-auto-correct-binding (kbd ""))
  :hook
  ((text-mode . flyspell-mode)
   ;; Don’t check comments, thats too annoying
   ;; (prog-mode . flyspell-prog-mode)
   ;; Might be slow in large org-files
   ;; (org-mode . flyspell-mode)
   (gfm-mode . flyspell-mode)
   (git-commit-mode . flyspell-mode))
  :config
  (unbind-key "C-." flyspell-mode-map)
  (nmap
    :prefix my/leader
    "t f" 'flyspell-mode)
  (nmap
    "C-c i b" 'flyspell-buffer
    "C-c i f" 'flyspell-mode))

Compilation

Kill compilation process before starting another, save all buffers on compile, scroll to the first compilation error automatically.

(setq-default
 compilation-always-kill t
 compilation-ask-about-save nil
 compilation-scroll-output 'first-error)

Dictionary

Powerthesaurus

(use-package powerthesaurus
 :after general
 :config
 (nmap
   :prefix my/leader
   "L" 'powerthesaurus-lookup-word-at-point))

If you got the error in process filter chances are the wordnik.com is down, try again later ;)

Synosaurus

(use-package synosaurus
 :after (general)
 :config
 (nmap
  :prefix my/leader
  "; ;" 'synosaurus-lookup
  "; '" 'synosaurus-choose-and-replace))

Define word

(use-package define-word
 :after general
 :defer 1
 :config
 (nmap
   :prefix my/leader
   "D" 'define-word-at-point))

Wordnut

Interface to WordNet lexical database.

(use-package wordnut
  :if (executable-find "wordnet"))

Dired

Constants (file extensions)

(defconst my/dired-html-files-extensions
  '("htm" "html" "xhtml" "phtml" "haml"
    "asp" "aspx" "xaml" "php" "jsp")
  "HTML files extensions")
(defconst my/dired-styles-files-extensions
  '("css" "sass" "scss" "less")
  "Styles files extensions")
(defconst my/dired-xml-files-extensions
  '("xml" "xsd" "xsl" "xslt" "wsdl")
  "XML files extensions")
(defconst my/dired-document-files-extensions
  '("doc" "docx" "ppt" "pptx" "xls" "xlsx"
    "csv" "rtf" "djvu" "epub""wps" "pdf" "texi" "tex"
    "odt" "ott" "odp" "otp" "ods" "ots"
    "odg" "otg")
  "Document files extensions")
(defconst my/dired-text-files-extensions
  '("txt" "md" "org" "ini" "conf" "rc" "vim" "vimrc" "exrc")
  "Text files extensions")
(defconst my/dired-sh-files-extensions
  '("sh" "bash" "zsh" "fish" "csh" "ksh"
    "awk" "ps1" "psm1" "psd1" "bat" "cmd")
  "Shell files extensions")
(defconst my/dired-source-files-extensions
  '("py" "c" "cc" "cpp" "cxx" "c++" "h" "hpp" "hxx" "h++"
    "java" "pl" "rb" "el" "pl" "pm" "l" "jl" "f90" "f95"
    "R" "php" "hs" "purs" "coffee" "ts" "js" "json" "m" "mm"
    "ml" "asm" "vb" "ex" "exs" "erl" "go" "clj" "cljs"
    "sql" "yml" "yaml" "toml" "rs" "idr" "cs" "mk" "make" "swift"
    "rake" "lua")
  "Source files extensions")
(defconst my/dired-compressed-files-extensions
  '("zip" "bz2" "tgz" "txz" "gz" "xz" "z" "Z"
    "war" "ear" "rar" "sar" "xpi" "apk" "tar" "7z"
    "gzip" "001" "ace" "lz"
    "lzma" "bzip2" "cab" "jar" "iso")
  "Compressed files extensions")
(defconst my/dired-image-files-extensions
  '("bmp" "jpg" "jpeg" "gif" "png" "tiff"
    "ico" "svg" "psd" "pcd" "raw" "exif"
    "BMP" "JPG" "PNG")
  "Image files extensions")
(defconst my/dired-audio-files-extensions
  '("mp3" "MP3" "ogg" "OGG" "flac" "FLAC" "wav" "WAV")
  "Dired Audio files extensions")
(defconst my/dired-video-files-extensions
  '("vob" "VOB" "mkv" "MKV" "mpe" "mpg" "MPG"
    "mp4" "MP4" "ts" "TS" "m2ts"
    "M2TS" "avi" "AVI" "mov" "MOV" "wmv"
    "asf" "m2v" "m4v" "mpeg" "MPEG" "tp")
  "Dired Video files extensions")
(defconst my/dired-misc-files-extensions
  '("DS_Store" "projectile" "cache" "elc" "dat" "meta")
  "Misc files extensions")

Dired

Setup dired.

(use-package dired
 :after general
 :ensure nil
 :custom
 ;; Do not bind C-x C-j since it's used by jabber.el
 (dired-bind-jump nil)
 :init
 ;; Prevents dired from creating an annoying popup
 ;; when dired-find-alternate-file is called
 (setq
  ;; If there is a dired buffer displayed in the next window,
  ;; use its current directory
  dired-dwim-target t
  dired-omit-verbose nil
  ;; human readable filesize
  dired-listing-switches "-ahlv"
  ;; recursive copy & delete
  dired-recursive-deletes 'always
  dired-recursive-copies 'always)
 (setq
  dired-garbage-files-regexp
  "\\.\\(?:aux\\|out\\|bak\\|dvi\\|log\\|orig\\|rej\\|toc\\|class\\)\\'")
 ;; Enable omit mode
 ;; (setq-default dired-omit-mode t)
 ;; Hide autosave files
 ;; (setq-default dired-omit-files "^\\.?#")
 ;; Uncomment the line below if you want to hide dot files
 ;; (setq-default dired-omit-files (concat dired-omit-files "\\|^\\.[^\\.]"))
 (setq
  dired-omit-extensions
  '("CVS" "RCS" ".o" "~" ".bin" ".lbin" ".fasl" ".ufsl" ".a" ".ln" ".blg"
    ".bbl" ".elc" ".lof" ".glo" ".idx" ".aux" ".glob" ".vo"
    ".lot" ".fmt" ".tfm" ".class" ".DS_Store"
    ".fas" ".lib" ".x86f" ".sparcf" ".lo" ".la" ".toc" ".aux" ".cp" ".fn"
    ".ky" ".pg" ".tp" ".vr" ".cps" ".fns" ".kys" ".pgs" ".tps" ".vrs"
    ".idx" ".lof" ".lot" ".glo" ".blg" ".bbl" ".cp" ".cps" ".fn" ".fns"
    ".ky" ".kys" ".pg" ".pgs" ".tp" ".tps" ".vr" ".vrs" ".gv" ".gv.pdf"))
 ;; macOS ls command doesn't support "--dired" option
 (when (string= system-type "darwin")
   (setq dired-use-ls-dired nil))
 :config
 (put 'dired-find-alternate-file 'disabled nil)
 (nmap
   :prefix my/leader
   "j" 'dired-jump)
 (nmap 'dired-mode-map
   "gg" 'evil-goto-first-line
   "G" 'evil-goto-line
   "b" 'bookmark-set)
 :hook
 (dired-mode . dired-hide-details-mode)
 (dired-mode . hl-line-mode)
 :diminish dired-mode)

Dired hide dotfiles

Allows to easily show/hide dotfiles.

(use-package dired-hide-dotfiles
 :config
 (nmap 'dired-mode-map
   "." 'dired-hide-dotfiles-mode)
 :hook
 (dired-mode . dired-hide-dotfiles-mode))

Stripe (disabled)

Use different background colors for even and odd lines. See the customization section.

(use-package stripe-buffer
  :hook
  (dired-mode . stripe-buffer-mode))

Dired fl

Extra Emacs font lock rules for a more colourful dired. See the package repo for more info.

(use-package diredfl
 :after dired
 :hook
 (dired-mode . diredfl-mode))

Dired rsync

(use-package dired-rsync
 :config
 (nmap 'dired-mode-map
   "r" 'dired-rsync))

Dired launch

Launch an external application from dired.

(use-package dired-launch
 :hook
 (dired-mode . dired-launch-mode)
 :init
 (setq dired-launch-default-launcher '("xdg-open"))
 :config
 (nmap 'dired-launch-mode-map
   "l" 'dired-launch-command))

Dired+

Setup dired+.

(use-package dired+
 :after dired
 :quelpa
 (dired+ :fetcher github :repo "emacsmirror/dired-plus")
 :commands
 (dired-read-dir-and-switches)
 :init
 (setq
  diredp-hide-details-initially-flag nil
  diredp-hide-details-propagate-flag nil))

Dired hacks.

Collection of useful dired additions.

Prerequisites

First, we need to install some dired hacks dependencies.

(use-package dash)
(use-package dired-hacks-utils
 :after dired
 :demand t)

Filter

(use-package dired-filter
 :after dired
 :hook
 (dired-mode . dired-filter-group-mode)
 :init
 (setq
  dired-filter-keep-expanded-subtrees nil
  dired-filter-group-saved-groups
  '(("default"
     ("video" (extension "mkv" "avi" "mp4" "webm"))
     ("archives" (extension "zip" "rar" "gz" "bz2" "tar"))
     ("pdf" (extension "pdf"))
     ("tex" (extension "tex" "bib"))
     ("js" (extension "js"))
     ("ts" (extension "ts"))
     ("json" (extension "json"))
     ("styles" (extension "css" "scss" "sass" "less"))
     ("html" (extension "html"))
     ("haskell" (extension "hs"))
     ("idris" (extension "idr"))
     ("purescript" (extension "purs"))
     ("c/c++"
      (extension
       "c" "cc" "cpp" "cxx" "c++"
       "h" "hpp" "hxx" "h++"))
     ("org" (extension "org"))
     ("lisp" (extension "el"))
     ("word" (extension "docx" "doc"))
     ("excel" (extension "xlsx" "xls"))
     ("text" (extension "txt"))
     ("svg" (extension "svg"))
     ("shell"
      (extension
       "sh" "bash" "zsh" "fish" "csh" "ksh"
       "awk" "ps1" "psm1" "psd1" "bat" "cmd"))
     ("audio"
      (extension
       "mp3" "ogg" "flac" "wav"))
     ("img"
      (extension
       "bmp" "jpg" "jpeg" "gif" "png" "tiff"
       "ico" "svg" "psd" "pcd" "raw" "exif")))))
 (nmap 'dired-mode-map
   "/" 'dired-filter-map
   "C-c C-t" 'dired-filter-group-toggle-header
   "C-c C-g" 'dired-filter-group-mode))

Avfs

(use-package dired-avfs
 :after (dired dired-hack-utils))

Open

(use-package dired-open
 :after (dired dired-hack-utils))

Narrow

(use-package dired-narrow
 :after (general dired dired-hack-utils)
 :config
 (nmap 'dired-mode-map
   "," 'dired-narrow))

Peep dired

Peep at files in another window from dired buffers.

(use-package peep-dired
 :after (dired general)
 :preface
 (defconst my/peep-dired/ignored-extensions
   (append
    my/dired-document-files-extensions
    my/dired-compressed-files-extensions
    my/dired-image-files-extensions
    my/dired-audio-files-extensions
    my/dired-video-files-extensions
    my/dired-misc-files-extensions))
 :hook
 (peep-dired . evil-normalize-keymaps)
 :init
 (setq
  peep-dired-ignored-extensions my/peep-dired/ignored-extensions
  peep-dired-cleanup-on-disable t
  peep-dired-enable-on-directories t)
 :config
 (nmap 'dired-mode-map
   "C-c C-v" 'peep-dired)
 (general-define-key
  :states '(normal)
  :keymaps 'peep-dired-mode-map
  "j" 'peep-dired-next-file
  "k" 'peep-dired-prev-file))

Neotree

Most of key bindings are provided by the evil-collection.

(use-package neotree
  :after (general)
  :functions
  (visual-line-mode)
  :preface
  (defvar my/neotree/open-app
    (if (eq system-type 'darwin)
        "open" "xdg-open"))
  (defun my/neotree/setup (_unused)
    (hide-mode-line-mode +1)
    (linum-mode -1)
    (visual-line-mode -1)
    (setq indicate-buffer-boundaries nil)
    (vi-tilde-fringe-mode -1))
  :init
  (setq
   neo-autorefresh t
   neo-theme (if (display-graphic-p) 'nerd 'arrow)
   neo-smart-open t
   neo-window-width 25
   neo-auto-indent-point t
   neo-create-file-auto-open t
   neo-mode-line-type 'none
   neo-confirm-create-file 'off-p
   neo-confirm-delete-file 'off-p
   neo-confirm-delete-directory-recursively 'off-p
   neo-confirm-kill-buffers-for-files-in-directory 'off-p
   neo-default-system-application my/neotree/open-app
   neo-confirm-create-directory 'off-p
   neo-confirm-change-root 'off-p)
  :hook
  (neo-after-create . my/neotree/setup)
  :config
  (nmap 'neotree-mode-map
    "gg" 'evil-goto-first-line
    "G" 'evil-goto-line
    "C" 'neotree-change-root)
  (nmap
    :prefix my/leader
    "q" 'neotree-show
    "Q" 'neotree-hide
    "r" 'neotree-find)
  (when (eq system-type 'darwin)
    (general-define-key
     "s-B" 'neotree-toggle)))

Icons

(use-package all-the-icons-dired
 :hook
 (dired-mode . all-the-icons-dired-mode))

Navigation

Ace window

Quickly switch between windows (splits).

When there are two windows, ace-window will call other-window. If there are more, each window will have the first character of its window label highlighted at the upper left of the window.

See the package repo for more info.

(use-package ace-window
 :custom
 (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l) "Use home row for selecting.")
 (aw-scope 'frame "Highlight only current frame.")
 :config
 (nmap
   :prefix my/leader
   "w" 'ace-window))

Windows

Winner

Undo/redo window layout (split pane) config.

(use-package winner
 :demand t
 :init
 (setq
  winner-dont-bind-my-keys t
  winner-boring-buffers
  '("*Completions*"
    "*Compile-Log*"
    "*inferior-lisp*"
    "*Fuzzy Completions*"
    "*Apropos*"
    "*Help*"
    "*cvs*"
    "*Buffer List*"
    "*Ibuffer*"
    "*esh command on file*"))
 :config
 (winner-mode 1)
 :config
 (nmap
   :prefix my/leader
   "U" 'winner-undo
   "R" 'winner-redo)
 (when (eq system-type 'darwin)
   (general-define-key
    "C-s-[" 'winner-undo
    "C-s-]" 'winner-redo)))

Transpose frame

(use-package transpose-frame
  :config
  (nmap
    "C-M-SPC" 'transpose-frame
    "C-M-u" 'flip-frame
    "C-M-i" 'flip-frame
    "C-M-y" 'flop-frame
    "C-M-o" 'flop-frame))

Zoom

Zoom a window to display as a single window temporarily.

(use-package zoom-window
  :config
  (nmap
    :prefix my/leader
    "RET" 'zoom-window-zoom))

Expand region

Increases the selected region by semantic units.

(use-package expand-region
 :after (general)
 :config
 (vmap
   "v" 'er/expand-region)
 (when (eq system-type 'darwin)
   (vmap
     "s-'" 'er/expand-region)))

Ivy

Setup ivy.

(use-package ivy
  :preface
  (defun my/ivy/switch-buffer-occur ()
    "Occur function for `ivy-switch-buffer' using `ibuffer'."
    (ibuffer nil (buffer-name) (list (cons 'name ivy--old-re))))
  :commands
  (ivy-mode ivy-set-occur)
  :custom
  (ivy-count-format "%d/%d " "Show anzu-like counter")
  :custom-face
  ;; (ivy-current-match ((t (:inherit 'hl-line))))
  ;; TODO: Make this theme-dependent (use :inherit)
  (ivy-current-match ((t (:background "#4782b4" :foreground "#fff"))))
  :init
  (setq
   ;; Enable bookmarks and recentf
   ;; (add 'recentf-mode' and bookmarks to 'ivy-switch-buffer')
   ivy-use-virtual-buffers t
   ;; Display full buffer name
   ivy-virtual-abbreviate 'full
   ;; Number of result lines to display
   ivy-height 12
   ;; Current input becomes selectable as a candidate
   ;; solves the issue of creating a file or
   ;; a directory `foo` when a file `foobar` already exists
   ;; another way is to use C-M-j
   ivy-use-selectable-prompt t
   ;; Wrap around ivy results
   ivy-wrap t
   ;; Omit ^ at the beginning of regexp
   ivy-initial-inputs-alist nil)
  :config
  (ivy-mode 1)
  ;; Enable fuzzy searching everywhere except:
  ;; - Switching buffers with Ivy
  ;; - Swiper
  ;; - Counsel projectile (find-file)
  (setq
   ivy-re-builders-alist
   '((swiper . ivy--regex-plus)
     (swiper-isearch . regexp-quote)
     (ivy-switch-buffer . ivy--regex-plus)
     (counsel-projectile-find-file . ivy--regex-plus)))
  (ivy-set-occur 'ivy-switch-buffer 'my/ivy/switch-buffer-occur)
  (nmap
    :prefix my/leader
    "b" 'ivy-switch-buffer)
  (nmap
    "C-c v" 'ivy-push-view
    "C-c V" 'ivy-pop-view)
  (when (eq system-type 'darwin)
    (general-define-key
     "s-b" 'ivy-switch-buffer
     "M-s-b" 'ivy-resume))
  (general-define-key
   :keymaps 'ivy-minibuffer-map
   "C-t" 'ivy-toggle-fuzzy
   "C-j" 'ivy-next-line
   "C-k" 'ivy-previous-line
   "C-n" 'ivy-next-history-element
   "C-p" 'ivy-previous-history-element
   "<C-return>" 'ivy-immediate-done
   "C-l" 'ivy-immediate-done
   "C-w" 'ivy-backward-kill-word)
  :diminish ivy-mode)

Ivy posframe.

It doesn’t work with evil-mode.

(use-package ivy-posframe
  :after (posframe)
  :config
  (setq ivy-posframe-height-alist
        '((swiper . 20)
          (t. 20)))

  (setq
   ivy-posframe-display-functions-alist
   '((swiper . nil)
     (counsel-bookmark . ivy-posframe-display-at-frame-center)
     (counsel-find-file . ivy-posframe-display-at-frame-center)
     (counsel-git-grep . ivy-posframe-display-at-frame-center)
     (counsel-package . ivy-posframe-display-at-frame-center)
     (counsel-load-theme . ivy-posframe-display-at-frame-center)
     (counsel-rg . ivy-posframe-display-at-frame-center)
     (counsel-fzf . ivy-posframe-display-at-frame-center)
     (counsel-imenu . ivy-posframe-display-at-frame-center)
     (counsel-describe-variable . ivy-posframe-display-at-frame-center)
     (counsel-describe-face . ivy-posframe-display-at-frame-center)
     (counsel-describe-function . ivy-posframe-display-at-frame-center)
     (counsel-unicode-char . ivy-posframe-display-at-frame-top-center)
     (counsel-ace-link . ivy-posframe-display-at-frame-top-center)
     (complete-symbol . ivy-posframe-display-at-point)
     (counsel-M-x . ivy-posframe-display-at-frame-center)
     (t . ivy-posframe-display)))
  (ivy-posframe-mode 1))

Ivy icons

(use-package all-the-icons-ivy
 :after (ivy projectile)
 :commands
 (all-the-icons-ivy-setup)
 :custom
 (all-the-icons-ivy-buffer-commands '() "Don't use for buffers.")
 (all-the-icons-ivy-file-commands
  '(counsel-find-file
    counsel-file-jump
    counsel-recentf
    counsel-projectile-find-file
    counsel-projectile-find-dir) "Prettify more commands.")
 :config
 (all-the-icons-ivy-setup))

Rich

More friendly interface for ivy. Here is the package repo.

(use-package ivy-rich
 :after ivy
 :commands
 ivy-rich-mode
 :init
 (setq
  ;; To abbreviate paths using abbreviate-file-name
  ;; (e.g. replace “/home/username” with “~”)
  ivy-rich-path-style 'abbrev)
 :config
 (ivy-rich-mode 1))

Xref

(use-package ivy-xref
 :custom
 (xref-show-xrefs-function 'ivy-xref-show-xrefs "Use Ivy to show xrefs"))

Flyspell correct

(use-package flyspell-correct-ivy
 :after (general flyspell ivy)
 :demand t
 :init
 (setq flyspell-correct-interface 'flyspell-correct-ivy)
 :config
 (nmap 'flyspell-mode-map
   "C-;" 'flyspell-correct-next))

IBuffer VC

(use-package ibuffer-vc
 :custom
 (ibuffer-formats
  '((mark modified read-only vc-status-mini " "
          (name 18 18 :left :elide)
          " "
          (size 9 -1 :right)
          " "
          (mode 16 16 :left :elide)
          " "
          filename-and-process)) "include vc status info")
 :hook
 (ibuffer . (lambda ()
              (ibuffer-vc-set-filter-groups-by-vc-root)
              (unless (eq ibuffer-sorting-mode 'alphabetic)
                (ibuffer-do-sort-by-alphabetic)))))

FZF

(use-package fzf)

Counsel

Setup counsel.

(use-package counsel
 :after general
 :init
 ;; much faster than grep
 (setq
  counsel-git-cmd "rg --files"
  ;;  truncate all lines that are longer than 120 characters
  counsel-grep-base-command
  "rg -i -M 120 --no-heading --line-number --color never %s .")
 :config
 (nmap
   "C-f" 'counsel-imenu)
 (imap
   "C-," 'counsel-unicode-char)
 (nmap
   :prefix my/leader
   "f" 'counsel-rg
   "F" 'counsel-fzf
   "h v" 'counsel-describe-variable
   "h f" 'counsel-describe-function
   "h F" 'counsel-describe-face)
 (when (eq system-type 'darwin)
   (nmap
     "s-f" 'counsel-rg))
 (nmap
   "M-x" 'counsel-M-x)
 (nmap
   :prefix "C-x"
   "C-r" 'find-file
   "C-f" 'counsel-find-file
   "C-g" 'counsel-git-grep
   "p" 'counsel-package)
 (nmap
   :prefix my/leader
   my/leader 'counsel-M-x
   "T" 'counsel-load-theme
   "J" 'counsel-bookmark))

Ace link

Package for selecting a link to jump to.

(use-package ace-link
 :after (counsel)
 :commands
 (ace-link-setup-default)
 :config
 (nmap
   "C-c C-l" 'counsel-ace-link)
 :config
 (ace-link-setup-default))

Counsel etags

(use-package counsel-etags
  :after (general counsel)
  :init
  ;; Don't ask before rereading the TAGS files if they have changed
  (setq tags-revert-without-query t)
  ;; Don't warn when TAGS files are large
  (setq large-file-warning-threshold nil)
  ;; (setq counsel-etags-extra-tags-files '("./codex.tags"))
  ;; Use a custom command to update tags
  ;; (setq counsel-etags-update-tags-backend
  ;;       (lambda (src-dir) (shell-command "make tags")))
  :config
  (nmap
    "C-]" 'counsel-etags-find-tag-at-point)
  :init
  (add-hook 'prog-mode-hook
    (lambda ()
      (add-hook 'after-save-hook
        'counsel-etags-virtual-update-tags 'append 'local)))
  :config
  ;; (with-eval-after-load 'counsel-etags
  ;;   (push "TAGS" counsel-etags-ignore-filenames)
  ;;   (push "build" counsel-etags-ignore-directories))
  (setq counsel-etags-update-interval 60))

Counsel ffdata

Access your Firefox bookmarks and history in Emacs.

(use-package counsel-ffdata
 :after (general)
 :config
 (nmap
  :prefix my/leader
  "1" 'counsel-ffdata-firefox-history
  "2" 'counsel-ffdata-firefox-bookmarks))

Swiper

(use-package swiper
  :after general
  :init
  ;; Recenter after swiper is finished
  (setq swiper-action-recenter t)
  :config
  (general-define-key
   :keymaps 'swiper-map
   "C-r" 'swiper-query-replace)
  (general-define-key
   :keymaps 'ivy-mode-map
   "C-k" 'ivy-previous-line)
  (nmap
    "C-s" 'swiper))

Dumb jump

(use-package dumb-jump
 :custom
 (dumb-jump-selector 'ivy)
 (dumb-jump-prefer-searcher 'ag)
 (nmap
   "C-c C-j" 'dumb-jump-go))

Avy

(use-package avy
 :defer 1
 :config
 (mmap
   :prefix "C-c j"
   "c" 'avy-goto-char
   "w" 'avy-goto-word-1
   "l" 'avy-goto-line))

Avy zap

(use-package avy-zap
 :bind
 ([remap zap-to-char] . avy-zap-to-char))

Avy flycheck

(use-package avy-flycheck
 :after (general avy flycheck)
 :commands
 avy-flycheck-setup
 :init
 (setq avy-flycheck-style 'pre)
 :config
 (avy-flycheck-setup)
 (nmap
   :prefix my/leader
   "n e" 'avy-flycheck-goto-error))

Tmux integration

Seamlessly navigate between Emacs and Tmux splits. See the package repo for more info.

(use-package navigate
 :quelpa
 (navigate :fetcher github :repo "keith/evil-tmux-navigator")
 :config
 (require 'navigate))

Projectile

Setup

(use-package projectile
 :after (general ivy)
 :commands
 projectile-mode
 :init
 ;; projectile requires this setting for ivy completion
 (setq
  projectile-indexing-method 'alien
  projectile-completion-system 'ivy
  ;; useful for very large projects
  projectile-enable-caching t
  projectile-sort-order 'recently-active
  projectile-mode-line nil
  projectile-use-git-grep t
  projectile-file-exists-remote-cache-expire (* 10 60)
  projectile-file-exists-local-cache-expire (* 5 60)
  projectile-require-project-root nil
  projectile-globally-ignored-directories
  '(".git" ".svn" ".hg" "_darcs"
    "out" "output" "repl"
    "dist" "dist-newstyle"
    ".vagrant"
    "project" "target" "compiled" ".bundle"
    "*build" "jar"
    "venv" ".virtualenv"
    "*__pycache__*" "*.egg-info"
    ".tox" ".cache" ".cabal-sandbox" ".stack-work"
    ".emacs.d" "elpa" "site-lisp"
    "bin" "eclipse-bin" ".ensime_cache" ".idea"
    ".eunit" ".bzr"
    "vendor" "uploads" "assets"
    "node_modules" "bower_components"
    "_build" ".psci_modules" ".pulp-cache")
  projectile-globally-ignored-files
  '(".DS_Store" "TAGS" ".nrepl-port" "*.gz" "*.pyc" ".purs-repl"
    "*.jar" "*.tar.gz" "*.tgz" "*.zip" "package-lock.json"))
 :config
 ;; use projectile everywhere
 (projectile-mode)
 ;; remove the mode name for projectile-mode, but show the project name
 ;; :delight '(:eval (concat " " (projectile-project-name)))
 (nmap
   :prefix my/leader
   "!" 'projectile-run-async-shell-command-in-root
   "DEL" 'projectile-invalidate-cache)
 (nmap
   "C-SPC SPC" 'projectile-commander)
 :diminish projectile-mode)

Counsel

Projectile replacements.

(use-package counsel-projectile
 :after (counsel projectile general)
 :config
 (nmap
   "C-q" 'counsel-projectile-find-file
   "C-a" 'counsel-projectile-switch-to-buffer
   "C-p" 'counsel-projectile-switch-project))

Git

With editor

Makes it easy to use the Emacsclient as the $EDITOR of child processes, making sure they know how to call home. For remote processes a substitute is provided, which communicates with Emacs on standard output instead of using a socket as the Emacsclient does.

(use-package with-editor
 :config
 (nmap 'with-editor-mode-map
   ;; it closes the Magit's git-commit window
   ;; instead of switching to evil-normal-state
   ;; [escape] 'with-editor-cancel
   "RET" 'with-editor-finish)
 (evil-set-initial-state 'with-editor-mode 'insert))

Git messenger

Popup commit message for current line.

(use-package git-messenger
  :config
  (nmap
    :prefix my/leader
    "g M" 'git-messenger:popup-message))

Magit

(use-package magit
  :demand t
  :custom
  (magit-log-buffer-file-locked t)
  (magit-refs-show-commit-count 'all)
  (magit-save-repository-buffers 'dontask)
  (git-messenger:use-magit-popup t)
  :config
  ;; Unset pager as it is not supported properly inside emacs.
  (setenv "GIT_PAGER" ""))

Evil-Magit

(use-package evil-magit
  :after (evil magit fullframe)
  :init
  (setq evil-magit-state 'normal)
  :config
  ;; (fullframe magit-log-all quit-window)
  ;; (fullframe magit-log-current quit-window)
  ;; When commiting, start in evil-insert state
  (with-eval-after-load 'evil
    (add-hook 'git-commit-mode-hook 'evil-insert-state)
    (evil-set-initial-state 'magit-log-edit-mode 'insert))
  (nmap
    :prefix my/leader
    "g w" 'magit-stage-file      ; "w" - write
    "g r" 'magit-unstage-file    ; "r" - remove
    "g R" 'magit-reset-soft      ; "R" - soft reset
    "g s" 'magit-status          ; "s" - status
    "g d" 'magit-diff-range      ; "d" - diff
    "g m" 'magit-merge-plain     ; "m" - merge
    "g b" 'magit-branch-checkout ; "b" - branch
    "g B" 'magit-branch-create   ; "B" - create a new branch
    "g g" 'magit-blame-addition  ; "g" - blame (for a quick access)
    "g c" 'magit-commit-create   ; "c" - commit
    "g z" 'magit-rebase-branch   ; "z" - rebase
    "g l" 'magit-log-all         ; "l" - log
    "g p" 'magit-push-other      ; "p" - push
    "g P" 'magit-pull)           ; "P" - pull
  (when (eq system-type 'darwin)
    (general-define-key
     "s-g 'magit-status")))

Magit todos (disabled)

Might be slow.

(use-package magit-todos
 :after (magit general)
 :commands
 (magit-todos-mode)
 :config
 (magit-todos-mode)
 (nmap
   :prefix my/leader
   "/" 'magit-todos-list))

Forge

(use-package forge)

Git gutter

(use-package git-gutter
 :after (general)
 :demand t
 :commands
 (global-git-gutter-mode)
 :config
 (global-git-gutter-mode)
 ;; (git-gutter:linum-setup)
 (custom-set-variables
  '(git-gutter:update-interval 2)
  '(git-gutter:modified-sign "*")
  '(git-gutter:added-sign "+")
  '(git-gutter:deleted-sign "-")
  '(git-gutter:hide-gutter nil))
 (set-face-foreground 'git-gutter:modified "#da8548")
 (set-face-foreground 'git-gutter:added "#98be65")
 (set-face-foreground 'git-gutter:deleted "#ff6c6b")
 (nmap
   :prefix my/leader
   "t g" 'git-gutter-mode)
 :diminish git-gutter-mode)

Time machine

(use-package git-timemachine)

Syntactic modes

(use-package gitattributes-mode)

(use-package gitignore-mode
  :mode
  ("/\\.dockerignore$" . gitignore-mode))

(use-package gitconfig-mode)

Magithub (disabled)

Might be slow for big projects.

(use-package magithub
 :ensure t
 :after magit
 :custom
 (magithub-clone-default-directory "~/projects/github/unsorted")
 :config
 (magithub-feature-autoinject t)
 (nmap 'magit-prefix-map
   "h b" 'magithub-browse
   "h c" 'magithub-clone
   "h C" 'magithub-create
   "h f" 'magithub-fork))

Gist

(use-package gist
 :after general
 :config
 (nmap
   :prefix my/leader
   "G l" 'gist-list
   "G b" 'gist-buffer
   "G B" 'gist-buffer-private
   "G r" 'gist-region
   "G R" 'gist-region-private))

Shell

Pager

Make less work inside Emacs shells. But disable it as the default pager.

(setenv "LESS" "--dumb --prompt=s")
(setenv "PAGER" "")

Eshell

(use-package eshell
  :ensure nil
  ;; :config
  ;; (unbind-key "C-j" eshell-mode-map)
  ;; (unbind-key "C-k" eshell-mode-map)
)

EM-smart

(use-package em-smart
 :ensure nil
 :config
 (eshell-smart-initialize)
 :custom
 (eshell-where-to-jump 'begin)
 (eshell-review-quick-commands nil)
 (eshell-smart-space-goes-to-end t))

Esh help

(use-package esh-help
 :defer t
 :commands
 (setup-esh-help-eldoc)
 :config
 (setup-esh-help-eldoc))

Esh autosuggest

(use-package esh-autosuggest
 :hook (eshell-mode . esh-autosuggest-mode))
(use-package eshell-prompt-extras
 :after esh-opt
 :commands
 (epe-theme-dakrone)
 :custom
 (eshell-prompt-function #'epe-theme-dakrone))

Fringe status

Command execution status indicator in the fringe.

(use-package eshell-fringe-status
  :hook
  (eshell-mode . eshell-fringe-status-mode))

EShell toggle

(use-package eshell-toggle
 :after (general)
 :custom
 (eshell-toggle-use-projectile-root t)
 (eshell-toggle-run-command nil)
 :config
 (nmap
   :prefix my/leader
   "`" 'eshell-toggle))

Undo

Propose

(use-package undo-propose
 :after general
 :config
 (nmap
   :prefix my/leader
   "u" 'undo-propose)
 (nmap 'undo-propose-mode-map
   :prefix my/leader
   "d" 'undo-propose-diff)
 (nmap 'undo-propose-mode-map
   "RET" 'undo-propose-finish
   [escape] 'undo-propose-cancel))

Tree

(use-package undo-tree
 :after general
 ;; :quelpa
 ;; (undo-tree :url "https://www.lawlist.com/lisp/undo-tree.el" :fetcher url)
 :commands
 (global-undo-tree-mode)
 :init
 (setq
  undo-tree-visualizer-timestamps t
  undo-tree-enable-undo-in-region nil
  ;; Attempt to fix the "unrecognized entry in undo list" error
  undo-tree-auto-save-history t
  undo-tree-history-directory-alist
  `((".*" . ,(expand-file-name "undo" user-emacs-directory))))
 ;; Diff is slow as hell and it doesn't destroy the diff buffer automatically.
 ;; I'd recommend turning it on/off manually when needed.
 ;; (setq undo-tree-visualizer-diff t)
 :config
 (global-undo-tree-mode)
 (general-define-key
  :states 'motion
  :keymaps
  '(undo-tree-visualizer-mode-map
    undo-tree-visualizer-selection-mode-map)
  "k" 'undo-tree-visualize-undo
  "j" 'undo-tree-visualize-redo
  "l" 'undo-tree-visualize-switch-branch-right
  "h" 'undo-tree-visualize-switch-branch-left
  "t" 'undo-tree-visualizer-toggle-timestamps
  "K" 'undo-tree-visualize-undo-to-x
  "J" 'undo-tree-visualize-redo-to-x
  [escape] 'undo-tree-visualizer-abort
  "RET" 'undo-tree-visualizer-quit)
 (nmap
   :prefix my/leader
   "u" 'undo-tree-visualize)
 :diminish undo-tree-mode)

SSH

Config mode

Emacs mode for editing ssh config files.

It does the following:

  • Fontify’s the SSH config keywords.
  • Keys for skipping from host section to host section.
  • Provides indentation.

See the package repo for details.

(use-package ssh-config-mode
 :mode
 (("/\\.ssh/config\\'" . ssh-config-mode)
  ("/sshd?_config\\'" . ssh-config-mode)
  ("/known_hosts\\'" . ssh-known-hosts-mode)
  ("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
 :hook
 (ssh-config-mode . turn-on-font-lock))

Tramp

Setup tramp.

(use-package tramp
 :ensure nil
 :custom
 ;; faster than scp
 (tramp-default-method "ssh")
 ;; disable autosave for tramp buffers
 (tramp-auto-save-directory "/tmp")
 (tramp-default-proxies-alist nil))

Counsel-tramp

Navigate tramp files.

(use-package counsel-tramp
 :after (counsel tramp general)
 :config
 (nmap
   "C-x t" 'counsel-tramp
   "C-x T" 'counsel-tramp-quit))

Docker-tramp

(use-package docker-tramp
  :after tramp)

Vagrant-tramp

(use-package vagrant-tramp
  :after tramp)

Kubernetes-tramp

(use-package kubernetes-tramp
  :after tramp)

Smartparens

Main

(use-package smartparens
 :commands
 (smartparens-mode
  sp-with-modes
  sp-local-pair
  sp-pair)
 :hook
 ((conf-mode text-mode prog-mode) . smartparens-mode)
 :config
 (use-package smartparens-config
  :ensure nil
  :demand t)
 (sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)
 (general-define-key
  :keymaps 'sp-keymap
  "M-F" 'sp-forward-symbol
  "M-B" 'sp-backward-symbol
  "C-M-k" 'sp-kill-sexp
  "C-M-w" 'sp-copy-sexp
  "C-M-t" 'sp-transpose-sexp
  "M-<left>" 'sp-forward-slurp-sexp
  "C-M-<left>" 'sp-forward-barf-sexp
  "M-<right>" 'sp-backward-slurp-sexp
  "C-M-<right>" 'sp-backward-barf-sexp
  "M-D" 'sp-splice-sexp
  "C-M-[" 'sp-select-previous-thing
  "C-M-]" 'sp-select-next-thing
  "C-c s u" 'sp-up-sexp
  "C-c s d" 'sp-down-sexp
  "C-c s t" 'sp-prefix-tag-object
  "C-c s p" 'sp-prefix-pair-object
  "C-c s c" 'sp-convolute-sexp
  "C-c s a" 'sp-absorb-sexp
  "C-c s e" 'sp-emit-sexp
  "C-c s p" 'sp-add-to-previous-sexp
  "C-c s n" 'sp-add-to-next-sexp
  "C-c s j" 'sp-join-sexp
  "C-c s s" 'sp-split-sexp
  "C-c s (" 'sp-wrap-round
  "C-c s [" 'sp-wrap-square
  "C-c s {" 'sp-wrap-curly)
 :diminish smartparens-mode)

Evil

(use-package evil-smartparens
 :config
 (add-hook 'smartparens-enabled-hook #'evil-smartparens-mode))

Snippets

Yasnippet

(use-package yasnippet
  :preface
  (defvar my/yasnippet/snippets
    (my/emacs-path "yasnippet-snippets/snippets"))
  :load-path
  (lambda () (my/emacs-path "yasnippet-snippets"))
  :ensure nil
  :defer 1
  :init
  (setq
   yas-wrap-around-region t
   yas-indent-line t
   yas-snippet-dirs `(,my/yasnippet/snippets))
  :config
  (yas-global-mode 1)
  (nmap
    :prefix my/leader
    "y i" 'yas-insert-snippet
    "y n" 'yas-new-snippet
    "y v" 'yas-visit-snippet-file
    "y r" 'yas-reload-all)
  (imap
    "C-l" 'yas-insert-snippet)
  :diminish yas-minor-mode)
(use-package ivy-yasnippet
 :config
 (imap
   "C-s" 'ivy-yasnippet))
(use-package auto-yasnippet
 :after (general yasnippet)
 :config
 (nmap
   :prefix my/leader
   "y c" 'aya-create
   "y e" 'aya-expand
   "y o" 'aya-open-line))

Yatemplate

Simple file templates for Emacs with YASnippet.

(use-package yatemplate
  :init
  (yatemplate-fill-alist))

Org

Main

(use-package org
  :after (general counsel)
  ;; :quelpa
  ;; (org
  ;;  :url
  ;;  "https://code.orgmode.org/bzg/org-mode.git"
  ;;  :fetcher git
  ;;  :files ("lisp/*.el" "contrib/lisp/*.el" "doc/dir" "doc/*.texi")
  ;;  :upgrade nil)
  :mode ("\\.org\\'" . org-mode)
  :commands
  (org-babel-do-load-languages)
  :init

Visually indent sections. This looks better for smaller files. Also, disallow editing invisible areas.

(setq org-startup-indented t)
(setq org-catch-invisible-edits 'error)

This feature came to Org in version 8. It lets you type “normal quotes” in the org buffer, as opposed to “this latex stuff”, and will transform them on export so that your HTML/text output looks nice and your latex export looks nice!

(setq org-export-with-smart-quotes t)

Forces to mark all child tasks as DONE before you can mark the parent as DONE.

(setq org-enforce-todo-dependencies t)

Allows displaying UTF-8 chars like \alpha.

(setq org-pretty-entities t)

Insert an annotation in a task when it is marked as done including a timestamp of when exactly that happened.

(setq org-log-done 'time)

Insert annotations when you change the deadline of a task, which will note the previous deadline date and when it was changed.

(setq org-log-redeadline (quote time))

Same as above, but for the scheduled dates.

(setq org-log-reschedule (quote time))

Hide leading stars.

(setq org-hide-leading-stars t)

Use syntax highlighting in source blocks while editing.

(setq org-src-fontify-natively t)

Noticeable ellipsis. Others:

, , , , , , ,

(setq org-ellipsis "")

Keep org files in Dropbox. And all of those files should be in included agenda.

(setq
 org-directory "~/Dropbox/org"
 org-agenda-files '("~/Dropbox/org/"))

Refile targets should include files and down to 9 levels into them.

(setq
 org-refile-targets
 (quote ((nil :maxlevel . 9)
  (org-agenda-files :maxlevel . 9))))

And inside those code blocks indentation should be correct depending on the source language used and have code highlighting.

(setq org-src-tab-acts-natively t)
(setq org-src-preserve-indentation t)
(setq org-src-fontify-natively t)

State changes for todos and also notes should go into a Logbook drawer:

(setq org-log-into-drawer t)

Open URLs in Firefox.

(setq
 org-file-apps
 (quote
  ((auto-mode . emacs)
   ("\\.mm\\'" . default)
   ("\\.x?html?\\'" . "firefox %s")
   ("\\.pdf\\'" . default))))

Custom capture templates.

(setq
 org-capture-templates
 '(("t" "todo" entry (file "todo.org") "* TODO %^{task name}\n%u\n%a\n")
   ("n" "note" entry (file "notes.org") "* %^{heading} %t %^g\n  %?\n")
   ("j" "journal" entry (file "journal.org") "* %U - %^{heading}\n  %?")))

I keep my links in links.org, export them to HTML and access them via browser. This makes the HTML file automatically on every save.

(defun org-mode-export-links ()
  "Export links document to HTML automatically when 'links.org' is changed"
  (when (equal (buffer-file-name) "~/Dropbox/org/links.org")
    (progn
      (org-html-export-to-html)
      (alert "HTML exported" :severity 'trivial :title "ORG"))))

(add-hook 'after-save-hook 'org-mode-export-links)

Set TODO priorities.

(setq
 org-highest-priority ?A
 org-lowest-priority ?C
 org-default-priority ?B)

Set default task sequence/lifecycle, colors and triggers.

(setq
  org-todo-keywords
  '((sequence "TODO" "IN-PROGRESS" "WAITING" "HOLD" "|" "DONE" "CANCELLED"))
  org-todo-keyword-faces
  '(("TODO" :foreground "magenta2" :weight bold)
    ("IN-PROGRESS" :foreground "dodger blue" :weight bold)
    ("WAITING" :foreground "orange" :weight bold)
    ("DONE" :foreground "forest green" :weight bold)
    ("HOLD" :foreground "magenta" :weight bold)
    ("CANCELLED" :foreground "forest green" :weight bold)
    ("BUG" :foreground "red" :weight bold)
    ("UNTESTED" . "purple"))
  org-todo-state-tags-triggers
  '(("CANCELLED" ("CANCELLED" . t))
    ("WAITING" ("WAITING" . t))
    ("HOLD" ("WAITING") ("HOLD" . t))
    (done ("WAITING") ("HOLD"))
    ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
    ("IN-PROGRESS" ("WAITING") ("CANCELLED") ("HOLD"))
    ("DONE" ("WAITING") ("CANCELLED") ("HOLD"))))

Do not dim blocked tasks.

(setq org-agenda-dim-blocked-tasks nil)

Compact the block agenda view.

(setq org-agenda-compact-blocks t)

Hide DONE items.

(setq
 org-agenda-skip-scheduled-if-done t
 org-agenda-skip-deadline-if-done t)

Set a 30 day span, instead of a week view.

(setq
 org-agenda-start-day "-3d"
 org-agenda-span 30)

Omit empty days in the agenda.

(setq org-agenda-show-all-dates nil)

Disable pre-warnings.

(setq org-deadline-warning-days 0)

Hide the time grid by default

(setq org-agenda-use-time-grid nil)

Make the agenda schedule prettier.

(setq
 org-agenda-prefix-format
 '((agenda . " %i %-12t% s %b\n")
   (timeline . "  % s")
   (todo . " %i %-12:c")
   (tags . " %i %-12:c")
   (search . " %i %-12:c")))

Next comes the :config section.

:config
(require 'org)

Makes inline latex previews bigger.

(setq
 org-format-latex-options
 (plist-put org-format-latex-options :scale 1.7))

Keybindings.

Fix moving between windows.

(nmap 'org-mode-map
 "C-k" 'windmove-up
 "C-j" 'windmove-down)

Other useful keybindings.

(nmap
  :prefix my/leader
  "t L" 'org-toggle-link-display
  "o" 'org-todo-list
  "O" 'counsel-org-goto-all
  "c" 'counsel-org-capture
  "k" 'org-narrow-to-subtree)
(mmap 'org-agenda-mode-map
  "C-c C-l" 'org-agenda-log-mode)
:delight "org")

Evil

Supplemental evil-mode keybindings to emacs org-mode. See the repo for keybindings cheatsheet.

(use-package evil-org
 :after (general org)
 :commands
 (evil-org-set-key-theme evil-org-agenda-set-keys)
 :preface
 (defun my/evil-org/setup ()
   (evil-org-set-key-theme)
   (evil-org-agenda-set-keys))
 :hook
 ((org-mode . evil-org-mode)
  (evil-org-mode . my/evil-org/setup))
 :init
 (setq
  evil-org-key-theme
  '(textobjects
    insert
    navigation
    additional
    shift
    todo
    heading))
 :config
 (require 'evil-org-agenda)
 :diminish evil-org-mode)

Bullets

Prettify headings and plain lists in Org mode. This package is a direct descendant of org-bullets, with most of the code base completely rewritten.

(use-package org-superstar
 :after (org)
 :hook
 (org-mode . org-superstar-mode))

I use org-superstart instead, so it is currently disabled.

(use-package org-bullets
 :after org
 :hook
 (org-mode . org-bullets-mode))

Cliplink

Paste links from clipboard and automatically fetch title.

(use-package org-cliplink
  :config
  (nmap 'org-mode-map
    :prefix my/leader
    "L" 'org-cliplink))

Pandoc exporter

(use-package ox-pandoc
 :defer 2)

Blogging with hugo

Install ox-hugo and enable auto export.

(use-package ox-hugo
  :after (ox org-capture)
  :defer 1
  :commands (org-hugo-slug)
  :custom
  (org-hugo-delete-trailing-ws nil)
  :config
  ;; (require 'ox-hugo)
  ;; Define variable to get rid of 'reference to free variable' warnings.
  (defun my/org-hugo/new-subtree-post ()
    "Returns `org-capture' template string for new blog post.
See `org-capture-templates' for more information."
    (let*
        ;; Prompt to enter the post title
        ((title (read-from-minibuffer "Post Title: "))
         (lang (read-from-minibuffer "Lang code (e.g. ru-ru): "))
         (date (format-time-string (org-time-stamp-format :long :inactive) (org-current-time)))
         (fname (concat (org-hugo-slug title) "." lang)))
      (mapconcat
       #'identity
       `(
         ,(concat "* TODO " title)
         ":PROPERTIES:"
         ,(concat ":EXPORT_FILE_NAME: " fname)
         ,(concat ":EXPORT_DATE: " date) ;Enter current date and time
         ":END:"
         "%?\n") ; Place the cursor here finally
       "\n")))
  ;; org-capture template to quickly create posts and generate slugs.
  (add-to-list
   'org-capture-templates
   '("b"
     "blog post"
     entry
     (file "~/projects/personal/blog/content-org/posts.org")
     (function my/org-hugo/new-subtree-post))))

Slim HTML export (disabled)

slimhtml is an emacs org mode export backend. It is a set of transcoders for common org elements which outputs minimal HTML.

(use-package htmlize
 :defer 2)
(use-package ox-slimhtml
 :defer 2)

(defun org-html-export-as-slimhtml
(&optional async subtreep visible-only body-only ext-plist)
  (interactive)
  (org-export-to-buffer 'slimhtml "*slimhtml*"
    async subtreep visible-only body-only ext-plist (lambda () (html-mode))))

(eval-after-load 'org
  `(define-key org-mode-map
     (kbd "s-O")
     (lambda ()
       (interactive)
       (org-html-export-as-slimhtml nil nil nil t)
       (with-no-warnings (mark-whole-buffer))
       ;; TODO: I don't use simpleclip, so need to update this
       ;; (simplecmlip-copy (point-min) (point-max))
       (delete-window))))

Org Download

Drag and drop images to org files.

(use-package org-download
  :defer 2
  :config
  ;; Org-download creates links, but I need to change the path
  ;; for my blog. This simple hook runs on every save.
  (defun org-mode-blog-fix-org-downloaded-image-paths ()
    (when (equal (buffer-file-name) "~/projects/personal/blog/content-org/blog.org")
      (progn
        (while (re-search-forward "file:../static" nil t)
          (replace-match "file:"))
        (while (re-search-backward "file:../static" nil t)
          (replace-match "file:")))))

  (add-hook 'after-save-hook 'org-mode-blog-fix-org-downloaded-image-paths)
  :hook
  (dired-mode-hook . org-download-enable))

LSP

Mode

Setup lsp-mode.

(use-package lsp-mode
  :after (general projectile)
  :commands (lsp)
  :init
  ;; Uncomment to inspect communication between client and the server
  (setq lsp-print-io t)
  (setq lsp-prefer-flymake nil)
  :config
  (dolist (dir '("vendor")) (push dir lsp-file-watch-ignored))
  (nmap
    :prefix my/leader
    "l r" 'lsp-restart-workspace)
  :delight "lsp")

LSP UI

(use-package lsp-ui
  :after (lsp-mode)
  :commands (lsp-ui-mode general)
  :config
  (add-hook 'lsp-mode-hook 'lsp-ui-mode)
  (add-hook 'lsp-after-open-hook 'lsp-enable-imenu)
  (add-hook 'lsp-ui-doc-frame-hook
    (lambda (frame _w)
      (set-face-attribute 'default frame :font "Hack" :height 100)))
  (setq
   lsp-ui-sideline-enable t
   lsp-ui-sideline-delay 0.5
   ;; Show hover messages in sideline
   lsp-ui-show-hover t
   ;; Show code actions in sideline
   lsp-ui-show-code-actions t
   lsp-enable-completion-at-point t
   lsp-ui-doc-position 'at-point
   lsp-ui-doc-header nil
   lsp-ui-doc-enable nil
   lsp-ui-doc-delay 0.25
   lsp-ui-doc-use-webkit nil
   lsp-ui-doc-include-signature t
   lsp-ui-doc-border "#222"
   lsp-ui-peek-fontify nil
   lsp-ui-peek-expand-function (lambda (xs) (mapcar #'car xs)))
  (nmap 'lsp-ui-mode-map
    :prefix my/leader
    "=" 'lsp-ui-sideline-apply-code-actions)
  (nmap 'haskell-mode-map
    :prefix my/leader
    "i" 'lsp-ui-doc-focus-frame
    "I" 'lsp-ui-imenu
    "t d" 'lsp-ui-doc-mode
    "t s" 'lsp-ui-sideline-mode)
  (general-def 'lsp-ui-peek-mode-map
    "h" 'lsp-ui-peek--select-next-file
    "l" 'lsp-ui-peek--select-prev-file
    "j" 'lsp-ui-peek--select-next
    "k" 'lsp-ui-peek--select-prev))

Company LSP

(use-package company-lsp
 :after (lsp-mode company)
 ;; :quelpa
 ;; (company-lsp :fetcher github :repo "tigersoldier/company-lsp")
 :commands (company-lsp)
 :init
 (setq
  ;; Don't filter results on the client side
  company-transformers nil
  company-lsp-cache-candidates 'auto
  ;; Fetch completion candidates asynchronously.
  company-lsp-async t
  ;; Enable snippet expansion on completion
  company-lsp-enable-snippet t)
 :config
 (push 'company-lsp company-backends))

Treemacs

(use-package lsp-treemacs
 :after (general)
 :commands lsp-treemacs-errors-list
 :config
 (nmap
   :prefix my/leader
   "e t" 'lsp-treemacs-errors-list))

Makefile

(use-package makefile-executor
  :config
  (add-hook 'makefile-mode-hook 'makefile-executor-mode))

Ivy

Provides an interactive ivy interface to the workspace symbol functionality offered by lsp-mode.

(use-package lsp-ivy)

Languages

Lisp

(use-package lisp-mode
  :ensure nil
  :config
  (put 'use-package 'lisp-indent-function 1)
  (put 'add-hook 'lisp-indent-function 1)
  (put :map 'lisp-indent-function 1))

Emacs Lisp

Mode

(use-package elisp-mode
  :after (general company smartparens)
  :ensure nil
  :preface
  (defun my/emacs-lisp-prettify-symbols-setup ()
    "Prettify `emacs-lisp-mode' specific symbols."
    (dolist (symbol '(("defun"    . )
                      ("defmacro" . )
                      ("defvar"   . )
                      ("defconst" . "ν_")))
      (cl-pushnew symbol prettify-symbols-alist :test #'equal)))
  :config
  (nmap 'emacs-lisp-mode-map
    "M-." 'find-function-at-point
    "M-," 'find-variable-at-point)
  (add-to-list 'company-backends 'company-elisp)
  (sp-with-modes 'emacs-lisp-mode
    (sp-local-pair "'" nil :actions nil))
  :hook
  (emacs-lisp-mode . my/emacs-lisp-prettify-symbols-setup))

Refs

(use-package elisp-refs
  :after elisp-mode)

Macrostep

(use-package macrostep
 :after elisp-mode
 :demand t
 :commands macrostep-expand
 :mode ("\\*.el\\'" . emacs-lisp-mode)
 :config
 ;; support Macrostep in Evil mode
 (general-define-key
  :keymaps 'macrostep-keymap
  "q" 'macrostep-collapse-all
  "e" 'macrostep-expand)
 (nmap
   :keymaps 'emacs-lisp-mode-map
   :prefix my/leader
   "m e" 'macrostep-expand))

Highlight

(use-package highlight-defined
 :custom
 (highlight-defined-face-use-itself t)
 :hook
 (emacs-lisp-mode . highlight-defined-mode))
(use-package highlight-quoted
 :hook
 (emacs-lisp-mode . highlight-quoted-mode))
(use-package highlight-sexp
  :quelpa
  (highlight-sexp :repo "daimrod/highlight-sexp" :fetcher github :version original)
  :hook
  (emacs-lisp-mode . highlight-sexp-mode)
  (lisp-mode . highlight-sexp-mode))

Prism package disperses lisp forms (and other languages) into a spectrum of color by depth.

I’ve disabled it for now because of error:

is Error (use-package): prism/:catch: Wrong number of arguments: (3 . 3), 0

(use-package anaphora)
(use-package prism
  :after (anaphora)
  :quelpa (prism :fetcher github :repo "alphapapa/prism.el"))

Evaluation Result OverlayS for Emacs Lisp.

(use-package eros
 :hook
 (emacs-lisp-mode . eros-mode))
(use-package ipretty
  :defer t
  :commands
  (ipretty-mode)
  :config
  (ipretty-mode 1))

Hide package namespace in your emacs-lisp code. For example, it changes whatever-mode to :mode.

(use-package nameless
 :hook
 (emacs-lisp-mode . nameless-mode)
 :custom
 (nameless-global-aliases '())
 (nameless-private-prefix t)
 :config
 (nmap 'emacs-lisp-mode-map
   :prefix my/leader
   "t n" 'nameless-mode))

Improve readability of escape characters in regular expressions.

(use-package easy-escape
  :diminish easy-escape-minor-mode
  :hook
  (emacs-lisp-mode . easy-escape-minor-mode))

Package lint

A linting library for elisp package metadata.

(use-package package-lint)

Flycheck checker for elisp package metadata.

(use-package flycheck-package
 :defer t
 :after flycheck
 (flycheck-package-setup))

Suggest

Discover functions.

(use-package suggest
  :preface
  (defun my/suggest-popup ()
    "Open suggest as a popup."
    (interactive)
    (let* ((window (selected-window))
           (dedicated-flag (window-dedicated-p window)))
      (set-window-dedicated-p window t)
      (suggest)
      (set-window-dedicated-p window dedicated-flag)))
  :config
  (nmap 'emacs-lisp-mode-map
    :prefix my/leader
    "E s" 'my/suggest-popup))

Haskell

Hasklig (ligatures)

(use-package hasklig-mode
  :commands
  (hasklig-mode)
  :delight "hl")

Mode

(use-package haskell-mode
  :after
  (general company eldoc)
  ;; :quelpa
  ;; (haskell-mode :fetcher github :repo "haskell/haskell-mode")
  :mode
  (("\\.hs\\(-boot\\)?\\'" . haskell-mode)
   ("\\.hcr\\'" . haskell-core-mode)
   ("\\.lhs\\'" . literate-haskell-mode)
   ("\\.cabal\\'" . haskell-cabal-mode)
   ("\\.x\\'" . prog-mode))
  :commands
  (haskell-compile-cabal-build-command
   haskell-interactive-mode-map)
  :preface
  (defun my/display-ctrl-D-as-space ()
    "Display `^D' as newline."
    (interactive)
    (setq buffer-display-table (make-display-table))
    (aset buffer-display-table ?\^D [?\ ]))
  (defun my/haskell-mode/setup ()
    (interactive)
    (setq buffer-face-mode-face '(:family "Hasklig"))
    (buffer-face-mode)
    ;; Treat symbol (e.g. "_") as a word
    (defalias 'forward-evil-word 'forward-evil-symbol)
    ;; (subword-mode 1)
    ;; (eldoc-overlay-mode)       ; annoying
    ;; (haskell-indentation-mode) ; hi2 FTW
    ;; Affects/breaks haskell-indentation-mode
    ;; (setq-local evil-auto-indent nil)
    (with-current-buffer (get-buffer-create "*haskell-process-log*")
      (my/display-ctrl-D-as-space))
    (hasklig-mode)
    (haskell-doc-mode)
    (haskell-collapse-mode)
    (haskell-decl-scan-mode)
    (electric-layout-mode)
    (electric-pair-local-mode)
    (electric-indent-local-mode)
    ;; There are some tools that dont't work with unicode symbols
    ;; I use Hasklig instead
    ;; (turn-on-haskell-unicode-input-method)
    (face-remap-add-relative 'font-lock-doc-face 'font-lock-comment-face))
  (defvar my/haskell-process-use-ghci nil)
  (defvar my/haskell-build-command-use-make nil)
  (defun my/haskell-mode/toggle-build-command ()
    "Toggle the build command"
    (interactive)
    (if my/haskell-build-command-use-make
        (progn
          (setq haskell-compile-cabal-build-command "cd %s && cabal new-build")
          (alert "Setting build command to:\n cabal new-build" :severity 'normal :title "Haskell"))
      (progn
        (setq haskell-compile-cabal-build-command "cd %s && make build")
        (alert "Setting build command to:\n make build" :severity 'normal :title "Haskell"))))
  (defun my/haskell-mode/toggle-process-type ()
    "Toggle GHCi process between cabal and ghci"
    (interactive)
    (if my/haskell-process-use-ghci
        (progn
          ;; You could set it to "cabal-repl" if
          ;; you're using the old cabal workflow
          (setq haskell-process-type 'cabal-new-repl)
          (setq my/haskell-process-use-ghci nil)
          (alert "Using cabal new-repl" :severity 'normal :title "Haskell"))
      (progn
        (setq haskell-process-type 'stack-ghci)
        (setq my/haskell-process-use-ghci t)
        (alert "Using stack ghci" :severity 'normal :title "Haskell"))))
  (defun my/haskell-mode/show-process-log ()
    "Display *haskell-process-log* buffer in other window"
    (interactive)
    (switch-to-buffer-other-window "*haskell-process-log*"))
  :hook
  (haskell-mode . my/haskell-mode/setup)
  :custom
  ;; Enable debug logging to *haskell-process-log* buffer
  (haskell-process-log t)
  ;; Don't generate tags via hasktags after saving
  (haskell-tags-on-save nil)
  ;; Don't run stylish-haskell on the buffer before saving.
  ;; It just inserts a bunch of spaces at the end of the line for no reason
  (haskell-stylish-on-save nil)
  ;; Suggest to add import statements using Hoogle as a backend
  (haskell-process-suggest-hoogle-imports t)
  ;; Suggest to add import statements using Hayoo as a backend
  (haskell-process-suggest-hayoo-imports t)
  ;; Replace SVG image text with actual images
  (haskell-svg-render-images t)
  ;; Don't eliminate the context part in a Haskell type
  (haskell-doc-chop-off-context nil)
  ;; Suggest removing import lines as warned by GHC
  (haskell-process-suggest-haskell-docs-imports t)
  ;; Search for the types of global functions by loading the files
  (haskell-doc-show-global-types t)
  ;; Don't show debugging tips when starting the process
  (haskell-process-show-debug-tips nil)
  ;; Don’t suggest removing import lines as warned by GHC
  ;; It is too annoying, sometimes I want to keep unused imports
  (haskell-process-suggest-remove-import-lines nil)
  ;; Don't suggest adding packages to .cabal file
  (haskell-process-suggest-add-package nil)
  ;; Don't suggest restarting the f*****g process
  (haskell-process-suggest-restart nil)
  ;; Don't suggest adding the OverloadedStrings extensions
  (haskell-process-suggest-overloaded-strings nil)
  ;; Auto import the modules reported by GHC to have been loaded
  (haskell-process-auto-import-loaded-modules t)
  ;; Show things like type info instead of printing to the message area
  ;; haskell-process-use-presentation-mode t
  ;; Don't popup errors in a separate buffer
  (haskell-interactive-popup-errors nil)
  ;; Make haskell-process-log look better
  (haskell-process-args-ghci '("-ferror-spans" "-fhide-source-paths"))
  (haskell-process-args-cabal-repl '("--ghc-options=-ferror-spans -fhide-source-paths"))
  (haskell-process-args-stack-ghci '("--ghci-options=-ferror-spans" "--no-build" "--no-load"))
  (haskell-process-args-cabal-new-repl '("--ghc-options=-ferror-spans -fhide-source-paths"))
  ;; Use "cabal new-repl" as the inferior haskell process
  (haskell-process-type 'cabal-new-repl)
  ;; haskell-process-args-stack-ghci '("--ghci-options=-ferror-spans")
  ;; haskell-compile-cabal-build-command "stack build --no-library-profiling"
  (haskell-compile-cabal-build-command "cd %s && cabal new-build")
  :config
  (add-to-list
   'electric-layout-rules
   '((?\{) (?\} . around)))
  (add-to-list
   'electric-layout-rules
   '((?\[) (?\] . around)))
  ;; Common key bindings
  (nmap '(haskell-mode-map haskell-cabal-mode-map haskell-interactive-mode-map)
    "C-c C-b" 'haskell-compile
    "C-c C-k" 'haskell-interactive-mode-kill
    "C-c C-r" 'haskell-process-restart
    "C-c C-d" 'haskell-cabal-add-dependency
    "C-c C-l" 'haskell-interactive-mode-clear
    "C-c C-h" 'haskell-hoogle
    "C-c SPC" 'haskell-session-change-target
    "C-c C-c" 'my/haskell-mode/show-process-log)
  (nmap '(haskell-mode-map haskell-cabal-mode-map)
    "C-c C-j" 'haskell-interactive-switch)
  (nmap '(haskell-mode-map haskell-interactive-mode-map)
    "C-c c v" 'haskell-cabal-visit-file
    "C-c c b" 'haskell-process-cabal-build
    "C-c c r" 'haskell-process-cabal)
  (nmap 'haskell-compilation-mode-map
    "C-k" 'windmove-up ;; bind it back
    "M-k" 'compilation-previous-error
    "M-j" 'compilation-next-error)
  (nmap 'haskell-mode-map
    "C-c T" 'my/haskell-mode/toggle-process-type
    "C-c b" 'my/haskell-mode/toggle-build-command
    "C-c H" 'haskell-hayoo
    "C-c C-m" 'haskell-auto-insert-module-template
    "C-c ." 'haskell-hide-toggle
    "C-c C-o" 'haskell-process-load-file
    "C-c C-SPC" 'haskell-interactive-copy-to-prompt
    "C-c C-f" 'haskell-mode-stylish-buffer
    "C-c C-t" 'haskell-process-do-type
    "C-c C-i" 'haskell-process-do-info
    ;; Hit it repeatedly to jump between groups of imports
    "C-c C-u" 'haskell-navigate-imports)
  (require 'haskell-interactive-mode)
  (unbind-key "C-j" haskell-interactive-mode-map)
  (nmap 'haskell-interactive-mode-map
    "C-c C-j" 'haskell-interactive-switch-back)
  (imap 'haskell-interactive-mode-map
    "C-c C-l" 'haskell-interactive-mode-clear)
  :delight "hs")

Literate Haskell

Remove the hard-coded literate-haskell-mode activation for .lhs files that haskell-mode comes with. In exchange, enable LaTeX mode whenever we open up a .lhs file. Using mmm-mode, we will activate haskell-mode in the code sections.

(setq
 auto-mode-alist
 (remove
  (rassoc 'literate-haskell-mode auto-mode-alist)
  auto-mode-alist))

(add-to-list 'auto-mode-alist '("\\.lhs$" . latex-mode))

Happy

(use-package happy-mode
  :quelpa (happy-mode :fetcher github :repo "sergv/happy-mode"))

Hi2

(use-package hi2
 :after haskell-mode
 :init
 (setq
  hi2-layout-offset 2
  hi2-left-offset 2
  hi2-where-post-offset 2)
 :config
 (put 'hi2-where-post-offset 'safe-local-variable 'numberp)
 (put 'hi2-left-offset 'safe-local-variable 'numberp)
 (put 'hi2-layout-offset 'safe-local-variable 'numberp)
 (imap
   'hi2-mode-map
   "<tab>" 'hi2-indent-line)
 :diminish hi2-mode)

Hindent (disabled)

Bear in mind that it doesn’t support unicode syntax so all your cool unicode operators will be replaced.

(use-package hindent
 :after (general haskell-mode)
 :hook
 (haskell-mode . hindent-mode)
 :config
 ;; "r " - reformat
 (vmap 'haskell-mode-map
   "C-c r" 'hindent-reformat-region)
 (nmap 'haskell-mode-map
   "C-c r" 'hindent-reformat-buffer
   "C-c R" 'hindent-reformat-decl)
 :diminish hindent-mode)

Ghcid (disabled)

My first attempt to get ghcid working inside Emacs. It works, but I still prefer to run it from inside the terminal.

(use-package ghcid
  :after (haskell-mode)
  :quelpa
  (ghcid :fetcher url :url "https://raw.githubusercontent.com/vyorkin/ghcid/nixos-bash/plugins/emacs/ghcid.el")
  :preface
  (defun my/ghcid/show-buffer ()
    (interactive)
    (show-buffer (ghcid-buffer-name)))
  (defun my/ghcid/set-arget (ghcid-targ &optional ghcid-test-targ)
    (interactive
     (list
      (completing-read
       "ghcid target: "
       (map 'list
            (lambda (targ)
              (format "%s:%s" (projectile-project-name) targ))
            (haskell-cabal-enum-targets)))
      (completing-read
       "ghcid --test target: " '("--test=main" "--test=Main.main" nil))))
    (setq ghcid-target ghcid-targ)
    (ghcid-kill)
    (ghcid))
  :custom
  ;; :config (setq-local default-directory projectile-project-root)
  (ghcid-target "")
  :config
  (nmap 'haskell-mode-map
    :prefix my/leader
    "#" 'ghcid
    "$" 'ghcid-stop
    "@" 'my/ghcid/set-arget
    "%" 'my/ghcid/show-buffer))

Ormolu

(use-package ormolu
  :quelpa
  (ormolu
   :fetcher github
   :repo "vyorkin/ormolu.el")
  :custom
  (ormolu-reformat-buffer-on-save nil)
  :config
  (nmap 'haskell-mode-map
    "C-c r" 'ormolu-format-buffer))

Company-cabal

(use-package company-cabal
 :after haskell-mode
 :config
 (add-to-list 'company-backends 'company-cabal))

Liquid types

Currenly untangled because I don’t always use LH.

(use-package liquid-types
  :after
  (haskell-mode flycheck)
  :config
  (require 'liquid-types)

Configure flycheck-liquidhs.

(add-hook 'haskell-mode-hook
  '(lambda () (flycheck-select-checker 'haskell-liquid)))
(add-hook 'literate-haskell-mode-hook
  '(lambda () (flycheck-select-checker 'haskell-liquid)))

Toggle minor mode on entering Haskell mode. Currently disabled, too.

(add-hook 'haskell-mode-hook
  '(lambda () (liquid-types-mode)))
(add-hook 'literate-haskell-mode-hook
  '(lambda () (liquid-types-mode)))
:delight "lh")

Hasky-stack

(use-package hasky-stack
 :after (general haskell-mode)
 :config
 (nmap 'haskell-mode-map
   :prefix my/leader
   "h s" 'hasky-stack-execute
   "h n" 'hasky-stack-new))

Hasky-extensions

(use-package hasky-extensions
 :after (general haskell-mode)
 :config
 (nmap 'haskell-mode-map
   :prefix my/leader
   "h e" 'hasky-extensions
   "h d" 'hasky-extensions-browse-docs))

LSP

I don’t use it currently. It might be slow when opening files. And it interferes with haskell-mode.

(use-package lsp-haskell
  :preface
  (defun my/lsp-haskell/start ()
    (require 'lsp-mode)
    (require 'lsp-haskell)
    (lsp))
  :init
  (setq lsp-haskell-set-completion-snippets-on t)
  :config
  (setq lsp-haskell-process-path-hie "ghcide")
  (setq lsp-haskell-process-args-hie '())
  ;; Comment/uncomment this line to see interactions between lsp client/server.
  ;;(setq lsp-log-io t)
  :hook (haskell-mode . my/lsp-haskell/start))

Eglot

I use lsp-haskell instead.

(use-package eglot
  :ensure t
  :config
  (add-to-list 'eglot-server-programs '(haskell-mode . ("ghcide" "--lsp"))))

PureScript

Mode

The PureScript mode.

(use-package purescript-mode
 :after (general files)
 :if (executable-find "purs")
 :load-path (lambda () (my/emacs-path "purescript-mode"))
 :ensure nil
 :preface
 (defvar my/purescript/path
  (my/emacs-path "purescript-mode"))
 (defun my/purescript-emmet ()
   (interactive)
   (let ((start (point))
         (end (save-excursion (beginning-of-line-text) (point))))
     (call-process-region start end "purescript-emmet" t t)))
 :config
 (require 'purescript-mode-autoloads)
 (add-to-list 'Info-default-directory-list my/purescript/path)
 (imap 'purescript-mode-map
   "C-c C-e" 'my/purescript-emmet))

A new, simple purescript mode for cheap syntax highlighting.

(use-package purescript-mode
 :quelpa (purescript-mode :fetcher github :repo "justinwoo/new-purescript-mode"))

PSC IDE

(use-package psc-ide
 :after (general purescript-mode)
 :quelpa
 (psc-ide
   :repo "purescript-emacs/psc-ide-emacs"
   :commit "230101a3d56c9e062c3ce2bf9a4dc077e5607cc0"
   :fetcher github)
 :commands (psc-ide-mode)
 :preface
 (defun my/psc-ide/setup ()
   (setq-local evil-auto-indent nil)
   (psc-ide-mode)
   (turn-on-purescript-unicode-input-method)
   (turn-on-purescript-indentation))
 :hook
 (purescript-mode . my/psc-ide/setup)
 :init
 ;; use the psc-ide server that is
 ;; relative to npm bin directory
 (setq psc-ide-use-npm-bin t)
 :config
 (general-define-key
  :states 'normal
  :keymaps 'psc-ide-mode-map
  "C-t" 'psc-ide-goto-definition
  "C-]" 'psc-ide-goto-definition
  "g d" 'psc-ide-goto-definition)
 :delight "psc-ide")

PSCI (disabled)

(use-package psci
 :disabled
 :after (purescript-mode)
 :hook
 (purescript-mode . inferior-psci-mode)
 :delight "psci")

Idris

(use-package idris-mode
 :custom
 (idris-repl-banner-functions '(idris-repl-text-banner))
 (idris-repl-prompt-style 'short))

Agda

(use-package agda2-mode
  :demand t
  :load-path "lisp/agda/src/data/emacs-mode"
  :config
  (nmap 'agda2-mode-map
    "gd" 'agda2-goto-definition-keyboard
    "C-c C-SPC" 'agda2-give))

ATS/ATS2

Mode

ATS2 mode.

(use-package ats-mode
  :load-path "lisp")

Flycheck.

(use-package flycheck-ats2
 :after (ats-mode))

Nix

Mode

An emacs major mode for editing nix expressions.

(use-package nix-mode
  :after (general)
  :mode ("\\.nix\\'" "\\.nix.in\\'")
  :config
  (nmap 'nix-mode-map
    "C-c r" 'nix-format-buffer)
  :delight "nix")

Drv mode

A major mode for viewing Nix derivations (.drv files).

(use-package nix-drv-mode
  :ensure nix-mode
  :mode "\\.drv\\'")

Shell (disabled)

(use-package nix-shell
  :ensure nix-mode
  :commands (nix-shell-unpack nix-shell-configure nix-shell-build))

REPL

(use-package nix-repl
  :ensure nix-mode
  :commands (nix-repl))

Update fetch

Command for updating fetch declarations in place.

(use-package nix-update
  :config
  (nmap 'nix-mode-map
    :prefix my/leader
    "n u" 'nix-update-fetch))

Company

Company backend for NixOS options.

(use-package company-nixos-options
  :after (company)
  :commands (company-nixos-options)
  :config
  (add-to-list 'company-backends 'company-nixos-options))

Sandbox

(use-package nix-sandbox)

Flycheck

TODO: https://github.com/travisbhartwell/nix-emacs#flycheck

Ocaml

Tuareg

Tuareg is an Emacs OCaml mode.

Provides:

  • Syntax highlighting.
  • REPL (aka toplevel).
  • OCaml debugger within Emacs.

Usage:

  • Start the OCaml REPL with M-x run-ocaml.
  • Run the OCaml debugger with M-x ocamldebug FILE.
(use-package tuareg
  :demand t
  :mode
  (("\\.ml[ily]?$" . tuareg-mode)
   ("\\.mly$" . tuareg-menhir)
   ("\\.topml$" . tuareg-mode)
   ("\\.atd$" . tuareg-mode))
  :init
  (setq tuareg-match-patterns-aligned t)
  :hook
  (caml-mode . tuareg-mode)
  :delight "ocaml")

Ocp-index

(defvar my/opam-config/share (string-trim-right (shell-command-to-string "opam config var share")))

;; (with-eval-after-load 'tuareg
;;   (add-to-list 'load-path (concat my/opam-config/share "/emacs/site-lisp"))
;;   (require 'ocp-index))

(use-package ocp-index
  :after (tuareg)
  :load-path (lambda () (concat my/opam-config/share "/emacs/site-lisp")))

Smartparens

(with-eval-after-load 'smartparens
  (sp-local-pair 'tuareg-mode "'" nil :actions nil)
  (sp-local-pair 'tuareg-mode "`" nil :actions nil))

Merlin

Context sensitive completion for OCaml. Provides modern IDE features. Implements a minor-mode that is supposed to be used on top of tuareg-mode.

See the package repo for more info.

(use-package merlin
  :after (company tuareg)
  :demand t
  :init
  ;; Disable merlin's own error checking
  ;; We'll use flycheck-ocaml for that
  (setq
   ;; merlin-command "/run/current-system/sw/bin/ocamlmerlin"
   merlin-error-after-save nil
   merlin-completion-with-doc t)
  :config
  (add-to-list 'company-backends 'merlin-company-backend)
  (nmap 'merlin-mode-map
    "C-t" 'merlin-locate
    "C-]" 'merlin-locate
    "C-[" 'merlin-pop-stack
    "g d" 'merlin-locate)
  (nmap 'merlin-mode-map
    :prefix my/leader
    "3" 'merlin-occurrences
    "4" 'merlin-jump
    "5" 'merlin-document
    "9" 'merlin-locate-ident
    "0" 'merlin-iedit-occurrences)
  :hook
  ((tuareg-mode caml-mode) . merlin-mode))

Merlin eldoc

Automatically (without using keybindings) provide information for the value under point in OCaml and ReasonML files.

(use-package merlin-eldoc
  :after (merlin)
  :custom
  (eldoc-echo-area-use-multiline-p t)   ; Use multiple lines when necessary
  (merlin-eldoc-max-lines 8)            ; But not more than 8
  (merlin-eldoc-type-verbosity 'min)    ; Don't display verbose types
  (merlin-eldoc-function-arguments t)   ; Show function arguments
  (merlin-eldoc-doc nil)                ; Don't show the documentation
  (merlin-eldoc-occurrences t)          ; Highlight occurences
  :config
  (nmap 'merlin-mode-map
    :prefix my/leader
    "m p" 'merlin-eldoc-jump-to-prev-occurrence
    "m n" 'merlin-eldoc-jump-to-next-occurrence)
  :hook
  ((tuareg-mode reason-mode) . merlin-eldoc-setup))

Customizations for merlin-eldoc

(with-eval-after-load 'merlin-eldoc
  (custom-set-faces
   (set-face-background 'merlin-eldoc-occurrences-face "#111")))

Utop

https://github.com/diml/utop#integration-with-emacs

(use-package utop
  :after (tuareg)
  :commands
  (utop-command)
  :config
  (setq utop-command "opam config exec utop -- -emacs")
  (autoload 'utop-minor-mode "utop" "Minor mode for utop" t)
  (nmap 'utop-mode-map
    "C-c C-j" 'utop
    "C-c C-SPC" 'utop-eval-phrase)
  :hook
  ((tuareg-mode reason-mode) . utop-minor-mode))

Formatting

TODO

(require 'ocamlformat)
(add-hook 'tuareg-mode-hook (lambda ()
  (general-define-key
    :states '(normal)
    :keymaps 'tuareg-mode-map
    "C-c r" 'ocamlformat)
  (add-hook 'before-save-hook #'ocamlformat-before-save)))

ocp-indent is disabled, I use ocamlformat instead

(use-package ocp-indent
  :after (tuareg)
  :config
  (nmap 'tuareg-mode-map
    "C-c r" 'ocp-indent-buffer))

Dune

A composable build system for OCaml.

(use-package dune)

Flycheck

OCaml support for Flycheck using Merlin.

(use-package flycheck-ocaml
 :after (flycheck merlin)
 :demand t
 :commands
 (flycheck-ocaml-setup)
 :config
 ;; Enable flycheck checker
 (flycheck-ocaml-setup))

Coq

This configuration relies on the Proof General to be cloned here: ~~/.emacs.d/lisp/PG~. See the Proof General docs for more info.

(use-package proof-general
  :custom
  (proof-delete-empty-windows t)
  ;; (proof-three-window-mode-policy 'smart)
  ;; see: https://github.com/ProofGeneral/PG/issues/404
  (proof-shrink-windows-tofit t)
  :delight "coq")
(use-package coq-mode
  :after (proof-site)
  :ensure nil
  :commands (coq-mode)
  :preface
  (defun my/company-coq/setup ()
    (interactive)
    (setq buffer-face-mode-face '(:family "Fira Code"))
    (setq-local
     prettify-symbols-alist
     '((":=" . ?≜)
       ("Proof." . ?∵)
       ("Qed." . ?■)
       ("Defined." . ?□)
       ("Alpha" . ) ("Beta" . ) ("Gamma" . )
       ("Delta" . ) ("Epsilon" . ) ("Zeta" . )
       ("Eta" . ) ("Theta" . ) ("Iota" . )
       ("Kappa" . ) ("Lambda" . ) ("Mu" . )
       ("Nu" . ) ("Xi" . ) ("Omicron" . )
       ("Pi" . ) ("Rho" . ) ("Sigma" . )
       ("Tau" . ) ("Upsilon" . ) ("Phi" . )
       ("Chi" . ) ("Psi" . ) ("Omega" . )
       ("alpha" . ) ("beta" . ) ("gamma" . )
       ("delta" . ) ("epsilon" . ) ("zeta" . )
       ("eta" . ) ("theta" . ) ("iota" . )
       ("kappa" . ) ("lambda" . ) ("mu" . )
       ("nu" . ) ("xi" . ) ("omicron" . ?ο)
       ("pi" . ) ("rho" . ) ("sigma" . )
       ("tau" . ) ("upsilon" . ) ("phi" . )
       ("chi" . ) ("psi" . ) ("omega" . )))
    (sp-local-pair 'coq-mode "'" nil :actions nil))
  :init
  (setq
   ;; Enable autocompletion for theorem names and
   ;; symbols defined in the libraries we load
   company-coq-live-on-the-edge t
   company-coq-disabled-features '()
  ;; Disable symbol prettification
   company-coq-disabled-features '(prettify-symbols)
   company-coq-dynamic-autocompletion t)
  :config
  (nmap 'coq-mode-map
    "C-C C-t" 'coq-About)
  (nmap 'coq-mode-map
    :prefix my/leader
    "3" 'coq-SearchAbout
    "4" 'coq-Print
    "5" 'coq-LocateNotation
    "6" 'coq-LocateConstant
    "7" 'coq-Inspect
    "8" 'coq-About
    "9" 'coq-Show
    "0" 'coq-Check)
  :hook
  (coq-mode . my/company-coq/setup))

IDE extensions for Proof General’s Coq mode: prettification, autocompletion, snippets, outlines, code folding, jumping to definition, integrated help, etc.

(use-package company-coq
  :after (proof-site coq-mode)
  :commands (company-coq-mode)
  :hook
  (coq-mode . company-coq-mode)
  :config
  (nmap 'coq-mode-map
    "g d" 'company-coq-jump-to-definition))

Lean

Emacs mode for the Lean theorem prover. Keybindings: https://github.com/leanprover/lean-mode#key-bindings-and-commands

(use-package lean-mode)

Minizinc

(use-package minizinc-mode
  :mode
  ("\\.mzn\\'"))

TLA+

(use-package tla-mode
  :quelpa
  (tla-mode :fetcher github :repo "ratish-punnoose/tla-mode")
  :mode "\.tla$")
(use-package polymode)

(use-package tla-pcal-mode
  :after (polymode)
  :quelpa
  (tla-pcal-mode :fetcher github :repo "mrc/tla-tools"))

Reason

(use-package reason-mode
 :quelpa
 (reason-mode :repo "reasonml-editor/reason-mode" :fetcher github :stable t)
 :config
 (add-hook
  'reason-mode-hook
  (lambda ()
    (setq utop-command "opam config exec -- rtop -emacs")
    (add-hook 'before-save-hook 'refmt-before-save)))
    (add-hook 'reason-mode-hook 'merlin-mode)
    (add-hook 'reason-mode-hook 'utop-minor-mode)
    (add-hook 'reason-mode-hook 'flycheck-mode)
    :delight "re")

SML

(use-package sml-mode
 :quelpa (sml-mode :fetcher github :repo "emacsmirror/sml-mode")
 :mode "\\.sml$")

Scheme

(use-package geiser
 :after general)

(use-package scheme
 :ensure nil
 :after (geiser)
 :preface
 (defun my/scheme/setup ()
   (geiser-mode t))
 :hook
 (scheme-mode . my/scheme/setup))

(use-package quack
 :after (scheme)
 :config
 (setq
  ;; use emacs-style fontification
  quack-fontify-style 'emacs))

Racket

(use-package faceup)
(use-package racket-mode
 :after
 (general
  smartparens
  org
  faceup
  geiser)
 :if (executable-find "racket")
 :mode ("\\.rkt[dl]?\\'" . racket-mode)
 :interpreter ("racket" . racket-mode)
 :hook
 (racket-mode . smartparens-mode)
 :init
 (setq
  geiser-scheme-implementation 'racket
  racket-smart-open-bracket-enable t)
 :config
 (add-to-list 'org-babel-load-languages '(racket . t))
 (sp-local-pair 'racket-mode "'" nil :actions nil)
 (sp-local-pair 'racket-mode "`" nil :actions nil))

Clojure

(use-package clojure-mode
 :after (general company org)
 :defer 1
 :commands
 (define-clojure-indent
  put-clojure-indent)
 :mode
 (("\\.clj\\'" . clojure-mode)
  ("\\.edn\\'" . clojure-mode)
  ("\\.boot\\'" . clojure-mode)
  ("\\.cljs.*\\'" . clojure-mode))
 :init
 (setq inferior-lisp-program "lein repl")
 :config
 (add-to-list 'org-babel-load-languages '(clojure . t))
 (nmap 'clojure-mode-map
   :prefix my/leader
   "C s" 'cider-start-http-server
   "C r" 'cider-refresh
   "C u" 'cider-user-ns
   "C R" 'cider-restart)
 (define-clojure-indent (fact 1))
 (define-clojure-indent (facts 1)))
(use-package clojure-mode-extra-font-locking
 :after (clojure-mode)
 :defer 1
 :init
 (font-lock-add-keywords
  nil
  '(("(\\(facts?\\)"
     (1 font-lock-keyword-face))
    ("(\\(background?\\)"
     (1 font-lock-keyword-face)))))
(use-package cider
 :after (clojure-mode)
 :defer 1
 :commands (cider-mode)
 :custom
 (cider-repl-result-prefix ";; => ")
 :init
 (setq
  ;; go right to the REPL buffer when it's finished connecting
  cider-repl-pop-to-buffer-on-connect t
  ;; when there's a cider error, show its buffer and switch to it
  cider-show-error-buffer t
  cider-auto-select-error-buffer t
  cider-repl-history-file "~/.emacs.d/cider-history"
  cider-repl-wrap-history t)
 :hook
 (clojure-mode . clojure-mode))
(use-package kibit-helper
 :defer 1)
(use-package flycheck-clojure
  :after (flycheck clojure-mode)
  :defer 1
  :commands
  (flycheck-clojure-setup)
  :config
  (eval-after-load 'flycheck '(flycheck-clojure-setup)))

Scala

(use-package scala-mode
 :after (general)
 :if (executable-find "scala"))
(use-package ensime
 :after (general scala-mode)
 :commands (ensime-mode)
 :init
 (setq
  ensime-server-version "2.0.0-SNAPSHOT"
  ensime-default-buffer-prefix "ENSIME-"
  ensime-startup-notification nil
  ensime-startup-snapshot-notification nil)
 :config
 (unbind-key "M-p" ensime-mode-map)
 (nmap 'scala-mode-map
   :prefix my/leader
   "s e" 'ensime)
 (nmap 'ensime-mode-map
   :prefix my/leader
   "r" 'ensime-inf-run-scala
   "s r" 'ensime-sbt-do-run
   "s c" 'ensime-sbt-do-compile)
 ;; TODO: looks like a perfect candidate for a Hydra?
 (nmap 'ensime-mode-map
   :prefix my/leader
   "s E" 'ensime-print-errors-at-point
   "s t" 'ensime-print-type-at-point
   "s o" 'ensime-import-type-at-point
   "s g" 'ensime-edit-definition-other-window
   "s ," 'ensime-pop-find-definition-stack
   "s ." 'ensime-edit-definition-of-thing-at-point))
(use-package sbt-mode
 :after (general scala-mode)
 :if (executable-find "sbt")
 :init
 (setq sbt:program-name "sbt -mem 2048 -v")
 (setq-default truncate-lines nil)
 :config
 (nmap 'scala-mode-map
   :prefix my/leader
   "s" 'sbt-start
   "r" 'sbt-command
   "p" 'sbt-run-previous-command)
 (general-define-key
  :keymaps 'sbt-mode-map
  :states '(normal insert)
  "M-j" 'compilation-next-error
  "M-k" 'compilation-previous-error)
 (evil-set-initial-state 'sbt-mode 'normal))

Kotlin

(use-package kotlin-mode)
(use-package flycheck-kotlin
 :after (kotlin-mode flycheck)
 :commands
 (flycheck-kotlin-setup)
 :config
 (flycheck-kotlin-setup))

Rust

(use-package rust-mode
 :after (company general)
 :if (executable-find "rustc")
 :commands (rust-mode)
 :config
 ;; enable rust-mode for .lalrpop files
 (add-to-list 'auto-mode-alist '("\\.lalrpop\\'" . rust-mode))
 (general-define-key
  :keymaps 'rust-mode-map
  "TAB" 'company-indent-or-complete-common
  "C-c C-b" 'rust-compile
  "C-c <tab>" 'rust-format-buffer))

Some of key bindings are provided by ==evil-collection=.

(use-package racer
 :after rust-mode
 :demand t
 :commands racer-mode
 :hook
 ((racer-mode . eldoc-mode)
  (racer-mode . company-mode)
  (rust-mode . racer-mode)))
(use-package cargo
 :after (general rust-mode)
 :config
 (nmap 'rust-mode-map
   :prefix my/leader
   "c ." 'cargo-process-repeat
   "c c" 'cargo-process-clean
   "c b" 'cargo-process-build
   "c c" 'cargo-process-check
   "c d" 'cargo-process-doc
   "c e" 'cargo-process-bench
   "c f" 'cargo-process-current-test
   "c f" 'cargo-process-fmt
   "c i" 'cargo-process-init
   "c n" 'cargo-process-new
   "c o" 'cargo-process-current-file-tests
   "c s" 'cargo-process-search
   "c u" 'cargo-process-update
   "c x" 'cargo-process-run
   "c X" 'cargo-process-run-example
   "t" 'cargo-process-test))
(use-package company-racer
 :after (racer company)
 :config
 (add-to-list 'company-backends 'company-racer))
(use-package flycheck-rust
  :config
  (with-eval-after-load 'rust-mode
    (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)))

Erlang

Elixir

(use-package elixir-mode
 :preface
 (defun my/elixir-mode/setup ()
   (when (and
          (string-equal "exs" (file-name-extension buffer-file-name))
          (string-equal "mix" (file-name-base buffer-file-name)))
     (alchemist-hex-mode 1)))
 :hook
 ((elixir-mode . alchemist-mode)
  (elixir-mode . my/elixir-mode/setup))
 :init
 (use-package alchemist
   :demand t
   :init
   (setq
    alchemist-goto-elixir-source-dir "~/projects/github/elixir"
    alchemist-goto-erlang-source-dir "/usr/local/Cellar/erlang/19.2.3")
   :config
   ;; additional keybindings are here
   ;; https://github.com/emacs-evil/evil-collection/blob/master/evil-collection-alchemist.el
   (evil-define-key 'normal alchemist-mode-map
     (kbd "C-j") nil
     (kbd "C-k") nil
     (kbd "M-j") 'alchemist-goto-jump-to-next-def-symbol
     (kbd "M-k") 'alchemist-goto-jump-to-previous-def-symbol)
   (nmap 'alchemist-mode-map
     :prefix my/leader
     ;; elixir general key bindings
     "tt" 'alchemist-mix-test
     "tf" 'alchemist-project-run-tests-for-current-file
     "," 'alchemist-test-toggle-test-report-display
     "h" 'alchemist-help-search-at-point
     "H" 'alchemist-help
     "a" 'alchemist-project-toggle-file-and-tests
     "A" 'alchemist-project-toggle-file-and-tests-other-window
     "m" 'alchemist-mix
     ;; elixir IEx-specific key bindings
     "e" 'alchemist-iex-project-run
     "r" 'alchemist-iex-reload-module)
   (vmap 'alchemist-mode-map
     :prefix my/leader
     "e" 'alchemist-iex-send-current-line
     "E" 'alchemist-iex-send-current-line-and-go
     "r" 'alchemist-iex-send-region
     "R" 'alchemist-iex-send-region-and-go)
   ;; elixir HEX-specific key bindings
   (nmap 'alchemist-hex-mode-map
     :prefix my/leader
     "i" 'alchemist-hex-info-at-point
     "I" 'alchemist-hex-info
     "r" 'alchemist-hex-releases-at-point
     "R" 'alchemist-hex-releases
     "f" 'alchemist-hex-search)))
(use-package elixir-format
 :quelpa (elixir-format :fetcher github :repo "anildigital/mix-format.el")
 :preface
 (defun my/elixir-format/setup ()
   (add-hook 'before-save-hook 'elixir-format-before-save))
 :custom
 (elixir-format-mix-path "/usr/local/bin/mix")
 :hook
 (elixir-mode . my/elixir-format/setup))
(use-package flycheck-elixir
  :after (flycheck elixir-mode))
(use-package flycheck-dialyxir
 :after (flycheck elixir-mode))
(use-package flycheck-credo
 :after (flycheck elixir-mode)
 :commands
 (flycheck-credo-setup)
 :config
 (flycheck-credo-setup))

Prolog

(use-package prolog
 :ensure nil
 :preface
 (defun my/mercury-mode/setup ()
   (electric-indent-mode -1))
 :commands
 (prolog-mode mercury-mode)
 :hook
 (mercury-mode . my/mercury-mode/setup)
 :mode
 (("\\.pl\\'" . prolog-mode)
  ("\\.m\\'" . mercury-mode))
 :init
 (setq prolog-system 'swi))

TODO: add https://github.com/flycheck/flycheck-mercury

Dhall

(use-package dhall-mode
 :custom
 (dhall-format-at-save t)
 :mode "\\.dhall\\'")

Terraform

Mode

(use-package terraform-mode
 :hook (terraform-mode . terraform-format-on-save-mode))

Company

(use-package company-terraform
 :after (terraform company)
 :commands
 (company-terraform-init)
 :config
 (company-terraform-init))

SQL

(use-package format-sql
 :after (general)
 :config
 (vmap 'sql-mode-map
   "C-c R" 'format-sql-region)
 (nmap 'sql-mode-map
   "C-c r" 'format-sql-buffer))
(use-package sqlup-mode
  :after (general)
  :hook
  ;; capitalize keywords in SQL mode
  ;; capitalize keywords in an interactive session (e.g. psql)
  ((sql-mode sql-interactive-mode) . sqlup-mode)
  :config
  (add-to-list 'sqlup-blacklist "name")
  (add-to-list 'sqlup-blacklist "public")
  (add-to-list 'sqlup-blacklist "state")
  (nmap
    :keymaps '(sql-mode-map sql-interactive-mode-map)
    :prefix my/leader
    "S u" 'sqlup-capitalize-keywords-in-region
    "S U" 'sqlup-capitalize-keywords-in-buffer))

Json

(use-package json-mode
  :mode "\\.bowerrc$")

Other JSON-related packages.

(use-package json-navigator)
(use-package json-reformat)

Yaml

(use-package yaml-mode
 :config
 :delight "yaml")
(use-package flycheck-yamllint
 :after (flycheck yaml-mode)
 :commands
 (flycheck-yamllint-setup)
 :config
 (flycheck-yamllint-setup))

Protobuf

(use-package protobuf-mode)

Markdown

(use-package markdown-mode
 :disabled
 :defer 1
 :commands (markdown-mode gfm-mode)
 :mode
 (("README\\.md\\'" . gfm-mode)
  ("\\.md\\'" . markdown-mode)
  ("\\.markdown\\'" . markdown-mode))
 :init
 (setq markdown-command "multimarkdown")
 :delight "md")
(use-package markdown-mode+
  :after markdown-mode)
(use-package jira-markup-mode
 :defer t
 :after atomic-chrome
 :mode ("\\.confluence$" . jira-markup-mode)
 :custom-update
 (atomic-chrome-url-major-mode-alist
  '(("atlassian\\.net$" . jira-markup-mode))))
(use-package gh-md
 :after (general markdown-mode)
 :config
 (nmap 'markdown-mode-map
   :prefix my/leader
   "m r" 'gh-md-render-region
   "m b" 'gh-md-render-buffer))

Emmet

(use-package emmet-mode
 :after (general sgml-mode)
 :defer 1
 :commands
 emmet-mode
 :hook
 ((sgml-mode ; auto-start on any markup modes
   css-mode  ; enable css abbreviation
   html-mode
   jade-mode) . emmet-mode)
 :config
 (imap
   "C-x C-o" 'emmet-expand-line)
 :delight "emmet")

Tex

Prolog

Python

(use-package python-mode
 :preface
 (defun my/python-mode/setup ()
   (mapc (lambda (pair) (push pair prettify-symbols-alist))
         '(("def" . "𝒇")
           ("class" . "𝑪")
           ("and" . "")
           ("or" . "")
           ("not" . "")
           ("in" . "")
           ("not in" . "")
           ("return" . "")
           ("yield" . "")
           ("for" . "")
           ("!=" . "")
           ("==" . "")
           (">=" . "")
           ("<=" . "")
           ("[]" . "")
           ("=" . ""))))
 :hook
 (python-mode . my/python-mode/setup))

Ruby

(use-package inf-ruby
 :hook
 ;; automatically switch from common ruby compilation modes
 ;; to interact with a debugger
 (compilation-filter . inf-ruby-auto-enter)
 ;; required to use binding.pry or byebug
 (after-init . inf-ruby-switch-setup))
(use-package robe
 :after (company)
 :hook
 (ruby-mode . robe-mode)
 :config
 (add-to-list 'company-backends 'company-robe)
 :delight "robe")
(use-package rubocop
 :after (robe)
 :hook
 (ruby-mode . rubocop-mode)
 :delight "rcop")
(use-package bundler
 :after general
 :config
 (nmap 'ruby-mode-map
   :prefix my/leader
   "b i" 'bundle-install
   "b c" 'bundle-console
   "b o" 'bundle-outdated
   "b u" 'bundle-update
   "b e" 'bundle-exec))
(use-package rbenv
 :commands
 (global-rbenv-mode)
 :preface
 (defun my/rbenv/modeline (current-ruby)
   (append
    '(" ruby [")
    (list (propertize current-ruby 'face 'rbenv-active-ruby-face))
    '("]")))
 :hook
 (ruby-mode . rbenv-use-corresponding)
 :init
 (setq rbenv-modeline-function 'my/rbenv/modeline)
 :config
 (global-rbenv-mode)
 (nmap 'ruby-mode-map
   :prefix "C-c R"
   "c" 'rbenv-use-corresponding
   "u" 'rbenv-use))
(use-package rake
 :after (general projectile)
 :init
 (setq rake-completion-system projectile-completion-system)
 :config
 (nmap 'ruby-mode-map
   :prefix my/leader
   "r" 'rake))
(use-package rspec-mode)
(use-package projectile-rails
 :after projectile
 :commands
 (projectile-rails-global-mode)
 :init
 (setq
  projectile-rails-vanilla-command "bin/rails"
  projectile-rails-spring-command "bin/spring"
  projectile-rails-zeus-command "bin/zeus")
 :config
 (projectile-rails-global-mode)
 :diminish)

PHP

(use-package php-mode
  :mode "\\.\\(php\\|inc\\)$")

Java

(use-package gradle-mode
  :hook ((java-mode kotlin-mode) . gradle-mode))
(use-package javadoc-lookup)

Kotlin

(use-package kotlin-mode)

Groovy

(use-package groovy-mode
 :mode ("\\.gradle$" . groovy-mode))

Web

Mode

(use-package web-mode
  :after (tide)
  :preface
  (defun my/web-mode/setup ()
    (interactive)
    (when (string-equal "tsx" (file-name-extension buffer-file-name))
      (setup-tide-mode)))
  :mode
  (("\\.html?\\'" . web-mode)
   ("\\.html\\.erb\\'" . web-mode)
   ("\\.erb\\'" . web-mode)
   ("\\.djhtml\\'" . web-mode)
   ("\\.tsx\\'" . web-mode)
   ("\\.jsx\\'" . web-mode)
   ("\\.mustache\\'" . web-mode)
   ("\\.jinja\\'" . web-mode)

   ("\\.css\\'" . web-mode)
   ("\\.scss\\'" . web-mode)

   ("\\.[agj]sp\\'" . web-mode)
   ("\\.as[cp]x\\'" . web-mode)
   ("\\.as\\'" . web-mode)

   ("\\.phtml\\'" . web-mode)
   ("\\.tpl\\.php\\'" . web-mode)
   ("\\.php\\'" . web-mode))

  :init
  (setq
   ;; indent HTML automatically
   web-mode-indent-style 2
   ;; offsets
   web-mode-markup-indent-offset 2
   web-mode-css-indent-offset 2
   web-mode-code-indent-offset 2

   web-mode-engines-alist
   '(("\\.jinja\\'"  . "django")
     ("php" . "\\.php[3-5]?"))

   web-mode-enable-auto-pairing t
   web-mode-enable-css-colorization t
   web-mode-enable-current-element-highlight t
   web-mode-enable-current-column-highlight nil)
  :config
  (flycheck-add-mode 'javascript-eslint 'web-mode)
  :hook
  (web-mode . my/web-mode/setup))

Cakecrumbs

Display current path for HTML/XML/CSS.

(use-package cakecrumbs
  :config
  (cakecrumbs-auto-setup))

Company

(use-package company-web
 :after company
 :demand t)

Styling

CSS mode

(use-package css-mode)

Counsel CSS

(use-package counsel-css)

LSP-CSS

SCSS mode

(use-package scss-mode
 :config
 :delight "scss")

Go

(use-package go-mode
  :after (company flycheck)
  :if (executable-find "go")
  :preface
  (defun my/go-mode/setup ()
    (add-hook 'before-save-hook 'gofmt-before-save)
    (add-hook 'go-mode-hook 'flycheck-mode)
    (setq-default)
    (setq standard-indent 8)
    (setq tab-width 8)
    (setq indent-tabs-mode 1))
  :mode "\\.go\\'"
  :hook
  (go-mode . my/go-mode/setup))
(use-package company-go
 :after (company go-mode)
 :hook
 (go-mode . company-mode)
 :config
 (add-to-list 'company-backends 'company-go))
(use-package go-stacktracer)

(use-package go-add-tags)

(use-package go-eldoc
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-gopath)

(use-package go-direx)

(use-package gotest)

(use-package go-playground)

TypeScript

TypeScript mode.

(use-package typescript-mode
  :preface
  (defun my/typescript-mode/setup ()
    ;; The error messages produced by tsc when its pretty flag
    ;; is turned on include ANSI color escapes, which by default
    ;; compilation-mode does not interpret. In order to get the
    ;; escapes parsed we do the following:
    (require 'ansi-color)
    (defun colorize-compilation-buffer ()
      (ansi-color-apply-on-region compilation-filter-start (point-max)))
    (add-hook 'compilation-filter-hook 'colorize-compilation-buffer))
  :custom
  (typescript-indent-level 2)
  :hook
  (typescript-mode . my/typescript-mode/setup))

TypeScript IDE.

(use-package tide
  :after (typescript-mode flycheck company)
  :preface
  (defun my/tide/setup ()
    (interactive)
    (tide-setup)
    (flycheck-mode +1)
    (eldoc-mode +1)
    (tide-hl-identifier-mode +1)
    (company-mode +1))
  :custom
  (tide-format-options
   '(:indentSize 2 :tabSize 2 :indentStyle 2))
  :config
  (flycheck-add-next-checker 'javascript-eslint 'jsx-tide 'append)
  (nmap tide-mode-map
    :prefix my/leader
    "0" 'tide-jsdoc-template)
  :hook
  ((typescript-mode . my/tide/setup)
   (before-save . tide-format-before-save)))

TypeScript REPL.

(use-package ts-comint
  :custom
  (ts-comint-program-command "ts-node"))

Flow

JavaScript

tern

(use-package tern
 :commands
 (tern-mode)
 :config
 ;; enable js completion between <script>...</script> etc
 (defadvice company-tern (before web-mode-set-up-ac-sources activate)
   "Set `tern-mode' based on current language before running company-tern."
   (message "advice")
   (if (equal major-mode 'web-mode)
       (let ((web-mode-cur-language (web-mode-language-at-pos)))
         (if (or (string= web-mode-cur-language "javascript")
                 (string= web-mode-cur-language "jsx"))
             (unless tern-mode (tern-mode))
           (if tern-mode (tern-mode -1)))))))

npm

(use-package npm-mode
 :commands
 (npm-mode npm-global-mode)
 :config
 (npm-global-mode)
 :diminish npm-mode)

js2

(use-package js2-mode
 :init
 ;; indent step is 2 spaces
 (setq-default js2-basic-offset 2)
 (setq-default js-indent-level 2)
 (setq
  ;; configure indentation
  js2-enter-indents-newline t
  js2-auto-indent-p t
  ;; Idle timeout before reparsing buffer
  js2-idle-timer-delay 0.5
  ;; disable error parsing in favor of Flycheck
  js2-strict-missing-semi-warning nil)
 :commands js2-mode
 :config
 (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
 :delight "js2")

eslintd-fix

A very fast JS linter and fixer.

(use-package eslintd-fix
 :hook
 (tide-mode . eslintd-fix-mode))

xref-js2

Jump to references/definitions using ag & js2-mode’s AST. See the repo for details.

(use-package xref-js2
 :preface
 (defun my/xref-js2/add-backend ()
   (add-hook 'xref-backend-functions
             'xref-js2-xref-backend nil t))
 :hook
 (js2-mode . my/xref-js2/add-backend)
 :config
 (unbind-key "M-." js2-mode-map))

js2-refactor

A JavaScript refactoring library.

(use-package js2-refactor
 :commands
(js2r-add-keybindings-with-prefix)
 :hook
 (js2-mode . js2-refactor-mode)
 :config
 ;; enable minor mode for js refactoring
 ;; see: https://github.com/magnars/js2-refactor.el#refactorings
 (js2r-add-keybindings-with-prefix "C-c C-j"))

rjxs-mode

(use-package rjsx-mode
 :demand t
 :commands rjsx-mode
 :mode "\\\.js$"
 :config
 (setq js-indent-level 2))

LSP

Typescript LSP support.

Flow LSP support.

prettier

(use-package prettier-js
 :hook
 ((js2-mode-hook web-mode-hook) . prettier-js-mode)
 :delight "pr")

GraphQL

(use-package graphql-mode
 :mode "\\.graphql\\'"
 :custom
 (graphql-url "http://localhost:8000/api/graphql/query"))

Vue

(use-package vue-mode)

Elm

(use-package elm-mode
  :custom
  (elm-format-on-save t)
  (elm-package-json "elm.json")
  (elm-tags-exclude-elm-stuff nil)
  (elm-tags-on-save t))
(use-package flycheck-elm
 :after (elm-mode flycheck)
 :hook
 (flycheck-mode . flycheck-elm-setup))

Nginx

(use-package nginx-mode)

D

(use-package d-mode)

C/C++

Emacs has a great built in C/C++ mode, but we can improve on it with irony-mode for code completion via libclang.

(use-package irony
 :hook
 (c-mode . irony-mode)
 (c++-mode . irony-mode))

Add company mode support.

(use-package company-irony
 :config
 (add-to-list 'company-backends 'company-irony))
(use-package irony-cdb
  :ensure nil
  :hook (irony-mode . irony-cdb-autosetup-compile-options))
(use-package irony-eldoc
  :hook (irony-mode . irony-eldoc))

Company mode backend for C/C++ header files with Irony.

(use-package company-irony-c-headers
  :after (irony)
  :config
  (add-to-list 'company-backends '(company-irony-c-headers company-irony)))

TODO: Use company-irony-c-headers to replace company-c-headers see yuutayamada/company-arduino#3

Auto-completion for C/C++ headers using Company. See: https://github.com/yuutayamada/company-arduino/tree/d7e369702b8eee63e6dfdeba645ce28b6dc66fb1#note

(use-package company-c-headers
  :after (irony company-irony)
  :config
  (defun company-c-headers-path-user-irony ()
    "Return the user include paths for the current buffer."
    (when irony-mode
      (irony--extract-user-search-paths
       irony--compile-options
       irony--working-directory)))
  (setq company-c-headers-path-user 'company-c-headers-path-user-irony))

Add flycheck support.

(use-package flycheck-irony
 :hook
 (flycheck-mode . flycheck-irony-setup))

CMake

(use-package cmake-mode
  :mode (("\\.cmake\\'" . cmake-mode)
         ("\\CMakeLists.txt$" . cmake-mode)))

(use-package cmake-font-lock
  :config
  (autoload 'cmake-font-lock-activate "cmake-font-lock" nil t)
  (add-hook 'cmake-mode-hook 'cmake-font-lock-activate))

(use-package eldoc-cmake
  :hook (cmake-mode . eldoc-cmake-enable))

Objective C

(use-package objc-font-lock
 :config
 (objc-font-lock-global-mode 1))

Matlab

Octave

(use-package octave
 :after general
 :ensure nil
 ;; Overlaps with mercury-mode
 :mode ("\\.octave\\'" . octave-mode))

Latex

(use-package tex
 :demand t
 :ensure auctex
 :config
 (setq-default TeX-engine 'luatex)
 (setq-default TeX-PDF-mode t)
 (setq-default TeX-master nil)
 (setq TeX-view-program-selection '((output-pdf "PDF Tools")))
 (setq reftex-plug-into-AUCTeX t)
 (setq reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource"))
 (setq reftex-use-external-file-finders t)
 (setq reftex-external-file-finders
       '(("tex" . "kpsewhich -format=.tex %f")
         ("bib" . "kpsewhich -format=.bib %f")))
 (setq reftex-insert-label-flags '("s" "sft" "e"))
 (setq TeX-electric-sub-and-superscrip t)
 (setq TeX-electric-math (cons "\\(" "\\)"))
 :hook
 ((LaTeX-mode . visual-line-mode)
  (LaTeX-mode . turn-on-auto-fill)
  (LaTeX-mode . flyspell-mode)
  (LaTeX-mode . LaTeX-math-mode)
  (LaTeX-mode . turn-on-reftex)
  (TeX-after-compilation-finished-functions
    . TeX-revert-document-buffer)))

(use-package auctex-latexmk
  :hook (LaTeX-mode . auctex-latexmk-setup))

Add company mode support. This package provides completion back-ends for math unicode symbols and latex tags.

(use-package company-math
 :config
 (add-to-list 'company-backends 'company-math-symbols-latex)
 (add-to-list 'company-backends 'company-math-symbols-unicode))

Toml

(use-package toml-mode)

Bison

Conflicts with happy-mode, so make sure to manually enable the happy-mode when working with .y parser files.

(use-package bison-mode)

Pug

(use-package pug-mode)

Jade

(use-package jade-mode)

Lua

(use-package lua-mode
  :preface
  (defun my/lua-prettify-symbols-setup ()
    (dolist (symbol '(("~="  . (?\s (Br . Bl) ?\s (Bc . Bc) ?≠))
                      ("function"  . )
                      ("math.huge" . ?∞)))
      (cl-pushnew symbol prettify-symbols-alist :test #'equal)))
  :mode "\\.lua\\'"
  :custom
  (lua-documentation-function 'eww)
  :init
  (setq lua-indent-level 2)
  :hook
  (lua-mode . my/lua-prettify-symbols-setup))

(use-package lua-block
  :after (lua-mode)
  :quelpa
  (lua-block
   :fetcher url
   :url "http://www.emacswiki.org/emacs/download/lua-block.el")
  :init
  (autoload 'lua-block-mode "lua-block" nil t)
  :delight "lb")

Haml

(use-package haml-mode)

Slim

(use-package slim-mode
 :delight "slim")

Robots.txt

(use-package robots-txt-mode)

Dotenv

(use-package dotenv-mode
 :config
 (add-to-list 'auto-mode-alist '("\\.env\\..*\\'" . dotenv-mode)))

CSV

(use-package csv-mode
  :mode "\\.[Cc][Ss][Vv]$"
  :init
  (setq
   ;; default separators for CSV files.
   csv-separators '("," ";" "|" " " "\t")
   ;; number of lines to consider part of header.
   csv-header-lines 1))

Api blueprint

(use-package apib-mode
  :after general
  :config
  (nmap 'apib-mode-map
    :prefix my/leader
    "z p" 'apib-parse           ; Parse the API Blueprint
    "z v" 'apib-validate        ; Validate the API Blueprint
    "z j" 'apib-get-json        ; Print all generated JSON bodies
    "z s" 'apib-get-json-schema ; Print all generated JSON Schemas
    ))

NASM

(use-package nasm-mode)

IASM

(use-package iasm-mode)

BNF

(use-package bnf-mode
 :mode "\\.bnf\\'")

CUDA

(use-package cuda-mode
  :mode
  (("\\.cu\\'" . cuda-mode)
   ("\\.cuh\\'" . cuda-mode)))

APL

(use-package gnu-apl-mode)
(use-package dyalog-mode)

Ansible

(use-package ansible)

Arduino

(use-package arduino-mode
  :init
  ;; TODO: irony-arduino-includes-options
  ;; see https://github.com/yuutayamada/company-arduino/issues/5
  ;; TODO: https://github.com/yuutayamada/company-arduino/issues/6
  :config
  ;; Activate irony-mode on arduino-mode
  (add-hook 'arduino-mode-hook 'irony-mode)
  (nmap
    :prefix my/leader
    "a v" 'arduino-verify
    "a u" 'arduino-upload
    "a i" 'arduino-install-library
    "a m" 'arduino-menu
    "a n" 'arduino-sketch-new
    "a b" 'arduino-install-boards
    "a s" 'arduino-serial-monitor))
(use-package company-arduino
  :after (irony company company-irony company-c-headers)
  :config
  ;; Add arduino's include options to irony-mode's variable
  (add-hook 'irony-mode-hook 'company-arduino-turn-on)
  ;; Configuration for company-c-headers.el
  ;; The `company-arduino-append-include-dirs' function appends
  ;; Arduino's include directories to the default directories
  ;; if `default-directory' is inside `company-arduino-home'. Otherwise
  ;; just returns the default directories.
  ;; Please change the default include directories accordingly.
  (defun my-company-c-headers-get-system-path ()
    "Return the system include path for the current buffer."
    (let ((default '("/usr/include/" "/usr/local/include/")))
      (company-arduino-append-include-dirs default t)))
  (setq company-c-headers-path-system 'my-company-c-headers-get-system-path))

GLSL

(use-package glsl-mode)

(use-package company-glsl)

Kconfig

(use-package kconfig-mode)

Scilla (disabled)

(use-package scilla
  :after (flycheck)
  :preface
  (setq scilla-root "/home/vyorkin/projects/work/zilliqa/scilla")
  :load-path (lambda () (concat scilla-root "/misc/emacs-mode")))
;; For enabling flycheck mode for Scilla.
(setq scilla-root "/home/vyorkin/projects/work/zilliqa/scilla")
;; Load the Scilla major mode.
(load-file (concat scilla-root "/misc/emacs-mode/scilla-mode.el"))

GDB

When gdb debugging, show the many windows (stack trace, break points, etc).

(use-package gdb-mi
  :ensure nil
  :commands (gdb-many-windows)
  :hook
  (gdb . gdb-many-windows))

DAP

(use-package dap-mode
 :config
 (dap-mode 1)
 (dap-ui-mode 1))

Coverage

Test coverage overlay. Highlights untested lines.

(use-package coverlay
  :preface
  (defun my/coverlay-mode-enable ()
    "Turn on `coverlay-mode'."
    (coverlay-minor-mode 1)
    (when (and (buffer-file-name) (not (bound-and-true-p coverlay--loaded-filepath)))
      (let* ((coverage-file
              (concat
               (locate-dominating-file (file-name-directory (buffer-file-name)) "coverage")
               "coverage"
               "/lcov.info")))
        (when (file-exists-p coverage-file)
          (coverlay-watch-file coverage-file)))))
  :custom
  (coverlay:mark-tested-lines nil)
  :diminish coverlay-minor-mode)

Quickrun

Run command quickly.

(use-package quickrun
  :preface
  (defun my/display-ctrl-M-as-newline ()
    "Display `^M' as newline."
    (interactive)
    (setq buffer-display-table (make-display-table))
    (aset buffer-display-table ?\^M [?\n]))
  :hook
  (quickrun--mode . my/display-ctrl-M-as-newline)
  :config
  (nmap
    :prefix my/leader
    "i q" 'quickrun
    "i r" 'quickrun-region
    "i a" 'quickrun-autorun-mode))

HTTP

(use-package restclient
 :mode
 ("\\.http\\'" . restclient-mode))
(use-package restclient-test
 :hook
 (restclient-mode-hook . restclient-test-mode))
(use-package ob-restclient
 :after (org restclient)
 :init
 (org-babel-do-load-languages
  'org-babel-load-languages
  '((restclient . t))))
(use-package company-restclient
 :after (company restclient)
 :custom-update
 (company-backends '(company-restclient)))

Docker

Emacs integration for Docker. Supports docker containers, images, volumes, networks, docker-machine and docker-compose.

(use-package docker
 :diminish docker-mode
 :config
 (nmap
   :prefix my/leader
   "d" 'docker))
(use-package docker-compose-mode)

Kubernetes

(use-package timonier
 :after general
 :init
 (setq timonier-k8s-proxy "http://localhost:8001"))

MMM

Provides a minor mode that allows Multiple Major Modes to coexist in one buffer.

(use-package mmm-mode
  :after (haskell-mode)
  :preface
  (defun my/mmm-mode/setup ()
    ;; go into mmm minor mode when class is given
    (make-local-variable 'mmm-global-mode)
    (setq mmm-global-mode 'true))
  :init
  (setq mmm-submode-decoration-level 1)
  :hook
  (haskell-mode . my/mmm-mode/setup)
  :config

Styles for Literate Haskell. Read here for more info.

(mmm-add-classes
 '((literate-haskell-bird
    :submode text-mode
    :front "^[^>]"
    :include-front true
    :back "^>\\|$")
   (literate-haskell-latex
    :submode literate-haskell-mode
    :front "^\\\\begin{code}"
    :front-offset (end-of-line 1)
    :back "^\\\\end{code}"
    :include-back nil
    :back-offset (beginning-of-line -1))))
(setq mmm-submode-decoration-level 0)

Re-fontify sub-mode portions when idle. The manual command for this is mmm-parse-buffer. If you don’t do this, then syntax highlighting won’t work for new regions of Haskell code in the \begin{code}...\end{code} blocks.

(setq mmm-parse-when-idle 't))

Tools

carbon-now-sh

(use-package carbon-now-sh
  :config
  (vmap 'prog-mode
    "C-c c" 'carbon-now-sh))

Help

Helpful

See the package repo for more info.

(use-package helpful
 :config
 (nmap
   :prefix my/leader
   "H h" 'helpful-at-point
   "H f" 'helpful-callable
   "H F" 'helpful-function
   "H v" 'helpful-variable
   "H c" 'helpful-command
   "H k" 'helpful-key))

Devdocs

Allows to easily search the DevDocs documentation.

(use-package devdocs
  :config
  (nmap
    :prefix my/leader
    "h h" 'devdocs-search))

Infrastructure

Net utils

(use-package net-utils
 :config
 (nmap
   :prefix my/leader
   "N p" 'ping
   "N i" 'ifconfig
   "N w" 'iwconfig
   "N n" 'netstat
   "N a" 'arp
   "N r" 'route
   "N h" 'nslookup-host
   "N d" 'dig
   "N s" 'smbclient))

IX

(use-package ix
 :after general
 :config
 (nmap
   :prefix my/leader
   "G i i" 'ix
   "G i b" 'ix-browse
   "G i d" 'ix-delete))

Direnv

Provides =direnv= integration for Emacs.

(use-package direnv
 :demand t
 :custom
 (direnv-always-show-summary t)
 :config
 (direnv-mode))

Calendar

(use-package calfw-org)
(use-package calfw
 :demand t
 :config
 (require 'calfw-org)

 ;; Nicer Unicode characters
 (setq
   cfw:fchar-junction ?╋
   cfw:fchar-vertical-line ?┃
   cfw:fchar-horizontal-line ?━
   cfw:fchar-left-junction ?┣
   cfw:fchar-right-junction ?┫
   cfw:fchar-top-junction ?┯
   cfw:fchar-top-left-corner ?┏
   cfw:fchar-top-right-corner ?┓))

Email

Notmuch

(use-package notmuch)

Search emails in Notmuch asynchronously with Ivy.

(use-package counsel-notmuch
  :after (notmuch counsel))

Mu4e

(use-package mu4e
 :ensure nil
 :commands
 (mu4e-html2text-command)
 :hook
 (after-init . mu4e-alert-enable-mode-line-display)
 :init
 (setq
  mu4e-maildir "~/.Mail"
  mu4e-drafts-folder "/vasiliy.yorkin/[Gmail].Drafts"
  mu4e-sent-folder "/vasiliy.yorkin/[Gmail].Sent Mail"
  mu4e-trash-folder "/vasiliy.yorkin/[Gmail].Trash"
  ;; don't save message to Sent Messages, Gmail/IMAP takes care of this
  mu4e-sent-messages-behavior 'delete
  ;; auto update every minute
  mu4e-update-interval (* 60 5)
  mu4e-headers-auto-update t
  mu4e-headers-date-format "%Y-%m-%d [%H:%M]"
  mu4e-headers-fields
  '((:date . 20)
    (:mailing-list . 14)
    (:from . 20)
    (:subject . nil))
  mu4e-view-fields '(:from :to :cc :subject :date :mailing-list :attachments :signature)
  ;; I was getting duplicate emails, this fixes it
  mu4e-headers-skip-duplicates t
  mu4e-view-show-addresses t
  mu4e-view-show-images t
  mu4e-use-fancy-chars t
  ;; sending
  message-send-mail-function 'message-send-mail-with-sendmail
  sendmail-program "/usr/bin/msmtp"
  user-full-name "Vasiliy Yorkin"
  ;; capturing
  org-mu4e-link-query-in-headers-mode nil
  ;; goobook
  external-abook-command "goobook query '%s' | cut -f 1,2"
  ;; mu4e alert
  mu4e-alert-interesting-mail-query "flag:unread AND NOT flag:trashed AND maildir:/vasiliy.yorkin/INBOX"
  mu4e-attachment-dir  "~/Downloads"
  mu4e-maildir-shortcuts
  '(("/vasiliy.yorkin/INBOX" . ?i)
    ("/vasiliy.yorkin/[Gmail].Sent Mail" . ?s)
    ("/vasiliy.yorkin/[Gmail].Trash" . ?t)
    ("/vasiliy.yorkin/[Gmail].Drafts" . ?d)
    ("/vasiliy.yorkin/[Gmail].All Mail" . ?a))
  mu4e-bookmarks
  '(("flag:unread AND NOT flag:trashed" "Unread messages"  ?u)
    ("date:today..now" "Today's messages" ?t)
    ("date:7d..now" "Last 7 days" ?w)
    ("date:1m..now" "Last month" ?m)
    ("mime:image/*" "Messages with images" ?p)
    (,(mapconcat
       'identity
       (mapcar
        (lambda (maildir)
          (concat "maildir:" (car maildir)))
        mu4e-maildir-shortcuts) " OR ")
     "All inboxes" ?i)))
 :config
 (require 'mu4e-contrib)
 (setq
  ;; mu4e-html2text-command 'mu4e-shr2text
  ;; shr-color-visible-distance-min 5
  ;; shr-use-colors nil
  ;; when using a dark theme the messages are hard to read
  ;; it can help to change the luminosity
  ;; shr-color-visible-luminance-min 80
  ;; textutil is an alternative to html2text for macOS
  ;; mu4e-html2text-command "textutil -stdin -format html -convert txt -stdout"
  mu4e-html2text-command "html2text -b 72")
 (advice-add 'shr-colorize-region :around (defun shr-no-colourise-region (&rest ignore)))
 (nmap
   :prefix my/leader
   "M" 'mu4e))
(use-package external-abook
 :after (quelpa)
 :quelpa (external-abook :fetcher github :repo "emacsmirror/external-abook"))
(use-package mu4e-alert
 :after (mu4e)
 :config
 (mu4e-alert-enable-mode-line-display)
 (mu4e-alert-enable-notifications)
 (mu4e-alert-set-default-style 'notifier))

Reading

PDF

Emacs support library for PDF files. You should run the following command manually:

M-x pdf-tools-install RET

To check if everything is ok:

M-x pdf-info-check-epdfinfo RET
(use-package pdf-tools
 :mode ("\\.pdf\\'" . pdf-view-mode)
 :commands
 (pdf-tools-install)
 :config
 (pdf-tools-install)
 (setq-default pdf-view-display-size 'fit-width))

Djvu

(use-package djvu)

EPUB

Major mode for reading EPUB’s in Emacs.

(use-package nov
  :preface
  (defun my/nov-delayed-render-setup ()
    (run-with-idle-timer 0.2 nil 'nov-render-document))
  (defun my/nov-fringes-setup ()
    "Hide the fringes for `nov-mode'."
    (set-window-fringes (get-buffer-window) 0 0 nil))
  :mode
  ("\\.epub$" . nov-mode)
  :hook
  (nov-mode . my/nov-delayed-render-setup)
  (nov-mode . my/nov-fringes-setup))

Translation

This package allows to translate the strings using Google Translate service directly from Emacs.

(use-package google-translate
 :after (general)
 :demand t
 :init
 (setq google-translate-default-source-language "en")
 (setq google-translate-default-target-language "ru")
 :config
 (require 'google-translate-default-ui)
 (nmap
  :prefix "C-c"
  "t" 'google-translate-at-point
  "q" 'google-translate-query-translate))

Search

Engine mode

(use-package engine-mode
 :config
 (engine-mode t)
 (engine/set-keymap-prefix (kbd "C-c C-s"))
 (defengine amazon
   "http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=%s")
 (defengine duckduckgo
   "https://duckduckgo.com/?q=%s"
   :keybinding "d")
 (defengine github
   "https://github.com/search?q=%s&type=Code"
   :keybinding "G")
 (defengine google
   "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
   :keybinding "g")
 (defengine google-images
   "http://www.google.com/images?hl=en&source=hp&biw=1440&bih=795&gbv=2&aq=f&aqi=&aql=&oq=&q=%s"
   :keybinding "i")
 (defengine google-maps
   "http://maps.google.com/maps?q=%s"
   :docstring "Mappin' it up."
   :keybinding "M")
 (defengine melpa
   "https://melpa.org/#/?q=%s"
   :docstring "Searching on melpa"
    :keybinding "m")
 (defengine project-gutenberg
   "http://www.gutenberg.org/ebooks/search/?query=%s")
 (defengine rfcs
   "http://pretty-rfc.herokuapp.com/search?q=%s")
 (defengine stack-overflow
   "https://stackoverflow.com/search?q=%s"
   :keybinding "s"
   :docstring "Search Stack Overlow")
 (defengine google-translate
   "https://translate.google.com/#view=home&op=translate&sl=en&tl=ru&text=%s"
   :keybinding "t")
 (defengine twitter
   "https://twitter.com/search?q=%s"
   :keybinding "T")
 (defengine wikipedia
   "http://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"
   :keybinding "w"
   :docstring "Searchin' the wikis.")
 (defengine pursuit
   "https://pursuit.purescript.org/search?q=%s"
   :keybinding "p")
 (defengine hoogle
   "https://www.haskell.org/hoogle/?hoogle=%s"
   :keybinding "h")
 (defengine hackage
   "https://hackage.haskell.org/packages/search?terms=%s"
   :keybinding "H")
 (defengine hayoo
   "http://hayoo.fh-wedel.de/?query=%s")
 (defengine wiktionary
   "https://www.wikipedia.org/search-redirect.php?family=wiktionary&language=en&go=Go&search=%s")
 (defengine wolfram-alpha
   "http://www.wolframalpha.com/input/?i=%s")
 (defengine urban-dictionary
   "https://www.urbandictionary.com/define.php?term=%s"
   :keybinding "u")
 (defengine youtube
   "http://www.youtube.com/results?aq=f&oq=&search_query=%s"
   :keybinding "y"))

Counsel web

(use-package counsel-web
 :after (general)
 :quelpa
 (counsel-web :fetcher github :repo "mnewt/counsel-web")
 :custom
 (counsel-web-search-action 'browse-url)
 (counsel-web-suggest-function 'counsel-web-suggest--google)
 (counsel-web-search-function 'counsel-web-search--google)
 :config
 (nmap
  :prefix my/leader
  "S" 'counsel-web-suggest))

Google this

I use engine-mode instead.

(use-package google-this
 :diminish google-this-mode
 :config
 (google-this-mode 1)
 (nmap
   :prefix my/leader
   "G" google-this-mode-submap))

Stack exchange

(use-package sx
 :config
 (nmap
   :prefix my/leader
   "' q" 'sx-tab-all-questions
   "' i" 'sx-inbox
   "' o" 'sx-open-link
   "' u" 'sx-tab-unanswered-my-tags
   "' a" 'sx-ask
   "' s" 'sx-search))

Messaging

Prerequisites

(use-package alert
 :commands (alert)
 :init
 (setq alert-style-default 'libinotify))

Slack

Slack client for Emacs.

(use-package slack
 :after (general company)
 :commands (slack-start)
 :secret
 (slack-start "slack.el")
 :init
 (setq
  slack-buffer-emojify t
  slack-prefer-current-team t)
 :config
 ;; Only use Slack company completion
 (make-local-variable 'company-backends)
 (setq company-backends '((company-slack-backend)))

 (add-hook
   'slack-mode-hook
   '(lambda ()
      (flycheck-mode -1)
      (company-mode -1)))

 (nmap 'slack-mode-map
   ",ra" 'slack-message-add-reaction
   ",rr" 'slack-message-remove-reaction
   ",rs" 'slack-message-show-reaction-users
   ",pl" 'slack-room-pins-list
   ",pa" 'slack-message-pins-add
   ",pr" 'slack-message-pins-remove
   ",mm" 'slack-message-write-another-buffer
   ",me" 'slack-message-edit
   ",md" 'slack-message-delete
   ",2" 'slack-message-embed-mention
   ",3" 'slack-message-embed-channel
   "\C-n" 'slack-buffer-goto-next-message
   "\C-p" 'slack-buffer-goto-prev-message)
 (nmap 'slack-edit-message-mode-map
   ",k" 'slack-message-cancel-edit
   ",s" 'slack-message-send-from-buffer
   ",2" 'slack-message-embed-mention
   ",3" 'slack-message-embed-channel))

Telega

telega.el is full featured unofficial client for Telegram platform for GNU Emacs.

Installation:

cd ~/.emacs/quelpa/build/telega
make compile
(use-package telega
  :quelpa
  (telega
   :fetcher github
   :repo "zevlg/telega.el"
   :branch "master"
   :files (:defaults "README.md" "etc" "server" "Makefile" "test.el"))
  :config
  (setq
   telega-proxies
   (list
    '(:server
      "proxy.digitalresistance.dog"
      :port 443
      :enable t
      :type (:@type "proxyTypeMtproto" :secret "d41d8cd98f00b204e9800998ecf8427e"))))
  :load-path "~/.emacs.d/quelpa/build/telega"
  :bind
  (:map telega-msg-button-map
    ("j" . nil)
    ("k" . nil)
    ("h" . nil)
    ("l" . nil))
  :custom
  (telega-completing-read-function #'ivy-completing-read))

ERC

(use-package erc
  :preface
  (defvar my/erc/default-nick "vyorkin")
  (defvar my/erc/default-name "Vasiliy Yorkin")
  (defun my/erc/line-setup ()
    "Line configuration for `erc-mode'."
    (visual-line-mode 0))
  (defun my/erc/parens-setup ()
    "Parenthesis configuration for `erc-mode'."
    (smartparens-strict-mode 0))
  (defun my/erc/setup ()
    (set (make-local-variable 'scroll-conservatively) 100)
    (erc-spelling-mode 1)
    (my/erc/line-setup)
    (my/erc/parens-setup))
  (defun my/erc/reset-track-mode ()
    (interactive)
    (setq erc-modified-channels-alist nil)
    (erc-modified-channels-update)
    (erc-modified-channels-display)
    (force-mode-line-update))
  (defun my/erc/connect ()
    (interactive)
    (erc
     :server "irc.freenode.net" :port 6667
     :nick my/erc/default-nick
     :password my/erc/default-password)
    (erc-ssl
     :server "irc.gitter.im" :port 6667
     :full-name my/erc/default-name
     :nick my/erc/default-nick
     :password my/erc/irc-gitter-password)
    ;; (erc :server "irc.oftc.net" :port 6667 :nick my/erc/default-nick)
    )
  :commands (erc erc-tls)
  :secret "erc.el"
  :hook
  (erc-mode . my/erc/setup)
  :custom
  (erc-hide-list '("JOIN" "NICK" "PART" "QUIT" "MODE"))
  ;; autojoin after successful NickServ identification,
  ;; rather than immediately on connecting
  (erc-autojoin-timing 'ident)
  (erc-prompt-for-password nil)
  (erc-autojoin-channels-alist
   '(("freenode.net"
      "#emacs" "#emacs-beginners"
      "#haskell" "#haskell-beginners"
      ;; "#haskell-blah" "#hackage"
      ;; "#haskell-lang" "#haskell-emacs" "#ghc"
      ;; "#hspec"
      ;; "#haskell-in-depth" "#ghcjs" "#haskell-ide-engine"
      "#ocaml"
      "#purescript"
      ;; "#elixir" "#emacs-elixir"
      "#idris" "#agda" "#coq"
      "#nix-lang" "#nixos" "#nixos-chat"
      ;; "#nixos-de" "#nix-darwin"
      "#lisp"
      "#i3"
      ;; "#i3-offtopic"
      )))
  (smartparens-mode 1)
  :config
  ;; Logging:
  (setq
   erc-log-insert-log-on-open nil
   erc-log-channels t
   erc-log-channels-directory "~/.irclogs/"
   erc-save-buffer-on-part t
   erc-hide-timestamps nil)
  (add-hook 'erc-insert-post-hook 'erc-save-buffer-in-logs)
  (add-hook 'erc-mode-hook '(lambda () (when (not (featurep 'xemacs))
                                    (set (make-variable-buffer-local
                                          'coding-system-for-write)
                                         'emacs-mule))))
  (add-hook 'erc-insert-post-hook 'erc-truncate-buffer)
  (setq erc-truncate-buffer-on-save t)
  ;; Truncate buffers so they don't hog core
  (setq erc-max-buffer-size 20000)
  (setq erc-track-exclude-types
        '("JOIN" "NICK" "PART" "QUIT" "MODE"
          "324" "329" "332" "333" "353" "477"))
  ;; Channel-specific prompt
  (setq erc-prompt (lambda () (concat "[" (buffer-name) "]")))
  ;; By default, ERC selects the channel buffers when it
  ;; reconnects. This makes it to connect to channels in the background
  (setq erc-join-buffer 'bury)
  ;; Appearance-related settings
  (setq erc-timestamp-only-if-changed-flag nil
        erc-timestamp-format "%H:%M "
        erc-fill-prefix "          "
        erc-fill-column 78
        erc-insert-timestamp-function 'erc-insert-timestamp-left
        ivy-use-virtual-buffers nil)
  ;; When carrying on a conversation in IRC, most typically you
  ;; want to address the person or people you last addressed.
  ;; This will automatically insert the last recipient after the
  ;; prompt, providing it was less than 3 minutes ago
  (defadvice erc-display-prompt (after conversation-erc-display-prompt activate)
    "Insert last recipient after prompt."
    (let ((previous
           (save-excursion
             (if (and (search-backward-regexp (concat "^[^<]*<" erc-nick ">") nil t)
                      (search-forward-regexp (concat "^[^<]*<" erc-nick ">"
                                                     " *\\([^:]*: ?\\)") nil t))
                 (match-string 1)))))
      ;; when we got something, and it was in the last 3 mins, put it in
      (when (and
             previous
             (> 180 (time-to-seconds
                     (time-since (get-text-property 0 'timestamp previous)))))
        (set-text-properties 0 (length previous) nil previous)
        (insert previous))))
  (erc-track-minor-mode 1)
  (erc-track-mode 1)
  (nmap
    :prefix my/leader
    "/" 'my/erc/connect)
  (nmap 'erc-mode-map
    "C-c r" 'my/erc/reset-track-mode))

Nickname Highlighting for ERC.

(use-package erc-hl-nicks)

A hexchat-like activity overview for ERC channels.

(use-package erc-status-sidebar
  :custom
  (erc-status-sidebar-width 34)
  :config
  (nmap 'erc-mode-map
    "C-c C-s" 'erc-status-sidebar-toggle))

Shows inline clickable youtube thumbnails, info and description in erc buffers. Uses youtube api v3.

(use-package erc-yt
  :config
  (add-to-list 'erc-modules 'youtube)
  (erc-update-modules))

Fetch and show received images in a ERC buffer.

(use-package erc-image
  :config
  (add-to-list 'erc-modules 'image)
  (erc-update-modules))

An Emacs mode for viewing ERC logs.

(use-package erc-view-log)

Pomodoro

Pomidor

(use-package pomidor
 :after general
 :init
 ;; (setq alert-default-style 'mode-line)
 (setq
  alert-default-style
  (if (eq system-type 'darwin) 'osx-notifier 'libnotify))
 ;; use afplay on macOS
 (when (eq system-type 'darwin)
   (setq
    pomidor-play-sound-file
    (lambda (file)
      (start-process
       "my-pomidor-play-sound"
       nil
       "afplay"
       file))))
 (setq
  pomidor-seconds (* 25 60)      ; 25 minutes
  pomidor-break-seconds (* 5 60) ; 5 minutes
  pomidor-sound-tick nil
  pomidor-sound-tack nil)
 :config
 (nmap
   :prefix my/leader
   "x x" 'pomidor
   "x s" 'pomidor-stop
   "x q" 'pomidor-quit
   "x b" 'pomidor-break
   "x r" 'pomidor-reset)
 (nmap 'pomidor-mode-map
   "Q" 'pomidor-quit
   "s" 'pomidor-stop    ; "RET"
   "b" 'pomidor-break   ; "SPC"
   "r" 'pomidor-reset))

RedTick

Provides a little pomodoro timer in the mode-line.

(use-package redtick
 :config
 (nmap
   :prefix my/leader
   "x t" 'redtick))

Recording

(use-package names
  :demand t)

(use-package camcorder
  :after (names)
  :custom
  (output-directory "~/Videos/camcorder")
  (gif-output-directory "~/Pictures/camcorder")
  :config
  (nmap
    :prefix my/leader
    "r r" 'camcorder-record
    "r R" 'camcorder-mode
    "r c" 'camcorder-convert-to-gif))

Statistics

SLOC

(use-package sloc
  :quelpa (sloc :fetcher github :repo "leoliu/sloc.el"))

Uptimes

Provides a simple system for tracking and displaying the uptimes of Emacs sessions.

(use-package uptimes)

Keyfreq

Measure how many time you execute commands. The following blog post explains this in details.

(use-package keyfreq
 :commands
 (keyfreq-mode keyfreq-autosave-mode)
 :config
 (keyfreq-mode 1)
 (keyfreq-autosave-mode 1))

Wakatime

Setup wakatime.

(use-package wakatime-mode
 :init
 (setq
  wakatime-api-key (getenv "WAKATIME_API_KEY")
  wakatime-cli-path "/run/current-system/sw/bin/wakatime")
 :config
 (global-wakatime-mode)
 :diminish wakatime-mode)

Hydra

Install

Install hydra.

(use-package hydra
 :config

Text scale

Define hydra for text scaling.

(defhydra hydra-zoom ()
  "
 ^Zoom^
───────────────────────────────────
"
  ("=" text-scale-increase nil)
  ("k" text-scale-increase "in")
  ("j" text-scale-decrease "out")
  ("+" text-scale-increase "in")
  ("-" text-scale-decrease "out")
  ("0" (text-scale-set 0) "remove"))

Window management

Define window management hydra.

(defhydra hydra-window ()
  "
Movement^^      ^Split^            ^Resize^
────────────────────────────────────────────────────
_h_ ←          _v_ertical          _H_ X←
_j_ ↓          _s_ horizontal      _J_ X↓
_k_ ↑          _U_ undo            _K_ X↑
_l_ →          _R_ reset           _L_ X→
_f_ollow       _d_lt Other
_SPC_ cancel   _o_nly this
"
  ("h" windmove-left)
  ("j" windmove-down)
  ("k" windmove-up)
  ("l" windmove-right)

  ("H" evil-window-increase-width)
  ("J" evil-window-increase-height)
  ("K" evil-window-decrease-height)
  ("L" evil-window-decrease-width)

  ("f" follow-mode)
  ("v"
   (lambda ()
     (interactive)
     (split-window-right)
     (windmove-right))
   )
  ("s"
   (lambda ()
     (interactive)
     (split-window-below)
     (windmove-down))
   )
  ("d" delete-window)
  ("o" delete-other-windows)
  ("i" ace-maximize-window)
  ("U"
   (progn
     (winner-undo)
     (setq this-command 'winner-undo))
   )
  ("R" winner-redo)
  ("SPC" nil))

Rectangle

(defhydra hydra-rectangle ()
  "
^Rectangle^
───────────────────
_m_: mark region
_k_: kill region
_y_: yank region
  "
  ("m" rectangle-mark-mode nil)
  ("y" yank-rectangle nil)
  ("k" kill-rectangle nil)

  ("l" forward-char)
  ("h" backward-char)
  ("j" next-line)
  ("k" previous-line)
  ("0" move-beginning-of-line)
  ("$" move-end-of-line))

Flycheck

(defhydra hydra-flycheck (:color blue)
  "
  ^
  ^Flycheck^          ^Errors^            ^Checker^
  ^────────^──────────^──────^────────────^───────^─────
  _M_ manual          _<_ previous        _?_ describe
  _v_ verify setup    _>_ next            _d_ disable
  ^^                  _f_ check           _m_ mode
  ^^                  _l_ list            _s_ select
  ^^                  ^^                  ^^
  "
  ("<" flycheck-previous-error :color pink)
  (">" flycheck-next-error :color pink)
  ("?" flycheck-describe-checker)
  ("M" flycheck-manual)
  ("d" flycheck-disable-checker)
  ("f" flycheck-buffer)
  ("l" flycheck-list-errors)
  ("m" flycheck-mode)
  ("s" flycheck-select-checker)
  ("v" flycheck-verify-setup))

Yasnippet

(defhydra hydra-yasnippet (:color blue :hint nil)
  "
^YASnippets^
───────────────────────
_i_: insert snippet
_v_: visit snippet files
_n_: new
_r_: reload all
  "
  ("i" yas-insert-snippet)
  ("v" yas-visit-snippet-file :color blue)
  ("n" yas-new-snippet)
  ("r" yas-reload-all))

Macro

(defhydra hydra-macro ()
  "
^Macro^
────────────────────────────
_j_: create new macro
_k_: end creation of new macro
_e_: execute last macro
_n_: insert Counter
  "
  ("j" kmacro-start-macro :color blue)
  ("k" kmacro-end-macro :colocr blue)
  ("e" kmacro-end-or-call-macro-repeat)
  ("n" kmacro-insert-counter))

Org

Base

(defhydra hydra-org/base ()
  "
^Org base^
───────────────
_s_: store link
_l_: insert link

_r_: refile
_t_: insert tag
"
  ("s" org-store-link nil :color blue)
  ("l" org-insert-link nil :color blue)
  ("r" org-refile nil :color blue)
  ("t" org-set-tags-command nil :color blue))

Link

(defhydra hydra-org/link ()
  "
^Org link^
────────────────────────────────────────────────────────
_i_ backward slurp     _o_ forward slurp    _n_ next link
_j_ backward barf      _k_ forward barf     _p_ previous link
"
  ("i" org-link-edit-backward-slurp)
  ("o" org-link-edit-forward-slurp)
  ("j" org-link-edit-backward-barf)
  ("k" org-link-edit-forward-barf)
  ("n" org-next-link)
  ("p" org-previous-link))

Table

(defhydra hydra-org/table ()
  "
^Org table^
──────────────────────────────────────────────────────────
_r_ recalculate     _w_ wrap region      _c_ toggle coordinates
_i_ iterate table   _t_ transpose        _D_ toggle debugger
_B_ iterate buffer  _E_ export table     _d_ edit field
_e_ eval formula    _s_ sort lines       ^^
"
  ("E" org-table-export :color blue)
  ("s" org-table-sort-lines)
  ("d" org-table-edit-field)
  ("e" org-table-eval-formula)
  ("r" org-table-recalculate)
  ("i" org-table-iterate)
  ("B" org-table-iterate-buffer-tables)
  ("w" org-table-wrap-region)
  ("D" org-table-toggle-formula-debugger)
  ("t" org-table-transpose-table-at-point)
  ("c" org-table-toggle-coordinate-overlays :color blue))

Babel

(defhydra hydra-org/babel ()
  "
^Org babel^
────────────────────────────────────────────────
_n_ next       _i_ info           _I_ insert header
_p_ prev       _c_ check          _e_ examplify region
_h_ goto head  _E_ expand         ^^
^^             _s_ split          ^^
^^             _r_ remove result  ^^
"
  ("i" org-babel-view-src-block-info)
  ("I" org-babel-insert-header-arg)
  ("c" org-babel-check-src-block :color blue)
  ("s" org-babel-demarcate-block :color blue)
  ("n" org-babel-next-src-block)
  ("p" org-babel-previous-src-block)
  ("E" org-babel-expand-src-block :color blue)
  ("e" org-babel-examplify-region :color blue)
  ("r" org-babel-remove-result :color blue)
  ("h" org-babel-goto-src-block-head))

Help

(defhydra hydra-help ()
  "
^Help^
────────────────────────────
_f_: callable
_F_: function
_v_: variable
_c_: command
_k_: key
_m_: mode
_l_: view lossage
_M_: view messages
"
  ("M" view-echo-area-messages :color blue)
  ("f" helpful-callable :color blue)
  ("F" helpful-function :color blue)
  ("v" helpful-variable :color blue)
  ("c" helpful-command :color blue)
  ("k" helpful-key :color blue)
  ("m" describe-mode :color blue)
  ("l" view-lossage :color blue))

Packages

(defhydra hydra-packages ()
  "
^Packages^
─────────────────
_l_: list
_r_: refresh
_d_: delete
_e_: describe
_i_: install
_f_: install file
"
  ("l" package-list-packages)
  ("r" package-refresh-contents)
  ("d" package-delete)
  ("i" package-install)
  ("f" package-install-file)
  ("e" describe-package))

Search online

(defhydra hydra-search-online ()
  "
  ^
^Search Online^
────────────────────────────────────────────────────────
_g_: google         _y_: youtube           _t_: twitter
_t_: translate      _u_: urban dictionary  _m_: melpa
_w_: wikipedia      _h_: hoogle            _M_: google maps
_s_: stack overflow _H_: hackage           _i_: google images
_G_: github         _p_: pursuit           _d_: duckduckgo
  "
  ("g" engine/search-google)
  ("t" engine/search-google-translate)
  ("w" engine/search-wikipedia)
  ("s" engine/search-stack-overflow)
  ("G" engine/search-github)
  ("y" engine/search-youtube)
  ("u" engine/search-urban-dictionary)
  ("h" engine/search-hoogle)
  ("H" engine/search-hackage)
  ("p" engine/search-pursuit)
  ("m" engine/search-melpa)
  ("T" engine/search-twitter)
  ("M" engine/search-google-maps)
  ("i" engine/search-google-images)
  ("d" engine/search-duckduckgo))

Key bindings

(nmap
  :prefix my/leader+
  "f" 'hydra-flycheck/body
  "h" 'hydra-help/body
  "o o" 'hydra-org/base/body
  "o l" 'hydra-org/link/body
  "o t" 'hydra-org/table/body
  "o b" 'hydra-org/babel/body
  "r" 'hydra-rectangle/body
  "m" 'hydra-macro/body
  "p" 'hydra-packages/body
  "C-SPC" 'hydra-search-online/body
  "S" 'hydra-yasnippet/body
  "t" 'hydra-zoom/body
  "w" 'hydra-window/body))

Delight

(use-package delight
 :config
 (delight
  '((emacs-lisp-mode "elisp" :major)
    (ruby-mode "ruby" :major)
    (elixir-mode "ex" elixir)
    (alchemist-mode "al" alchemist)
    (alchemist-hex-mode "alhex" alchemist)
    (alchemist-test-mode "altest" alchemist)
    (rust-mode "rs" rust)
    (purescript-mode "purs" purescript)
    (javascript-mode "js" js)
    (eldoc-mode "eldoc" eldoc)
    (outline-minor-mode "outl" outline)
    ;; (hi-lock-mode "hi" hi-lock)
    (subword-mode "sw" subword))))

Diminish

Hide minor modes to save space.

(use-package diminish
 :config
 (diminish 'abbrev-mode)
 (diminish 'auto-fill-function)
 (with-eval-after-load 'face-remap (diminish 'buffer-face-mode))
 (with-eval-after-load 'with-editor (diminish 'with-editor-mode))
 (eval-after-load "purescript-indentation" '(diminish 'purescript-indentation-mode))
 (eval-after-load "dired" '(diminish 'dired-omit-mode))
 (eval-after-load "hideshow" '(diminish 'hs-minor-mode))
 (eval-after-load "eldoc" '(diminish 'eldoc-mode))
 (eval-after-load "hi-lock" '(diminish 'hi-lock-mode)))

Finalize

Restore the frequency of garbage collections.

(setq gc-cons-threshold (* 2 1000 1000))

emacs.d's People

Contributors

vyorkin avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.