Skip to content

Latest commit

 

History

History
1942 lines (1670 loc) · 53.3 KB

README.org

File metadata and controls

1942 lines (1670 loc) · 53.3 KB

Foreword and keynotes

Use-package

Use-package is an Emacs configuration manager (not a package manager!) that allows you to keep init file(s) clean, tidy and declarative.

  • use it for built-in packages/libraries too (without :ensure t)
  • each variable/face setting or each function call belongs to the one and only package which provides the symbol

To find out, where do they belong to, use M-x describe-variable, M-x describe-face or M-x describe-function accordingly.

Setting variables

“Traditional” setq is almost always means changing a customizable variable, so can be rewritten with customize-set-variable and therefore with :custom keyword, it supports inline comments. Besides that some defcustoms have get/set functions so setq-ing will have no effect unless you run a setter manually .

At the same time I don’t use Customization interface, and my own custom-file is =/dev/null=.

An example

;; "Don't show splash screen"
(setq inhibit-startup-screen t)

becomes

:custom
(inhibit-startup-screen t "Don't show splash screen")

Faces

There’s :custom-face, so

(set-face-attributes 'Man-overstrike nil :inherit font-lock-type-face :bold t)

becomes

:custom-face
(Man-overstrike ((t (:inherit font-lock-type-face :bold t))))

Hardcoded faces can break themes, so I use :inherit for customizations, if possible.

Hooks

add-hook:hook

Key-binding

define-key:bind

Sequential loading

use :after if you want to load a package after another one

Installing packages from source code

There are several ways to do it, but I prefer Quelpa since it’s compatible with Emacs Package manager

Definitions

I put all defuns to separate packages/libraries to keep the config declarative

More on key-binding

  • I try not to hardcode bindings starting with C-x, C-c and C-h, which are bound to ctl-x-map, mode-specific-map and help-map respectively. Not that I’m not happy with all these defaults (except C-h, see simple package below), but I want to be able to rebind them to something else (SPC, mouse-1, break, gas or whatever), at least for my own bindings — sadly, some plugins hardcode them (and that causes issues for alternative bindings users), but I hope it will change someday.
  • I use named prefix keymaps so they are visible in minibuffer while Which-key is active.
  • I use remap if I want to rebind a command to a “better” version of it and do an explicit keys declaration when I rebind it to something completely different.
  • Where mnemonics conflicts with ergonomics - prefer the former.

Package system

Initialization

By default, Emacs knows about GNU ELPA only, add some more repositories.

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

(require 'package)
(customize-set-variable 'package-archives
                        `(("melpa" . "https://melpa.org/packages/")
                          ,@package-archives))
(customize-set-variable 'package-enable-at-startup nil)
(package-initialize)

Use-package installation and setup

It can’t install itself so we have to bootstrap it

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

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

(put 'use-package 'lisp-indent-function 1)

(use-package use-package-core
  :custom
  ;; (use-package-verbose t)
  ;; (use-package-minimum-reported-time 0.005)
  (use-package-enable-imenu-support t))

Now we can enable the Garbage Collector Magic Hack

(use-package gcmh
  :ensure t
  :demand t
  :config
  (gcmh-mode 1))

Use use-package to extend its own functionality by some more useful keywords.

(use-package system-packages
  :ensure t
  :custom
  (system-packages-noconfirm t))

(use-package use-package-ensure-system-package :ensure t)

Quelpa “is a tool to compile and install Emacs Lisp packages locally from local or remote source code”

(use-package quelpa
  :ensure t
  :defer t
  :custom
  (quelpa-update-melpa-p nil "Don't update the MELPA git repo."))

(use-package quelpa-use-package
  :ensure t)

No more manual package installation, now we can install packages directly from github.

This one tries to speed up Emacs startup a little bit

(use-package fnhh
  :quelpa
  (fnhh :repo "a13/fnhh" :fetcher github)
  :config
  (fnhh-mode 1))

This adds :custom-update keyword to use-package.

(use-package use-package-custom-update
  :quelpa
  (use-package-custom-update
   :repo "a13/use-package-custom-update"
   :fetcher github
   :version original))

Try packages without installing

(use-package try
  :ensure t
  :defer t)
(use-package paradox
  :ensure t
  :defer 1
  :config
  (paradox-enable))

Global defaults

Common

These were defined in C code, so use emacs pseudo-package to set them.

(use-package emacs
  :load-path "secrets"
  :init
  (put 'narrow-to-region 'disabled nil)
  (put 'downcase-region 'disabled nil)
  (fset 'x-popup-menu #'ignore)
  :custom
  (frame-resize-pixelwise t)
  (default-frame-alist '((menu-bar-lines 0)
                         (tool-bar-lines 0)
                         (vertical-scroll-bars)))
  (scroll-step 1)
  (inhibit-startup-screen t "Don't show splash screen")
  (use-dialog-box nil "Disable dialog boxes")
  (x-gtk-use-system-tooltips nil)
  (use-file-dialog nil)
  (enable-recursive-minibuffers t "Allow minibuffer commands in the minibuffer")
  (indent-tabs-mode nil "Spaces!")
  (tab-width 4)
  (debug-on-quit nil)
  :config
  ;; Terminal emacs doesn't have it
  (when (fboundp 'set-fontset-font)
    ;; a workaround for old charsets
    (set-fontset-font "fontset-default" 'cyrillic
                      (font-spec :registry "iso10646-1" :script 'cyrillic))
    ;; TODO: is it possible to not hardcode fonts?
    (set-fontset-font t 'symbol
                      (font-spec :family
                                 (if (eq system-type 'darwin)
                                     "Apple Color Emoji"
                                   "Symbola"))
                      nil 'prepend)))

Default keybindings customization and other built-in settings

Disable suspending on C-z

(use-package frame
  :bind
  ("C-z" . nil)
  :custom
  (initial-frame-alist '((vertical-scroll-bars))))

C-c C-g always quits minubuffer

(use-package delsel
  :bind
  (:map mode-specific-map
        ("C-g" . minibuffer-keyboard-quit)))

Make C-w and C-h kill a word/char before cursor (see Unix keyboard shortcuts, don’t know what to do with C-u though).

NB: rebinding C-h breaks M-x kmacro-edit-lossage, so you have to use something like M-x edit-kbd-macro RET F1-l instead.

(use-package simple
  :defer 0.1
  :custom
  (kill-ring-max 30000)
  (column-number-mode 1)
  :config
  (toggle-truncate-lines 1)
  :bind
  ;; remap ctrl-w/ctrl-h
  (("C-w" . backward-kill-word)
   ("C-h" . delete-backward-char)
   :map ctl-x-map
   ("C-k" . kill-region)
   ("K" . kill-current-buffer)))

But we still need to access help somehow

(use-package help
  :defer t
  :bind
  (("C-?" . help-command)
   :map mode-specific-map
   ("h" . help-command)))

Who uses list-buffers?

(use-package ibuffer
  :bind
  ([remap list-buffers] . ibuffer))

Files

Saving

(use-package files
  :hook
  (before-save . delete-trailing-whitespace)
  :custom
  (require-final-newline t)
  ;; backup settings
  (backup-by-copying t)
  (backup-directory-alist
   `((".*" . ,(locate-user-emacs-file "backups"))))
  (delete-old-versions t)
  (kept-new-versions 6)
  (kept-old-versions 2)
  (version-control t))

(use-package autorevert
  :defer 0.1)
(use-package recentf
  :defer 0.1
  :custom
  (recentf-auto-cleanup 30)
  :config
  (recentf-mode)
  (run-with-idle-timer 30 t 'recentf-save-list))

Quick access to init files

(use-package iqa
  :ensure t
  :custom
  (iqa-user-init-file (locate-user-emacs-file "README.org")
                      "Edit README.org by default.")
  :config
  (iqa-setup-default))

I don’t use Customize, so put custom-file “nowhere”.

(use-package cus-edit
  :defer t
  :custom
  ;; (custom-file (make-temp-file "emacs-custom") "Store customizations in a temp file")
  (custom-file null-device "Don't store customizations"))

Somehow file-related too

(use-package vlf
  :defer t
  :ensure t
  :after (ivy counsel)
  :init
  (ivy-add-actions 'counsel-find-file '(("l" vlf "view large file"))))

(use-package epa
  :defer t
  :custom
  (epg-gpg-program "gpg")
  (epa-pinentry-mode nil))

(use-package uniquify
  :defer 0.1
  :custom
  (uniquify-buffer-name-style 'forward))

Tramp

(use-package tramp
  :defer t
  :config
  (put 'temporary-file-directory 'standard-value `(,temporary-file-directory))
  :custom
  (tramp-backup-directory-alist backup-directory-alist)
  (tramp-default-method "ssh")
  (tramp-default-proxies-alist nil))

(use-package sudo-edit
  :ensure t
  :config (sudo-edit-indicator-mode)
  :bind (:map ctl-x-map
              ("M-s" . sudo-edit)))

Uncategorized

Get environment variables from the shell

(use-package exec-path-from-shell
  :ensure t
  :defer 0.1
  :config
  (exec-path-from-shell-initialize))

(use-package xr
  :ensure t
  :defer t)

Eshell

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

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

(use-package esh-autosuggest
  :ensure t
  :hook (eshell-mode . esh-autosuggest-mode))

(use-package esh-module
  :defer t
  :custom-update
  (eshell-modules-list '(eshell-tramp)))

(use-package eshell-prompt-extras
  :ensure t
  :after (eshell esh-opt)
  :custom
  (eshell-prompt-function #'epe-theme-dakrone))

(use-package eshell-toggle
  :ensure t
  :after projectile
  :custom
  (eshell-toggle-use-projectile-root t)
  (eshell-toggle-run-command nil)
  :bind
  ("M-`" . eshell-toggle))

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

Dired

(use-package ls-lisp
  :defer t
  :custom
  (ls-lisp-emulation 'MS-Windows)
  (ls-lisp-ignore-case t)
  (ls-lisp-verbosity nil))

(use-package dired
  :custom (dired-dwim-target t "guess a target directory")
  :hook
  (dired-mode . dired-hide-details-mode))

(use-package dired-x
  :bind
  ([remap list-directory] . dired-jump)
  :custom
  ;; do not bind C-x C-j since it's used by jabber.el
  (dired-bind-jump nil))

(use-package dired-toggle
  :ensure t
  :defer t)

(use-package dired-hide-dotfiles
  :ensure t
  :bind
  (:map dired-mode-map
        ("." . dired-hide-dotfiles-mode))
  :hook
  (dired-mode . dired-hide-dotfiles-mode))

(use-package diredfl
  :ensure t
  :hook
  (dired-mode . diredfl-mode))

(use-package async
  :ensure t
  :defer t
  :custom
  (dired-async-mode 1))

(use-package dired-rsync
  :ensure t
  :bind
  (:map dired-mode-map
        ("r" . dired-rsync)))

(use-package dired-launch
  :ensure t
  :hook
  (dired-mode . dired-launch-mode))

(use-package dired-git-info
  :ensure t
  :bind
  (:map dired-mode-map
        (")" . dired-git-info-mode)))

(use-package dired-recent
  :ensure t
  :bind
  (:map
   dired-recent-mode-map ("C-x C-d" . nil))
  :config
  (dired-recent-mode 1))

Interface

Localization

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

(use-package ispell
  :defer t
  :custom
  (ispell-local-dictionary-alist
   '(("russian"
      "[АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщьыъэюяіїєґ’A-Za-z]"
      "[^АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщьыъэюяіїєґ’A-Za-z]"
      "[-']"  nil ("-d" "uk_UA,ru_RU,en_US") nil utf-8)))
  (ispell-program-name "hunspell")
  (ispell-dictionary "russian")
  (ispell-really-aspell nil)
  (ispell-really-hunspell t)
  (ispell-encoding8-command t)
  (ispell-silently-savep t))

(use-package flyspell
  :defer t
  :custom
  (flyspell-delay 1))

(use-package flyspell-correct-ivy
  :ensure t
  :bind (:map flyspell-mode-map
              ("C-c $" . flyspell-correct-at-point)))

Fonts

Provide face-font-family-alternatives for all the fonts we are going to use to avoid errors in case of their absense.

(use-package faces
  :custom
  (face-font-family-alternatives
   '(("Monospace" "courier" "fixed")
     ("Consolas" "Monaco" "Roboto Mono" "PT Mono" "Terminus" "Monospace")
     ("Monospace Serif" "CMU Typewriter Text" "Courier 10 Pitch" "Monospace")
     ("Serif" "Alegreya" "CMU Serif" "Georgia" "Cambria" "Times New Roman" "DejaVu Serif" "serif")))
  :custom-face
  (variable-pitch ((t (:family "Serif" :height 135))))
  (fixed-pitch ((t (:family "Monospace Serif" :height 125))))
  (default ((t (:family "Monospace Serif" :height 125)))))

(use-package font-lock
  :defer t
  :custom-face
  (font-lock-comment-face ((t (:inherit font-lock-comment-face :italic t))))
  (font-lock-doc-face ((t (:inherit font-lock-doc-face :italic t))))
  (font-lock-string-face ((t (:inherit font-lock-string-face :italic t)))))

Color themes

(use-package open-color
  :quelpa
  (open-color :repo "a13/open-color.el" :fetcher github :version original))

(use-package lor-oc-theme
  :config
  (load-theme 'lor-oc t)
  :load-path "/home/dk/git/lor-theme"
  ;; :quelpa
  ;; (lor-theme :repo "a13/lor-theme" :fetcher github :version original)
  )

GUI

(Almost) smooth mouse scrolling

(use-package mwheel
  :custom
  (mouse-wheel-scroll-amount '(1
                               ((shift) . 5)
                               ((control))))
  (mouse-wheel-progressive-speed nil))

(use-package pixel-scroll
  :config
  (pixel-scroll-mode))

Disable gui elements we don’t need:

(use-package tooltip
  :defer t
  :custom
  (tooltip-mode -1))

Add those we want instead:

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

(use-package fancy-battery
  :ensure t
  :hook
  (after-init . fancy-battery-mode))

Fancy stuff

(use-package olivetti
  :defer t
  :ensure t
  :custom
  (olivetti-body-width 95))

(use-package font-lock+
  :defer t
  :quelpa
  (font-lock+ :repo "emacsmirror/font-lock-plus" :fetcher github))

(use-package all-the-icons
  :ensure t
  :defer t
  :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))))

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

(use-package all-the-icons-ivy
  :defer t
  :ensure t
  :after ivy
  :custom
  (all-the-icons-ivy-buffer-commands '() "Don't use for buffers.")
  :config
  (all-the-icons-ivy-setup))

(use-package mood-line
  :ensure t
  :custom-face
  (mode-line ((t (:inherit default (:box (:line-width -1 :style released-button))))))
  :hook
  (after-init . mood-line-mode))

And the winner is…

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

Highlighting

(use-package paren
  :config
  (show-paren-mode t))

(use-package hl-line
  :hook
  (prog-mode . hl-line-mode))

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

(use-package highlight-escape-sequences
  :ensure t
  :config (hes-mode))

(use-package hl-todo
  :ensure t
  :custom-face
  (hl-todo ((t (:inherit hl-todo :italic t))))
  :hook ((prog-mode . hl-todo-mode)
         (yaml-mode . hl-todo-mode)))

(use-package page-break-lines
  :ensure t
  :hook
  (help-mode . page-break-lines-mode)
  (prog-mode . page-break-lines-mode)
  (special-mode . page-break-lines-mode)
  (compilation-mode . page-break-lines-mode))

(use-package rainbow-delimiters
  :ensure t
  :hook
  (prog-mode . rainbow-delimiters-mode))

(use-package rainbow-identifiers
  :ensure t
  :custom
  (rainbow-identifiers-cie-l*a*b*-lightness 80)
  (rainbow-identifiers-cie-l*a*b*-saturation 50)
   ;; (rainbow-identifiers-choose-face-function
   ;;  #'rainbow-identifiers-cie-l*a*b*-choose-face)
  :hook
  (emacs-lisp-mode . rainbow-identifiers-mode) ; actually, turn it off
  (prog-mode . rainbow-identifiers-mode))

(use-package rainbow-mode
  :ensure t
  :hook '(prog-mode help-mode))

(use-package so-long
  :quelpa (so-long :url "https://raw.githubusercontent.com/emacs-mirror/emacs/master/lisp/so-long.el" :fetcher url)
  :config (global-so-long-mode))

Minibuffer (search, commands)

I prefer Ivy/Counsel/Swiper over Helm

;; counsel-M-x can use this one
(use-package amx :ensure t :defer t)

(use-package ivy
  :ensure t
  :custom
  ;; (ivy-re-builders-alist '((t . ivy--regex-fuzzy)))
  (ivy-count-format "%d/%d " "Show anzu-like counter")
  (ivy-use-selectable-prompt t "Make the prompt line selectable")
  :custom-face
  (ivy-current-match ((t (:inherit 'hl-line))))
  :bind
  (:map mode-specific-map
        ("C-r" . ivy-resume))
  :config
  (ivy-mode t))

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

(use-package counsel
  :ensure t
  :bind
  (([remap menu-bar-open] . counsel-tmm)
   ([remap insert-char] . counsel-unicode-char)
   ([remap isearch-forward] . counsel-grep-or-swiper)
   :map mode-specific-map
   :prefix-map counsel-prefix-map
   :prefix "c"
   ("a" . counsel-apropos)
   ("b" . counsel-bookmark)
   ("B" . counsel-bookmarked-directory)
   ("c w" . counsel-colors-web)
   ("c e" . counsel-colors-emacs)
   ("d" . counsel-dired-jump)
   ("f" . counsel-file-jump)
   ("F" . counsel-faces)
   ("g" . counsel-org-goto)
   ("h" . counsel-command-history)
   ("H" . counsel-minibuffer-history)
   ("i" . counsel-imenu)
   ("j" . counsel-find-symbol)
   ("l" . counsel-locate)
   ("L" . counsel-find-library)
   ("m" . counsel-mark-ring)
   ("o" . counsel-outline)
   ("O" . counsel-find-file-extern)
   ("p" . counsel-package)
   ("r" . counsel-recentf)
   ("s g" . counsel-grep)
   ("s r" . counsel-rg)
   ("s s" . counsel-ag)
   ("t" . counsel-org-tag)
   ("v" . counsel-set-variable)
   ("w" . counsel-wmctrl)
   :map help-map
   ("F" . counsel-describe-face))
  :custom
  (counsel-grep-base-command
   "rg -i -M 120 --no-heading --line-number --color never %s %s")
  (counsel-search-engines-alist
   '((google
      "http://suggestqueries.google.com/complete/search"
      "https://www.google.com/search?q="
      counsel--search-request-data-google)
     (ddg
      "https://duckduckgo.com/ac/"
      "https://duckduckgo.com/html/?q="
      counsel--search-request-data-ddg)))
  :init
  (counsel-mode))

(use-package swiper :ensure t)

(use-package counsel-web
  :defer t
  :quelpa
  (counsel-web :repo "mnewt/counsel-web" :fetcher github))

(use-package counsel-world-clock
  :ensure t
  :after counsel
  :bind
  (:map counsel-prefix-map
        ("C" .  counsel-world-clock)))

(use-package ivy-rich

  :ensure t
  :config
  (ivy-rich-project-root-cache-mode t)
  (ivy-rich-mode 1))

(use-package helm-make
  :defer t
  :ensure t
  :custom (helm-make-completion-method 'ivy))

Usually, I don’t use isearch, but just in case

(use-package isearch
  :bind
  ;; TODO: maybe get a keybinding from global map
  (:map isearch-mode-map
        ("C-h" . isearch-delete-char)))

(use-package char-fold
  :defer 0.2
  :custom
  (char-fold-symmetric t)
  (search-default-mode #'char-fold-to-regexp)
  :quelpa (char-fold :url "https://raw.githubusercontent.com/emacs-mirror/emacs/master/lisp/char-fold.el"
                     :fetcher url))

Indicate minibuffer depth

(use-package mb-depth
  :config
  (minibuffer-depth-indicate-mode 1))

Quick jumps

Ace-jump is dead, long live Avy!

(use-package avy
  :ensure t
  :bind
  (("C-:" .   avy-goto-char-timer)
   ("C-." .   avy-goto-word-1)
   :map goto-map
   ("M-g" . avy-goto-line)
   :map search-map
   ("M-s" . avy-goto-word-1)))

(use-package ivy-avy
  :after (ivy avy)
  :ensure t)

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

(use-package ace-jump-buffer
  :ensure t
  :bind
  (:map goto-map
        ("b" . ace-jump-buffer)))

(use-package ace-window
  :ensure t
  :custom
  (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l) "Use home row for selecting.")
  (aw-scope 'frame "Highlight only current frame.")
  :bind
  ("M-o" . ace-window))

(use-package link-hint
  :ensure t
  :bind
  (("<XF86Search>" . link-hint-open-link)
   ("S-<XF86Search>" . link-hint-copy-link)
   :map mode-specific-map
   :prefix-map link-hint-keymap
   :prefix "l"
   ("o" . link-hint-open-link)
   ("c" . link-hint-copy-link)))

(use-package ace-link
  :ensure t
  :after link-hint ; to use prefix keymap
  :bind
  (:map link-hint-keymap
        ("l" . counsel-ace-link))
  :config
  (ace-link-setup-default))

Regions/Kill ring/Clipboard

(use-package select
  :custom
  (selection-coding-system 'utf-8)
  (select-enable-clipboard t "Use the clipboard"))

(use-package expand-region
  :ensure t
  :bind
  (("C-=" . er/expand-region)
   ("C-+" . er/contract-region)
   :map mode-specific-map
   :prefix-map region-prefix-map
   :prefix "r"
   ("(" . er/mark-inside-pairs)
   (")" . er/mark-outside-pairs)
   ("'" . er/mark-inside-quotes)
   ([34] . er/mark-outside-quotes) ; it's just a quotation mark
   ("o" . er/mark-org-parent)
   ("u" . er/mark-url)
   ("b" . er/mark-org-code-block)
   ("." . er/mark-method-call)
   (">" . er/mark-next-accessor)
   ("w" . er/mark-word)
   ("d" . er/mark-defun)
   ("e" . er/mark-email)
   ("," . er/mark-symbol)
   ("<" . er/mark-symbol-with-prefix)
   (";" . er/mark-comment)
   ("s" . er/mark-sentence)
   ("S" . er/mark-text-sentence)
   ("p" . er/mark-paragraph)
   ("P" . er/mark-text-paragraph)))

(use-package elec-pair
  :config
  (electric-pair-mode))

(use-package edit-indirect
  :ensure t
  :after expand-region ; to use region-prefix-map
  :bind
  (:map region-prefix-map
        ("r" . edit-indirect-region)))

(use-package clipmon
  :ensure t
  :defer 0.1
  :config
  (clipmon-mode))

(use-package copy-as-format
  :ensure t
  :custom
  (copy-as-format-default "slack" "or Telegram")
  :bind
  (:map mode-specific-map
        :prefix-map copy-as-format-prefix-map
        :prefix "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)
        ("c" . copy-as-format-hipchat)
        ("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)))

(use-package hungry-delete
  :ensure t
  :hook
  (text-mode . hungry-delete-mode)
  (prog-mode . hungry-delete-mode))

Help

(use-package man
  :defer t
  :custom
  (Man-notify-method 'pushy "show manpage HERE")
  :custom-face
  (Man-overstrike ((t (:inherit font-lock-type-face :bold t))))
  (Man-underline ((t (:inherit font-lock-keyword-face :underline t)))))

(use-package woman
  :defer t
  :custom-face
  (woman-bold ((t (:inherit font-lock-type-face :bold t))))
  (woman-italic ((t (:inherit font-lock-keyword-face :underline t)))))

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

(use-package keyfreq
  :defer 0.1
  :ensure t
  :config
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1))

(use-package which-key
  :ensure t
  :custom
  (which-key-show-transient-maps t)
  :config
  (which-key-mode))

(use-package free-keys
  :ensure t
  :defer t
  :commands free-keys)

(use-package helpful
  :ensure t
  :defer t)

Internet

Jabber

;; (use-package jabber
;;   :defer t
;;   :config
;;   (setq jabber-history-enabled t
;;         jabber-use-global-history nil
;;         fsm-debug nil)
;;   :custom
;;   (jabber-auto-reconnect t)
;;   (jabber-chat-buffer-format "*-jc-%n-*")
;;   (jabber-groupchat-buffer-format "*-jg-%n-*")
;;   (jabber-chat-foreign-prompt-format "▼ [%t] %n> ")
;;   (jabber-chat-local-prompt-format "▲ [%t] %n> ")
;;   (jabber-muc-colorize-foreign t)
;;   (jabber-muc-private-buffer-format "*-jmuc-priv-%g-%n-*")
;;   (jabber-rare-time-format "%e %b %Y %H:00")
;;   (jabber-resource-line-format "   %r - %s [%p]")
;;   (jabber-roster-buffer "*-jroster-*")
;;   (jabber-roster-line-format "%c %-17n")
;;   (jabber-roster-show-bindings nil)
;;   (jabber-roster-show-title nil)
;;   (jabber-roster-sort-functions (quote (jabber-roster-sort-by-status jabber-roster-sort-by-displayname jabber-roster-sort-by-group)))
;;   (jabber-show-offline-contacts nil)
;;   (jabber-show-resources nil))

;; (use-package jabber-otr
;;   :ensure t
;;   :defer t)

;; (use-package secrets-jabber
;;   :defer t
;;   :load t
;;   :after jabber)

;; (use-package point-im
;;   :defer t
;;   :defines point-im-reply-id-add-plus
;;   :after jabber
;;   :quelpa
;;   (point-im :repo "a13/point-im.el" :fetcher github :version original)
;;   :custom
;;   (point-im-reply-id-add-plus nil)
;;   :hook
;;   (jabber-chat-mode . point-im-mode))

Slack

(use-package slack
  :ensure t
  :defer t
  :commands (slack-start)
  :custom
  (slack-buffer-emojify t "enable emoji")
  (slack-prefer-current-team t))

;; (use-package secrets-slack
;;   :load t
;;   :after slack)

;; TODO: move somewhere
(use-package alert
  :defer t
  :ensure t
  :commands (alert)
  :custom
  (alert-default-style 'libnotify))

Web

(use-package shr
  :defer t
  :custom
  (shr-use-fonts nil))

(use-package shr-color
  :defer t
  :custom
  (shr-color-visible-luminance-min 80 "Improve the contrast"))

(use-package eww
  :defer t
  :custom
  (eww-search-prefix "https://duckduckgo.com/html/?kd=-1&q="))

(use-package browse-url
  :bind
  ([f5] . browse-url))

(use-package bruh
  :defer t
  :after browse-url
  :quelpa
  (bruh :repo "a13/bruh" :fetcher github)
  :custom-update
  (bruh-images-re
   '("^https?://img-fotki\\.yandex\\.ru/get/"
     "^https?://pics\\.livejournal\\.com/.*/pic/"
     "^https?://l-userpic\\.livejournal\\.com/"
     "^https?://img\\.leprosorium\\.com/[0-9]+$"))
  :custom
  (browse-url-browser-function #'bruh-browse-url)
  (bruh-default-browser #'bruh-chromium-new-app)
  (bruh-videos-browser-function #'bruh-mpv))


(use-package webjump
  :bind
  (([S-f5] . webjump))
  :config
  (setq webjump-sites
        (append '(("debian packages" .
                   [simple-query "packages.debian.org" "http://packages.debian.org/" ""]))
                webjump-sample-sites)))

(use-package atomic-chrome
  :defer 0.3
  :ensure t
  :custom
  (atomic-chrome-url-major-mode-alist
   '(("reddit\\.com" . markdown-mode)
     ("github\\.com" . gfm-mode)
     ("redmine" . textile-mode))
   "Major modes for URLs.")
  :config
  (atomic-chrome-start-server))

(use-package shr-tag-pre-highlight
  :ensure t
  ;;:defer t
  :after shr
  :custom-update
  (shr-external-rendering-functions
   '((pre . shr-tag-pre-highlight))))

(use-package google-this
  :defer 0.1
  :ensure t
  :bind
  (:map mode-specific-map
        ("g" . #'google-this-mode-submap)))

(use-package multitran
  :ensure t
  :defer t)

(use-package imgbb
  :ensure t
  :defer t)

Org

(use-package calendar
  :defer t
  :custom
  (calendar-week-start-day 1))

(use-package org
  :defer t
  ;; to be sure we have the latest Org version
  ;; :ensure org-plus-contrib
  :hook
  (org-mode . variable-pitch-mode)
  (org-mode . visual-line-mode)
  :custom
  (org-adapt-indentation t)
  (org-src-tab-acts-natively t))

;; (use-package org-passwords
;;   :ensure org-plus-contrib
;;   :bind
;;   (:map org-mode-map
;;         ("C-c C-p p" . org-passwords-copy-password)
;;         ("C-c C-p u" . org-passwords-copy-username)
;;         ("C-c C-p o" . org-passwords-open-url)))

 (use-package org-bullets
  :ensure t
  :custom
  ;; org-bullets-bullet-list
  ;; default: "◉ ○ ✸ ✿"
  ;; large: ♥ ● ◇ ✚ ✜ ☯ ◆ ♠ ♣ ♦ ☢ ❀ ◆ ◖ ▶
  ;; Small: ► • ★ ▸
  (org-bullets-bullet-list '(""))
  ;; others: ▼, ↴, ⬎, ⤷,…, and ⋱.
  ;; (org-ellipsis "⤵")
  (org-ellipsis "")
  :hook
  (org-mode . org-bullets-mode))

(use-package htmlize
  :ensure t
  :defer t
  :custom
  (org-html-htmlize-output-type 'css)
  (org-html-htmlize-font-prefix "org-"))

(use-package org-jira
  :defer t
  :ensure t
  :init
  (make-directory "~/.org-jira" t))

;; (use-package secrets-jira)

Writing

Thesaurus

(use-package synosaurus
  :defer t
  :ensure t
  :custom
  (synosaurus-choose-method 'default)
  :config
  (synosaurus-mode))

Style

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

(use-package flycheck-grammarly
  :defer t
  :quelpa
  (flycheck-grammarly :repo "jcs-elpa/flycheck-grammarly"  :fetcher github))

Programming-related

(use-package ibuffer-vc
  :defer t
  :ensure t
  :config
  (define-ibuffer-column icon
    (:name "Icon" :inline t)
    (all-the-icons-ivy--icon-for-mode major-mode))
  :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)))))

(use-package git-modes
  :ensure t
  :defer t)

(use-package generic-x)

(use-package magit
  :ensure t
  :custom
  (magit-clone-default-directory (expand-file-name "~/git/"))
  (magit-completing-read-function 'ivy-completing-read "Force Ivy usage.")
  :bind
  (:map mode-specific-map
        :prefix-map magit-prefix-map
        :prefix "m"
        (("a" . magit-stage-file) ; the closest analog to git add
         ("b" . magit-blame)
         ("B" . magit-branch)
         ("c" . magit-checkout)
         ("C" . magit-commit)
         ("d" . magit-diff)
         ("D" . magit-discard)
         ("f" . magit-fetch)
         ("g" . vc-git-grep)
         ("G" . magit-gitignore)
         ("i" . magit-init)
         ("l" . magit-log)
         ("m" . magit)
         ("M" . magit-merge)
         ("n" . magit-notes-edit)
         ("p" . magit-pull-branch)
         ("P" . magit-push-current)
         ("r" . magit-reset)
         ("R" . magit-rebase)
         ("s" . magit-status)
         ("S" . magit-stash)
         ("t" . magit-tag)
         ("T" . magit-tag-delete)
         ("u" . magit-unstage)
         ("U" . magit-update-index))))

(use-package forge
  :defer t
  :after magit
  :ensure t)

(use-package git-timemachine
  :ensure t
  :defer t)

(use-package browse-at-remote
  :ensure t
  :after link-hint
  :bind
  (:map link-hint-keymap
        ("r" . browse-at-remote)
        ("k" . browse-at-remote-kill)))

(use-package smerge-mode
  :defer t)

(use-package diff-hl
  :ensure t
  :hook
  ((magit-post-refresh . diff-hl-magit-post-refresh)
   (prog-mode . diff-hl-mode)
   (org-mode . diff-hl-mode)
   (dired-mode . diff-hl-dired-mode)))

(use-package smart-comment
  :ensure t
  :bind ("M-;" . smart-comment))

(use-package projectile
  :defer 0.2
  :ensure t
  :bind
  (:map mode-specific-map ("p" . projectile-command-map))
  :custom
  (projectile-create-missing-test-files t)
  (projectile-project-root-files-functions
   '(projectile-root-local
     projectile-root-top-down
     projectile-root-bottom-up
     projectile-root-top-down-recurring))
  (projectile-completion-system 'ivy))

(use-package counsel-projectile
  :ensure t
  :after counsel projectile
  :config
  (counsel-projectile-mode))

Search

(use-package ag
  :ensure t
  :defer t
  :ensure-system-package (ag . silversearcher-ag)
  :custom
  (ag-highlight-search t "Highlight the current search term."))

(use-package dumb-jump
  :ensure t
  :defer t
  :custom
  (dumb-jump-selector 'ivy)
  (dumb-jump-prefer-searcher 'ag))

Autocompletion

Company. There’s also Auto-Complete as an alternative.

(use-package company
  :ensure t
  :bind
  (:map company-active-map
        ("C-n" . company-select-next-or-abort)
        ("C-p" . company-select-previous-or-abort))
  :hook
  (after-init . global-company-mode))

(use-package company-quickhelp
  :ensure t
  :defer t
  :custom
  (company-quickhelp-delay 3)
  (company-quickhelp-mode 1))

(use-package company-shell
  :ensure t
  :after company
  :defer t
  :custom-update
  (company-backends '(company-shell)))

Use hippie-expand

(use-package hippie-exp
  :bind
  ([remap dabbrev-expand] . hippie-expand))

Snippets

(use-package autoinsert
  :hook
  (find-file . auto-insert))

(use-package yasnippet
  :defer 0.1
  :ensure t
  :custom
  (yas-prompt-functions '(yas-completing-prompt))
  :config
  (yas-reload-all)
  :hook
  ((prog-mode feature-mode)  . yas-minor-mode))

(use-package doom-snippets
  :defer t
  :quelpa
  (doom-snippets
   :repo "hlissner/doom-snippets"
   :fetcher github
   :files ("*" (:exclude ".*" "README.md")))
  :after yasnippet)

Checking/linting

(use-package flycheck
  :ensure t
  :hook
  (prog-mode . flycheck-mode))

(use-package avy-flycheck
  :ensure t
  :defer t
  :config
  (avy-flycheck-setup))

(use-package cov
  :ensure t
  :defer t)

Languages support

https://imgs.xkcd.com/comics/lisp_cycles.png

Emacs Lisp

(use-package lisp
  :hook
  (after-save . check-parens))

(use-package elisp-mode
  :bind
  (:map emacs-lisp-mode-map
        ("C-c C-d C-d" . describe-function)
        ("C-c C-d d" . describe-function)
        ("C-c C-k" . eval-buffer)))

(use-package highlight-defined
  :ensure t
  :custom
  (highlight-defined-face-use-itself t)
  :hook
  (help-mode . highlight-defined-mode)
  (emacs-lisp-mode . highlight-defined-mode))

(use-package highlight-quoted
  :ensure t
  :hook
  (emacs-lisp-mode . highlight-quoted-mode))

(use-package highlight-sexp
  :quelpa
  (highlight-sexp :repo "daimrod/highlight-sexp" :fetcher github :version original)
  :hook
  (clojure-mode . highlight-sexp-mode)
  (emacs-lisp-mode . highlight-sexp-mode)
  (lisp-mode . highlight-sexp-mode))

(use-package eros
  :ensure t
  :hook
  (emacs-lisp-mode . eros-mode))

(use-package suggest
  :ensure t
  :defer t)

(use-package ipretty
  :defer t
  :ensure t
  :config
  (ipretty-mode 1))

(use-package nameless
  :ensure t
  :hook
  (emacs-lisp-mode .  nameless-mode)
  :custom
  (nameless-global-aliases '())
  (nameless-private-prefix t))

;; bind-key can't bind to keymaps
(use-package erefactor
  :ensure t
  :defer t)

(use-package flycheck-package
  :ensure t
  :hook
  (emacs-lisp-mode . flycheck-package-setup))

(use-package elsa
  :defer t
  :ensure t)

(use-package flycheck-elsa
  :ensure t
  :hook
  (emacs-lisp-mode . flycheck-elsa-setup))

;; (use-package dash
;;   :custom
;;   (dash-enable-fontlock t))

Scheme

(use-package geiser
  :ensure t
  :defer t)

Clojure

(use-package clojure-mode
  :ensure t
  :defer t
  :config
  (define-clojure-indent
    (pfor 1)
    (if-let-failed? 'defun)
    (if-let-ok? 'defun)
    (when-let-failed? 'defun)
    (when-failed 'defun)
    (when-let-ok? 'defun)
    (attempt-all 'defun)
    (alet 'defun)
    (mlet 'defun)))

(use-package clj-refactor
  :defer t
  :ensure t)

(use-package anakondo
  :ensure t
  :hook
  (clojure-mode . anakondo-minor-mode)
  (clojurescript-mode . anakondo-minor-mode)
  (clojurec-mode . anakondo-minor-mode))

(use-package flycheck-clj-kondo
  :ensure t)

(use-package clojure-snippets
  :ensure t
  :defer t)

(use-package cider
  :ensure t
  :defer t
  :custom
  (cider-repl-display-help-banner nil))

(use-package kibit-helper
  :ensure t
  :defer t)

Common Lisp

Disabled for now…

(use-package slime
  :ensure t
  :disabled
  :config
  (setq inferior-lisp-program "/usr/bin/sbcl"
        lisp-indent-function 'common-lisp-indent-function
        slime-complete-symbol-function 'slime-fuzzy-complete-symbol
        slime-startup-animation nil)
  (slime-setup '(slime-fancy)))

Erlang

(use-package erlang
  :ensure t
  :defer t
  :custom
  (erlang-compile-extra-opts '(debug_info))
  :config
  (require 'erlang-start))


(use-package company-erlang
  :ensure t
  :hook
  (erlang-mode #'company-erlang-init))

Go

(use-package go-mode
  :ensure t
  :defer t
  :bind
  (:map go-mode-map
        ("M-." . godef-jump)
        ("M-]" . next-error)
        ("M-[" . previous-error))
  :hook
  (before-save . gofmt-before-save)
  :custom
  (gofmt-command "goimports")
  :init
  (setenv "GO111MODULE" "on")
  (or (getenv "GOPATH")
      (setenv "GOPATH" (expand-file-name "~/go")))
  (setenv "PATH" (concat (getenv "GOPATH") "/bin" ":" (getenv "PATH"))))

(use-package company-go
  :after go-mode
  :ensure t
  :defer t
  :config
  (push 'company-go company-backends))

(use-package go-guru
  :ensure t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package flycheck-golangci-lint
  :ensure t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

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

Lua

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

JS

(use-package conkeror-minor-mode
  :ensure t
  :disabled
  :defer t
  :hook
  (js-mode . (lambda ()
               (when (string-match "conkeror" (or (buffer-file-name) ""))
                 (conkeror-minor-mode 1)))))

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

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

Shell

(use-package sh-script
  :mode (("zshecl" . sh-mode)
         ("\\.zsh\\'" . sh-mode))
  :custom
  ;; zsh
  (system-uses-terminfo nil))

(use-package executable
  :hook
  (after-save . executable-make-buffer-file-executable-if-script-p))

Configuration files

(use-package apt-sources-list
  :ensure t)

(use-package ssh-config-mode
  :ensure t
  :init
  (autoload 'ssh-config-mode "ssh-config-mode" t)
  :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))

Markup

(use-package markdown-mode
  :ensure t
  :ensure-system-package markdown
  :mode (("\\`README\\.md\\'" . gfm-mode)
         ("\\.md\\'"          . markdown-mode)
         ("\\.markdown\\'"    . markdown-mode))
  :custom
  (markdown-command "markdown"))

(use-package jira-markup-mode
  :ensure t
  :defer t
  :after atomic-chrome
  :mode ("\\.confluence$" . jira-markup-mode)
  :custom-update
  (atomic-chrome-url-major-mode-alist
   '(("atlassian\\.net$" . jira-markup-mode))))

Misc

(use-package csv-mode
  :ensure t
  :mode
  (("\\.[Cc][Ss][Vv]\\'" . csv-mode)))

(use-package groovy-mode
  :defer t
  :ensure t
  :custom
  (groovy-indent-offset 2))

(use-package jenkinsfile-mode
  :defer t
  :quelpa
  (jenkinsfile-mode :repo "john2x/jenkinsfile-mode" :fetcher github))

(use-package aql-mode
  :defer t
  :quelpa
  (aql-mode :repo "a13/aql-mode" :fetcher github)
  :mode
  (("\\.arango$" . aql-mode)))


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

HTTP

(use-package restclient
  :ensure t
  :mode
  ("\\.http\\'" . restclient-mode))

(use-package restclient-test
  :ensure t
  :hook
  (restclient-mode-hook . restclient-test-mode))

(use-package ob-restclient
  :ensure t
  :after org restclient
  :init
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((restclient . t))))

(use-package company-restclient
  :ensure t
  :after (company restclient)
  :custom-update
  (company-backends '(company-restclient)))

External utilities

Network

(use-package net-utils
  :ensure-system-package traceroute
  :bind
  (:map mode-specific-map
        :prefix-map net-utils-prefix-map
        :prefix "n"
        ("p" . ping)
        ("i" . ifconfig)
        ("w" . iwconfig)
        ("n" . netstat)
        ("p" . ping)
        ("a" . arp)
        ("r" . route)
        ("h" . nslookup-host)
        ("d" . dig)
        ("s" . smbclient)
        ("t" . traceroute)))

Docker

(use-package docker
  :ensure t
  :bind
  (:map mode-specific-map
        ("d" . docker)))

;; not sure if these two should be here
(use-package dockerfile-mode
  :ensure t
  :defer t
  :mode "Dockerfile\\'")

(use-package docker-compose-mode
  :ensure t
  :defer t)

Kubernetes

(use-package k8s-mode
  :ensure t
  :hook (k8s-mode . yas-minor-mode))

(use-package kubernetes
  :ensure t
  :commands (kubernetes-overview))

Misc

Tmux interaction

(use-package emamux
  :ensure t
  :defer t)

Debian stuff

(use-package debian-el
  :ensure t
  :defer t)

Shortcuts with non-English layout.

(use-package unipunct-ng
  :quelpa
  (unipunct-ng
   :fetcher url
   :url "https://raw.githubusercontent.com/a13/xkb-custom/master/contrib/unipunct-ng.el"))

(use-package reverse-im
  :ensure t
  :demand t
  :after unipunct-ng char-fold
  :bind
  ("M-T" . reverse-im-translate-word)
  :custom
  (reverse-im-char-fold t)
  (reverse-im-read-char-advice-function #'reverse-im-read-char-exclude)
  (reverse-im-input-methods '("russian-unipunct-ng"))
  :config
  (reverse-im-mode t))

The end…

;; Local Variables:
;; eval: (add-hook 'after-save-hook (lambda () (let ((inhibit-redisplay t) (inhibit-message t) (emacs-lisp-mode-hook '())) (org-babel-tangle))) nil t)
;; End:
;;; init.el ends here